2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "common/filter.h"
26 #include "common/maths.h"
27 #include "common/utils.h"
28 #include "common/time.h"
31 float nullFilterApply(void *filter
, float input
)
37 float nullFilterApply4(void *filter
, float input
, float f_cut
, float dt
)
45 // PT1 Low Pass filter
47 static float pt1ComputeRC(const float f_cut
)
49 return 1.0f
/ (2.0f
* M_PIf
* f_cut
);
52 // f_cut = cutoff frequency
53 void pt1FilterInitRC(pt1Filter_t
*filter
, float tau
, float dT
)
58 filter
->alpha
= filter
->dT
/ (filter
->RC
+ filter
->dT
);
61 void pt1FilterInit(pt1Filter_t
*filter
, float f_cut
, float dT
)
63 pt1FilterInitRC(filter
, pt1ComputeRC(f_cut
), dT
);
66 void pt1FilterSetTimeConstant(pt1Filter_t
*filter
, float tau
) {
70 float pt1FilterGetLastOutput(pt1Filter_t
*filter
) {
74 void pt1FilterUpdateCutoff(pt1Filter_t
*filter
, float f_cut
)
76 filter
->RC
= pt1ComputeRC(f_cut
);
77 filter
->alpha
= filter
->dT
/ (filter
->RC
+ filter
->dT
);
80 float FAST_CODE NOINLINE
pt1FilterApply(pt1Filter_t
*filter
, float input
)
82 filter
->state
= filter
->state
+ filter
->alpha
* (input
- filter
->state
);
86 float pt1FilterApply3(pt1Filter_t
*filter
, float input
, float dT
)
89 filter
->state
= filter
->state
+ dT
/ (filter
->RC
+ dT
) * (input
- filter
->state
);
93 float FAST_CODE NOINLINE
pt1FilterApply4(pt1Filter_t
*filter
, float input
, float f_cut
, float dT
)
95 // Pre calculate and store RC
97 filter
->RC
= pt1ComputeRC(f_cut
);
100 filter
->dT
= dT
; // cache latest dT for possible use in pt1FilterApply
101 filter
->alpha
= filter
->dT
/ (filter
->RC
+ filter
->dT
);
102 filter
->state
= filter
->state
+ filter
->alpha
* (input
- filter
->state
);
103 return filter
->state
;
106 void pt1FilterReset(pt1Filter_t
*filter
, float input
)
108 filter
->state
= input
;
114 float pt2FilterGain(float f_cut
, float dT
)
116 const float order
= 2.0f
;
117 const float orderCutoffCorrection
= 1 / sqrtf(powf(2, 1.0f
/ order
) - 1);
118 float RC
= 1 / (2 * orderCutoffCorrection
* M_PIf
* f_cut
);
119 // float RC = 1 / (2 * 1.553773974f * M_PIf * f_cut);
120 // where 1.553773974 = 1 / sqrt( (2^(1 / order) - 1) ) and order is 2
121 return dT
/ (RC
+ dT
);
124 void pt2FilterInit(pt2Filter_t
*filter
, float k
)
126 filter
->state
= 0.0f
;
127 filter
->state1
= 0.0f
;
131 void pt2FilterUpdateCutoff(pt2Filter_t
*filter
, float k
)
136 FAST_CODE
float pt2FilterApply(pt2Filter_t
*filter
, float input
)
138 filter
->state1
= filter
->state1
+ filter
->k
* (input
- filter
->state1
);
139 filter
->state
= filter
->state
+ filter
->k
* (filter
->state1
- filter
->state
);
140 return filter
->state
;
146 float pt3FilterGain(float f_cut
, float dT
)
148 const float order
= 3.0f
;
149 const float orderCutoffCorrection
= 1 / sqrtf(powf(2, 1.0f
/ order
) - 1);
150 float RC
= 1 / (2 * orderCutoffCorrection
* M_PIf
* f_cut
);
151 // float RC = 1 / (2 * 1.961459177f * M_PIf * f_cut);
152 // where 1.961459177 = 1 / sqrt( (2^(1 / order) - 1) ) and order is 3
153 return dT
/ (RC
+ dT
);
156 void pt3FilterInit(pt3Filter_t
*filter
, float k
)
158 filter
->state
= 0.0f
;
159 filter
->state1
= 0.0f
;
160 filter
->state2
= 0.0f
;
164 void pt3FilterUpdateCutoff(pt3Filter_t
*filter
, float k
)
169 FAST_CODE
float pt3FilterApply(pt3Filter_t
*filter
, float input
)
171 filter
->state1
= filter
->state1
+ filter
->k
* (input
- filter
->state1
);
172 filter
->state2
= filter
->state2
+ filter
->k
* (filter
->state1
- filter
->state2
);
173 filter
->state
= filter
->state
+ filter
->k
* (filter
->state2
- filter
->state
);
174 return filter
->state
;
177 // rate_limit = maximum rate of change of the output value in units per second
178 void rateLimitFilterInit(rateLimitFilter_t
*filter
)
183 float rateLimitFilterApply4(rateLimitFilter_t
*filter
, float input
, float rate_limit
, float dT
)
185 if (rate_limit
> 0) {
186 const float rateLimitPerSample
= rate_limit
* dT
;
187 filter
->state
= constrainf(input
, filter
->state
- rateLimitPerSample
, filter
->state
+ rateLimitPerSample
);
190 filter
->state
= input
;
193 return filter
->state
;
196 float filterGetNotchQ(float centerFrequencyHz
, float cutoffFrequencyHz
)
198 return centerFrequencyHz
* cutoffFrequencyHz
/ (centerFrequencyHz
* centerFrequencyHz
- cutoffFrequencyHz
* cutoffFrequencyHz
);
201 void biquadFilterInitNotch(biquadFilter_t
*filter
, uint32_t samplingIntervalUs
, uint16_t filterFreq
, uint16_t cutoffHz
)
203 float Q
= filterGetNotchQ(filterFreq
, cutoffHz
);
204 biquadFilterInit(filter
, filterFreq
, samplingIntervalUs
, Q
, FILTER_NOTCH
);
207 // sets up a biquad Filter
208 void biquadFilterInitLPF(biquadFilter_t
*filter
, uint16_t filterFreq
, uint32_t samplingIntervalUs
)
210 biquadFilterInit(filter
, filterFreq
, samplingIntervalUs
, BIQUAD_Q
, FILTER_LPF
);
214 static void biquadFilterSetupPassthrough(biquadFilter_t
*filter
)
216 // By default set as passthrough
224 void biquadFilterInit(biquadFilter_t
*filter
, uint16_t filterFreq
, uint32_t samplingIntervalUs
, float Q
, biquadFilterType_e filterType
)
226 // Check for Nyquist frequency and if it's not possible to initialize filter as requested - set to no filtering at all
227 if (filterFreq
< (1000000 / samplingIntervalUs
/ 2)) {
229 const float sampleRate
= 1.0f
/ ((float)samplingIntervalUs
* 0.000001f
);
230 const float omega
= 2.0f
* M_PIf
* ((float)filterFreq
) / sampleRate
;
231 const float sn
= sin_approx(omega
);
232 const float cs
= cos_approx(omega
);
233 const float alpha
= sn
/ (2 * Q
);
236 switch (filterType
) {
248 biquadFilterSetupPassthrough(filter
);
251 const float a0
= 1 + alpha
;
252 const float a1
= -2 * cs
;
253 const float a2
= 1 - alpha
;
255 // precompute the coefficients
256 filter
->b0
= b0
/ a0
;
257 filter
->b1
= b1
/ a0
;
258 filter
->b2
= b2
/ a0
;
259 filter
->a1
= a1
/ a0
;
260 filter
->a2
= a2
/ a0
;
262 biquadFilterSetupPassthrough(filter
);
265 // zero initial samples
266 filter
->x1
= filter
->x2
= 0;
267 filter
->y1
= filter
->y2
= 0;
270 FAST_CODE
float biquadFilterApplyDF1(biquadFilter_t
*filter
, float input
)
273 const float result
= filter
->b0
* input
+ filter
->b1
* filter
->x1
+ filter
->b2
* filter
->x2
- filter
->a1
* filter
->y1
- filter
->a2
* filter
->y2
;
275 /* shift x1 to x2, input to x1 */
276 filter
->x2
= filter
->x1
;
279 /* shift y1 to y2, result to y1 */
280 filter
->y2
= filter
->y1
;
286 // Computes a biquad_t filter on a sample
287 float FAST_CODE NOINLINE
biquadFilterApply(biquadFilter_t
*filter
, float input
)
289 const float result
= filter
->b0
* input
+ filter
->x1
;
290 filter
->x1
= filter
->b1
* input
- filter
->a1
* result
+ filter
->x2
;
291 filter
->x2
= filter
->b2
* input
- filter
->a2
* result
;
295 float biquadFilterReset(biquadFilter_t
*filter
, float value
)
297 filter
->x1
= value
- (value
* filter
->b0
);
298 filter
->x2
= (filter
->b2
- filter
->a2
) * value
;
302 FAST_CODE
void biquadFilterUpdate(biquadFilter_t
*filter
, float filterFreq
, uint32_t refreshRate
, float Q
, biquadFilterType_e filterType
)
305 float x1
= filter
->x1
;
306 float x2
= filter
->x2
;
307 float y1
= filter
->y1
;
308 float y2
= filter
->y2
;
310 biquadFilterInit(filter
, filterFreq
, refreshRate
, Q
, filterType
);
319 void initFilter(const uint8_t filterType
, filter_t
*filter
, const float cutoffFrequency
, const uint32_t refreshRate
) {
320 const float dT
= US2S(refreshRate
);
322 if (cutoffFrequency
) {
323 if (filterType
== FILTER_PT1
) {
324 pt1FilterInit(&filter
->pt1
, cutoffFrequency
, dT
);
325 } if (filterType
== FILTER_PT2
) {
326 pt2FilterInit(&filter
->pt2
, pt2FilterGain(cutoffFrequency
, dT
));
327 } if (filterType
== FILTER_PT3
) {
328 pt3FilterInit(&filter
->pt3
, pt3FilterGain(cutoffFrequency
, dT
));
330 biquadFilterInitLPF(&filter
->biquad
, cutoffFrequency
, refreshRate
);
335 void assignFilterApplyFn(uint8_t filterType
, float cutoffFrequency
, filterApplyFnPtr
*applyFn
) {
336 *applyFn
= nullFilterApply
;
337 if (cutoffFrequency
) {
338 if (filterType
== FILTER_PT1
) {
339 *applyFn
= (filterApplyFnPtr
) pt1FilterApply
;
340 } if (filterType
== FILTER_PT2
) {
341 *applyFn
= (filterApplyFnPtr
) pt2FilterApply
;
342 } if (filterType
== FILTER_PT3
) {
343 *applyFn
= (filterApplyFnPtr
) pt3FilterApply
;
345 *applyFn
= (filterApplyFnPtr
) biquadFilterApply
;