Citlali
Loading...
Searching...
No Matches
filter.h
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Core>
4#include <unsupported/Eigen/CXX11/Tensor>
5#include <unsupported/Eigen/SpecialFunctions>
6
7#include <cmath>
8#include <boost/math/special_functions/bessel.hpp>
9
11
12namespace timestream {
13
14class Filter {
15public:
17
18 Eigen::VectorXd filter;
19 Eigen::Index n_terms;
20
21 std::vector<double> w0s, qs;
22 Eigen::VectorXd notch_a, notch_b;
23
24 void make_filter(double);
25 void make_notch_filter(double);
26
27 template <typename Derived>
28 void convolve(Eigen::DenseBase<Derived> &);
29
30 template <typename Derived>
31 void iir(Eigen::DenseBase<Derived> &);
32};
33
34void Filter::make_filter(double fsmp) {
35 // calculate nyquist frequency
36 double nyquist = fsmp / 2.;
37 // scale upper frequency cutoff to Nyquist frequency
38 auto f_low = freq_low_Hz / nyquist;
39 // scale lower frequency cutoff to Nyquist frequency
40 auto f_high = freq_high_Hz / nyquist;
41
42 // check if upper frequency limit (lowpass)
43 // is larger than lower frequency limit (highpass)
44 double f_stop = (f_high < f_low) ? 1. : 0.;
45
46 // determine alpha parameter based on Gibbs factor
47 double alpha;
48
49 if (a_gibbs < 21.0) {
50 alpha = 0.0;
51 }
52 else if (a_gibbs > 50.0) {
53 alpha = 0.1102 * (a_gibbs - 8.7);
54 }
55 else {
56 alpha = 0.5842 * std::pow(a_gibbs - 21.0, 0.4) + 0.07886 * (a_gibbs - 21.0);
57 }
58
59 // argument for bessel function
60 Eigen::VectorXd arg = Eigen::VectorXd::LinSpaced(n_terms, 1, n_terms);
61 arg = alpha * (1.0 - (arg / n_terms).cwiseAbs2().array()).sqrt();
62
63 // calculate the coefficients from bessel functions.
64 double i_0_alpha = boost::math::cyl_bessel_i(0, alpha);
65
66 Eigen::VectorXd coef = arg.unaryExpr([i_0_alpha](double x) {
67 return boost::math::cyl_bessel_i(0, x) / i_0_alpha;
68 });
69
70 // generate time array
71 Eigen::VectorXd t = Eigen::VectorXd::LinSpaced(n_terms, 1, n_terms) * pi;
72
73 // multiply coefficients by time array trig functions
74 coef = coef.array()*(sin(t.array()*f_high) - sin(t.array()*f_low)) /
75 t.array();
76
77 // populate the filter vector
78 filter.resize(2 * n_terms + 1);
79 filter.setZero();
80 filter.head(n_terms) = coef.reverse();
81 filter(n_terms) = f_high - f_low - f_stop;
82 filter.tail(n_terms) = coef;
83
84 // normalize with sum
85 //double filter_sum = filter.sum();
86 //filter = filter.array() / filter_sum;
87}
88
89void Filter::make_notch_filter(double fsmp) {
90 for (Eigen::Index i=0; i<w0s.size(); i++) {
91 double w0 = w0s[i];
92 double Q = qs[i];
93 w0 = 2*w0/fsmp;
94
95 // Get bandwidth
96 double bw = w0/Q;
97
98 // Normalize inputs
99 bw = bw*pi;
100 w0 = w0*pi;
101
102 // Compute -3dB attenuation
103 double gb = 1/sqrt(2);
104
105 //if ftype == "notch":
106 // Compute beta: formula 11.3.4 (p.575) from reference [1]
107 double beta = (sqrt(1.0-pow(gb,2.0))/gb)*tan(bw/2.0);
108 //elif ftype == "peak":
109 // Compute beta: formula 11.3.19 (p.579) from reference [1]
110 // beta = (gb/np.sqrt(1.0-gb**2.0))*np.tan(bw/2.0)
111 //else:
112 // raise ValueError("Unknown ftype.")
113
114 // Compute gain: formula 11.3.6 (p.575) from reference [1]
115 double gain = 1.0/(1.0+beta);
116
117 // Compute numerator b and denominator a
118 // formulas 11.3.7 (p.575) and 11.3.21 (p.579)
119 // from reference [1]
120 //if ftype == "notch":
121 Eigen::VectorXd b(3);
122 b << 1.0, -2.0*cos(w0), 1.0;
123 b = gain*b;
124 //b = gain*np.array([1.0, -2.0*np.cos(w0), 1.0]);
125 //else:
126 //double b = (1.0-gain)*np.array([1.0, 0.0, -1.0]);
127 Eigen::VectorXd a(3);
128 a << 1.0, -2.0*gain*cos(w0), (2.0*gain-1.0);
129 //double a = np.array([1.0, -2.0*gain*np.cos(w0), (2.0*gain-1.0)])
130
131 notch_a = a;//.push_back(a);
132 notch_b = b;//.push_back(b);
133 }
134}
135
136template <typename Derived>
137void Filter::convolve(Eigen::DenseBase<Derived> &in) {
138 // array to tell which dimension to do the convolution over
139 Eigen::array<ptrdiff_t, 1> dims{0};
140
141 // map the Eigen Matrices to Tensors to work with the Eigen::Tensor
142 // convolution method
143 Eigen::TensorMap<Eigen::Tensor<double, 2>> in_tensor(in.derived().data(),
144 in.rows(), in.cols());
145 Eigen::TensorMap<Eigen::Tensor<double, 1>> filter_tensor(filter.data(),
146 filter.size());
147 // convolve
148 Eigen::Tensor<double, 2> out_tensor(
149 in_tensor.dimension(0) - filter_tensor.dimension(0) + 1, in.cols());
150
151 // run the tensor convolution
152 out_tensor = in_tensor.convolve(filter_tensor, dims);
153
154 // replace the scan data with the filtered data through an Eigen::Map
155 // the first and last nterms samples are not overwritten
156 in.block(n_terms, 0, out_tensor.dimension(0),
157 in.cols()) =
158 Eigen::Map<Eigen::MatrixXd>(out_tensor.data(), out_tensor.dimension(0),
159 out_tensor.dimension(1));
160}
161
162template <typename Derived>
163void Filter::iir(Eigen::DenseBase<Derived> &in) {
164
165 Derived out(in.rows(),in.cols());
166 out.setZero();
167
168 for (Eigen::Index i=0; i < in.cols(); ++i) {
169 double x_2 = 0.;
170 double x_1 = 0.;
171 double y_2 = 0.;
172 double y_1 = 0.;
173 for (Eigen::Index j=0; j<in.rows(); ++j) {
174 out(j,i) = notch_a(0) * in(j,i) + notch_a(1) * x_1 + notch_a(2) * x_2
175 + notch_b(1) * y_1 + notch_b(2) * y_2;
176 x_2 = x_1;
177 x_1 = in(j,i);
178 y_2 = y_1;
179 y_1 = out(j,i);
180 }
181 }
182
183 in = std::move(out);
184}
185
186} // namespace timestream
Definition filter.h:14
void iir(Eigen::DenseBase< Derived > &)
Definition filter.h:163
double freq_high_Hz
Definition filter.h:16
std::vector< double > w0s
Definition filter.h:21
std::vector< double > qs
Definition filter.h:21
Eigen::VectorXd filter
Definition filter.h:18
double a_gibbs
Definition filter.h:16
double freq_low_Hz
Definition filter.h:16
void make_notch_filter(double)
Definition filter.h:89
Eigen::VectorXd notch_a
Definition filter.h:22
void convolve(Eigen::DenseBase< Derived > &)
Definition filter.h:137
Eigen::VectorXd notch_b
Definition filter.h:22
void make_filter(double)
Definition filter.h:34
Eigen::Index n_terms
Definition filter.h:19
constexpr auto pi
Definition constants.h:6
Definition clean.h:10