|
本帖最后由 文波_苏州 于 2020-12-20 19:20 编辑
在实际音频应用中,数字滤波器是常见的组件。我们有时用它从原始信号中提取想要的信号,有时利用它对原始信号进行一些变化达到想要的音效。
LPC55S69中的PowerQuad是专门为数字信号处理和矩阵计算设计的模块,自然也支持常用的数字滤波器。SDK PowerQuad IIR filter的官方例程位于:boards/lpcxpresso55s69/driver_examples/powerquad/filter/,NXP工程师Eli Hughes也写了精彩的应用笔记讲解PowerQuad中IIR滤波器的使用:https://community.nxp.com/t5/MCU ... tering/ba-p/1131184。
在大致了解了背景知识之后,改动或增加几行代码就能把IIR滤波器加入USB音频应用。
首先产生一个16bit位深的单频方波作为被处理信号:
然后设计滤波器。利用在线DSP设计平台https://www.micromodeler.com/dsp/采样频率需要改成48000Hz。从Eli的文章中我们知道NXP官方库主要用的是IIR Direct Form2, 所以Biquad选择Direct Form2。我们这次只是定性评估,所以简单拖拽一下大致保证滤波器的起始和截止频率在几百到几千赫兹即可,之后复制粘贴。得到两组系数,分别是高通和低通。
注意到NXP所用的多项式是有负号的,所以a1和a2要变号,参见:https://community.nxp.com/t5/Kin ... n-Tool/ta-p/1127670。
- #define BUF_LEN 16
- bool is_filtering = false;
- bool is_highpass = false;
- int16_t sq_wave_amp_in_16 = 0;
- int16_t bufcnt = 0;
- int16_t biquadResult[BUF_LEN] = {0};
- int16_t dataForBiquad[BUF_LEN] = {1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int16_t biquadRef[BUF_LEN] = {257, -240, 112, 93, -80, -27, 47, 2, -24, 5, 11, -5, -4, 4, 1, -2};
- void filter_init(void)
- {
- pq_biquad_state_t state_lp = {
- .compreg = 0,
- .param =
- {
- .v_n_1 = 0.0f,
- .v_n = 0.0f,
- .a_1 = -1.880f,
- .a_2 = 0.890f,
- .b_0 = 0.00266f,
- .b_1 = 0.00531f,
- .b_2 = 0.00266f,
- },
- };
- .param =
- {
- .v_n_1 = 0.0f,
- .v_n = 0.0f,
- .a_1 = 0.8772579569675075f,
- .a_2 = 0.0f,
- .b_0 = 0.9386289973682456f,
- .b_1 = -0.9386289973682456f,
- .b_2 = -0.0f,
- },
- };
- pq_prescale_t prescale;
- prescale.inputPrescale = 0;
- prescale.outputPrescale = 0;
- prescale.outputSaturate = 0;
- PQ_SetCoprocessorScaler(POWERQUAD, &prescale);
- // Init the biquad0 filter
- if ( is_highpass )
- PQ_BiquadRestoreInternalState(POWERQUAD, 0, &state_hp );
- else
- PQ_BiquadRestoreInternalState(POWERQUAD, 0, &state_lp );
- /* Ignore the sanity check for now
- PQ_VectorBiqaudDf2Fixed16(dataForBiquad, biquadResult, ARRAY_SIZE(biquadRef));
- for (uint32_t i = 0; i < ARRAY_SIZE(biquadRef); i++)
- {
- //EXAMPLE_ASSERT_TRUE(biquadRef[i] == biquadResult[i]);
- }
- */
- printf( "power quad inited\n" );
- }
复制代码
增加一个filter_toggle()函数,这样就可以用OKdo-E1板上的按钮动态切换所用的滤波器种类,或者干脆不用滤波器:
- void filter_toggle()
- {
- if ( is_filtering )
- {
- is_filtering = false;
- printf( "Stop filtering\n\r" );
- }
- else
- {
- is_filtering = true;
- printf( "Start filtering\n\r" );
- if ( is_highpass )
- {
- is_highpass = false;
- }
- else
- {
- is_highpass = true;
- }
- filter_init();
- printf( "Set to highpass %d\n\r", is_highpass ) ;
- }
- }
- void filter_biqud_in16()
- {
- if ( is_filtering )
- {
- PQ_VectorBiqaudDf2Fixed16(dataForBiquad, biquadResult, ARRAY_SIZE(biquadRef));
- //printf(">");
- }
- else
- {
- memcpy( biquadResult, dataForBiquad, BUF_LEN * 2 );
- //printf(".");
- }
- }
- uint8_t filter_sample_in_16x16( uint32_t cnt )
- {
- uint8_t out_buf = 0;
- if ( ( cnt / 2 ) % 2 )
- {
- out_buf = 0x00;
- }
- else
- {
- int16_t sample;
-
- dataForBiquad[bufcnt] = generate_1k_sq_wave_on_right_in_16();
- sample = biquadResult[bufcnt];
- if ( !( cnt % 4 ) )
- out_buf = (0x00ff & sample );
- else
- {
- out_buf = ( 0xff00 & sample ) >> 8;
- if ( ++bufcnt == BUF_LEN )
- {
- filter_biqud_in16();
- bufcnt = 0;
- }
- }
- }
-
- return out_buf;
- }
- uint8_t filter_sample(uint8_t buf, uint32_t cnt )
- {
- return filter_sample_in_16x16( cnt );
- }
复制代码- usb_status_t USB_DeviceHidKeyboardAction(void)
- {
- if (g_ButtonPress)
- {
- //s_UsbDeviceHidKeyboard.buffer[0] = 0x04U;
- g_ButtonPress = false;
- filter_toggle();
- printf( "SW1 pressed, " );
- /*return USB_DeviceHidSend(g_UsbDeviceComposite->hidKeyboard.hidHandle, USB_HID_KEYBOARD_ENDPOINT,
- s_UsbDeviceHidKeyboard.buffer, USB_HID_KEYBOARD_REPORT_LENGTH);*/
- }
- else if (g_CodecMuteUnmute)
- {
- s_UsbDeviceHidKeyboard.buffer[0] = 0x00U;
- g_CodecMuteUnmute = false;
- return USB_DeviceHidSend(g_UsbDeviceComposite->hidKeyboard.hidHandle, USB_HID_KEYBOARD_ENDPOINT,
- s_UsbDeviceHidKeyboard.buffer, USB_HID_KEYBOARD_REPORT_LENGTH);
- }
- else
- {
- return kStatus_USB_Success;
- }
- }
复制代码
在main()函数中调用 filte_int():
项目文件加一行,编译滤波器驱动:
编译烧写后,还是利用Audacity来看得到的信号。
原始方波:
高通:
低通,直观上我们看到方波已经被处理成了接近正弦波,高频成份被滤掉了。
用耳机听录下来的音轨,区别也是明显的,经过低通后,声音变得“纯”了。
稍加改动,我们就可以利用USB的音频回环来对一首音乐进行处理,从而对滤波器的特性得到更加直观的认识。
- uint8_t filter_sample_in_16x16( uint8_t buf, uint32_t cnt )
- {
- uint8_t out_buf = 0;
- if ( ( cnt / 2 ) % 2 )
- {
- out_buf = 0x00;
- }
- else
- {
- int16_t sample;
-
- //dataForBiquad[bufcnt] = generate_1k_sq_wave_on_right_in_16();
- if ( !( cnt % 4 ) )
- dataForBiquad[bufcnt] = 0x00ff & buf;
- else
- {
- dataForBiquad[bufcnt] = ( buf << 8 ) | dataForBiquad[bufcnt];
- }
- sample = biquadResult[bufcnt];
- if ( !( cnt % 4 ) )
- out_buf = (0x00ff & sample );
- else
- {
- out_buf = ( 0xff00 & sample ) >> 8;
- if ( ++bufcnt == BUF_LEN )
- {
- filter_biqud_in16();
- bufcnt = 0;
- }
- }
- }
-
- return out_buf;
- }
复制代码
我们录一段测试音轨,先是不加滤波,之后是高通,之后又是不滤波,最后是低通。
jiu_test.zip
(2.03 MB, 下载次数: 1)
|
|