Skip to content

Commit 28cc9b1

Browse files
authored
Merge pull request #209 from xmos/release/v5.2.0
Release v5.2.0 to main
2 parents beef6eb + 34e6c86 commit 28cc9b1

File tree

13 files changed

+199
-12
lines changed

13 files changed

+199
-12
lines changed

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
lib_mic_array change log
22
========================
33

4+
5.2.0
5+
-----
6+
7+
* Added 48 kHz decimator design script
8+
* Added documentation to cover 32 kHz and 48 kHz deciamtors
9+
410
5.1.0
511
-----
612

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ The CHANGELOG contains information about the current and previous versions.
3030
Related application notes
3131
.........................
3232

33-
None
33+
See the `demos/` subdirectory for simple examples. Also, `sln_voice` uses this library extensively and contains
34+
multiple examples both bare-metal and under the RTOS. See https://github.com/xmos/sln_voice/tree/develop/examples.
122 KB
Loading
123 KB
Loading

doc/programming_guide/src/decimator_stages.rst

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,119 @@ C++ API directly.
169169
Note that both the first and second stage filters are implemented using
170170
fixed-point arithmetic which requires the coefficients to be presented in a
171171
particular 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+

doc/programming_guide/src/introduction.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ See :ref:`getting_started` to get going.
1212

1313
.. note::
1414

15-
Version 5.0 does not currently support XS2 or XS1 devices.
15+
Version 5.0 does not currently support XS2 or XS1 devices. Please use version 4.5.0 if you need support for these devices: https://github.com/xmos/lib_mic_array/releases/tag/v4.5.0
1616

1717

1818
Find the latest version of ``lib_mic_array`` on `GitHub

doc/programming_guide/src/overview.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Capabilities
2424
* Second stage has fully configurable tap count and decimation factor
2525
* Custom filter coefficients can be used for either stage
2626
* Reference filter with total decimation factor of 192 is provided (16 kHz
27-
output sample rate w/ 3.072 MHz PDM clock)
27+
output sample rate w/ 3.072 MHz PDM clock).
28+
* Filter generation scripts and examples are included to support 32 kHz and 48 kHz.
2829

2930
* Supports 1-, 4- and 8-bit ports.
3031
* Supports 1 to 16 microphones
@@ -74,6 +75,10 @@ PDM rx is typically run within an interrupt on the same hardware core as the
7475
decimation thread, but it can also be run as a separate thread in cases where
7576
many channels result in a high processing load.
7677

78+
Likewise, the decimators may be split into multiple parallel hardware threads
79+
in the case where the processing load exceeds the MIPS available in a single
80+
thread.
81+
7782
Step 1: PDM Capture
7883
*******************
7984

doc/programming_guide/src/resource_usage.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ applications in ``demo/measure_mips``.
119119
| PDM Freq | S2DF | S2TC | PdmRx | 1 mic | 2 mic | 4 mic | 8 mic |
120120
| | | | | MIPS | MIPS | MIPS | MIPS |
121121
+============+======+======+=======+=======+=======+=======+=======+
122-
| 3.072 MHz | 6 | 65 | ISR | 10.65 | 22.00 | TBD | TBD |
122+
| 3.072 MHz | 6 | 65 | ISR | 10.65 | 22.00 | 43.70 | N/A |
123123
+------------+------+------+-------+-------+-------+-------+-------+
124-
| 3.072 MHz | 6 | 65 |Thread | 9.33 | 19.37 | TBD | TBD |
124+
| 3.072 MHz | 6 | 65 |Thread | 9.33 | 19.37 | 38.48 | 75.90 |
125125
+------------+------+------+-------+-------+-------+-------+-------+
126126
| 6.144 MHz | 6 | 65 | ISR | 21.26 | 43.89 | TBD | TBD |
127127
+------------+------+------+-------+-------+-------+-------+-------+

lib_mic_array/module_build_info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = 5.0.3
1+
VERSION = 5.2.0
22

33
DEPENDENT_MODULES = lib_xcore_math
44

script/filter_design/design_filter.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,44 @@ def good_32k_filter(int_coeffs: bool):
320320
return coeffs
321321

322322

323+
def good_48k_filter(int_coeffs: bool):
324+
fs_0 = 3072000
325+
decimations = [32, 2]
326+
327+
# stage 1 parameters
328+
ma_stages = 5
329+
330+
# stage 2 parameters
331+
cutoff = 20000
332+
transition_bandwidth = 1000
333+
taps_2 = 96
334+
fir_window = ("kaiser", 6.5)
335+
stage_2 = stage_params(cutoff, transition_bandwidth, taps_2, fir_window)
336+
337+
coeffs = design_2_stage(fs_0, decimations, ma_stages, stage_2, int_coeffs=int_coeffs)
338+
339+
return coeffs
340+
341+
342+
def small_48k_filter(int_coeffs: bool):
343+
fs_0 = 3072000
344+
decimations = [32, 2]
345+
346+
# stage 1 parameters
347+
ma_stages = 5
348+
349+
# stage 2 parameters
350+
cutoff = 20000
351+
transition_bandwidth = 1000
352+
taps_2 = 64
353+
fir_window = ("kaiser", 8)
354+
stage_2 = stage_params(cutoff, transition_bandwidth, taps_2, fir_window)
355+
356+
coeffs = design_2_stage(fs_0, decimations, ma_stages, stage_2, int_coeffs=int_coeffs)
357+
358+
return coeffs
359+
360+
323361
def main():
324362
coeffs = small_2_stage_filter(int_coeffs=True)
325363
out_path = "small_2_stage_filter_int.pkl"
@@ -333,10 +371,20 @@ def main():
333371
out_path = "good_3_stage_filter_int.pkl"
334372
ft.save_packed_filter(out_path, coeffs)
335373

374+
# For more info on 32kHz and 48kHz design, see
375+
# https://xmosjira.atlassian.net/wiki/spaces/CONF/pages/3805052950/32k+and+48k+Hz+lib+mic+array
376+
336377
coeffs = good_32k_filter(int_coeffs=True)
337378
out_path = "good_32k_filter_int.pkl"
338379
ft.save_packed_filter(out_path, coeffs)
339380

381+
coeffs = good_48k_filter(int_coeffs=True)
382+
out_path = "good_48k_filter_int.pkl"
383+
ft.save_packed_filter(out_path, coeffs)
384+
385+
coeffs = small_48k_filter(int_coeffs=True)
386+
out_path = "small_48k_filter_int.pkl"
387+
ft.save_packed_filter(out_path, coeffs)
340388

341389
if __name__ == "__main__":
342390
main()

0 commit comments

Comments
 (0)