2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #include "common/filter.h"
28 #include "common/maths.h"
29 #include "common/utils.h"
31 #define BIQUAD_Q 1.0f / sqrtf(2.0f) /* quality factor - 2nd order butterworth*/
33 // PTn cutoff correction = 1 / sqrt(2^(1/n) - 1)
34 #define CUTOFF_CORRECTION_PT2 1.553773974f
35 #define CUTOFF_CORRECTION_PT3 1.961459177f
39 float nullFilterApply(filter_t
*filter
, float input
)
45 // PT1 Low Pass filter
47 FAST_CODE_NOINLINE
float pt1FilterGain(float f_cut
, float dT
)
49 float omega
= 2.0f
* M_PIf
* f_cut
* dT
;
50 return omega
/ (omega
+ 1.0f
);
53 // Calculates filter gain based on delay (time constant of filter) - time it takes for filter response to reach 63.2% of a step input.
54 float pt1FilterGainFromDelay(float delay
, float dT
)
57 return 1.0f
; // gain = 1 means no filtering
60 const float cutoffHz
= 1.0f
/ (2.0f
* M_PIf
* delay
);
61 return pt1FilterGain(cutoffHz
, dT
);
64 void pt1FilterInit(pt1Filter_t
*filter
, float k
)
70 void pt1FilterUpdateCutoff(pt1Filter_t
*filter
, float k
)
75 FAST_CODE
float pt1FilterApply(pt1Filter_t
*filter
, float input
)
77 filter
->state
= filter
->state
+ filter
->k
* (input
- filter
->state
);
81 // PT2 Low Pass filter
83 FAST_CODE
float pt2FilterGain(float f_cut
, float dT
)
85 // shift f_cut to satisfy -3dB cutoff condition
86 return pt1FilterGain(f_cut
* CUTOFF_CORRECTION_PT2
, dT
);
89 // Calculates filter gain based on delay (time constant of filter) - time it takes for filter response to reach 63.2% of a step input.
90 float pt2FilterGainFromDelay(float delay
, float dT
)
93 return 1.0f
; // gain = 1 means no filtering
96 const float cutoffHz
= 1.0f
/ (M_PIf
* delay
* CUTOFF_CORRECTION_PT2
);
97 return pt2FilterGain(cutoffHz
, dT
);
100 void pt2FilterInit(pt2Filter_t
*filter
, float k
)
102 filter
->state
= 0.0f
;
103 filter
->state1
= 0.0f
;
107 void pt2FilterUpdateCutoff(pt2Filter_t
*filter
, float k
)
112 FAST_CODE
float pt2FilterApply(pt2Filter_t
*filter
, float input
)
114 filter
->state1
= filter
->state1
+ filter
->k
* (input
- filter
->state1
);
115 filter
->state
= filter
->state
+ filter
->k
* (filter
->state1
- filter
->state
);
116 return filter
->state
;
119 // PT3 Low Pass filter
121 FAST_CODE
float pt3FilterGain(float f_cut
, float dT
)
123 // shift f_cut to satisfy -3dB cutoff condition
124 return pt1FilterGain(f_cut
* CUTOFF_CORRECTION_PT3
, dT
);
127 // Calculates filter gain based on delay (time constant of filter) - time it takes for filter response to reach 63.2% of a step input.
128 float pt3FilterGainFromDelay(float delay
, float dT
)
131 return 1.0f
; // gain = 1 means no filtering
134 const float cutoffHz
= 1.0f
/ (M_PIf
* delay
* CUTOFF_CORRECTION_PT3
);
135 return pt3FilterGain(cutoffHz
, dT
);
138 void pt3FilterInit(pt3Filter_t
*filter
, float k
)
140 filter
->state
= 0.0f
;
141 filter
->state1
= 0.0f
;
142 filter
->state2
= 0.0f
;
146 void pt3FilterUpdateCutoff(pt3Filter_t
*filter
, float k
)
151 FAST_CODE
float pt3FilterApply(pt3Filter_t
*filter
, float input
)
153 filter
->state1
= filter
->state1
+ filter
->k
* (input
- filter
->state1
);
154 filter
->state2
= filter
->state2
+ filter
->k
* (filter
->state1
- filter
->state2
);
155 filter
->state
= filter
->state
+ filter
->k
* (filter
->state2
- filter
->state
);
156 return filter
->state
;
161 // get notch filter Q given center frequency (f0) and lower cutoff frequency (f1)
162 // Q = f0 / (f2 - f1) ; f2 = f0^2 / f1
163 float filterGetNotchQ(float centerFreq
, float cutoffFreq
)
165 return centerFreq
* cutoffFreq
/ (centerFreq
* centerFreq
- cutoffFreq
* cutoffFreq
);
168 /* sets up a biquad filter as a 2nd order butterworth LPF */
169 void biquadFilterInitLPF(biquadFilter_t
*filter
, float filterFreq
, uint32_t refreshRate
)
171 biquadFilterInit(filter
, filterFreq
, refreshRate
, BIQUAD_Q
, FILTER_LPF
, 1.0f
);
174 void biquadFilterInit(biquadFilter_t
*filter
, float filterFreq
, uint32_t refreshRate
, float Q
, biquadFilterType_e filterType
, float weight
)
176 biquadFilterUpdate(filter
, filterFreq
, refreshRate
, Q
, filterType
, weight
);
178 // zero initial samples
179 filter
->x1
= filter
->x2
= 0;
180 filter
->y1
= filter
->y2
= 0;
183 FAST_CODE
void biquadFilterUpdate(biquadFilter_t
*filter
, float filterFreq
, uint32_t refreshRate
, float Q
, biquadFilterType_e filterType
, float weight
)
186 const float omega
= 2.0f
* M_PIf
* filterFreq
* refreshRate
* 0.000001f
;
187 const float sn
= sin_approx(omega
);
188 const float cs
= cos_approx(omega
);
189 const float alpha
= sn
/ (2.0f
* Q
);
191 switch (filterType
) {
193 // 2nd order Butterworth (with Q=1/sqrt(2)) / Butterworth biquad section with Q
194 // described in http://www.ti.com/lit/an/slaa447/slaa447.pdf
196 filter
->b0
= filter
->b1
* 0.5f
;
197 filter
->b2
= filter
->b0
;
198 filter
->a1
= -2 * cs
;
199 filter
->a2
= 1 - alpha
;
203 filter
->b1
= -2 * cs
;
205 filter
->a1
= filter
->b1
;
206 filter
->a2
= 1 - alpha
;
212 filter
->a1
= -2 * cs
;
213 filter
->a2
= 1 - alpha
;
217 const float a0
= 1 + alpha
;
219 // precompute the coefficients
227 filter
->weight
= weight
;
230 FAST_CODE
void biquadFilterUpdateLPF(biquadFilter_t
*filter
, float filterFreq
, uint32_t refreshRate
)
232 biquadFilterUpdate(filter
, filterFreq
, refreshRate
, BIQUAD_Q
, FILTER_LPF
, 1.0f
);
235 /* Computes a biquadFilter_t filter on a sample (slightly less precise than df2 but works in dynamic mode) */
236 FAST_CODE
float biquadFilterApplyDF1(biquadFilter_t
*filter
, float input
)
239 const float result
= filter
->b0
* input
+ filter
->b1
* filter
->x1
+ filter
->b2
* filter
->x2
- filter
->a1
* filter
->y1
- filter
->a2
* filter
->y2
;
241 /* shift x1 to x2, input to x1 */
242 filter
->x2
= filter
->x1
;
245 /* shift y1 to y2, result to y1 */
246 filter
->y2
= filter
->y1
;
252 /* Computes a biquadFilter_t filter in df1 and crossfades input with output */
253 FAST_CODE
float biquadFilterApplyDF1Weighted(biquadFilter_t
* filter
, float input
)
256 const float result
= biquadFilterApplyDF1(filter
, input
);
258 // crossfading of input and output to turn filter on/off gradually
259 return filter
->weight
* result
+ (1 - filter
->weight
) * input
;
262 /* Computes a biquadFilter_t filter in direct form 2 on a sample (higher precision but can't handle changes in coefficients */
263 FAST_CODE
float biquadFilterApply(biquadFilter_t
*filter
, float input
)
265 const float result
= filter
->b0
* input
+ filter
->x1
;
267 filter
->x1
= filter
->b1
* input
- filter
->a1
* result
+ filter
->x2
;
268 filter
->x2
= filter
->b2
* input
- filter
->a2
* result
;
273 // Phase Compensator (Lead-Lag-Compensator)
275 void phaseCompInit(phaseComp_t
*filter
, const float centerFreqHz
, const float centerPhaseDeg
, const uint32_t looptimeUs
)
277 phaseCompUpdate(filter
, centerFreqHz
, centerPhaseDeg
, looptimeUs
);
283 FAST_CODE
void phaseCompUpdate(phaseComp_t
*filter
, const float centerFreqHz
, const float centerPhaseDeg
, const uint32_t looptimeUs
)
285 const float omega
= 2.0f
* M_PIf
* centerFreqHz
* looptimeUs
* 1e-6f
;
286 const float sn
= sin_approx(centerPhaseDeg
* RAD
);
287 const float gain
= (1 + sn
) / (1 - sn
);
288 const float alpha
= (12 - sq(omega
)) / (6 * omega
* sqrtf(gain
)); // approximate prewarping (series expansion)
290 filter
->b0
= 1 + alpha
* gain
;
291 filter
->b1
= 2 - filter
->b0
;
292 filter
->a1
= 1 - alpha
;
294 const float a0
= 1 / (1 + alpha
);
301 FAST_CODE
float phaseCompApply(phaseComp_t
*filter
, const float input
)
304 const float result
= filter
->b0
* input
+ filter
->b1
* filter
->x1
- filter
->a1
* filter
->y1
;
306 // shift input to x1 and result to y1
313 // Slew filter with limit
315 void slewFilterInit(slewFilter_t
*filter
, float slewLimit
, float threshold
)
317 filter
->state
= 0.0f
;
318 filter
->slewLimit
= slewLimit
;
319 filter
->threshold
= threshold
;
322 FAST_CODE
float slewFilterApply(slewFilter_t
*filter
, float input
)
324 if (filter
->state
>= filter
->threshold
) {
325 if (input
>= filter
->state
- filter
->slewLimit
) {
326 filter
->state
= input
;
328 } else if (filter
->state
<= -filter
->threshold
) {
329 if (input
<= filter
->state
+ filter
->slewLimit
) {
330 filter
->state
= input
;
333 filter
->state
= input
;
335 return filter
->state
;
340 void laggedMovingAverageInit(laggedMovingAverage_t
*filter
, uint16_t windowSize
, float *buf
)
342 filter
->movingWindowIndex
= 0;
343 filter
->windowSize
= windowSize
;
345 filter
->movingSum
= 0;
346 memset(filter
->buf
, 0, windowSize
* sizeof(float));
347 filter
->primed
= false;
350 FAST_CODE
float laggedMovingAverageUpdate(laggedMovingAverage_t
*filter
, float input
)
352 filter
->movingSum
-= filter
->buf
[filter
->movingWindowIndex
];
353 filter
->buf
[filter
->movingWindowIndex
] = input
;
354 filter
->movingSum
+= input
;
356 if (++filter
->movingWindowIndex
== filter
->windowSize
) {
357 filter
->movingWindowIndex
= 0;
358 filter
->primed
= true;
361 const uint16_t denom
= filter
->primed
? filter
->windowSize
: filter
->movingWindowIndex
;
362 return filter
->movingSum
/ denom
;
365 // Simple fixed-point lowpass filter based on integer math
367 void simpleLPFilterInit(simpleLowpassFilter_t
*filter
, int32_t beta
, int32_t fpShift
)
371 filter
->fpShift
= fpShift
;
374 int32_t simpleLPFilterUpdate(simpleLowpassFilter_t
*filter
, int32_t newVal
)
376 filter
->fp
= (filter
->fp
<< filter
->beta
) - filter
->fp
;
377 filter
->fp
+= newVal
<< filter
->fpShift
;
378 filter
->fp
>>= filter
->beta
;
379 int32_t result
= filter
->fp
>> filter
->fpShift
;
385 void meanAccumulatorInit(meanAccumulator_t
*filter
)
387 filter
->accumulator
= 0;
391 void meanAccumulatorAdd(meanAccumulator_t
*filter
, const int8_t newVal
)
393 filter
->accumulator
+= newVal
;
397 int8_t meanAccumulatorCalc(meanAccumulator_t
*filter
, const int8_t defaultValue
)
400 int8_t retVal
= filter
->accumulator
/ filter
->count
;
401 meanAccumulatorInit(filter
);