-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathAudioFilterConvolution_F32.h
203 lines (188 loc) · 8.05 KB
/
AudioFilterConvolution_F32.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
******************************************************************************
* @file AudioFilterConvolution_F32.cpp
* @author Giuseppe Callipo - IK8YFW - [email protected]
* @version V2.0.0
* @date 06-02-2021
* @brief F32 Filter Convolution
*
******************************************************************************
******************************************************************************
This software is based on the AudioFilterConvolution routine
Written by Brian Millier on Mar 2017
https://circuitcellar.com/research-design-hub/fancy-filtering-with-the-teensy-3-6/
and modified by Giuseppe Callipo - ik8yfw.
Modifications:
1) Class refactoring, change some methods visibility;
2) Filter coefficients calculation included into class;
3) Change the class for running in both with F32
OpenAudio_ArduinoLibrary for Teensy;
4) Added initFilter method for single anf fast initialization and on
the fly reinititializzation;
5) Optimize it to use as output audio filter on SDR receiver.
6) Optimize the time execution
*******************************************************************/
/* Additional Notes from Bob
* Object creations is required. See the OpenAudio_ArduinoLibrary
* Design Tool for object declarations along with
* automatic generatin of code. As an example this could produce
* the following needed global code
* AudioFilterConvolution_F32 FilterConv(audio_settings);
* AudioConnection_F32 patchCord1(FilterConv,0,Output_i2s,0);
* AudioConnection_F32 patchCord2(FilterConv,0,Output_i2s,1);
*
* There are three class functions:
* void initFilter(float32_t fc, float32_t Astop,
* int type, float32_t dfc);
* void passThrough(int stat);
* float32_t* getCoeffPtr(void);
*
* initFilter() is used to design the "mask" function that sets the filter
* response. All filters use the Kaiser window that is characterized by
* a programable first sidelobe level and decreasing sidelobes as the
* frequency departs from the pass band. For many applications this is an
* excellent response. The response type is set by the integer "type." The
* options are:
* type=LOWPASS Low pass with fc cutoff frequency and dfc not used.
* type=HIGHPASS High pass with fc cutoff frequency and dfc not used.
* type=BANDPASS Band pass with fc center frequency and dfc pass band width.
* type=BANDREJECT Band reject with fc center frequency and dfc reject band width.
* type=HILBERT Hilbert transform. *** Not Currently Available ***
*
* Astop is a value in dB that approximates the first sidelobe level
* going into the stop band. This is a feature of the Kaiser window that
* allows trading off first sidelobe levels against the speed of
* transition from the passband to the stop band(s). Values in the 25
* to 70 dB range work well.
*
* Two examples of initFilter():
* // IK8YFW CW - Centered at 800Hz, ( 40 db x oct ), 2=BPF, width = 1200Hz
* FilterConv.initFilter((float32_t)800, 40, 2, 1200.0);
*
* // IK8YFWSSB - Centered at 1500Hz, ( 60 db x oct ), 2=BPF, width = 3000Hz
* FilterConv.initFilter((float32_t)1500, 60, 2, 3000.0);
*
* The band edges of filters here are specified by their -6 dB points.
*
* passThrough(int stat) allows data for this filter object to be passed through
* unchanged with stat=1. The dfault is stat=0.
*
* getCoeffPtr() returns a pointer to the coefficient array. To use this, compute
* the coefficients of a 512 tap FIR filter with the desired response. Then
* load the 512 float32_t buffer with the coefficients. Disabling the audio
* path may be needed to prevent "pop" noises.
*
* An alternate way to specify
*
* This class is compatible with, and included in, OpenAudio_ArduinoLibrary_F32.
* If you are using the include OpenAudio_ArduinoLibrary.h, this class's
* include file will be swept in.
*
* Only block_size = 128 is supported.
* Sample rate can be changed.
*
* Speed of execution is the force behind the convolution filter form.
* Measured 128 sample in update() is 139 microseconds (T4.x).
* Comparison with a conventional FIR from this library, the
* AudioFilterFIRGeneral_F32, showed that a 512 tap FIR gave
* essentially the same response but was somewhat slower at
* 225 microseconds per 128 update. Also, note that this form of the
* computation uses about 44 kB of data memory where the direct FIR
* uses about 10 kB.
*
* See the example TestConvolutionFilter.ino for more inforation on the
* use of this class.
*
* NOTE: This filter can be run under Teensy 3.5, 3.6, 4.0, 4.1 ONLY
*
* Removed #defines that were not needed. Thanks K7MDL. Bob 6 Mar 2022
* Separated Teensy 3 and 4 parts. Thanks Paul Bob 16 Jan 2023
*
* ************************************************************ */
// Only exists for T3.5 through T4.1:
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
#ifndef AudioFilterConvolution_F32_h_
#define AudioFilterConvolution_F32_h_
#include <AudioStream_F32.h>
#include "arm_math.h"
#include "arm_common_tables.h"
#if defined(__IMXRT1062__)
#include "arm_const_structs.h"
#endif
#define MAX_NUMCOEF 513
#define PIH_F32 1.5707963f
#define LOWPASS 0
#define HIGHPASS 1
#define BANDPASS 2
#define BANDREJECT 3
#define HILBERT 4
class AudioFilterConvolution_F32 :
public AudioStream_F32
{
public:
AudioFilterConvolution_F32(void) :
AudioStream_F32(1, inputQueueArray_F32)
{
fs = AUDIO_SAMPLE_RATE;
//block_size = 128; // Always
// INFO: __MK20DX128__ T_LC; __MKL26Z64__ T3.0; __MK20DX256__ T3.1 and T3.2
// __MK64FX512__) T3.5; __MK66FX1M0__ T3.6; __IMXRT1062__ T4.0 and T4.1
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
arm_cfft_radix4_init_f32(&fft_instFwd, 1024, 0, 1);
arm_cfft_radix4_init_f32(&fft_instRev, 1024, 1, 1);
// arm CMSIS library has predefined structures of type arm_cfft_instance_f32
// arm_cfft_sR_f32_len1024 is one of the structures
#endif
};
AudioFilterConvolution_F32(const AudioSettings_F32 &settings) :
AudioStream_F32(1, inputQueueArray_F32)
{
// Performs the first initialize
fs = settings.sample_rate_Hz;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
arm_cfft_radix4_init_f32(&fft_instFwd, 1024, 0, 1);
arm_cfft_radix4_init_f32(&fft_instRev, 1024, 1, 1);
#endif
};
virtual void update(void);
void passThrough(int stat);
void initFilter (void) {impulse(FIR_Coef);}
void initFilter (float32_t fc, float32_t Astop,
int type, float32_t dfc);
float32_t* getCoeffPtr(void) {return &FIR_Coef[0];}
private:
float32_t fs;
audio_block_f32_t *inputQueueArray_F32[1];
float32_t *sp_L;
volatile uint8_t state;
int i;
int k;
int l;
int passThru=0;
int enabled=0;
float32_t FIR_Coef[MAX_NUMCOEF];
const uint32_t FFT_length = 1024;
float32_t FIR_filter_mask[2048] __attribute__((aligned(4)));
float32_t buffer[2048] __attribute__((aligned(4)));
float32_t tbuffer[2048]__attribute__((aligned(4)));
float32_t FFT_buffer[2048] __attribute__((aligned(4)));
float32_t iFFT_buffer[2048] __attribute__((aligned(4)));
float32_t last_sample_buffer_L[512];
void impulse(float32_t *coefs);
int aaa = 0;
float32_t Izero (float32_t x);
float32_t m_sinc(int m, float32_t fc);
void calc_FIR_coeffs (float32_t * coeffs, int numCoeffs,
float32_t fc, float32_t Astop,
int type, float32_t dfc,
float32_t Fsamprate);
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
arm_cfft_radix4_instance_f32 fft_instFwd, fft_instRev;
// #elif defined(__IMXRT1062__)
// arm_cfft_instance_f32 arm_cfft_sR_f32_len1024 is built into cmsis
#endif
};
// end of read only once
#endif
// End T3.5, T3.6 or T4.x
#endif