SlZijlstra#
- class mobgap.stride_length.SlZijlstra(
- *,
- orientation_method: BaseOrientationEstimation | None = None,
- acc_smoothing: BaseFilter = cf(ButterworthFilter(cutoff_freq_hz=0.1, filter_type='highpass', order=4, zero_phase=True)),
- speed_smoothing: BaseFilter = cf(ButterworthFilter(cutoff_freq_hz=1, filter_type='highpass', order=4, zero_phase=True)),
- step_length_smoothing: BaseFilter = cf(HampelFilter(half_window_size=2, n_sigmas=3.0)),
- max_interpolation_gap_s: float = 3,
- step_length_scaling_factor: float = 1.14675,
Implementation of the stride length algorithm by Zijlstra (2003) [1] modified by Soltani (2021) [2].
This algorithms uses an inverted pendulum model to estimate the step length. The step length is then “smoothed” using a robust outlier removal approach to deal with missing initial contacts. The output stride length is reported as the average for each 1 second bin within the data.
For more details see the Notes section.
This is based on the implementation published as part of the mobilised project [3]. However, this implementation deviates from the original implementation in some places. For details, see the notes section and the examples.
- Parameters:
- step_length_scaling_factor
The scaling factor for the Zijlstra biomechanical model. The final step length per step, will be scaled by this factor. Possible attributes are step_length_scaling_factor_ms_ms and step_length_scaling_factor_ms_all.
- acc_smoothing
Lowpass filter applied to the vertical acceleration before integration.
- speed_smoothing
Lowpass filter applied to the calculated vertical velocity for integration.
- step_length_smoothing
The filter used to smooth the step length. This is used to remove outliers in the step length (e.g. when initial contacts are not detected). The filter is applied twice, once to the raw step length and a second time on the interpolated step length values per second. We recommend to use a Hampel filter for this.
- max_interpolation_gap_s
The maximum gap in seconds that is interpolated. If the gap is larger than this value, the second is filled with NaNs. We don’t fill “gaps” at the start and end of the recording, as we assume that gait sequences are cut anyway to start and end with a valid initial contact.
- orientation_method
The orientation method for aligning the sensor axes with the global reference system. If this argument is not passed, orientation is not performed (default value: None).
- Other Parameters:
- data
The raw IMU data of the gait sequence passed to the
calculatemethod.- initial_contacts
The initial contacts passed to the
calculatemethod.- sampling_rate_hz
The sampling rate of the IMU data in Hz passed to the
calculatemethod.- sensor_height_m
Height of the sensor mounted on the lower-back in meters.
- Attributes:
- stride_length_per_sec_
The main output of the stride length calculation. It provides a DataFrame with the column
stride_length_mthat contains the stride length values with one value per full second of the provided data. The unit ism. The index of this dataframe is namedsec_center_samplesand contains the sample number of the center of the each second.- raw_step_length_per_step_
Secondary output. It provides a copy of the passed initial contact df with an additional column
step_length_mthat contains the estimated step length for each step. Note, that the df is one row shorter thant the passed list of ICs, as there is one less actual step then ICs.- step_length_per_sec_
Secondary output. A pandas dataframe of the same shape as
stride_length_per_sec_, but containing the intermediate step length values in a column calledstep_length_m
Notes
The core algorithm performs the following steps:
Sensor alignment (optional): Madgwick complementary filter
High-pass filtering –> lower cut-off: 0.1 Hz, filter design: Butterworth IIR, filter order: 4
Integration of vertical acceleration –> vertical speed
Drift removal (high-pass filtering) –> lower cut-off: 1 Hz, filter design: Butterworth IIR, filter order: 4
Integration of vertical speed –> vertical displacement d(t)
Compute total vertical displacement during the step (d_step):
\[d_step = |max(d(t)) - min(d(t))|\]Biomechanical model:
\[\text{StepLength} = A * 2 * \sqrt{2 * LBh * d_{step} - d_{step}^2}\]- A
tuning coefficient, optimized by grid search.
- LBh
sensor height in meters, representative of the height of the center of mass.
This output is then further post-processed and interpolated to second bins:
We calculate the step length from the initial contacts. This results in one less step time than initial contacts. We replicate the last step length to get the same number of step lengths as initial contacts, to also provide a step length value for the last initial contact for the last part of a gait sequence.
We smooth the step length to remove outliers (using a Hampel filter by default).
We calculate the step length per second by averaging the step length over the second. This is a little tricky, as some seconds might not contain any initial contacts. For all seconds that contain at least one initial contact, we calculate the average step length over the second. The step length for seconds without initial contacts is interpolated linearly based on the surrounding values. If the gap is larger than the specified maximum interpolation gap, the second is filled with NaNs. We don’t fill “gaps” at the start and end of the recording, as we assume that gait sequences are cut anyway to start and end with a valid initial contact.
We smooth the step length per second again to remove outliers on a per second level.
We multiply by 2 to convert from step length per second to stride length per second. This is an approximation and will not reflect the exact stride length of any individual stride.
In case there are less initial contacts than the window size of the smoothing filter, we return NaNs for all seconds.
This approach deviates from the original Matlab implementations in a couple of ways:
The original Matlab implementation has no concept of “maximum interpolation gap”. Values are interpolated by taking the average of the surrounding values, independent of the length of the gap. We decided to introduce a maximum interpolation gap to not mask “issues” in the ic-detection.
When values are interpolated, the original Matlab implementation uses the average of the surrounding values. We decided to use linear interpolation instead, as this is more robust to outliers. These approaches are identical, if we only need to interpolate a single value, but for larger gaps, linear interpolation will start favoring the “closer” neighboring values, which we think is more appropriate.
[1]W. Zijlstra, & A. L. Hof, “Assessment of spatio-temporal gait parameters from trunk accelerations during human walking” Gait & posture, vol. 18, no. 2, pp. 1-10, 2003.
[2]A. Soltani, et al. “Algorithms for walking speed estimation using a lower-back-worn inertial sensor: A cross-validation on speed ranges.” IEEE TNSRE, vol 29, pp. 1955-1964, 2021.
Methods
Predefined factors for scaling the step length model.
calculate(data, initial_contacts, *, ...)Calculate per-sec stride length values in the passed data..
clone()Create a new instance of the class with all parameters copied over.
get_params([deep])Get parameters for this algorithm.
set_params(**params)Set the parameters of this Algorithm.
- __init__(
- *,
- orientation_method: BaseOrientationEstimation | None = None,
- acc_smoothing: BaseFilter = cf(ButterworthFilter(cutoff_freq_hz=0.1, filter_type='highpass', order=4, zero_phase=True)),
- speed_smoothing: BaseFilter = cf(ButterworthFilter(cutoff_freq_hz=1, filter_type='highpass', order=4, zero_phase=True)),
- step_length_smoothing: BaseFilter = cf(HampelFilter(half_window_size=2, n_sigmas=3.0)),
- max_interpolation_gap_s: float = 3,
- step_length_scaling_factor: float = 1.14675,
- class PredefinedParameters[source]#
Predefined factors for scaling the step length model.
The step length scaling factor to be used in the biomechanical model. The provided values are optimized based on the MsProject dataset as part of the Mobilise-D project.
- Attributes:
- step_length_scaling_factor_ms_ms
Optimized factor based on all MS patients within the MsProject dataset. Default value for the
SlZijlstraalgorithm.- step_length_scaling_factor_ms_all
Optimized factor based on ALL participants within the MsProject dataset.
Examples
>>> SlZijlstra( ... max_interpolation_gap_s=2, ... **SlZijlstra.PredefinedParameters.step_length_scaling_factor_ms_ms, ... )
- calculate(
- data: DataFrame,
- initial_contacts: DataFrame,
- *,
- sampling_rate_hz: float,
- sensor_height_m: float,
- **_: Unpack[dict[str, Any]],
Calculate per-sec stride length values in the passed data..
- Parameters:
- data
The raw IMU data of a single sensor. We usually assume that this is one gait sequence (i.e. that there are no non-walking periods in the data).
- initial_contacts
The initial contacts of the gait sequence. This should be passed as a DataFrame with the colum
icthat contains the sample number of the initial contacts. We usually assume that the first IC marks the start of the passed gait sequence and the last IC marks the end.- sampling_rate_hz
The sampling rate of the IMU data in Hz.
- Returns:
- self
The instance of the class with the
stride_length_per_sec_list_attribute set to the estimated stride length per second values.
- clone() Self[source]#
Create a new instance of the class with all parameters copied over.
This will create a new instance of the class itself and all nested objects
- get_params(deep: bool = True) dict[str, Any][source]#
Get parameters for this algorithm.
- Parameters:
- deep
Only relevant if object contains nested algorithm objects. If this is the case and deep is True, the params of these nested objects are included in the output using a prefix like
nested_object_name__(Note the two “_” at the end)
- Returns:
- params
Parameter names mapped to their values.