@@ -169,4 +169,119 @@ C++ API directly.
169169Note that both the first and second stage filters are implemented using
170170fixed-point arithmetic which requires the coefficients to be presented in a
171171particular format. The Python scripts `stage1.py ` and `stage2.py `, provided with
172- this library, can be used to help with this formatting. See the associated README for usage details.
172+ this library, can be used to help with this formatting. See the associated README for usage details.
173+
174+
175+ Configuring for 32 kHz or 48 kHz output
176+ ***************************************
177+
178+ Filter design scripts are provided to support higher output sampling rates than the default 16 kHz.
179+
180+ Both stage 1 and stage 2 need to be updated because the first stage needs a higher
181+ cut off frequency before samples are passed to the downsample by three (32 kHz) or two (48 kHz) second stage
182+ decimator.
183+
184+ From the command line, follow these instructions::
185+
186+ python filter_design/design_filter.py # generate the filter .pkl files
187+ python stage1.py good_32k_filter_int.pkl # convert the .pkl file to a C style array for stage 1
188+ python stage2.py good_32k_filter_int.pkl # convert the .pkl file to a C style array for stage 2
189+
190+ .. note ::
191+ Use `good_48k_filter_int.pkl ` instead of `good_32k_filter_int.pkl ` to support 48 kHz.
192+
193+
194+ Next copy the output from last two scripts into a source file. This could be your `mic_array.cpp `
195+ file which launches the mic array tasks. It may look something like this::
196+
197+ #define MIC_ARRAY_32K_STAGE_1_TAP_COUNT 148
198+ #define MIC_ARRAY_32K_STAGE_1_FILTER_WORD_COUNT 128
199+ static const uint32_t WORD_ALIGNED stage1_32k_coefs[MIC_ARRAY_32K_STAGE_1_FILTER_WORD_COUNT]
200+ {
201+ .... the coeffs
202+ };
203+
204+ #define MIC_ARRAY_32K_STAGE_2_TAP_COUNT 96
205+ static constexpr right_shift_t stage2_32k_shift = 3;
206+
207+ static const int32_t WORD_ALIGNED stage2_32k_coefs[MIC_ARRAY_32K_STAGE_2_TAP_COUNT] = {
208+ .... the coeffs
209+ };
210+
211+ The new decimation object must now be declared that references your new filter coefficients.
212+ Again, this example is for 32 kHz output since the decimation factor is 3.::
213+
214+ using TMicArray = mic_array::MicArray<mic_count,
215+ mic_array::TwoStageDecimator<mic_count,
216+ 3,
217+ MIC_ARRAY_32K_STAGE_2_TAP_COUNT>,
218+ mic_array::StandardPdmRxService<MIC_ARRAY_CONFIG_MIC_IN_COUNT,
219+ mic_count,
220+ 3>,
221+ typename std::conditional<MIC_ARRAY_CONFIG_USE_DC_ELIMINATION,
222+ mic_array::DcoeSampleFilter<mic_count>,
223+ mic_array::NopSampleFilter<mic_count>>::type,
224+ mic_array::FrameOutputHandler<mic_count,
225+ MIC_ARRAY_CONFIG_SAMPLES_PER_FRAME,
226+ mic_array::ChannelFrameTransmitter>>;
227+
228+
229+ Next you need to change how you initialise and run the mic array task to reference your new
230+ mic array custom object. Normally the following code would be used in `ma_init() `::
231+
232+ mics.Init();
233+ mics.SetPort(pdm_res.p_pdm_mics);
234+ mic_array_resources_configure(&pdm_res, MIC_ARRAY_CONFIG_MCLK_DIVIDER);
235+ mic_array_pdm_clock_start(&pdm_res);
236+
237+ however if you wish to use custom filters then the initialisation would look like this::
238+
239+ mics.Decimator.Init(stage1_32k_coefs, stage2_32k_coefs, stage2_32k_shift);
240+ mics.PdmRx.Init(pdm_res.p_pdm_mics);
241+ mic_array_resources_configure(&pdm_res, MIC_ARRAY_CONFIG_MCLK_DIVIDER);
242+ mic_array_pdm_clock_start(&pdm_res);
243+
244+
245+ Finally, the `ma_task() ` function needs to be changed from the default way of calling::
246+
247+ mics.SetOutputChannel(c_frames_out);
248+ mics.InstallPdmRxISR();
249+ mics.UnmaskPdmRxISR();
250+ mics.ThreadEntry();
251+
252+ to using the custom version of the object::
253+
254+ mics.OutputHandler.FrameTx.SetChannel(c_frames_out);
255+ mics.PdmRx.InstallISR();
256+ mics.PdmRx.UnmaskISR();
257+ mics.ThreadEntry();
258+
259+
260+ The increased sample rate will place a higher MIPS burden on the processor. The typical
261+ MIPS usage (see section :ref: `resource_usage `) is in the order of 11 MIPS per channel
262+ using a 16 kHz output decimator.
263+
264+ Increasing the output sample rate to 32 kHz using the same length filters will increase
265+ processor usage per channel to approximately 13 MIPS rising to 15.6 MIPS for 48 kHz.
266+
267+ Increasing the filer lengths to 148 and 96 for stages 1 and 2 respectively at 48 kHz
268+ will increase processor usage per channel to around 20 MIPS.
269+
270+ Filter Characteristics for `good_32k_filter_int.pkl `
271+ ''''''''''''''''''''''''''''''''''''''''''''''''''''
272+
273+ The plot below indicates the frequency response of the first and second stages of the
274+ provided 32 kHz filters as well as the cascaded overall response. Note that the
275+ overall combined response provides a nice flat passband.
276+
277+ .. image :: 32k_freq_response.png
278+
279+ Filter Characteristics for `good_48k_filter_int.pkl `
280+ ''''''''''''''''''''''''''''''''''''''''''''''''''
281+
282+ The plot below indicates the frequency response of the first and second stages of the
283+ provided 48 kHz filters as well as the cascaded overall response. Note that the
284+ overall combined response provides a nice flat passband.
285+
286+ .. image :: 48k_freq_response.png
287+
0 commit comments