fbgsense 0.1
Generic FBG spectrum analysis tool
savgol.h
1#pragma once
2
3/*
4 * Copyright 2017-2018 CNRS-UM LIRMM
5 * Copyright 2019-2021 CNRS-UM LIRMM, CNRS-AIST JRL
6 *
7 * https://raw.githubusercontent.com/arntanguy/gram_savitzky_golay/master/src/gram_savitzky_golay.cpp
8 * https://raw.githubusercontent.com/arntanguy/gram_savitzky_golay/master/include/gram_savitzky_golay/gram_savitzky_golay.h
9 */
10
11
12#include <vector>
13#include <iostream>
14#include <cassert>
15
16namespace savgol {
17
22 inline double GramPoly(const int i, const int m, const int k, const int s)
23 {
24 if (k > 0)
25 {
26 return (4. * k - 2.) / (k * (2. * m - k + 1.)) * (i * GramPoly(i, m, k - 1, s) + s * GramPoly(i, m, k - 1, s - 1))
27 - ((k - 1.) * (2. * m + k)) / (k * (2. * m - k + 1.)) * GramPoly(i, m, k - 2, s);
28 }
29 else
30 {
31 if (k == 0 && s == 0)
32 return 1.;
33 else
34 return 0.;
35 }
36 }
37
41 inline double GenFact(const int a, const int b)
42 {
43 double gf = 1.;
44
45 for (int j = (a - b) + 1; j <= a; j++)
46 {
47 gf *= j;
48 }
49 return gf;
50 }
51
56 inline double Weight(const int i, const int t, const int m, const int n, const int s)
57 {
58 double w = 0;
59 for (int k = 0; k <= n; ++k)
60 {
61 w = w
62 + (2 * k + 1) * (GenFact(2 * m, k) / GenFact(2 * m + k + 1, k + 1)) * GramPoly(i, m, k, 0)
63 * GramPoly(t, m, k, s);
64 }
65 return w;
66 }
67
72 inline std::vector<double> ComputeWeights(const int m, const int t, const int n, const int s)
73 {
74 std::vector<double> weights(2 * static_cast<size_t>(m) + 1);
75 for (int i = 0; i < 2 * m + 1; ++i)
76 {
77 weights[static_cast<size_t>(i)] = Weight(i - m, t, m, n, s);
78 }
79 return weights;
80 }
81
83 {
85 unsigned m = 5;
87 // For real-time, should be t=m
88 int t = 5;
90 unsigned n = 3;
92 unsigned s = 0;
94 double dt = 1;
95
100
119 SavitzkyGolayFilterConfig(unsigned m, int t, unsigned n, unsigned s, double dt = 1.) : m(m), t(t), n(n), s(s), dt(dt)
120 {
121 }
122
126 int data_point() const
127 {
128 return t;
129 }
130
134 unsigned derivation_order() const
135 {
136 return s;
137 }
138
142 unsigned order() const
143 {
144 return n;
145 }
146
150 unsigned window_size() const
151 {
152 return 2 * m + 1;
153 }
154
158 double time_step() const
159 {
160 return dt;
161 }
162
163 friend std::ostream& operator<<(std::ostream& os, const SavitzkyGolayFilterConfig& conf)
164 {
165 os << "m : " << conf.m << std::endl
166 << "Window Size (2*m+1) : " << 2 * conf.m + 1 << std::endl
167 << "n (Order) :" << conf.n << std::endl
168 << "s (Differentiate) : " << conf.s << std::endl
169 << "t: Filter point ([-m,m]): " << conf.t << std::endl;
170 return os;
171 }
172 };
173
175 {
176 SavitzkyGolayFilter(unsigned m, int t, unsigned n, unsigned s, double dt = 1.) : conf_(m, t, n, s, dt)
177 {
178 init();
179 }
180
181 SavitzkyGolayFilter(const SavitzkyGolayFilterConfig& conf) : conf_(conf)
182 {
183 init();
184 }
185
187 {
188 init();
189 }
190
191 void configure(const SavitzkyGolayFilterConfig& conf)
192 {
193 conf_ = conf;
194 init();
195 }
196
210 template<typename ContainerT>
211 typename ContainerT::value_type filter(const ContainerT& v) const
212 {
213 assert(v.size() == weights_.size() && v.size() > 0);
214 using T = typename ContainerT::value_type;
215 T res = weights_[0] * v[0];
216 for (size_t i = 1; i < v.size(); ++i)
217 {
218 res += weights_[i] * v[i];
219 }
220 return res / dt_;
221 }
222
223 std::vector<double> weights() const
224 {
225 return weights_;
226 }
227
228 SavitzkyGolayFilterConfig config() const
229 {
230 return conf_;
231 }
232
233 private:
234 SavitzkyGolayFilterConfig conf_;
235 std::vector<double> weights_;
236 void init()
237 {
238 // Compute weights for the time window 2*m+1, for the t'th least-square
239 // point of the s'th derivative
240 weights_ = ComputeWeights(static_cast<int>(conf_.m), conf_.t, static_cast<int>(conf_.n), static_cast<int>(conf_.s));
241 dt_ = std::pow(conf_.time_step(), conf_.derivation_order());
242 }
243 double dt_;
244 };
245}
Definition: savgol.h:83
unsigned m
Window size is 2*m+1.
Definition: savgol.h:85
int t
Time at which the filter is applied.
Definition: savgol.h:88
unsigned window_size() const
Full size of the filter's window 2*m+1
Definition: savgol.h:150
int data_point() const
Time at which the filter is evaluated.
Definition: savgol.h:126
unsigned order() const
Polynomial order.
Definition: savgol.h:142
unsigned n
Polynomial order.
Definition: savgol.h:90
unsigned s
Derivation order (0 for no derivation)
Definition: savgol.h:92
unsigned derivation_order() const
Derivation order.
Definition: savgol.h:134
SavitzkyGolayFilterConfig(unsigned m, int t, unsigned n, unsigned s, double dt=1.)
Construct a filter with the specified configuration.
Definition: savgol.h:119
SavitzkyGolayFilterConfig()
Construct a filter with default weights.
Definition: savgol.h:99
double time_step() const
Time step.
Definition: savgol.h:158
double dt
Time step.
Definition: savgol.h:94
Definition: savgol.h:175
ContainerT::value_type filter(const ContainerT &v) const
Apply Savitzky-Golay convolution to the data x should have size 2*m+1 As the function only applies a ...
Definition: savgol.h:211