1#include "internal/SavitskyGolay.h"
8SavitzkyGolay::SavitzkyGolay(
int radius,
int poly_order)
9 : window_radius_(radius), window_size_(2 * radius + 1), poly_order_(poly_order) {
11 assert(window_size_ > poly_order_);
13 compute_coefficients();
16std::vector<Point> SavitzkyGolay::filter(
const std::vector<Point> &data) {
17 if (data.size() < window_size_) {
21 std::vector<Point> result(data.size());
24 for (
size_t i = window_radius_; i < data.size() - window_radius_; ++i) {
26 for (
int j = -window_radius_; j <= window_radius_; ++j) {
27 val += data[i + j] * coeffs_[j + window_radius_];
34 for (
int i = 0; i < window_radius_; ++i) result[i] = data[i];
35 for (
size_t i = data.size() - window_radius_; i < data.size(); ++i) result[i] = data[i];
40std::vector<Point> SavitzkyGolay::filter_wrap(
const std::vector<Point> &data) {
42 if (data.size() < window_size_) {
46 std::vector<Point> result(data.size());
47 std::copy(data.begin(), data.end(), result.begin());
49 for (
size_t i = 0; i < data.size(); ++i) {
51 for (
int j = -window_radius_; j <= window_radius_; ++j) {
55 }
else if (k >= data.size()) {
58 val = val + data[k] * coeffs_[j + window_radius_];
68std::vector<std::vector<float>> SavitzkyGolay::invert_matrix(std::vector<std::vector<float>> A) {
70 std::vector<std::vector<float>> inv(n, std::vector<float>(n, 0.0));
73 for (
int i = 0; i < n; ++i) inv[i][i] = 1.0;
75 for (
int i = 0; i < n; ++i) {
77 float pivot = A[i][i];
79 if (std::abs(pivot) < 1e-10)
throw std::runtime_error(
"Matrix singular, cannot invert.");
82 for (
int j = 0; j < n; ++j) {
88 for (
int k = 0; k < n; ++k) {
90 float factor = A[k][i];
91 for (
int j = 0; j < n; ++j) {
92 A[k][j] -= factor * A[i][j];
93 inv[k][j] -= factor * inv[i][j];
101void SavitzkyGolay::compute_coefficients() {
106 int rows = poly_order_ + 1;
107 std::vector<std::vector<float>> J(rows, std::vector<float>(rows));
109 for (
int i = 0; i < rows; ++i) {
110 for (
int j = 0; j < rows; ++j) {
112 for (
int k = -window_radius_; k <= window_radius_; ++k) {
113 sum += std::pow(k, i + j);
120 auto J_inv = invert_matrix(J);
127 coeffs_.resize(window_size_);
128 for (
int k = -window_radius_; k <= window_radius_; ++k) {
130 for (
int j = 0; j < rows; ++j) {
131 weight += J_inv[0][j] * std::pow(k, j);
133 coeffs_[k + window_radius_] = weight;