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/>.
23 #include "flight/lowpass.h"
25 //#define DEBUG_LOWPASS
27 void generateLowpassCoeffs2(int16_t freq
, lowpass_t
*filter
)
32 // generates coefficients for a 2nd-order butterworth low-pass filter
33 float freqf
= (float)freq
*0.001f
;
34 float omega
= tanf((float)M_PI
*freqf
/2.0f
);
35 float scaling
= 1.0f
/ (omega
*omega
+ 1.4142136f
*omega
+ 1.0f
);
38 #if defined(UNIT_TEST) && defined(DEBUG_LOWPASS)
39 printf("lowpass cutoff: %f, omega: %f\n", freqf
, omega
);
42 filter
->bf
[0] = scaling
* omega
*omega
;
43 filter
->bf
[1] = 2.0f
* filter
->bf
[0];
44 filter
->bf
[2] = filter
->bf
[0];
47 filter
->af
[1] = scaling
* (2.0f
* omega
*omega
- 2.0f
);
48 filter
->af
[2] = scaling
* (omega
*omega
- 1.4142136f
* omega
+ 1.0f
);
50 // Scale for fixed-point
51 filter
->input_bias
= 1500; // Typical servo range is 1500 +/- 500
52 filter
->input_shift
= 16;
53 filter
->coeff_shift
= 24;
54 fixedScaler
= (float)(1ULL << filter
->coeff_shift
);
55 for (i
= 0; i
< LOWPASS_NUM_COEF
; i
++) {
56 filter
->a
[i
] = LPF_ROUND(filter
->af
[i
] * fixedScaler
);
57 filter
->b
[i
] = LPF_ROUND(filter
->bf
[i
] * fixedScaler
);
58 #if defined(UNIT_TEST) && defined(DEBUG_LOWPASS)
59 printf("(%d) bf: %f af: %f b: %ld a: %ld\n", i
,
60 filter
->bf
[i
], filter
->af
[i
], filter
->b
[i
], filter
->a
[i
]);
67 int32_t lowpassFixed(lowpass_t
*filter
, int32_t in
, int16_t freq
)
73 // Check to see if cutoff frequency changed
74 if (freq
!= filter
->freq
) {
78 // Initialize if needed
80 generateLowpassCoeffs2(freq
, filter
);
81 for (coefIdx
= 0; coefIdx
< LOWPASS_NUM_COEF
; coefIdx
++) {
82 filter
->x
[coefIdx
] = (in
- filter
->input_bias
) << filter
->input_shift
;
83 filter
->y
[coefIdx
] = (in
- filter
->input_bias
) << filter
->input_shift
;
88 // Unbias input and scale
89 in_s
= (in
- filter
->input_bias
) << filter
->input_shift
;
92 for (coefIdx
= LOWPASS_NUM_COEF
-1; coefIdx
> 0; coefIdx
--) {
93 filter
->x
[coefIdx
] = filter
->x
[coefIdx
-1];
94 filter
->y
[coefIdx
] = filter
->y
[coefIdx
-1];
99 out
= filter
->x
[0] * filter
->b
[0];
100 for (coefIdx
= 1; coefIdx
< LOWPASS_NUM_COEF
; coefIdx
++) {
101 out
-= filter
->y
[coefIdx
] * filter
->a
[coefIdx
];
102 out
+= filter
->x
[coefIdx
] * filter
->b
[coefIdx
];
105 // Scale output by coefficient shift
106 out
>>= filter
->coeff_shift
;
107 filter
->y
[0] = (int32_t)out
;
109 // Scale output by input shift and round
110 out
= (out
+ (1 << (filter
->input_shift
-1))) >> filter
->input_shift
;
113 out
+= filter
->input_bias
;