CadFromIc#

class mobgap.cadence.CadFromIc(
*,
step_time_smoothing: BaseFilter = cf(HampelFilter(half_window_size=2, n_sigmas=3.0)),
max_interpolation_gap_s: int = 3,
)[source]#

Calculate cadence per second directly from initial contacts.

This method will directly take the initial contacts provided in to the calculate method and calculate the cadence per second from them. We further assume that the initial contacts are sorted and that the first initial contact is the start of the passed data and the last initial contact is the end of a passed data.

Note

This method does not recalculate the initial contacts, but uses the passed initial contacts directly. Hence, it assumes that you want to use the same IC detector for the cadence calculation as for the IC detection. If you want to use a different IC detector for the cadence calculation, you should use the CadFromIcDetector, which will internally use the passed IC detector to calculate the initial contacts again just for the cadence calculation.

This uses a robust outlier removal approach to deal with missing initial contacts. The output cadence is reported as the average for each 1 second bin within the data. Note that an incomplete second at the end is included, to make sure that the entire data range is covered.

Regions (i.e. second bouts) with no initial contacts are interpolated linearly based on the surrounding values, if the gap is smaller than the specified maximum interpolation gap. Regions without initial contacts that are larger than the specified maximum interpolation gap or at the very start or end of the recording are filled with NaNs.

For more details see the Notes section.

Parameters:
step_time_smoothing

The filter used to smooth the step time. This is used to remove outliers in the step time/cadence (e.g. when initial contacts are not detected). The filter is applied twice, once to the raw step time and a second time on the interpolated step time 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.

Other Parameters:
data

The raw IMU data in the body passed to the calculate method.

initial_contacts

The initial contacts passed to the calculate method.

sampling_rate_hz

The sampling rate of the IMU data in Hz passed to the calculate method.

Attributes:
cadence_per_sec_

The main output of the cadence calculation. It provides a DataFrame with the column cadence_spm that contains the cadence values with one value per full second of the provided data. The unit is 1/min. The index of this dataframe is named sec_center_samples and contains the sample number of the center of the each second.

Notes

The full process of calculating the cadence per second from initial contacts is as follows:

  1. We calculate the step time from the initial contacts. This results in one less step time than initial contacts. We replicate the last step time to get the same number of step times as initial contacts, to also provide a cadence value for the last initial contact for the last part of a gait sequence.

  2. We smooth the step time to remove outliers (using a Hampel filter by default).

  3. We calculate the step time per second by averaging the step time 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 time over the second. The step time 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.

  4. We smooth the step time per second again to remove outliers on a per second level.

  5. We calculate the cadence per second by taking the inverse of the step time per second.

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:

  1. The original Matlab implementation calculates the cadence first (before any smoothing) or interpolation, while we perform all calculations on the step time and only calculate the cadence at the very end. The reasoning behind that is that because cadence is calculated by taking an inverse, it is much harder to reason about outliers in the cadence values. Because of this “projection” it is also much harder to reason about what the effect of linear interpolation on the cadence values is.

  2. 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.

  3. 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.

  4. The original Matlab implementation extrapolates missing values at the start and end of the recording, by simply repeating the first/last value. This was done, to make sure that subsequent calculations don’t need to deal with NaNs, but can easily mask issues in the ic-detection.

Methods

calculate(data, *, initial_contacts, ...)

Calculate cadence from the passed data and initial contacts..

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__(
*,
step_time_smoothing: BaseFilter = cf(HampelFilter(half_window_size=2, n_sigmas=3.0)),
max_interpolation_gap_s: int = 3,
) None[source]#
calculate(
data: DataFrame,
*,
initial_contacts: DataFrame,
sampling_rate_hz: float,
**_: Unpack[dict[str, Any]],
) Self[source]#

Calculate cadence from the passed data and initial contacts..

Parameters:
data

The raw IMU data in the body frame. 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 ic that 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 cadence_per_sec_ attribute set to the calculated cadence.

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.

set_params(**params: Any) Self[source]#

Set the parameters of this Algorithm.

To set parameters of nested objects use nested_object_name__para_name=.

Examples using mobgap.cadence.CadFromIc#

The Mobilise-D pipeline: Step-by-Step Breakdown

The Mobilise-D pipeline: Step-by-Step Breakdown

Cadence from Initial Contacts

Cadence from Initial Contacts

Cadence Evaluation

Cadence Evaluation