Sensor Motion

Provides tools for analyzing sensor-collected human motion data. This includes, for example, estimation of gait dynamics from accelerometer data, and conversion to physical activity (MVPA) counts from acceleration. Also contains a few useful functions for pre-processing and visualizing accelerometer signals.

This package was primarily developed for use on Android sensor data collected at the Attentional Neuroscience Lab (University of British Columbia).

Accessing Documentation

Documentation is available via docstrings provided with the code, and an online API reference found at ReadTheDocs.

To view documentation for a function or module, first make sure the package has been imported:

>>> import sensormotion as sm

Then, use the built-in help function to view the docstring for any module or function:

>>> help(sm.gait)
>>> help(sm.peak.find_peaks)

Package Overview

gait module
Calculate various types of gait dynamics (cadence, symmetry etc.)
pa module
Calculate physical activity (PA) levels with conversion to activity counts
peak module
Detect peaks and valleys in a signal
plot module
Wrapper functions for creating simple graphs
signal module
Signal processing tools such as filtering and cross-correlation
utils module
General utility functions used throughout the package

Module Reference

sensormotion.gait module

Calculate gait dynamics.

Functions for the calculation of variance gait dynamics from acceleration data (e.g. step symmetry, cadence).

cadence(time, peak_times, time_units='ms')[source]

Calculate cadence of the current signal.

Cadence (steps per minute) can be estimated by detecting peaks in the acceleration vector. Given 1) the duration of the signal and 2) the number of steps/peaks in the signal, we can calculate an estimate of steps per minute.

Peak detection provides number of steps within the time frame of the signal. This is then extrapolated from milliseconds to minutes to estimate cadence.

Parameters:
  • time (ndarray) – Time vector of the original acceleration signal. Used to calculate duration of the input signal.
  • peak_times (ndarray) – Time of each peak, returned by sensormotion.peak.find_peaks(). This provides the number of steps within the timeframe of the signal.
  • time_units ({‘ms’, ‘s’}, optional) – Units of the time signal.
Returns:

cadence – Estimated cadence for the input signal.

Return type:

float

step_count(peak_times)[source]

Count total number of steps in the signal.

This is simply the number of peaks detected in the signal.

Parameters:peak_times (ndarray) – Times of the peaks detected by sensormotion.peak.find_peaks().
Returns:step_count – Number of steps/peaks in the signal.
Return type:int
step_regularity(autocorr_peak_values)[source]

Calculate step and stride regularity from autocorrelation peak values.

Step and stride regularity measures based on Moe-Nilssen (2004) - Estimation of gait cycle characteristics by trunk accelerometry.

If calculating regularity from acceleration in the vertical axis, this function receives the detected peaks from the vertical axis autocorrelation.

However, if calculating regularity from lateral axis acceleration, you should pass in both peaks and valleys from the autocorrelation of the lateral axis.

Step regularity:

Perfect step regularity will be 1.0 for vertical axis autocorrelation (the larger the better, capped at 1.0).

For the lateral axis, perfect regularity is -1.0 (the smaller the better, capped at -1.0).

Stride regularity:

Perfect stride regularity will be 1.0 for vertical axis autocorrelation (the larger the better, capped at 1.0).

Lateral axis sign and interpretation are the same as the vertical axis.

Parameters:autocorr_peak_values (ndarray) – Values of the autocorrelation peaks/valleys detected by sensormotion.peak.find_peaks(). This should contain only peak values when looking at the vertical axis, and both peak and valley values when looking at the lateral axis.
Returns:
  • step_reg (float) – Step regularity. Value is capped at 1.0 or -1.0 depending on the axis of interest.
  • stride_reg (float) – Stride regularity. Capped at 1.0 for both vertical and lateral axes.
step_symmetry(autocorr_peak_values)[source]

Calculate step symmetry from autocorrelation peak values.

Step symmetry measures based on Moe-Nilssen (2004) - Estimation of gait cycle characteristics by trunk accelerometry.

If calculating symmetry from acceleration in the vertical axis, this function receives the detected peaks from the vertical axis autocorrelation.

However, if calculating symmetry from lateral axis acceleration, you should pass in both peaks and valleys from the autocorrelation of the lateral axis.

Perfect step symmetry is 1.0 for the vertical axis - larger values are more symmetric, capped at 1.0.

Perfect step symmetry is -1.0 for the lateral axis - smaller values are more symmetric, capped at -1.0.

Parameters:autocorr_peak_values (ndarray) – Values of the autocorrelation peaks/valleys detected by sensormotion.peak.find_peaks(). This should contain only peak values when looking at the vertical axis, and both peak and valley values when looking at the lateral axis.
Returns:step_sym – Step symmetry. Value is capped at 1.0 or -1.0 depending on the axis of interest.
Return type:float
step_time(peak_times)[source]

Calculate step timing information.

Step timing can be calculated from the peak times of the original acceleration signal. This includes mean time between steps, standard deviation of step time, and the coefficient of variation (sd/mean).

Parameters:peak_times (ndarray) – Times of the peaks detected by sensormotion.peak.find_peaks().
Returns:
  • step_time_mean (float) – Mean time between all steps/peaks in the signal.
  • step_time_sd (float) – Standard deviation of the distribution of step times in the signal.
  • step_time_cov (float) – Coefficient of variation. Calculated as sd/mean.

sensormotion.pa module

Calculate physical activity (PA) levels with conversion to activity counts.

Functions for converting raw sensor data to physical activity (PA) or moderate-to-vigorous physical activity (MVPA) counts, similar to those given by dedicated accelerometers such as Actigraph devices.

For a uniaxial accelerometer, the signal should first be passed into sensormotion.pa.convert_counts(), then the counts should categorized using sensormotion.pa.cut_points().

For a triaxial accelerometer, an additional step is required. Each axis should first be passed into sensormotion.pa.convert_counts() separately, then the 3 count vectors should be passed into sensormotion.signal.vector_magnitude() to calculate vector magnitude (VM) of the counts. Finally, the single VM vector should be categorized using sensormotion.pa.cut_points().

convert_counts(x, time, time_scale='ms', epoch=60, rectify='full', integrate='simpson', plot=False, fig_size=(10, 5))[source]

Convert acceleration to physical activity (PA) counts.

Given an acceleration signal over a single axis, integrate the signal for each time window (epoch). The area under the curve for each epoch is the physical activity count for that time period.

Linearly interpolated values are used if exact multiples of epoch are not found in the time signal.

Parameters:
  • x (ndarray) – Acceleration signal to be converted to PA counts.
  • time (ndarray) – Time signal associated with x.
  • time_scale ({‘ms’, ‘s’}, optional) – The unit that time is measured in. Either seconds (s) or milliseconds (ms).
  • epoch (int, optional) – The duration of each time window in seconds. Counts will be calculated over this period. PA counts are usually measured over 60 second epochs. sensormotion.pa.cut_points() also requires 60 second epochs, however, if you’re using your own cut point set and just want raw count values feel free to use any sized epoch.
  • rectify ({‘full’, ‘half’}, optional) – Type of rectifier to use on the input acceleration signal. This is to ensure that PA counts take into consideration negative acceleration values. Full-wave rectification turns all negative values into positive ones. Half-wave rectification sets all negative values to zero.
  • integrate ({‘simpson’, ‘trapezoid’}, optional) – Integration method to use for each epoch.
  • plot (bool, optional) – Toggle to display a plot of PA counts over time.
  • fig_size (tuple, optional) – If plotting, set the width and height of the resulting figure.
Returns:

counts – PA count values for each epoch.

Return type:

ndarray

cut_points(x, set_name, n_axis, plot=False, fig_size=(10, 5))[source]

Categorize physical activity (PA) counts into intensity categories.

Use a pre-specified cut-point set to determine the intensity level of each epoch of PA. Cut-point sets are from published research articles, and a summary can be found in the Actigraph FAQ: https://actigraph.desk.com/customer/en/portal/articles/2515803-what-s-the-difference-among-the-cut-points-available-in-actilife

Important: The cut-point sets used here assume each count epoch is 60 seconds long. If you’re using counts from sensormotion.pa.convert_counts() make sure you had set the value of epoch to 60. Don’t use this function if you use different length epochs.

Parameters:
  • x (ndarray) – Vector of counts calculated by sensormotion.pa.convert_counts() or vector magnitude from sensormotion.signal.vector_magnitude(). This can either be from a single axis or a vector magnitude, but set the n_axis parameter accordingly.

  • set_name ({‘butte_preschoolers’, ‘freedson_adult’, ‘freedson_children’, ‘keadle_women’}) – The name of the cut-point set to use.

    These are listed in the Actigraph FAQ, and the corresponding research article is shown below:

    butte_preschoolers: Butte et al. (2013) - Prediction of Energy Expenditure and Physical Activity in Preschoolers

    freedson_adult (uniaxial): Freedson et al. (1998) - Calibration of the Computer Science and Applications, Inc. accelerometer

    freedson_adult (triaxial): Freedson et al. (2011) - Validation and Comparison of ActiGraph Activity Monitors

    freedson_children: Freedson et al. (2005) - Calibration of accelerometer output for children

    keadle_women: Keadle et al. (2014) - Impact of accelerometer data processing decisions on the sample size, wear time and physical activity level of a large cohort study

  • n_axis ({1, 3}) – Number of axes over which acceleration was recorded (1 = uniaxial, 3 = triaxial accelerometer). This is used to determine the cut-point set values to use as some sets are for counts over a single axis, whereas others are thresholds for vector magnitude (calculated from 3 axes).

  • plot (bool, optional) – Toggle to display a plot of PA counts with category thresholds marked.

  • fig_size (tuple, optional) – If plotting, set the width and height of the resulting figure.

Returns:

  • category (list) – List of intensity categories for each epoch of PA, as determined by the cut-point set thresholds.
  • time_spent (ndarray) – Amount of time (counts) spent at each PA intensity level.

sensormotion.peak module

Peak detection algorithms.

This modules contains functions for detecting peaks and valleys in signals. Signals can also be detrended by estimating a baseline prior to peak detection.

Based on work by Lucas Hermann Negri.

find_peaks(time, signal, peak_type='peak', min_val=0.5, min_dist=25, detrend=0, plot=False, show_grid=True, fig_size=(10, 5))[source]

Find peaks in a signal.

Calculate and return the peaks and/or valleys of a signal. Can optionally detrend a signal before peak detection. A plot can be created that displays the original signal with overlaid peaks and valleys.

Parameters:
  • time (ndarray) – Time vector (X-axis) component of the input signal.
  • signal (ndarray) – Value (Y-axis) of the signal over time.
  • peak_type ({‘peak’, ‘valley’, ‘both’}, optional) – Type of peaks to be detected. peak will return positive peaks. valley will return negative peaks. both will return both peaks and valleys. Peak indices are calculated by calling sensormotion.peak.indexes().
  • min_val (float between [0., 1.], optional) – Normalized threshold. Only the peaks with amplitude higher than the threshold will be detected.
  • min_dist (int, optional) – Minimum distance between each detected peak. The peak with the highest amplitude is preferred to satisfy this constraint.
  • detrend (int, optional) – Degree of the polynomial that will estimate the data baseline. A low degree may fail to detect all the baseline present, while a high degree may make the data too oscillatory, especially at the edges. A value of 0 will not apply any baseline detrending. The baseline for detrending is calculated by sensormotion.signal.baseline().
  • plot (bool, optional) – Toggle to create a plot of the signal with peaks/valleys overlaid.
  • show_grid (bool, optional) – If creating a plot, toggle to show grid lines
  • fig_size (tuple, optional) – If creating a plot, set the width and height of the resulting figure.
Returns:

  • peak_times (ndarray) – Array containing the time of each peak.
  • peak_values (ndarray) – Array containing the value of each peak.
  • signal_detrended (ndarray, optional) – If detrend has been selected (detrend > 0), an additional array is returned containing the detrended signal.

indexes(y, thres=0.3, min_dist=1)[source]

Peak detection routine.

Finds the numeric index of the peaks in y by taking its first order difference. By using thres and min_dist parameters, it is possible to reduce the number of detected peaks. y must be signed.

Parameters:
  • y (ndarray (signed)) – 1D amplitude data to search for peaks.
  • thres (float between [0., 1.]) – Normalized threshold. Only the peaks with amplitude higher than the threshold will be detected.
  • min_dist (int) – Minimum distance between each detected peak. The peak with the highest amplitude is preferred to satisfy this constraint.
Returns:

peak_indexes – Array containing the numeric indexes of the peaks that were detected

Return type:

ndarray

sensormotion.plot module

Matplotlib plotting functions.

Convenience wrappers around common matplotlib pyplot plot calls. This module simplifies the creation of filter frequency response curves and general signal plots over time.

plot_filter_response(frequency, sample_rate, filter_type, filter_order=2, show_grid=True, fig_size=(10, 5))[source]

Plot filter frequency response.

Generate a plot showing the frequency response curve of a filter with the specified parameters.

Parameters:
  • frequency (int or tuple of ints) – The cutoff frequency for the filter. If filter_type is set as ‘bandpass’ then this needs to be a tuple of integers representing the lower and upper bound frequencies. For example, for a bandpass filter with range of 2Hz and 10Hz, you would pass in the tuple (2, 10). For filter types with a single cutoff frequency then a single integer should be used.
  • sample_rate (float) – Sampling rate of the signal.
  • filter_type ({‘lowpass’, ‘highpass’, ‘bandpass’, ‘bandstop’}) – Type of filter to build.
  • filter_order (int, optional) – Order of the filter.
  • show_grid (bool, optional) – Toggle to show grid lines on the plot.
  • fig_size (tuple, optional) – Tuple containing the width and height of the resulting figure.
plot_signal(time, signal, title='', xlab='', ylab='', line_width=1, alpha=1, color='k', subplots=False, show_grid=True, fig_size=(10, 5))[source]

Plot signals over time.

Convenience wrapper around pyplot to quickly create plots of signals over time. This is useful if you want to avoid remembering the syntax for matplotlib.

Parameters:
  • time (ndarray) – Time vector of the signal (X-axis)

  • signal (ndarray or list of dicts) – If plotting a single line, you can pass in a single array.

    If you want to plot multiple lines (either on the same plot, or as subplots) you should pass in a list of dictionaries. Each dictionary represents a separate line and contains options for that line. The dictionary can hold the follow keys: ‘data’ (required), ‘label’, ‘color’, ‘alpha’, ‘line_width’.

    For example, a 2 line plot can be created like this:

    >>> plot.plot_signal(time_array, [{'data': line1_data,
                                       'label': 'line 1',
                                       'color': 'b'},
                                      {'data': line2_data,
                                       'label': 'second line',
                                       'line_Width': 4}])
    
  • title (str, optional) – Title of the plot.

  • xlab (str, optional) – Label for the x axis.

  • ylab (str, optional) – Label for the y axis.

  • line_width (int or float, optional) – Width of the plot lines.

  • alpha (int or float, optional) – Alpha of the plot lines.

  • color (str, optional) – Colour of the plot lines. Receives a string following the matplotlib colors API: http://matplotlib.org/api/colors_api.html

  • subplots (bool, optional) – If multiple lines are passed in, should they be displayed on the same plot (False)? Or should each be displayed in separate subplots (True)?

  • show_grid (bool, optional) – Toggle to display grid lines on the plot.

  • fig_size (tuple, optional) – Set the figure size of the resulting plot.

sensormotion.signal module

Signal-processing functions.

Functions for pre-processing signals (e.g. filtering, cross-correlation). Mostly wrappers around numpy/scipy functions, but with some sane defaults and calculation of required values (e.g. Nyquist frequency and associated cutoff).

baseline(y, deg=None, max_it=None, tol=None)[source]

Computes the baseline of a given data.

Iteratively performs a polynomial fitting in the data to detect its baseline. At every iteration, the fitting weights on the regions with peaks are reduced to identify the baseline only.

Parameters:
  • y (ndarray) – Data to detect the baseline.
  • deg (int) – Degree of the polynomial that will estimate the data baseline. A low degree may fail to detect all the baseline present, while a high degree may make the data too oscillatory, especially at the edges.
  • max_it (int) – Maximum number of iterations to perform.
  • tol (float) – Tolerance to use when comparing the difference between the current fit coefficients and the ones from the last iteration. The iteration procedure will stop when the difference between them is lower than tol.
Returns:

baseline – Array with the baseline amplitude for every original point in y

Return type:

ndarray

build_filter(frequency, sample_rate, filter_type, filter_order)[source]

Build a butterworth filter with specified parameters.

Calculates the Nyquist frequency and associated frequency cutoff, and builds a Butterworth filter from the parameters.

Parameters:
  • frequency (int or tuple of ints) – The cutoff frequency for the filter. If filter_type is set as ‘bandpass’ then this needs to be a tuple of integers representing the lower and upper bound frequencies. For example, for a bandpass filter with range of 2Hz and 10Hz, you would pass in the tuple (2, 10). For filter types with a single cutoff frequency then a single integer should be used.
  • sample_rate (float) – Sampling rate of the signal.
  • filter_type ({‘lowpass’, ‘highpass’, ‘bandpass’, ‘bandstop’}) – Type of filter to build.
  • filter_order (int, optional) – Order of the filter.
Returns:

  • b (ndarray) – Numerator polynomials of the IIR filter.
  • a (ndarray) – Denominator polynomials of the IIR filter.

detrend_signal(signal, degree)[source]

Detrend a signal.

Detrends a signal using a polynomial fit with the specified degree.

Parameters:
  • signal (ndarray) – Signal values to detrend.
  • degree (int) – Degree of the polynomial that will estimate the data baseline. A low degree may fail to detect all the baseline present, while a high degree may make the data too oscillatory, especially at the edges. A value of 0 will not apply any baseline detrending. The baseline for detrending is calculated by sensormotion.signal.baseline().
Returns:

detrended_signal – Detrended form of the original signal.

Return type:

ndarray

fft(signal, sampling_rate, plot=False, show_grid=True, fig_size=(10, 5))[source]

Perform FFT on signal.

Compute 1D Discrete Fourier Transform using Fast Fourier Transform. Optionally, plot the power spectrum of the frequency domain.

Parameters:
  • signal (ndarray) – Input array to be transformed.
  • sampling_rate (float) – Sampling rate of the input signal.
  • plot (bool, optional) – Toggle to display a plot of the power spectrum.
  • show_grid (bool, optional) – If creating a plot, toggle to show grid lines on the figure.
  • fig_size (tuple, optional) – If plotting, set the width and height of the resulting figure.
Returns:

signal_fft – Transformation of the original input signal.

Return type:

ndarray

filter_signal(b, a, signal)[source]

Filter a signal.

Simple wrapper around scipy.signal.filtfilt() to apply a foward-backward filter to preserve phase of the input. Requires the numerator and denominator polynomials from sensormotion.signal.build_filter().

Parameters:
  • b (ndarray) – Numerator polynomial coefficients of the filter.
  • a (ndarray) – Denominator polynomial coefficients of the filter.
  • signal (ndarray) – Input array to be filtered.
Returns:

signal_filtered – Filtered output of the original input signal.

Return type:

ndarray

rectify_signal(signal, rectifier_type='full', plot=False, show_grid=True, fig_size=(10, 5))[source]

Rectify a signal.

Run a signal through a full or half-wave rectifier. Optionally plot the resulting signal.

Parameters:
  • signal (ndarray) – Input signal to be rectified.
  • rectifier_type ({‘full’, ‘half’}, optional) – Type of rectifier to use. Full-wave rectification turns all negative values into positive ones. Half-wave rectification sets all negative values to zero.
  • plot (bool, optional) – Toggle to display a plot of the rectified signal.
  • show_grid (bool, optional) – If creating a plot, toggle to show grid lines on the figure.
  • fig_size (tuple, optional) – If plotting, set the width and height of the resulting figure.
Returns:

output – Rectified signal.

Return type:

ndarray

vector_magnitude(*args)[source]

Calculate the vector magnitude/euclidean norm of multiple vectors.

Given an arbitrary number of input vectors, calculate the vector magnitude/euclidean norm using the Pythagorean theorem.

Parameters:*args (ndarray) – Each parameter is a numpy array representing a single vector. Multiple vectors can be passed in, for example, vector_magnitude(x, y, z)
Returns:vm – Vector magnitude across all input vectors.
Return type:ndarray
xcorr(x, y, scale='none', plot=False, show_grid=True, fig_size=(10, 5))[source]

Cross-correlation between two 1D signals.

Calculate the cross-correlation between two signals for all time lags (forwards and backwards). If the inputs are different lengths, zeros will be appended to the shorter input.

All 4 scaling options (none, biased, unbiased, and coeff) reproduce the output from MATLAB’s xcorr() function.

Optionally, plots can be created to visualize the cross-correlation values at each lag.

Parameters:
  • x (ndarray) – First input signal.
  • y (ndarray) – Second input signal. Pass in x again for autocorrelation.
  • scale ({‘none’, ‘biased’, ‘unbiased’, ‘coeff’}, optional) – Scaling options for the cross-correlation values. Replicates MATLAB’s options for scaling.
  • plot (bool, optional) – Toggle to display a plot of the cross-correlations.
  • show_grid (bool, optional) – If creating a plot, toggle to show grid lines on the figure.
  • fig_size (tuple, optional) – If plotting, set the width and height of the resulting figure.
Returns:

  • corr (ndarray) – Cross-correlation values.
  • lags (ndarray) – Lags for the cross-correlations.

sensormotion.utils module

Utility functions used across the rest of the package.

ceildiv(a, b)[source]

Ceiling division.

Divide and round up the result.

Parameters:
  • a (int or float) – dividend (numerator) to be divided.
  • b (int or float) – divisor (denominator) to divide by.
Returns:

result – quotient of the division, rounded up to the nearest integer.

Return type:

float