MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ savitzky_golay()

MAYAFLUX_API std::vector< double > MayaFlux::Kinesis::Discrete::savitzky_golay ( size_t  window,
size_t  poly_order,
size_t  derivative = 0 
)

Savitzky-Golay FIR coefficients for smoothing or differentiation.

Fits a polynomial of degree poly_order to a sliding window by least squares and evaluates the requested derivative of that fit at the window centre. With derivative 0 this smooths while preserving peak shape better than a boxcar of the same length; with derivative 1 or 2 it estimates rate of change with far less noise amplification than a raw finite difference, since the differentiation acts on the fitted polynomial rather than on the samples.

This is the block and node form of the kernel that Kinesis::Differential::backward_difference computes per sample on glm types. The streaming form divides by an observed dt and handles irregular timing; this form assumes uniform spacing and returns coefficients in sample units, so a caller needing physical units scales by 1 / dt^derivative.

Returned in FIR tap order: index 0 multiplies the newest sample. Group delay is (window - 1) / 2 samples.

Parameters
windowKernel length, forced odd, must exceed poly_order
poly_orderDegree of the fitted polynomial
derivativeWhich derivative of the fit to evaluate; 0 smooths
Returns
Coefficient vector of length window, or empty if window <= poly_order

Definition at line 323 of file Coefficients.cpp.

324{
325 const size_t n = force_odd(window);
326 if (n <= poly_order || derivative > poly_order)
327 return {};
328
329 const auto rows = static_cast<Eigen::Index>(n);
330 const auto cols = static_cast<Eigen::Index>(poly_order) + 1;
331 const double half = static_cast<double>(n - 1) * 0.5;
332
333 Eigen::MatrixXd vandermonde(rows, cols);
334 for (Eigen::Index i = 0; i < rows; ++i) {
335 const double z = static_cast<double>(i) - half;
336 double p = 1.0;
337 for (Eigen::Index j = 0; j < cols; ++j) {
338 vandermonde(i, j) = p;
339 p *= z;
340 }
341 }
342
343 const Eigen::MatrixXd pseudo = vandermonde
344 .completeOrthogonalDecomposition()
345 .pseudoInverse();
346
347 double factorial = 1.0;
348 for (size_t k = 2; k <= derivative; ++k)
349 factorial *= static_cast<double>(k);
350
351 const Eigen::VectorXd row = pseudo.row(static_cast<Eigen::Index>(derivative)) * factorial;
352
353 std::vector<double> h(n);
354 for (size_t i = 0; i < n; ++i)
355 h[i] = row(static_cast<Eigen::Index>(n - 1 - i));
356
357 return h;
358}
uint32_t rows
uint32_t h
Definition InkPress.cpp:29
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23

References h, rows, and window.