Developer World
Spresense Arduino Library v3.2.0-77d75a4
FFT.h
1/*
2 * FFT.h - FFT Library
3 * Copyright 2019, 2021 Sony Semiconductor Solutions Corporation
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef _FFT_H_
21#define _FFT_H_
22
23/* Use CMSIS library */
24#define ARM_MATH_CM4
25#define __FPU_PRESENT 1U
26#include <cmsis/arm_math.h>
27
28#include "RingBuff.h"
29
30/*------------------------------------------------------------------*/
31/* Type Definition */
32/*------------------------------------------------------------------*/
33/* WINDOW TYPE */
34typedef enum e_windowType {
35 WindowHamming,
36 WindowHanning,
37 WindowFlattop,
38 WindowRectangle
39} windowType_t;
40
41/*------------------------------------------------------------------*/
42/* Input buffer */
43/*------------------------------------------------------------------*/
44template <int MAX_CHNUM, int FFTLEN> class FFTClass
45{
46public:
47 void begin(){
48 begin(WindowHamming, MAX_CHNUM, (FFTLEN / 2));
49 }
50
51 bool begin(windowType_t type, int channel, int overlap){
52 if (channel > MAX_CHNUM) return false;
53 if (overlap > (FFTLEN / 2)) return false;
54
55 m_overlap = overlap;
56 m_channel = channel;
57
58 clear();
59 create_coef(type);
60 if (!fft_init()) {
61 return false;
62 }
63
64 for(int i = 0; i < MAX_CHNUM; i++) {
65 ringbuf_fft[i] = new RingBuff(MAX_CHNUM * FFTLEN * sizeof(q15_t));
66 }
67
68 return true;
69 }
70
71 bool put(q15_t* pSrc, int sample) {
72 /* Ringbuf size check */
73 if(m_channel > MAX_CHNUM) return false;
74 if(sample > ringbuf_fft[0]->remain()) return false;
75
76 if (m_channel == 1) {
77 /* the faster optimization */
78 ringbuf_fft[0]->put((q15_t*)pSrc, sample);
79 } else {
80 for (int i = 0; i < m_channel; i++) {
81 ringbuf_fft[i]->put(pSrc, sample, m_channel, i);
82 }
83 }
84 return true;
85 }
86
87 int get_raw(float* out, int channel) {
88 return get_raw(out, channel, true);
89 }
90
91 int get(float* out, int channel) {
92 return get_raw(out, channel, false);
93 }
94
95 void clear() {
96 for (int i = 0; i < MAX_CHNUM; i++) {
97 memset(tmpInBuf[i], 0, FFTLEN);
98 }
99 }
100
101 void end(){}
102
103
104 bool empty(int channel){
105 return (ringbuf_fft[channel]->stored() < FFTLEN);
106 }
107
108private:
109
110 RingBuff* ringbuf_fft[MAX_CHNUM];
111
112 int m_channel;
113 int m_overlap;
114 arm_rfft_fast_instance_f32 S;
115
116 /* Temporary buffer */
117 float tmpInBuf[MAX_CHNUM][FFTLEN];
118 float coef[FFTLEN];
119 float tmpOutBuf[FFTLEN];
120
121 void create_coef(windowType_t type) {
122 for (int i = 0; i < FFTLEN / 2; i++) {
123 if (type == WindowHamming) {
124 coef[i] = 0.54f - (0.46f * arm_cos_f32(2 * PI * (float)i / (FFTLEN - 1)));
125 } else if (type == WindowHanning) {
126 coef[i] = 0.54f - (1.0f * arm_cos_f32(2 * PI * (float)i / (FFTLEN - 1)));
127 } else if (type == WindowFlattop) {
128 coef[i] = 0.21557895f - (0.41663158f * arm_cos_f32(2 * PI * (float)i / (FFTLEN - 1)))
129 + (0.277263158f * arm_cos_f32(4 * PI * (float)i / (FFTLEN - 1)))
130 - (0.083578947f * arm_cos_f32(6 * PI * (float)i / (FFTLEN - 1)))
131 + (0.006947368f * arm_cos_f32(8 * PI * (float)i / (FFTLEN - 1)));
132 } else {
133 coef[i] = 1;
134 }
135 coef[FFTLEN -1 - i] = coef[i];
136 }
137 }
138
139 bool fft_init(){
140 switch (FFTLEN){
141 case 32:
142 arm_rfft_32_fast_init_f32(&S);
143 break;
144 case 64:
145 arm_rfft_64_fast_init_f32(&S);
146 break;
147 case 128:
148 arm_rfft_128_fast_init_f32(&S);
149 break;
150 case 256:
151 arm_rfft_256_fast_init_f32(&S);
152 break;
153 case 512:
154 arm_rfft_512_fast_init_f32(&S);
155 break;
156 case 1024:
157 arm_rfft_1024_fast_init_f32(&S);
158 break;
159 case 2048:
160 arm_rfft_2048_fast_init_f32(&S);
161 break;
162 case 4096:
163 arm_rfft_4096_fast_init_f32(&S);
164 break;
165 default:
166 puts("error!");
167 return false;
168 break;
169 }
170 return true;
171 }
172
173 void fft(float *pSrc, float *pDst) {
174 arm_rfft_fast_f32(&S, pSrc, pDst, 0);
175 }
176
177 void fft_amp(float *pSrc, float *pDst) {
178 /* calculation */
179 arm_rfft_fast_f32(&S, pSrc, tmpOutBuf, 0);
180 arm_cmplx_mag_f32(tmpOutBuf, pDst, FFTLEN / 2);
181 }
182
183 int get_raw(float* out, int channel, int raw) {
184 static float tmpFft[FFTLEN];
185
186 if(channel >= m_channel) return false;
187 if (ringbuf_fft[channel]->stored() < FFTLEN) return 0;
188
189 for (int i=0;i<m_overlap;i++) {
190 tmpInBuf[channel][i] = tmpInBuf[channel][FFTLEN - m_overlap + i];
191 }
192
193 /* Read from the ring buffer */
194 ringbuf_fft[channel]->get(&tmpInBuf[channel][m_overlap], FFTLEN - m_overlap);
195
196 for (int i = 0; i < FFTLEN; i++) {
197 tmpFft[i] = tmpInBuf[channel][i] * coef[i];
198 }
199
200 if(raw){
201 /* Calculate only FFT */
202 fft(tmpFft, out);
203 }else{
204 /* Calculate FFT for convert to amplitude */
205 fft_amp(tmpFft, out);
206 }
207 return (FFTLEN - m_overlap);
208 }
209
210
211};
212
213#endif /*_FFT_H_*/
Definition: FFT.h:45
Definition: RingBuff.h:26