1#include "internal/SavitskyGolay.h"
8SavitzkyGolay::SavitzkyGolay(
int radius,
int poly_order)
9 : window_radius_(radius)
10 , window_size_(2 * radius + 1)
11 , poly_order_(poly_order) {
13 assert(window_size_ > poly_order_);
15 compute_coefficients();
18std::vector<Point> SavitzkyGolay::filter(
const std::vector<Point>& data) {
19 if (data.size() < window_size_) {
23 std::vector<Point> result(data.size());
26 for (
size_t i = window_radius_; i < data.size() - window_radius_; ++i) {
28 for (
int j = -window_radius_; j <= window_radius_; ++j) {
29 val += data[i + j] * coeffs_[j + window_radius_];
36 for (
int i = 0; i < window_radius_; ++i)
38 for (
size_t i = data.size() - window_radius_; i < data.size(); ++i)
44std::vector<Point> SavitzkyGolay::filter_wrap(
const std::vector<Point>& data) {
46 if (data.size() < window_size_) {
50 std::vector<Point> result(data.size());
51 std::copy(data.begin(), data.end(), result.begin());
53 for (
size_t i = 0; i < data.size(); ++i) {
55 for (
int j = -window_radius_; j <= window_radius_; ++j) {
59 }
else if (k >= data.size()) {
62 val = val + data[k] * coeffs_[j + window_radius_];
72std::vector<std::vector<float>> SavitzkyGolay::invert_matrix(std::vector<std::vector<float>> A) {
74 std::vector<std::vector<float>> inv(n, std::vector<float>(n, 0.0));
77 for (
int i = 0; i < n; ++i)
80 for (
int i = 0; i < n; ++i) {
82 float pivot = A[i][i];
84 if (std::abs(pivot) < 1e-10)
85 throw std::runtime_error(
"Matrix singular, cannot invert.");
88 for (
int j = 0; j < n; ++j) {
94 for (
int k = 0; k < n; ++k) {
96 float factor = A[k][i];
97 for (
int j = 0; j < n; ++j) {
98 A[k][j] -= factor * A[i][j];
99 inv[k][j] -= factor * inv[i][j];
107void SavitzkyGolay::compute_coefficients() {
112 int rows = poly_order_ + 1;
113 std::vector<std::vector<float>> J(rows, std::vector<float>(rows));
115 for (
int i = 0; i < rows; ++i) {
116 for (
int j = 0; j < rows; ++j) {
118 for (
int k = -window_radius_; k <= window_radius_; ++k) {
119 sum += std::pow(k, i + j);
126 auto J_inv = invert_matrix(J);
133 coeffs_.resize(window_size_);
134 for (
int k = -window_radius_; k <= window_radius_; ++k) {
136 for (
int j = 0; j < rows; ++j) {
137 weight += J_inv[0][j] * std::pow(k, j);
139 coeffs_[k + window_radius_] = weight;