-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathIIRDesigner.cpp
226 lines (196 loc) · 7.44 KB
/
IIRDesigner.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Copyright (c) 2015-2015 Tony Kirke
// Copyright (c) 2016-2016 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include <Pothos/Framework.hpp>
#include <Pothos/Proxy.hpp>
#include <complex>
#include <iostream>
#include <spuce/filters/design_iir.h>
#include <spuce/filters/iir_coeff.h>
using namespace spuce;
/***********************************************************************
* |PothosDoc IIR Designer
*
* Designer for IIR filter taps.
* This block emits a "tapsChanged" signal upon activations,
* and when one of the parameters is modified.
* The "tapsChanged" signal contains two arrays of taps,
* and can be connected to a IIR filter's setIIR method.
*
* |category /Filter
* |keywords iir filter taps highpass lowpass
* |alias /blocks/iir_designer
*
* |param type[Filter Type] The type of filter taps to generate.
* |option [Low Pass] "LOW_PASS"
* |option [High Pass] "HIGH_PASS"
* |option [Band Pass] "BAND_PASS"
* |option [Band Stop] "BAND_STOP"
*
* |param iir[IIR Type] The type of IIR filter.
* |default "butterworth"
* |option [Butterworth] "butterworth"
* |option [Chebyshev] "chebyshev"
* |option [Chebyshev2] "chebyshev2"
* |option [Elliptic] "elliptic"
* |widget ComboBox(editable=true)
*
* |param sampRate[Sample Rate] The sample rate, in samples per second.
* The transition frequencies must be within the Nyqist frequency of the sampling rate.
* |default 44100
* |units Sps
*
* |param order[Order] The order of the IIR filter.
* |default 2
* |widget SpinBox(minimum=1)
*
* |param freqLower[Lower Freq] The lower transition frequency.
* For low and high pass filters, this is the only transition frequency.
* |default 4000
* |units Hz
*
* |param freqUpper[Upper Freq] The higher transition frequency.
* Only used for band pass and band stop filters.
* |default 8000
* |units Hz
*
* |param stopBandAtten[Stop Band Attenuation] The stop band attenuation for elliptic filters.
* |default 60
* |units dB
*
* |param ripple[Ripple] For Chebyshev or Elliptic filters
* This is pass band ripple in dB
* |default 0.1
* |units dB
*
* |factory /comms/iir_designer()
* |setter setFilterType(type)
* |setter setIIRType(iir)
* |setter setSampleRate(sampRate)
* |setter setFrequencyLower(freqLower)
* |setter setFrequencyUpper(freqUpper)
* |setter setOrder(order)
* |setter setRipple(ripple)
* |setter setStopBandAtten(stopBandAtten)
**********************************************************************/
class IIRDesigner : public Pothos::Block {
public:
static Block *make(void) { return new IIRDesigner(); }
IIRDesigner(void)
: _filterType("LOW_PASS"),
_IIRType("butterworth"),
_sampRate(1.0),
_freqLower(0.1),
_freqUpper(0.2),
_stopBandAtten(0.1),
_ripple(0.1),
_order(4) {
auto env = Pothos::ProxyEnvironment::make("managed");
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setFilterType));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, filterType));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setIIRType));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, IIRType));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setSampleRate));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, sampleRate));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setFrequencyLower));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, frequencyLower));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setFrequencyUpper));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, frequencyUpper));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setOrder));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, order));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setRipple));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, ripple));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, setStopBandAtten));
this->registerCall(this, POTHOS_FCN_TUPLE(IIRDesigner, stopBandAtten));
this->registerSignal("tapsChanged");
this->recalculate();
}
void setFilterType(const std::string &type) {
_filterType = type;
this->recalculate();
}
std::string filterType(void) const { return _filterType; }
void setIIRType(const std::string &type) {
_IIRType = type;
this->recalculate();
}
std::string IIRType(void) const { return _IIRType; }
void setSampleRate(const double rate) {
_sampRate = rate;
this->recalculate();
}
double sampleRate(void) const { return _sampRate; }
void setFrequencyLower(const double freq) {
_freqLower = freq;
this->recalculate();
}
double frequencyLower(void) const { return _freqLower; }
void setFrequencyUpper(const double freq) {
_freqUpper = freq;
this->recalculate();
}
double frequencyUpper(void) const { return _freqUpper; }
void setOrder(const size_t num) {
_order = num;
this->recalculate();
}
size_t order(void) const { return _order; }
void setRipple(const double rip) {
_ripple = rip;
this->recalculate();
}
double ripple(void) const { return _ripple; }
void setStopBandAtten(const double db) {
_stopBandAtten = db;
this->recalculate();
}
double stopBandAtten(void) const { return _stopBandAtten; }
void activate(void) { this->recalculate(); }
private:
void recalculate(void);
std::string _filterType;
std::string _IIRType;
double _sampRate;
double _freqLower;
double _freqUpper;
double _stopBandAtten;
double _ripple;
size_t _order;
};
void IIRDesigner::recalculate(void) {
if (not this->isActive()) return;
double bw;
double center_frequency = 0.25;
// check for error
if (_order == 0) throw Pothos::Exception("IIRDesigner()", "order must be positive");
if (_sampRate <= 0) throw Pothos::Exception("IIRDesigner()", "sample rate must be positive");
if (_freqLower <= 0) throw Pothos::Exception("IIRDesigner()", "lower frequency must be positive");
if (_freqLower >= _sampRate / 2) throw Pothos::Exception("IIRDesigner()", "lower frequency Nyquist fail");
if ( _filterType == "BAND_PASS" || _filterType == "BAND_STOP") {
if (_freqUpper <= 0) throw Pothos::Exception("IIRDesigner()", "upper frequency must be positive");
if (_freqUpper >= _sampRate/2) throw Pothos::Exception("IIRDesigner()", "upper frequency Nyquist fail");
bw = 0.5*(_freqUpper - _freqLower)/_sampRate;
center_frequency = 0.5*(_freqUpper + _freqLower)/_sampRate; // Should be sqrt(w1*w2) ?
if (_freqUpper <= _freqLower) {
throw Pothos::Exception("IIRDesigner()", "upper frequency <= lower frequency");
} else if (bw < 0.001) {
throw Pothos::Exception("IIRDesigner()", " bandpass bandwidth too small < 0.001");
}
} else {
bw = _freqLower/_sampRate;
}
// generate the filter design
iir_coeff* filt = design_iir(_IIRType, _filterType, _order, bw, _ripple,
_stopBandAtten, center_frequency);
if (filt == nullptr) {
throw Pothos::InvalidArgumentException("IIRDesigner(" + _filterType + "," + _IIRType + ")", "unknown filter or band type");
}
// get the tap from iir_coeff for iir_filter, incorporating the gain to feedforward taps
std::vector<double> b = filt->get_b();
std::vector<double> a = filt->get_a();
// Group together feed forward and feed back taps into 1 vector for transferring to IIR filter
for (size_t i=0;i<a.size();i++) b.push_back(a[i]);
delete filt;
this->emitSignal("tapsChanged", b);
}
static Pothos::BlockRegistry registerIIRDesigner("/comms/iir_designer", &IIRDesigner::make);