GithubHelp home page GithubHelp logo

gaitmap's People

Contributors

aksei avatar akuederle avatar dprossel avatar livhe avatar maltebastelt avatar malteolle avatar matthiaszuerl avatar nilsroth avatar raulsimpetru avatar richrobe avatar ullrimar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

gaitmap's Issues

HMM labeled training issue

@nilsroth I think there was a bug in the training code for labeled training of the combined model

In this code snippet, you are attempting to set the only the edges that are not there yet.
However, you assume that the e.g. the entry for state transition 15 to 16 is at position (15, 16) in the transition matrix. However, because of the "sorting" bug in pomegranate this is not the case.
In result, some edges are not written and some edges are overwritten, eventhough they exist already.

# Add missing transitions which will "connect" transition-hmm and stride-hmm
for trans in transitions:
# if edge already exists, skip
if not model_untrained.dense_transition_matrix()[trans[0], trans[1]]:
add_transition(model_untrained, ["s%d" % (trans[0]), "s%d" % (trans[1])], 0.1)

I fixed that by getting the existing transitions based on the actual statenames and checking based on that.

Could you check, if the same issue exists in your old training code?

With my fix, the train-hmm example now produces an actual usable HMM :)

[INFO] HMM training is not reproducible

For some reason the hmm training example is not fully reproducible...

After some fixes it seems to work consistently on my machine, but running it as a Github action still produces different results.
As the stride output is still consistent (even though the actual model has slight differences), I commented out the part of the test, but I would like to understand what is going on...

Stride definition for the `stride_list` argument of event detection

Dear all,

if I remember correctly, then in the Hannink et al. (2018) paper different definitions for the strides were used (e.g., midstance-to-midstance versus initial contact-to-initial contact versus msDTW).

Now, when I want to detect specific gait events from my inertial sensor data, I need to supply the event detection algorithm, e.g., RamppEventDetection, with the stride_list. Does it matter which definition I use for the strides? Or is the only requirement that there are no gaps between subsequent strides? So could I theoretically also define my strides from midswing-to-midswing, for example?

Best regards,
Robbin

HMM pre-processing fails if sampling rate is not a multiple of 51.2

The "naive" upsampling implemnted here does not work with samplingrates that are not a even multiple

def inverse_transform_state_sequence(self, state_sequence: np.ndarray, *, sampling_rate_hz: float) -> np.ndarray:
"""Inverse transform a state sequence to the original sampling rate.
Parameters
----------
state_sequence
The state sequence to be transformed back to the original sampling rate.
This is done by repeating each state for the number of samples it was downsampled to.
sampling_rate_hz
The sampling rate of the original data in Hz
Returns
-------
The state sequence in the original sampling rate
"""
return np.repeat(state_sequence, sampling_rate_hz / self.sampling_rate_feature_space_hz)

We should use proper interpolation using "nearest"

@HaMora @Aksei Jelena wanted to fix this I think? Any updates? And if she does not have time, could one of you have a look at that?

Contribution guide

We should have a short Contribution guide in the README and a longer guide in the guide section

Pomegranate is set to optional but is required

pomegranate is set to optional in pyproject but it is contained in gaitmap/base.py

Ideas for solution:

  • try-catch the import
  • move import to the places where it is needed
  • make pomegranate non-optional

@AKuederle: what would you prefer and do you have any other suggestion?

Make downloading the example data easier

If installing gaitmap from github, we don't include the example data.
We expect users to download the files manually. However, this requires them to download the files one-by-one via the Github interface, which can be annoying.

Maybe we can provide an automatic function that downloads the files via the github API?

Maybe pooch can handle this?

Change names for global axis to `gx`, `gy`, and `gz`

To clearly indicate the coordinate system we are working in, global positions and orientations should be marked as gx, gy, and gz instead of just xyz.

This would need to be changed in the pos and ori methods, the Spatial Para Calculation, some examples and the general documentation.

Swapping accelerometer and gyroscope data?

Dear all,

it is a bit confusing how accelerometer and gyroscope data are used in the Madgwick AHRS implementation. When the data are enumerated over, the naming of acc and gyro seems to be swapped. Eventually, two and three lines below this is compensated for by calling:

            gyro=acc_val,
            acc=gyro_val,

but would it not make more sense to just change the zip order, e.g., for i, (acc_val, gyro_val) in enumerate(zip(acc, gyro)): and have:

            gyro=gyro_val,
            acc=acc_val,

Best regards,
Robbin

Tests fail if pomegrenate not installed

Steps to reproduce:

  1. clone repository
  2. poetry install
  3. poetry run poe test

Result:

poetry run poe test
Poe => pytest --cov=gaitmap --cov=gaitmap_mad --cov-report=term-missing --cov-report=xml
ImportError while loading conftest '.../gaitmap/tests/conftest.py'.
tests\conftest.py:9: in <module>
    from pomegranate import GeneralMixtureModel, State
E   ModuleNotFoundError: No module named 'pomegranate'

Expected Result:
Should work...

Suggestion:

  • either: add info to README that developers need to install pomegrenate (and also statsmodels) if they want to run tests
    . or: skip pomegranate tests if it is not installed

Per Column Transformer

First suggestion for a PerColumnTransformer

class PerColumnTransformer(BaseTransformer, TrainableTransformerMixin):
    transformer: BaseTransformer
    per_column_transformer: OptimizableParameter[Optional[List[Tuple[str, BaseTransformer]]]]

    def __init__(
        self, transformer: BaseTransformer, *, per_col_transformer: Optional[List[Tuple[str, BaseTransformer]]] = None
    ):
        self.transformer = transformer
        self.per_col_transformer = per_col_transformer

    def transform(self, data: SingleSensorData, **kwargs) -> Self:
        self.data = data
        transformed_data = {}
        # We either used the per column transformer that are already created during self_optimize or we create them
        # here.
        # Note, that we don't store them in the parameters, when they are created here, because this is the "action"
        # method and we don't want to modify parameters in an action method.
        per_col_transformer = self.per_col_transformer or [
            (col_name, self.transformer.clone()) for col_name in data.columns
        ]
        for col_name, transformer in per_col_transformer:
            transformed_data[col_name] = transformer.clone().transform(data[col_name], **kwargs).transformed_data_
        self.transformed_data_ = pd.concat(transformed_data, axis=1)
        return self

    def self_optimize(self, data: Sequence[SingleSensorData], **kwargs) -> Self:
        # If there is no per_col_transformer set yet, we create one transformer for each column.
        if self.per_col_transformer is None:
            self.per_col_transformer = [(col_name, self.transformer.clone()) for col_name in data[0].columns]
        optimized_transformers = []
        for col_name, transformer in self.per_col_transformer:
            if isinstance(transformer, TrainableTransformerMixin):
                transformer = transformer.self_optimize([d[[col_name]] for d in data], **kwargs)
            optimized_transformers.append((col_name, transformer.clone()))

        self.per_col_transformer = optimized_transformers
        return self

Direction of two synchronized sensors

Hi,

I'm having a problem with rotation to sensor frame definition. My sensors are placed in the same orientation as in the example you give, so I apply this as in the example:

# rotate left_sensor first by -90 deg around the z-axis, followed by a -90 deg rotation around the x-axis. As the rotation matrix is multiplied from the left, the rotation matrix  results in:
left_rot = rotation_from_angle(np.array([1, 0, 0]), np.deg2rad(-90)) * rotation_from_angle(
    np.array([0, 0, 1]), np.deg2rad(-90)
)

# rotate right_sensor first by +90 deg around the z-axis, followed by a +90 deg rotation around the x-axis
right_rot = rotation_from_angle(np.array([1, 0, 0]), np.deg2rad(90)) * rotation_from_angle(
    np.array([0, 0, 1]), np.deg2rad(90)
)

rotations = dict(left_sensor=left_rot, right_sensor=right_rot)

The problem is that when I reconstruct the trajectory, my 2 sensors seem to be pointing in opposite directions, whereas they are mounted on a person walking with both legs in the same direction.

traj_reconstruction

Is this a problem you've experienced before?

Stricter dtype checks for integers

With pandas 2.0 and higher, some type conversion got stricter or are not allowed anymore (e.g. you can not convert from float to the new Int64 dtype with safe casting.

To provide better error messages to the user, we should check if the conversion to integeres works for things like stride lists in the is_stride_list (and similar method) and provide actionable error messages

Preprocessing functions should leave additional columns untouched and potentially support magnetometers directly

At the moment preprocessing functions for rotation and coordinate transformation only rotate acc and gyr data.

All other columns are actually removed from the dataset. While we don't have any algorithms that support anything besides acc and gyr data at the moment, it would be nice to allow users that have additional columns (i.e. mag or baro) to use the pre-processing functions without any additional work.

In particular the magnetometer would require special attention, as we would need to define a sensor and a body frame for it and explicitly rotate it as part of the respective functions.

This was first suggested in #50

Tests fail on windows

Steps to reproduce:

  • Windows 10
  • clone
  • poetry install
  • pip install pomegranate==0.14.2
  • pip install statsmodels
  • poetry run poe test

Result:

FAILED tests/test_data_transforms/test_feature_transformer.py::TestResample::test_resample_roi_list - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_evaluation_utlis/test_parameter_errors.py::TestCalculateAggregatedParameterErrors::test_doctest - assert 3 == 0
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_single_window_fit[NormZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_single_window_fit[AredZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w4_default_overlap[NormZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w4_default_overlap[AredZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w3[NormZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w3[AredZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w6_default_overlap[NormZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_max_overlap_metric_max_w6_default_overlap[AredZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_real_data_regression[NormZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestNormZuptDetector::test_real_data_regression[AredZuptDetector] - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_moving_window_zupt_detector.py::TestShoeZuptDetector::test_real_data_regression - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_stride_event_zupt_detector.py::TestStrideEventZuptDetector::test_region_0 - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_stride_event_zupt_detector.py::TestStrideEventZuptDetector::test_edge_case - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_stride_event_zupt_detector.py::TestStrideEventZuptDetector::test_with_overlap - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
FAILED tests/test_zupt_detection/test_stride_event_zupt_detector.py::TestStrideEventZuptDetector::test_simple - AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="start") are different
===================================================================== 17 failed, 2077 passed, 41 skipped, 157 warnings in 577.91s (0:09:37) ======================================================================

Pypi

Remember we need to publish to seperate packages to Pypi and then update our dev dependencies

-> Note: we should also test, if installing from a subdir still works correctly when installing from the git repo

Docu for pretrained HMM

@nilsroth HMM branch is merged ;) The only thing missing is a little bit of docu about your pre-trained model.

I.e. what dataset was it trained on, what specifications, what to expect with regards to performance, when to use it/when not to use it. Could you write a couple of sentences? If you just put it in the response here, I will add it to the code.

Thanks!

Cannot rotate a given dataset

Hi all,

I am trying to integrate the gaitmap algorithsm in our workflow. Currently I am looking into 9-DOF IMU data from a low back-worn, left foot-worn and right foot-worn IMU that is already time-synchronized. I have prepared the data as a pandas DataFrame with a multi-index column header, and accelerometer data in m/s^2, gyroscope data in deg/s, and magnetometer data in Gauss.

Now, the data for the right foot is not in the gaitmap coordinate system (the +x axis points backwards, the +y axis points to the lateral side, i.e., data needs to be rotated by 180 degrees around the +z axis (that points up)). Therefore I constructed the following dictionary of rotation matrix:

rotation_matrics = {
      "left_foot": np.eye(3),
      "right_foot": np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]),
      "low_back": np.eye(3)
  }

and then I wanted to automatically align the sensor data with the gaitmap coordinate systems:

from gaitmap.utils.rotations import rotate_dataset
rotated_data = rotate_dataset(data, rotation_matrices)

However, this gives me an error:
Exception has occurred: AttributeError 'numpy.ndarray' object has no attribute 'apply' File "D:\Projects\Brescia\main.py", line 34, in main rotated_data = rotate_dataset(data, rotation_matrics) File "D:\Projects\Brescia\main.py", line 40, in <module> main() AttributeError: 'numpy.ndarray' object has no attribute 'apply'

Any idea how to resolve this?

Best from Kiel,
Robbin

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.