1 |
std::vector<double> butterworth_filter(const std::vector<double>& input, double cutoff_frequency, double sampling_rate, int order)
|
2 |
{
|
3 |
int N = input.size();
|
4 |
std::vector<double> output(N, 0.0);
|
5 |
|
6 |
// cf, init
|
7 |
double nyquist = 0.5 * sampling_rate;
|
8 |
double normalized_cutoff = cutoff_frequency / nyquist;
|
9 |
|
10 |
std::vector<double> a(order + 1, 0.0);
|
11 |
std::vector<double> b(order + 1, 0.0);
|
12 |
|
13 |
double theta = M_PI * normalized_cutoff;
|
14 |
double d = 1.0 / std::tan(theta);
|
15 |
double d_squared = d * d;
|
16 |
|
17 |
a[0] = 1.0 / (1.0 + std::sqrt(2.0) * d + d_squared);
|
18 |
a[1] = 2.0 * a[0];
|
19 |
a[2] = a[0];
|
20 |
b[1] = 2.0 * (1.0 - d_squared) * a[0];
|
21 |
b[2] = (1.0 - std::sqrt(2.0) * d + d_squared) * a[0];
|
22 |
|
23 |
for (int i = 2; i < N; ++i)
|
24 |
{
|
25 |
#ifdef NDEBUG
|
26 |
#else
|
27 |
printf("\nFiltering index: %i\n",i);
|
28 |
#endif
|
29 |
output[i] = a[0] * input[i] + a[1] * input[i - 1] + a[2] * input[i - 2] - b[1] * output[i - 1] - b[2] * output[i - 2];
|
30 |
}
|
31 |
|
32 |
return output;
|
33 |
}
|
34 |
|
35 |
class Filter
|
36 |
{
|
37 |
public:
|
38 |
Filter() {}
|
39 |
|
40 |
void set_history_size(size_t new_size)
|
41 |
{
|
42 |
history_size_ = new_size;
|
43 |
if (x_history_.size() > history_size_) x_history_.resize(history_size_);
|
44 |
if (y_history_.size() > history_size_) y_history_.resize(history_size_);
|
45 |
if (z_history_.size() > history_size_) z_history_.resize(history_size_);
|
46 |
}
|
47 |
|
48 |
geometry_msgs::msg::TransformStamped apply_filter(const geometry_msgs::msg::TransformStamped& transform)
|
49 |
{
|
50 |
x_history_.push_back(transform.transform.translation.x);
|
51 |
y_history_.push_back(transform.transform.translation.y);
|
52 |
z_history_.push_back(transform.transform.translation.z);
|
53 |
|
54 |
if (x_history_.size() > history_size_) x_history_.pop_front();
|
55 |
if (y_history_.size() > history_size_) y_history_.pop_front();
|
56 |
if (z_history_.size() > history_size_) z_history_.pop_front();
|
57 |
|
58 |
#ifdef NDEBUG
|
59 |
#else
|
60 |
printf("\nHistory Size: %zu", history_size_);
|
61 |
printf("\nDeque x_history_ size: %zu", x_history_.size());
|
62 |
printf("\nDeque y_history_ size: %zu", y_history_.size());
|
63 |
printf("\nDeque z_history_ size: %zu", z_history_.size());
|
64 |
#endif
|
65 |
geometry_msgs::msg::TransformStamped filtered_transform = transform;
|
66 |
|
67 |
if (x_history_.size() >= history_size_)
|
68 |
{
|
69 |
std::vector<double> x_filtered = butterworth_filter(
|
70 |
std::vector<double>(x_history_.begin(), x_history_.end()), cutoff_frequency_, sampling_rate_, order_);
|
71 |
std::vector<double> y_filtered = butterworth_filter(
|
72 |
std::vector<double>(y_history_.begin(), y_history_.end()), cutoff_frequency_, sampling_rate_, order_);
|
73 |
std::vector<double> z_filtered = butterworth_filter(
|
74 |
std::vector<double>(z_history_.begin(), z_history_.end()), cutoff_frequency_, sampling_rate_, order_);
|
75 |
|
76 |
filtered_transform.transform.translation.x = x_filtered.back();
|
77 |
filtered_transform.transform.translation.y = y_filtered.back();
|
78 |
filtered_transform.transform.translation.z = z_filtered.back();
|
79 |
}
|
80 |
|
81 |
return filtered_transform;
|
82 |
}
|
83 |
|
84 |
private:
|
85 |
std::deque<double> x_history_;
|
86 |
std::deque<double> y_history_;
|
87 |
std::deque<double> z_history_;
|
88 |
size_t history_size_ = 20;
|
89 |
double cutoff_frequency_ = 10.0;
|
90 |
double sampling_rate_ = 100.0;
|
91 |
int order_ = 2;
|
92 |
};
|