Skip to content

Inertial measurement unit (IMU)

Inertial measurement units (IMUs) are electronic devices that measure and report a body's specific force (acceleration and angular velocity) and orientation (roll, pitch, and yaw). IMU signals are often used to measure activity, posture, and gait. In PhysioKit, we provide a variety of routines for processing IMU signals.

physiokit.imu.clean

clean(data, lowcut=3, highcut=11, sample_rate=1000, order=3, axis=-1)

Clean accelerometer signal using biquad filter.

By default applies a 3rd order Butterworth filter between 0.5 and 4 Hz.

Parameters:

  • data (NDArray) –

    Accelerometer signal

  • lowcut (float, default: 3 ) –

    Lower cutoff in Hz. Defaults to 3 Hz.

  • highcut (float, default: 11 ) –

    Upper cutoff in Hz. Defaults to 11 Hz.

  • sample_rate (float, default: 1000 ) –

    Sample rate in Hz. Defaults to 1000 Hz.

  • order (int, default: 3 ) –

    Filter order. Defaults to 3 (3rd order Butterworth filter).

  • axis (int, default: -1 ) –

    Axis to apply against. Defaults to -1.

Returns:

  • NDArray

    npt.NDArray: Cleaned signal

Source code in physiokit/imu/clean.py
def clean(
    data: npt.NDArray,
    lowcut: float = 3,
    highcut: float = 11,
    sample_rate: float = 1000,
    order: int = 3,
    axis: int = -1,
) -> npt.NDArray:
    """Clean accelerometer signal using biquad filter.

    By default applies a 3rd order Butterworth filter between 0.5 and 4 Hz.

    Args:
        data (npt.NDArray): Accelerometer signal
        lowcut (float, optional): Lower cutoff in Hz. Defaults to 3 Hz.
        highcut (float, optional): Upper cutoff in Hz. Defaults to 11 Hz.
        sample_rate (float, optional): Sample rate in Hz. Defaults to 1000 Hz.
        order (int, optional): Filter order. Defaults to 3 (3rd order Butterworth filter).
        axis (int, optional): Axis to apply against. Defaults to -1.

    Returns:
        npt.NDArray: Cleaned signal
    """

    return filter_signal(
        data=data,
        lowcut=lowcut,
        highcut=highcut,
        sample_rate=sample_rate,
        order=order,
        forward_backward=True,
        axis=axis,
    )

physiokit.imu.metrics

compute_counts(data, sample_rate=1000, epoch_len=10, min_thresh=4, max_thresh=128)

Compute counts from raw accelerometer data.

Reference: https://doi.org/10.1038/s41598-022-16003-x

Parameters:

  • data (NDArray) –

    2-D raw accelerometer data [ts x axis] in G.

  • sample_rate (float, default: 1000 ) –

    Sampling rate in Hz. Defaults to 1000 Hz.

  • epoch_len (int, default: 10 ) –

    Epoch length in seconds. Defaults to 10.

  • min_thresh (int, default: 4 ) –

    Minimum threshold. Defaults to 4.

  • max_thresh (int, default: 128 ) –

    Maximum threshold. Defaults to 128.

Returns:

  • NDArray

    npt.NDArray: 2-D counts data [ts x axis] in counts.

Source code in physiokit/imu/metrics.py
def compute_counts(
    data: npt.NDArray, sample_rate: float = 1000, epoch_len: int = 10, min_thresh: int = 4, max_thresh: int = 128
) -> npt.NDArray:
    """Compute counts from raw accelerometer data.

    Reference: https://doi.org/10.1038/s41598-022-16003-x

    Args:
        data (npt.NDArray): 2-D raw accelerometer data [ts x axis] in G.
        sample_rate (float, optional): Sampling rate in Hz. Defaults to 1000 Hz.
        epoch_len (int, optional): Epoch length in seconds. Defaults to 10.
        min_thresh (int, optional): Minimum threshold. Defaults to 4.
        max_thresh (int, optional): Maximum threshold. Defaults to 128.

    Returns:
        npt.NDArray: 2-D counts data [ts x axis] in counts.
    """

    # 1. Resample to 30 Hz
    data = resample_signal(data, sample_rate=sample_rate, target_rate=30, axis=0)

    # 2. Bandpass filter
    data = _count_bpf_filter(data)

    # 3. Rectify, & threshold
    data = np.abs(data)
    data[data < min_thresh] = 0
    data[data > max_thresh] = max_thresh
    data = np.floor(data)

    # 4. Downsample to 10 Hz by taking moving average (n=3)
    data = np.nanmean(data.reshape((-1, 3, data.shape[1])), axis=1)

    # 5. Find counts by summing over epoch length
    counts = np.zeros((data.shape[0] // (10 * epoch_len),) + data.shape[1:], dtype=int)
    for i in range(0, counts.shape[0]):
        counts[i] = np.sum(data[i * 10 * epoch_len : (i + 1) * 10 * epoch_len], axis=0)
    # END FOR

    return counts

compute_enmo(x, y, z)

Compute ENMO from x, y, and z accelerometer data.

Reference: https://doi.org/10.1371/journal.pone.0142533

Parameters:

  • x (NDArray) –

    x-axis accelerometer data

  • y (NDArray) –

    y-axis accelerometer data

  • z (NDArray) –

    z-axis accelerometer data

Returns:

  • NDArray

    npt.NDArray: ENMO data

Source code in physiokit/imu/metrics.py
def compute_enmo(x: npt.NDArray, y: npt.NDArray, z: npt.NDArray) -> npt.NDArray:
    """Compute ENMO from x, y, and z accelerometer data.

    Reference: https://doi.org/10.1371/journal.pone.0142533

    Args:
        x (npt.NDArray): x-axis accelerometer data
        y (npt.NDArray): y-axis accelerometer data
        z (npt.NDArray): z-axis accelerometer data

    Returns:
        npt.NDArray: ENMO data
    """
    enmo = np.maximum(np.sqrt(x**2 + y**2 + z**2) - 1, 0)
    return enmo

compute_tilt_angles(x, y, z, in_radians=True)

Compute tilt angles from x, y, and z accelerometer data.

Reference: https://doi.org/10.1371/journal.pone.0142533

Parameters:

  • x (NDArray) –

    x-axis accelerometer data

  • y (NDArray) –

    y-axis accelerometer data

  • z (NDArray) –

    z-axis accelerometer data

  • in_radians (bool, default: True ) –

    If True, return angles in radians. Defaults to True.

Returns:

  • tuple[NDArray, NDArray, NDArray]

    tuple[npt.NDArray, npt.NDArray, npt.NDArray]: Tilt angles in radians or degrees

Source code in physiokit/imu/metrics.py
def compute_tilt_angles(
    x: npt.NDArray, y: npt.NDArray, z: npt.NDArray, in_radians: bool = True
) -> tuple[npt.NDArray, npt.NDArray, npt.NDArray]:
    """Compute tilt angles from x, y, and z accelerometer data.

    Reference: https://doi.org/10.1371/journal.pone.0142533

    Args:
        x (npt.NDArray): x-axis accelerometer data
        y (npt.NDArray): y-axis accelerometer data
        z (npt.NDArray): z-axis accelerometer data
        in_radians (bool, optional): If True, return angles in radians. Defaults to True.

    Returns:
        tuple[npt.NDArray, npt.NDArray, npt.NDArray]: Tilt angles in radians or degrees

    """
    x2 = x**2
    y2 = y**2
    z2 = z**2
    factor = 1 if in_radians else 180.0 / np.pi
    angle_x = np.arctan2(x, np.sqrt(y2 + z2)) * factor
    angle_y = np.arctan2(y, np.sqrt(x2 + z2)) * factor
    angle_z = np.arctan2(z, np.sqrt(x2 + y2)) * factor
    return angle_x, angle_y, angle_z