skdh.utility.math.moving_sd#

skdh.utility.math.moving_sd(a, w_len, skip, trim=True, axis=-1, return_previous=True)#

Compute the moving sample standard deviation.

Parameters:
aarray-like

Signal to compute moving sample standard deviation for.

w_lenint

Window length in number of samples.

skipint

Window start location skip in number of samples.

trimbool, optional

Trim the ends of the result, where a value cannot be calculated. If False, these values will be set to NaN. Default is True.

axisint, optional

Axis to compute the moving standard deviation along. Default is -1.

return_previousbool, optional

Return previous moments. These are computed either way, and are therefore optional returns. Default is True.

Returns:
msdnumpy.ndarray

Moving sample standard deviation. Note that if the moving axis is not the last axis, then the result will not be c-contiguous.

mmeannumpy.ndarray, optional.

Moving mean. Note that if the moving axis is not the last axis, then the result will not be c-contiguous. Only returned if return_previous=True.

Warning

Catastropic cancellation is a concern when skip is less than wlen due to the cumulative sum-type algorithms being used, when input values are very very large, or very very small. With typical IMU data values this should not be an issue, even for very long data series (multiple days worth of data).

Notes

On the moving axis, the output length can be computed as follows:

\[\frac{n - w_{len}}{skip} + 1\]

where n is the length of the moving axis. For cases where skip != 1 and trim=False, the length of the return on the moving axis can be calculated as:

\[\frac{n}{skip}\]

Most efficient computations are for skip values that are either factors of wlen, or greater or equal to wlen.

Examples

Compute the with non-overlapping windows:

>>> import numpy as np
>>> x = np.arange(10)**2
>>> moving_sd(x, 3, 3, return_previous=True)
(array([ 2.081666  ,  8.02080628, 14.0118997 ]),
 array([ 1.66666667, 16.66666667, 49.66666667]))

Compute with overlapping windows:

>>> moving_mean(x, 3, 1, return_previous=False)
array([ 2.081666  ,  4.04145188,  6.02771377,  8.02080628, 10.0166528 ,
       12.01388086, 14.0118997 , 16.01041328])

Compute without trimming:

>>> moving_mean(x, 3, 1, trim=False, return_previous=False)
array([ 2.081666  ,  4.04145188,  6.02771377,  8.02080628, 10.0166528 ,
       12.01388086, 14.0118997 , 16.01041328, nan, nan])

Compute on a nd-array to see output shape. On the moving axis, the output should be equal to \((n - w_{len}) / skip + 1\).

>>> n = 500
>>> window_length = 100
>>> window_skip = 50
>>> shape = (3, n, 5, 10)
>>> y = np.random.random(shape)
>>> res = moving_sd(y, window_length, window_skip, axis=1, return_previous=False)
>>> print(res.shape)
(3, 9, 5, 10)

Check flags for different axis output

>>> z = np.random.random((10, 10, 10))
>>> moving_sd(z, 3, 3, axis=0, return_previous=False).flags['C_CONTIGUOUS']
False
>>> moving_sd(z, 3, 3, axis=1, return_previous=False).flags['C_CONTIGUOUS']
False
>>> moving_sd(z, 3, 3, axis=2, return_previous=False).flags['C_CONTIGUOUS']
True