mad-lab-fau / gaitmap Goto Github PK
View Code? Open in Web Editor NEWThe Gait and Movement Analysis Package
Home Page: https://gaitmap.readthedocs.io
License: Other
The Gait and Movement Analysis Package
Home Page: https://gaitmap.readthedocs.io
License: Other
@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.
gaitmap/gaitmap/future/hmm/segmentation_model.py
Lines 281 to 285 in ff2a333
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 :)
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...
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
We should have a short Contribution guide in the README and a longer guide in the guide section
pomegranate is set to optional in pyproject but it is contained in gaitmap/base.py
Ideas for solution:
@AKuederle: what would you prefer and do you have any other suggestion?
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?
We should add tests testing spatial para calc with partial infos and an IC stride list
In the main explanation at the top of the docstring, we should cite the papers that the algorithm is based on.
We do that sometimes, but we are not very consistent with it.
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.
We should add an image to the spatial parameter estimation showing which angles and distances we actually provide.
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
Steps to reproduce:
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:
pomegrenate
(and also statsmodels
) if they want to run testsAt the moment, we focus on spatial-temporal parameters. However, there are a bunch of raw signal features that might be interesting as well.
For example, gait smoothness seems to be promising:
https://www.mdpi.com/1424-8220/20/12/3577]
https://www.mdpi.com/1660-4601/19/20/13440
https://www.sciencedirect.com/science/article/abs/pii/S0966636222005355?via%3Dihub
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
Add tests for 3.10 and 3.11 in the CI. Note that we can not include pomegranate tests there
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.
Is this a problem you've experienced before?
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
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
Pomegrante, the library currently used for HMMs is currently rewritten using a torch backend.
This is expected to solve many of the outstanding issues of pomegrante.
Once the new version matures, we should check, if it is possible to migrate to it.
Steps to reproduce:
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) ======================================================================
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
@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!
Current validation method are geared towards stride by stride validation.
We should also add methods to compare aggregated parameters. I.e. parameters averaged over a gait test/entire day
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.