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/>.
20 //#define DEBUG_LOWPASS
23 #include "flight/lowpass.h"
26 static lowpass_t lowpassFilterReference;
27 static lowpass_t lowpassFilter;
29 #include "unittest_macros.h"
30 #include "gtest/gtest.h"
32 static float lowpassRef(lowpass_t *filter, float in, int16_t freq)
37 // Check to see if cutoff frequency changed
38 if (freq != filter->freq) {
42 // Initialize if needed
44 generateLowpassCoeffs2(freq, filter);
45 for (coefIdx = 0; coefIdx < LOWPASS_NUM_COEF; coefIdx++) {
46 filter->xf[coefIdx] = in;
47 filter->yf[coefIdx] = in;
53 for (coefIdx = LOWPASS_NUM_COEF-1; coefIdx > 0; coefIdx--) {
54 filter->xf[coefIdx] = filter->xf[coefIdx-1];
55 filter->yf[coefIdx] = filter->yf[coefIdx-1];
60 out = filter->xf[0] * filter->bf[0];
61 for (coefIdx = 1; coefIdx < LOWPASS_NUM_COEF; coefIdx++) {
62 out += filter->xf[coefIdx] * filter->bf[coefIdx];
63 out -= filter->yf[coefIdx] * filter->af[coefIdx];
70 TEST(LowpassTest, Lowpass)
72 int16_t servoCmds[3000];
73 int16_t expectedOut[3000];
79 uint16_t sampleCount = sizeof(servoCmds) / sizeof(int16_t);
81 // generate inputs and expecteds
82 for (sampleIdx = 0; sampleIdx < sampleCount; sampleIdx++) {
83 if (sampleIdx < 1000) {
84 servoCmds[sampleIdx] = 500;
85 } else if (sampleIdx >= 1000 && sampleIdx < 2000) {
86 servoCmds[sampleIdx] = 2500;
88 servoCmds[sampleIdx] = 1500;
91 if ((sampleIdx >= 900 && sampleIdx < 1000) ||
92 (sampleIdx >= 1900 && sampleIdx < 2000)||
93 (sampleIdx >= 2900 && sampleIdx < 3000)) {
94 expectedOut[sampleIdx] = servoCmds[sampleIdx];
96 expectedOut[sampleIdx] = -1;
100 // Test all frequencies
101 for (freq = 10; freq <= 400; freq++) {
103 printf("*** Testing freq: %d (%f)\n", freq, ((float)freq * 0.001f));
106 for (sampleIdx = 0; sampleIdx < sampleCount; sampleIdx++)
109 filterOut = (int16_t)lowpassFixed(&lowpassFilter, servoCmds[sampleIdx], freq);
111 // Floating-point reference
112 referenceOut = (int16_t)(lowpassRef(&lowpassFilterReference, (float)servoCmds[sampleIdx], freq) + 0.5f);
114 if (expectedOut[sampleIdx] >= 0) {
115 EXPECT_EQ(filterOut, expectedOut[sampleIdx]);
118 // TODO adjust precision to remove the need for this?
119 EXPECT_LE(filterOut, referenceOut + 1);
120 EXPECT_GE(filterOut, referenceOut - 1);