查看: 1589|回复: 0

[评测分享] 【NXP OKdo E1双核Cortex M33开发板 】USB音频PowerQuad IIR 滤波

[复制链接]

该用户从未签到

发表于 2020-12-20 17:24:09 | 显示全部楼层 |阅读模式
分享到:
本帖最后由 文波_苏州 于 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位深的单频方波作为被处理信号:

Screen Shot 2020-12-20 at 1.50.36 AM.png

然后设计滤波器。利用在线DSP设计平台https://www.micromodeler.com/dsp/采样频率需要改成48000Hz。从Eli的文章中我们知道NXP官方库主要用的是IIR Direct Form2, 所以Biquad选择Direct Form2。我们这次只是定性评估,所以简单拖拽一下大致保证滤波器的起始和截止频率在几百到几千赫兹即可,之后复制粘贴。得到两组系数,分别是高通和低通。
Screen Shot 2020-12-20 at 1.53.44 AM.png

注意到NXP所用的多项式是有负号的,所以a1和a2要变号,参见:https://community.nxp.com/t5/Kin ... n-Tool/ta-p/1127670
  1. #define BUF_LEN 16
  2. bool is_filtering = false;
  3. bool is_highpass = false;
  4. int16_t sq_wave_amp_in_16 = 0;
  5. int16_t bufcnt = 0;
  6. int16_t biquadResult[BUF_LEN]  = {0};
  7. int16_t dataForBiquad[BUF_LEN] = {1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  8. int16_t biquadRef[BUF_LEN]     = {257, -240, 112, 93, -80, -27, 47, 2, -24, 5, 11, -5, -4, 4, 1, -2};

  9. void filter_init(void)
  10. {
  11.     pq_biquad_state_t state_lp = {
  12.         .compreg = 0,
  13.         .param =
  14.             {
  15.                 .v_n_1 = 0.0f,
  16.                 .v_n   = 0.0f,
  17.                 .a_1   = -1.880f,
  18.                 .a_2   = 0.890f,
  19.                 .b_0   = 0.00266f,
  20.                 .b_1   = 0.00531f,
  21.                 .b_2   = 0.00266f,
  22.             },
  23.     };
  24.         .param =
  25.             {
  26.                 .v_n_1 = 0.0f,
  27.                 .v_n   = 0.0f,
  28.                 .a_1   = 0.8772579569675075f,
  29.                 .a_2   = 0.0f,
  30.                 .b_0   = 0.9386289973682456f,
  31.                 .b_1   = -0.9386289973682456f,
  32.                 .b_2   = -0.0f,
  33.             },
  34.     };
  35.     pq_prescale_t prescale;
  36.     prescale.inputPrescale  = 0;
  37.     prescale.outputPrescale = 0;
  38.     prescale.outputSaturate = 0;

  39.     PQ_SetCoprocessorScaler(POWERQUAD, &prescale);
  40.     // Init the biquad0 filter
  41.     if ( is_highpass )
  42.             PQ_BiquadRestoreInternalState(POWERQUAD, 0, &state_hp );
  43.     else
  44.             PQ_BiquadRestoreInternalState(POWERQUAD, 0, &state_lp );
  45. /* Ignore the sanity check for now
  46.     PQ_VectorBiqaudDf2Fixed16(dataForBiquad, biquadResult, ARRAY_SIZE(biquadRef));
  47.     for (uint32_t i = 0; i < ARRAY_SIZE(biquadRef); i++)
  48.     {
  49.         //EXAMPLE_ASSERT_TRUE(biquadRef[i] == biquadResult[i]);
  50.     }
  51. */
  52.     printf( "power quad inited\n" );
  53. }
复制代码

增加一个filter_toggle()函数,这样就可以用OKdo-E1板上的按钮动态切换所用的滤波器种类,或者干脆不用滤波器:

  1. void filter_toggle()
  2. {
  3.         if ( is_filtering )
  4.         {
  5.                 is_filtering = false;
  6.                 printf( "Stop filtering\n\r" );
  7.         }
  8.         else
  9.         {
  10.                 is_filtering = true;
  11.                 printf( "Start filtering\n\r" );
  12.                 if ( is_highpass )
  13.                 {
  14.                         is_highpass = false;

  15.                 }
  16.                 else
  17.                 {
  18.                         is_highpass = true;
  19.                 }
  20.                 filter_init();
  21.                 printf( "Set to highpass %d\n\r", is_highpass ) ;
  22.         }
  23. }



  24. void filter_biqud_in16()
  25. {
  26.         if ( is_filtering )
  27.         {
  28.                 PQ_VectorBiqaudDf2Fixed16(dataForBiquad, biquadResult, ARRAY_SIZE(biquadRef));
  29.                 //printf(">");
  30.         }
  31.         else
  32.         {
  33.                 memcpy( biquadResult, dataForBiquad, BUF_LEN * 2 );
  34.                 //printf(".");
  35.         }

  36. }

  37. uint8_t filter_sample_in_16x16( uint32_t cnt )
  38. {
  39.         uint8_t out_buf = 0;
  40.         if ( ( cnt / 2 ) % 2 )
  41.         {      
  42.                 out_buf = 0x00;
  43.         }
  44.         else
  45.         {
  46.                 int16_t sample;
  47.                
  48.                 dataForBiquad[bufcnt] = generate_1k_sq_wave_on_right_in_16();
  49.                 sample = biquadResult[bufcnt];

  50.                 if ( !( cnt % 4 ) )
  51.                         out_buf = (0x00ff & sample );
  52.                 else
  53.                 {
  54.                         out_buf = ( 0xff00 & sample ) >> 8;
  55.                         if ( ++bufcnt == BUF_LEN )
  56.                         {
  57.                                 filter_biqud_in16();
  58.                                 bufcnt = 0;
  59.                         }
  60.                 }
  61.         }
  62.         
  63.         return out_buf;
  64. }

  65. uint8_t filter_sample(uint8_t buf, uint32_t cnt )
  66. {
  67.         return filter_sample_in_16x16( cnt );
  68. }
复制代码
  1. usb_status_t USB_DeviceHidKeyboardAction(void)
  2. {
  3.     if (g_ButtonPress)
  4.     {
  5.         //s_UsbDeviceHidKeyboard.buffer[0] = 0x04U;
  6.         g_ButtonPress = false;
  7.         filter_toggle();
  8.         printf( "SW1 pressed, " );
  9.         /*return USB_DeviceHidSend(g_UsbDeviceComposite->hidKeyboard.hidHandle, USB_HID_KEYBOARD_ENDPOINT,
  10.                                  s_UsbDeviceHidKeyboard.buffer, USB_HID_KEYBOARD_REPORT_LENGTH);*/
  11.     }
  12.     else if (g_CodecMuteUnmute)
  13.     {
  14.         s_UsbDeviceHidKeyboard.buffer[0] = 0x00U;
  15.         g_CodecMuteUnmute = false;
  16.         return USB_DeviceHidSend(g_UsbDeviceComposite->hidKeyboard.hidHandle, USB_HID_KEYBOARD_ENDPOINT,
  17.                                  s_UsbDeviceHidKeyboard.buffer, USB_HID_KEYBOARD_REPORT_LENGTH);
  18.     }
  19.     else
  20.     {
  21.         return kStatus_USB_Success;
  22.     }
  23. }
复制代码

在main()函数中调用 filte_int():

Screen Shot 2020-12-20 at 2.23.58 AM.png
项目文件加一行,编译滤波器驱动:

Screen Shot 2020-12-20 at 2.44.35 AM.png


编译烧写后,还是利用Audacity来看得到的信号。

原始方波:
Screen Shot 2020-12-20 at 2.30.51 AM.png


Screen Shot 2020-12-20 at 2.32.17 AM.png

高通:

Screen Shot 2020-12-20 at 2.33.34 AM.png

Screen Shot 2020-12-20 at 2.34.16 AM.png

低通,直观上我们看到方波已经被处理成了接近正弦波,高频成份被滤掉了。

Screen Shot 2020-12-20 at 2.35.04 AM.png

Screen Shot 2020-12-20 at 2.35.59 AM.png

用耳机听录下来的音轨,区别也是明显的,经过低通后,声音变得“纯”了。

稍加改动,我们就可以利用USB的音频回环来对一首音乐进行处理,从而对滤波器的特性得到更加直观的认识。
  1. uint8_t filter_sample_in_16x16( uint8_t buf, uint32_t cnt )
  2. {
  3.         uint8_t out_buf = 0;
  4.         if ( ( cnt / 2 ) % 2 )
  5.         {      
  6.                 out_buf = 0x00;
  7.         }
  8.         else
  9.         {
  10.                 int16_t sample;
  11.                
  12.                 //dataForBiquad[bufcnt] = generate_1k_sq_wave_on_right_in_16();
  13.                 if ( !( cnt % 4 ) )
  14.                         dataForBiquad[bufcnt] = 0x00ff & buf;
  15.                 else
  16.                 {
  17.                         dataForBiquad[bufcnt] = ( buf << 8  ) | dataForBiquad[bufcnt];
  18.                 }


  19.                 sample = biquadResult[bufcnt];

  20.                 if ( !( cnt % 4 ) )
  21.                         out_buf = (0x00ff & sample );
  22.                 else
  23.                 {
  24.                         out_buf = ( 0xff00 & sample ) >> 8;
  25.                         if ( ++bufcnt == BUF_LEN )
  26.                         {
  27.                                 filter_biqud_in16();
  28.                                 bufcnt = 0;
  29.                         }
  30.                 }
  31.         }
  32.         
  33.         return out_buf;
  34. }
复制代码


我们录一段测试音轨,先是不加滤波,之后是高通,之后又是不滤波,最后是低通。

jiu_test.zip (2.03 MB, 下载次数: 1)
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|与非网

GMT+8, 2025-1-27 08:32 , Processed in 0.121754 second(s), 17 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.