Skip to contents

This function applies a Savitzky-Golay filter to smooth movement data while preserving higher moments (peaks, valleys) better than moving average filters. The implementation uses zero-phase filtering to prevent temporal shifts in the data.

Usage

filter_sgolay(
  x,
  sampling_rate,
  window_size = ceiling(sampling_rate/10) * 2 + 1,
  order = 3,
  preserve_edges = FALSE,
  na_action = "linear",
  keep_na = FALSE,
  ...
)

Arguments

x

Numeric vector containing the movement data to be filtered

sampling_rate

Sampling rate of the data in Hz. Must match your data collection rate (e.g., 60 for 60 FPS motion capture).

window_size

Window size in samples (must be odd). Controls the amount of smoothing. Larger windows give more smoothing but may over-attenuate genuine movement features. Default is automatically calculated as sampling_rate/10 (rounded up to nearest odd number).

order

Polynomial order (default = 3). Controls how well the filter preserves higher-order moments in the data: - order=2: Preserves position, velocity (good for smooth movements) - order=3: Also preserves acceleration (good for most movement data) - order=4: Also preserves jerk (good for quick movements) - order=5: Maximum preservation (may retain too much noise)

preserve_edges

Logical indicating whether to use progressively smaller windows at the beginning and end of the signal to reduce edge effects (default = FALSE). Note: This only affects the signal endpoints, not internal discontinuities.

na_action

Method to handle NA values before filtering. One of: - "linear": Linear interpolation (default) - "spline": Spline interpolation for smoother curves - "locf": Last observation carried forward - "value": Replace with a constant value - "error": Raise an error if NAs are present

keep_na

Logical indicating whether to restore NAs to their original positions after filtering (default = FALSE)

...

Additional arguments passed to replace_na()

Value

Numeric vector containing the filtered movement data

Details

The Savitzky-Golay filter fits successive polynomials to sliding windows of the data. This approach preserves higher moments of the data better than simple moving averages or Butterworth filters, making it particularly suitable for movement data where preserving features like peaks and valleys is important.

Edge Handling: When preserve_edges = TRUE, the function uses progressively smaller windows near the beginning and end of the signal to reduce endpoint distortion. This only affects the signal endpoints - it does not detect or handle internal discontinuities or sharp events within the data.

Parameter Selection Guidelines:

  • window_size:

    • For 60 FPS: 5-15 frames (83-250ms) for quick movements, 15-31 for slow movements

    • For 120 FPS: 7-21 frames (58-175ms) for quick movements, 21-51 for slow movements

    • For 500 FPS: 25-75 frames (50-150ms) for quick movements, 75-151 for slow movements The default window_size = sampling_rate/10 works well for typical human movement.

  • order:

    • order=2: Smooth movements, position analysis

    • order=3: Most movement analysis (default)

    • order=4: Quick movements, sports analysis

    • order=5: Very quick movements, impact analysis Note: order must be less than window_size

Common values by application:

  • Gait analysis (60 FPS): window_size=15, order=3

  • Sports biomechanics (120 FPS): window_size=21, order=4

  • Impact analysis (500 FPS): window_size=51, order=4

  • Posture analysis (60 FPS): window_size=31, order=2

References

Savitzky, A., & Golay, M.J.E. (1964). Smoothing and Differentiation of Data by Simplified Least Squares Procedures. Analytical Chemistry, 36(8), 1627-1639.

See also

filter_lowpass for frequency-based filtering sgolayfilt for the base Savitzky-Golay implementation replace_na for details on NA handling methods

Examples

# Generate example movement data: smooth motion + noise
t <- seq(0, 5, by = 1/60)  # 60 FPS data
x <- sin(2*pi*0.5*t) + rnorm(length(t), 0, 0.1)

# Basic filtering with default parameters (60 FPS)
filtered <- filter_sgolay(x, sampling_rate = 60)

# Adjusting parameters for quick movements
filtered_quick <- filter_sgolay(x, sampling_rate = 60,
                               window_size = 11, order = 4)

# High-speed camera data (500 FPS) with larger window
filtered_high <- filter_sgolay(x, sampling_rate = 500,
                              window_size = 51, order = 3)