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 | };
|