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_width = ceiling(sampling_rate/10) * 2 + 1,
order = 3,
na_action = "linear",
keep_na = TRUE,
...
)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_width
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)
- na_action
Method used to fill
NAvalues before filtering, so the filter sees a complete series. One of"linear"(default),"spline","stine","locf","value", or"error"to abort whenNAs are present. Filling is internal: whether the filled values reach the output is controlled bykeep_na.- keep_na
Logical. If
TRUE(default), positions that wereNAin the input areNAin the output — gaps stay gaps. IfFALSE, the values used to fill those gaps are kept, so the output has fewerNAs than the input and genuinely-missing stretches come back as interpolated estimates.- ...
Additional arguments passed to replace_na_with()
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.
Edges are handled by signal::sgolayfilt() using extrapolation from the
nearest interior polynomial fit, which is the standard Savitzky-Golay
edge convention.
Parameter Selection Guidelines:
window_width:
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_width = 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_width
Common values by application:
Gait analysis (60 FPS): window_width=15, order=3
Sports biomechanics (120 FPS): window_width=21, order=4
Impact analysis (500 FPS): window_width=51, order=4
Posture analysis (60 FPS): window_width=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
replace_na_with() 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_width = 11, order = 4)
# High-speed camera data (500 FPS) with larger window
filtered_high <- filter_sgolay(x, sampling_rate = 500,
window_width = 51, order = 3)