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/>.
26 #include "common/maths.h"
27 #include "common/sdft.h"
29 #define SDFT_R 0.9999f // damping factor for guaranteed SDFT stability (r < 1.0f)
31 static FAST_DATA_ZERO_INIT
float rPowerN
; // SDFT_R to the power of SDFT_SAMPLE_SIZE
32 static FAST_DATA_ZERO_INIT
bool isInitialized
;
33 static FAST_DATA_ZERO_INIT complex_t twiddle
[SDFT_BIN_COUNT
];
35 static void applySqrt(const sdft_t
*sdft
, float *data
);
38 void sdftInit(sdft_t
*sdft
, const int startBin
, const int endBin
, const int numBatches
)
41 rPowerN
= powf(SDFT_R
, SDFT_SAMPLE_SIZE
);
42 const float c
= 2.0f
* M_PIf
/ (float)SDFT_SAMPLE_SIZE
;
44 for (int i
= 0; i
< SDFT_BIN_COUNT
; i
++) {
46 twiddle
[i
] = SDFT_R
* (cos_approx(phi
) + _Complex_I
* sin_approx(phi
));
52 sdft
->startBin
= startBin
;
53 sdft
->endBin
= endBin
;
54 sdft
->numBatches
= numBatches
;
55 sdft
->batchSize
= (sdft
->endBin
- sdft
->startBin
) / sdft
->numBatches
+ 1; // batchSize = ceil(numBins / numBatches)
57 for (int i
= 0; i
< SDFT_SAMPLE_SIZE
; i
++) {
58 sdft
->samples
[i
] = 0.0f
;
61 for (int i
= 0; i
< SDFT_BIN_COUNT
; i
++) {
67 // Add new sample to frequency spectrum
68 FAST_CODE
void sdftPush(sdft_t
*sdft
, const float sample
)
70 const float delta
= sample
- rPowerN
* sdft
->samples
[sdft
->idx
];
72 sdft
->samples
[sdft
->idx
] = sample
;
73 sdft
->idx
= (sdft
->idx
+ 1) % SDFT_SAMPLE_SIZE
;
75 for (int i
= sdft
->startBin
; i
<= sdft
->endBin
; i
++) {
76 sdft
->data
[i
] = twiddle
[i
] * (sdft
->data
[i
] + delta
);
81 // Add new sample to frequency spectrum in parts
82 FAST_CODE
void sdftPushBatch(sdft_t
* sdft
, const float sample
, const int batchIdx
)
84 const int batchStart
= sdft
->batchSize
* batchIdx
;
85 int batchEnd
= batchStart
;
87 const float delta
= sample
- rPowerN
* sdft
->samples
[sdft
->idx
];
89 if (batchIdx
== sdft
->numBatches
- 1) {
90 sdft
->samples
[sdft
->idx
] = sample
;
91 sdft
->idx
= (sdft
->idx
+ 1) % SDFT_SAMPLE_SIZE
;
92 batchEnd
+= sdft
->endBin
- batchStart
+ 1;
94 batchEnd
+= sdft
->batchSize
;
97 for (int i
= batchStart
; i
< batchEnd
; i
++) {
98 sdft
->data
[i
] = twiddle
[i
] * (sdft
->data
[i
] + delta
);
103 // Get squared magnitude of frequency spectrum
104 FAST_CODE
void sdftMagSq(const sdft_t
*sdft
, float *output
)
109 for (int i
= sdft
->startBin
; i
<= sdft
->endBin
; i
++) {
110 re
= crealf(sdft
->data
[i
]);
111 im
= cimagf(sdft
->data
[i
]);
112 output
[i
] = re
* re
+ im
* im
;
117 // Get magnitude of frequency spectrum (slower)
118 FAST_CODE
void sdftMagnitude(const sdft_t
*sdft
, float *output
)
120 sdftMagSq(sdft
, output
);
121 applySqrt(sdft
, output
);
125 // Get squared magnitude of frequency spectrum with Hann window applied
126 // Hann window in frequency domain: X[k] = -0.25 * X[k-1] +0.5 * X[k] -0.25 * X[k+1]
127 FAST_CODE
void sdftWinSq(const sdft_t
*sdft
, float *output
)
133 for (int i
= (sdft
->startBin
+ 1); i
< sdft
->endBin
; i
++) {
134 val
= sdft
->data
[i
] - 0.5f
* (sdft
->data
[i
- 1] + sdft
->data
[i
+ 1]); // multiply by 2 to save one multiplication
137 output
[i
] = re
* re
+ im
* im
;
142 // Get magnitude of frequency spectrum with Hann window applied (slower)
143 FAST_CODE
void sdftWindow(const sdft_t
*sdft
, float *output
)
145 sdftWinSq(sdft
, output
);
146 applySqrt(sdft
, output
);
150 // Apply square root to the whole sdft range
151 static FAST_CODE
void applySqrt(const sdft_t
*sdft
, float *data
)
153 for (int i
= sdft
->startBin
; i
<= sdft
->endBin
; i
++) {
154 data
[i
] = sqrtf(data
[i
]);