extractors.pyGait

Module: extractors.pyGait

This program implements some of the feature extraction equations from:

“iGAIT: An interactive accelerometer based gait analysis system” Mingjing Yang, Huiru Zheng, Haiying Wang, Sally McClean, Dave Newell. 2012. Computer methods and programs in biomedicine 108:715-723. DOI:10.1016/j.cmpb.2012.04.004 http://www.ncbi.nlm.nih.gov/pubmed/22575802

iGait was written as a Matlab file and compiled as a Windows application. It assumes a fixed accelerometer position, and derived heel strike timings from an assumed anterior-posterior orientation along the y-axis.

iGAIT inputs ::
  • sample rate
  • threshold (anterior-posterior acceleration, to detect heel contact)
  • distance
iGAIT features ::
  • spatio-temporal features, from estimates of heel strikes:
    • cadence = number of steps divided by walking time
    • distance-based measures (mean step length, velocity)
  • regularity and symmetry (each direction):
    • step/stride regularity
    • symmetry
  • root mean square (each direction)

  • spectral features (each direction):
    • integral of the power spectral density (IPSD)
    • main frequency: frequency with the maximum value of PSD
    • frequencies when PSD is cumulated (CPSD)
pyGait functions compute all of iGAIT’s features except spectral features::
  • gait_features() for all heel strike-based estimates:
    • cadence
    • mean step length and velocity (if distance supplied)
    • regularity and symmetry (each direction)
  • root_mean_square():
    • root mean square (each direction)
Authors:

Copyright 2015, Sage Bionetworks (http://sagebase.org), Apache v2.0 License

Functions

mhealthx.extractors.pyGait.gait(strikes, data, duration, distance=None)

Extract gait features from estimated heel strikes and accelerometer data.

This function extracts all of iGAIT’s features that depend on the estimate of heel strikes:

- cadence = number of steps divided by walk time
- step/stride regularity
- step/stride symmetry
- mean step/stride length and velocity (if distance supplied)
strikes : numpy array
heel strike timings
data : list or numpy array
accelerometer data along forward axis
duration : float
duration of accelerometer reading (s)
distance : float
distance traversed
number_of_steps : integer
estimated number of steps based on heel strikes
velocity : float
velocity (if distance)
avg_step_length : float
average step length (if distance)
avg_stride_length : float
average stride length (if distance)
cadence : float
number of steps divided by duration
step_durations : numpy array
step durations
avg_step_duration : float
average step duration
sd_step_durations : float
standard deviation of step durations
strides : list of two lists of floats
stride timings for each side
avg_number_of_strides : float
estimated number of strides based on alternating heel strikes
stride_durations : list of two lists of floats
estimated stride durations
avg_stride_duration : float
average stride duration
sd_step_durations : float
standard deviation of stride durations
step_regularity : float
measure of step regularity along axis
stride_regularity : float
measure of stride regularity along axis
symmetry : float
measure of gait symmetry along axis
>>> from mhealthx.xio import read_accel_json, compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> from mhealthx.extractors.pyGait import heel_strikes
>>> threshold = 0.2
>>> order = 4
>>> cutoff = 5
>>> data = ay
>>> plot_test = False
>>> strikes, strike_indices = heel_strikes(data, sample_rate, threshold, order, cutoff, plot_test)
>>> from mhealthx.extractors.pyGait import gait
>>> distance = 90
>>> a = gait(strikes, data, duration, distance)
mhealthx.extractors.pyGait.gait_regularity_symmetry(data, step_period, stride_period)

Compute step and stride regularity and symmetry from accelerometer data.

The iGAIT software assumes that the y-axis is anterior-posterior, and restricts some feature extraction to this orientation. In this program, we compute every measure for an arbitrary axis.

From Yang, et al., 2012:

“The peak value a1 = NFC(t1), which is found at the t1 lag time to be a step period, indicates the step regularity in a direction. The peak value a2 = NFC(t2), which was found at the t2 lag time to be a stride period, indicates the stride regularity in a direction. The variance of the stride regularity and step regularity D = |a2 - a1, can be used as an indicator to measure gait asymmetry. A smaller value of D indicates a more symmetric gait. A larger value of D indicates a more asymmetric gait. In total, iGAIT extracts seven regularity and symmetry features from the acceleration data, namely

- Step regularity: vertical (VT), anterior-posterior (AP) directions
- Stride regularity: VT, AP, medial-lateral (ML) directions
- Symmetry: VT, AP directions
data : list or numpy array
accelerometer data for one (preferably forward) axis
step_period : integer
step period
stride_period : integer
stride period
step_regularity : float
step regularity measure along axis
stride_regularity : float
stride regularity measure along axis
symmetry : float
symmetry measure along axis
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.extractors.pyGait import gait_regularity_symmetry
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> data = ay
>>> step_period = 2
>>> stride_period = 1
>>> step_regularity, stride_regularity, symmetry = gait_regularity_symmetry(data, step_period, stride_period)
mhealthx.extractors.pyGait.heel_strikes(data, sample_rate, threshold=0.2, order=4, cutoff=5, plot_test=False, t=None)

Estimate heel strike times between sign changes in accelerometer data.

The iGAIT software assumes that the y-axis is anterior-posterior, and restricts some feature extraction to this orientation. In this program, we compute heel strikes for an arbitrary axis.

Re: heel strikes (from Yang, et al., 2012): “The heel contacts are detected by peaks preceding the sign change of AP acceleration [3]. In order to automatically detect a heel contact event, firstly, the AP acceleration is low pass filtered by the 4th order zero lag Butterworth filter whose cut frequency is set to 5 Hz. After that, transitional positions where AP acceleration changes from positive to negative can be identified. Finally the peaks of AP acceleration preceding the transitional positions, and greater than the product of a threshold and the maximum value of the AP acceleration are denoted as heel contact events... This threshold is defined as the ratio to the maximum value of the AP acceleration, for example 0.5 indicates the threshold is set at 50% of the maximum AP acceleration. Its default value is set to 0.4 as determined experimentally in this paper, where this value allowed correct detection of all gait events in control subjects. However, when a more irregular pattern is analysed, the threshold should be less than 0.4. The user can test different threshold values and find the best one according to the gait event detection results.”

data : list or numpy array
accelerometer data along one axis (preferably forward direction)
sample_rate : float
sample rate of accelerometer reading (Hz)
threshold : float
ratio to the maximum value of the anterior-posterior acceleration
order : integer
order of the Butterworth filter
cutoff : integer
cutoff frequency of the Butterworth filter (Hz)
plot_test : Boolean
plot heel strikes?
t : list or numpy array
accelerometer time points
strikes : numpy array of floats
heel strike timings
strike_indices : list of integers
heel strike timing indices
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.signals import compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> from mhealthx.extractors.pyGait import heel_strikes
>>> threshold = 0.4
>>> order = 4
>>> cutoff = max([1, sample_rate/10])
>>> plot_test = True
>>> data = np.abs(ax) + np.abs(ay) + np.abs(az)
>>> strikes, strike_indices = heel_strikes(data, sample_rate, threshold, order, cutoff, plot_test, t)
mhealthx.extractors.pyGait.project_axes(vectors, unit_vectors)

Project vectors on unit vectors.

vectors : list of lists of x, y, z coordinates or numpy array equivalent unit_vectors : list of lists of x, y, z coordinates (or numpy arrays)

unit vectors to project vectors onto
projection_vectors : list of lists of x, y, z coordinates
vectors projected onto unit vectors
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.signals import compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> vectors = zip(axyz[0], axyz[1], axyz[2])
>>> vectors = [vectors[0], vectors[1], vectors[2]]
>>> from mhealthx.extractors.pyGait import project_axes
>>> unit_vectors = [1, 1, 1]
>>> projection_vectors = project_axes(vectors, unit_vectors)
mhealthx.extractors.pyGait.project_walk_direction_attitude(ax, ay, az, uw, ux, uy, uz)

Project accelerometer data on local walk direction by attitude rotation.

ax : list or numpy array
x-axis accelerometer data
ay : list or numpy array
y-axis accelerometer data
az : list or numpy array
z-axis accelerometer data
uw : list or numpy array
w of attitude quaternion
ux : list or numpy array
x of attitude quaternion
uy : list or numpy array
y of attitude quaternion
uz : list or numpy array
z of attitude quaternion
px : numpy array
accelerometer data along x axis projected on unit vector
py : numpy array
accelerometer data along y axis projected on unit vector
pz : numpy array
accelerometer data along z axis projected on unit vector
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.signals import compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 0
>>> t, axyz, gxyz, wxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> uw, ux, uy, uz = wxyz
>>> from mhealthx.extractors.pyGait import project_walk_direction_attitude
>>> px, py, pz = project_walk_direction_attitude(ax, ay, az, uw, ux, uy, uz)
mhealthx.extractors.pyGait.project_walk_direction_preheel(ax, ay, az, t, sample_rate, stride_fraction, threshold, order, cutoff)

Project accelerometer data on local walk (not cardinal) direction.

NOTE::
This calls walk_direction_preheel(), which computes a single walk direction. It does NOT estimate walking direction for every time point, like walk_direction_attitude().
ax : numpy array
accelerometer data along x axis
ay : numpy array
accelerometer data along y axis
az : numpy array
accelerometer data along z axis
t : list or numpy array
accelerometer time points
sample_rate : float
sample rate of accelerometer reading (Hz)
stride_fraction : float
fraction of stride assumed to be deceleration phase of primary leg
threshold : float
ratio to the maximum summed acceleration to extract peaks
order : integer
order of the Butterworth filter
cutoff : integer
cutoff frequency of the Butterworth filter (Hz)
px : numpy array
accelerometer data along x axis projected on unit vector
py : numpy array
accelerometer data along y axis projected on unit vector
pz : numpy array
accelerometer data along z axis projected on unit vector
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.extractors.pyGait import project_walk_direction_preheel
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> stride_fraction = 1.0/8.0
>>> threshold = 0.5
>>> order = 4
>>> cutoff = max([1, sample_rate/10])
>>> px, py, pz = project_walk_direction_preheel(ax, ay, az, t, sample_rate, stride_fraction, threshold, order, cutoff)
mhealthx.extractors.pyGait.walk_direction_attitude(ax, ay, az, uw, ux, uy, uz, plot_test=False)

Estimate local walk (not cardinal) directions by rotation with attitudes.

Translated by Arno Klein from Elias Chaibub-Neto’s R code.

ax : list or numpy array
x-axis accelerometer data
ay : list or numpy array
y-axis accelerometer data
az : list or numpy array
z-axis accelerometer data
uw : list or numpy array
w of attitude quaternion
ux : list or numpy array
x of attitude quaternion
uy : list or numpy array
y of attitude quaternion
uz : list or numpy array
z of attitude quaternion
plot_test : Boolean
plot rotated vectors?
directions : list of lists of three floats
unit vector of local walk (not cardinal) direction at each time point
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.signals import compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 0
>>> t, axyz, gxyz, wxyz, rxyz, sample_rate, duration = read_accel_json(input_file, device_motion, start)
>>> ax, ay, az = axyz
>>> uw, ux, uy, uz = wxyz
>>> from mhealthx.extractors.pyGait import walk_direction_attitude
>>> plot_test = True
>>> directions = walk_direction_attitude(ax, ay, az, uw, ux, uy, uz, plot_test)
mhealthx.extractors.pyGait.walk_direction_preheel(ax, ay, az, t, sample_rate, stride_fraction=0.125, threshold=0.5, order=4, cutoff=5, plot_test=False)

Estimate local walk (not cardinal) direction with pre-heel strike phase.

Inspired by Nirupam Roy’s B.E. thesis: “WalkCompass: Finding Walking Direction Leveraging Smartphone’s Inertial Sensors,” this program derives the local walk direction vector from the end of the primary leg’s stride, when it is decelerating in its swing. While the WalkCompass relies on clear heel strike signals across the accelerometer axes, this program just uses the most prominent strikes, and estimates period from the real part of the FFT of the data.

NOTE::
This algorithm computes a single walk direction, and could compute multiple walk directions prior to detected heel strikes, but does NOT estimate walking direction for every time point, like walk_direction_attitude().
ax : list or numpy array
x-axis accelerometer data
ay : list or numpy array
y-axis accelerometer data
az : list or numpy array
z-axis accelerometer data
t : list or numpy array
accelerometer time points
sample_rate : float
sample rate of accelerometer reading (Hz)
stride_fraction : float
fraction of stride assumed to be deceleration phase of primary leg
threshold : float
ratio to the maximum value of the summed acceleration across axes
plot_test : Boolean
plot most prominent heel strikes?
direction : numpy array of three floats
unit vector of local walk (not cardinal) direction
>>> from mhealthx.xio import read_accel_json
>>> from mhealthx.signals import compute_sample_rate
>>> input_file = '/Users/arno/DriveWork/mhealthx/mpower_sample_data/deviceMotion_walking_outbound.json.items-a2ab9333-6d63-4676-977a-08591a5d837f5221783798792869048.tmp'
>>> device_motion = True
>>> start = 150
>>> t, axyz, gxyz, uxyz, rxyz, sample_rate, duration = read_accel_json(input_file, start, device_motion)
>>> ax, ay, az = axyz
>>> from mhealthx.extractors.pyGait import walk_direction_preheel
>>> threshold = 0.5
>>> stride_fraction = 1.0/8.0
>>> order = 4
>>> cutoff = max([1, sample_rate/10])
>>> plot_test = True
>>> direction = walk_direction_preheel(ax, ay, az, t, sample_rate, stride_fraction, threshold, order, cutoff, plot_test)