首页 理论教育 实时滤波器技术:梳状滤波器优化方案

实时滤波器技术:梳状滤波器优化方案

时间:2023-06-23 理论教育 版权反馈
【摘要】:下面给出实时实现梳状滤波器的3种C语言代码。程序清单10.9:对ISRs_A.c梳状滤波器的变量声明摘要第1行声明阵列的索引值,第2行定义缓冲器长度,第5行定义了增益。程序清单10.10:来自于ISRs_A.c的实时梳状滤波器梳状滤波器涉及的实时步骤下面对程序清单10.10进行解释。这仅用于实现IIR滤波器。程序清单10.11:在ISRs_B.c梳状滤波器的高效循环缓存ISRs_A和ISRs_B的惟一不同就在于此。现在DSK上运行的是改进的梳状滤波器。

实时滤波器技术:梳状滤波器优化方案

下面给出实时实现梳状滤波器的3种C语言代码。这3种代码都很简单,可以通过把某行变成注释行而在FIR和IIR滤波器之间来回转换。如果选择FIR滤波器,C语言代码更接近程序清单10.2的Matlab例子。如果选择IIR滤波器,C语言代码更接近程序清单10.5的Matlab例子(即直接Ⅱ型,所以仅需一个循环缓冲器)。

运行该应用程序所需的文件位于本书CD中第10章的目录ccs\Echo下。所感兴趣的主要文件是ISRs_A.c,ISRs_B.c和ISRs_C.c。注意,任何时间只能在项目中加载这些ISR文件之一。ISR文件包括必需的变量声明并进行实际滤波操作。

要讨论的一个问题是如何声明一些变量。和类似C语言的Matlab示例一样,实现循环缓冲器的阵列可提供滤波器所需延迟。

程序清单10.9:对ISRs_A.c梳状滤波器的变量声明摘要

978-7-111-33881-9-Part02-34.jpg

第1行声明阵列的索引值,第2行定义缓冲器长度,第5行定义了增益。前一例子中,缓冲器长度和增益分别等于Rα。假定采样频率为48kHz,R等于96000可以提供2s延迟。第3、4行分配缓冲器所需内存。因为左声道采样和右声道采样都需空间,阵列实际需要192000(2×96000)个元素。注意,第3行很关键,漏掉这一行是常见错误。利用C语言编译器输出的链接器试图把所有数据都放置在内置的RAM中以提高速度,然而192000个浮点数的阵列无法容纳在内存中。没有第3行,链接器就会产生错误信息,从而无法创建阵列。遗憾的是,出现在代码编辑器下端的这个错误信息通常是看不到的,这是因为这个信息滚动到看不到了。如果没有第3行,加载运行程序时,滤波器输出会是0(静音)。第3行让编译器把名为buffer的阵列放置在名为CEO(外部SDRAM)的内存区。这样,有足够的空间来创建阵列,链接器就不会出问题,程序才可正确运行。另一常见错误是第4、5行不使用关键词volatile(这个问题请参看本书附录F)。

ISRs_A.c中执行实际滤波操作的部分是名为McBSP_TX_ISR()的传送(transmit)ISR部分。为了使用立体声编解码器(如原始C6713编解码器,用于C6711的基于PCM3006的子卡编解码器等),程序的实现和左右声道滤波器无关。然而,为清楚起见,程序清单10.10之后仅讨论左声道的内容。

程序清单10.10:来自于ISRs_A.c的实时梳状滤波器

978-7-111-33881-9-Part02-35.jpg

梳状滤波器涉及的实时步骤

下面对程序清单10.10进行解释。

(1)第1行:传送ISR首先把当前采样(由接收ISR从codec接收的16位整数)转换成浮点数值并将其作为当前输入元素,等于x[0]。

(2)第3行:将当前(即最新)采样写入循环缓冲器,覆盖掉最老的采样。

(3)第6行:在下一行代码使索引增加之前,保存指向最新值的采样值。这仅用于实现IIR滤波器。实际上,运行FIR代码时,很可能编译器会给出变量“newest”未被使用的警告。无需理会这个警告。

(4)第7行:与前面Matlab示例中的mod()一样,模运算符(C和C++中都是字符“%”)同样使索引“绕回”,从而这行使缓冲器成为循环的。该行还包括前缀“++”,在进行模运算之前增加索引值。这样,该行代码保证索引值指向循环缓冲器中当前最老的采样。

(5)第12行:这行进行FIR滤波操作。如果需要IIR梳状滤波器就把这行注释掉。

(6)第16和18行:这两行共同以直接Ⅱ型的方式进行IIR滤波操作。如果需要FIR梳状滤波器就把这两行注释掉。如你所见,这两行代码实现如图10.2所示

下面框图的IIR梳状滤波器。要实现如图10.2所示上面框图的IIR梳状滤波器,只需要简单地把第18行的索引变量oldest改成newest。

(7)第21行:这行代码把滤波操作的结果y[0]转换成变量CodecDa-taIn.Channel[LEFT],以通过传送ISR的其余代码传递给codec侧的DAC。

理解代码之后

现在,把所有文件复制到一个单独目录。在CCS打开项目并“Rebuild All”。构建完成后,“Load Program”至DSK并单击“Run”。现在梳状滤波器在DSK上运行着。使用吉他送话器作为输入,听一听输出。应该听到回声(FIR滤波器)或者间隔2s的回声(IIR滤波器),这是由于每个信道的缓冲器长度为96000(假定采样频率为48kHz)。可以把BUFFER_LENGTH定义的长度任意改成其他值以使用不同R值。改变后,保存ISR文件,重新构建项目,重新加载程序,并运行。类似地,可以试着改变变量gain的值以使用不同的α值。

对ISRs_A的小改进

虽然上面程序中第7行的代码使用的模运算符使循环缓冲器易于实现,但是实时处理时并不推荐该方法。模是除法运算后的余数,在一行代码中使用模就要强制进行除法运算,这对CPU周期来说成本是很高的,因为DSP没有支持除法的硬件。更有效的方式是实现ISRs_B.c中使用的循环缓冲器,其中,第7行的代码用下面两行代替。(www.xing528.com)

程序清单10.11:在ISRs_B.c梳状滤波器的高效循环缓存

978-7-111-33881-9-Part02-36.jpg

ISRs_A和ISRs_B的惟一不同就在于此。一个更常见的做法是,将循环缓冲器的长度取为2的幂(即2 n),由于可以通过将其与2 n-1相加而快速实现索引绕回,所以这个做法可以实现更高效的代码。读者感兴趣的话,可以对此进行研究。

要用ISRs_B代替ISRs_A,在左边的项目窗口上单击ISRs_A.c右键并选择“Remove from project”。在程序编辑器窗口上部单击“Project”→“Add Files to Project”并选择ISRs_B.c,然后单击“Rebuild All”。完成构建后,将程序加载(或重新加载)进DSK并单击“Run”。现在DSK上运行的是改进的梳状滤波器。

ISRs_C允许进行交互控制

与ISRs_B.c相比,ISRs_C.c有一行小的改变,允许使用名为GEL的文件。本书第11章会对GEL(即通用扩展语言)进行解释,这里仅简单说明一下。

我们希望可以交互改变延迟时间R和增益值α,因而我们创建可用于此的两个滑动条控制。虽然gain已声明为变量,所以程序允许时可以改变gain,但是BUFF-ER_LENGTH定义(设定延迟时间)在编译时已经固定了。因而,增加下面一行以便在允许时改变延迟时间。

978-7-111-33881-9-Part02-37.jpg

GEL文件本身很简单,具体如下。

程序清单10.12:GEL文件Echo.gel用于ISRs_C.c梳状滤波器

978-7-111-33881-9-Part02-38.jpg

下面对GEL文件程序代码进行说明。

(1)第1行:在程序编辑器的GEL下拉菜单中增加项目“Echo Controls”。

(2)第5行:创建称为“DelayControl”的滑动条,下限值是0,上限值是96000,一次滚动增加2400,一页滚动1。将这些信息赋给本地GEL整数变量my-delayfactor。

(3)第7行:mydelayfactor的值被赋给ISRs_C的代表变量C变量MyDelay-Samples。假定采样频率为48kHz,这样得到0.0~2.0s增量为50ms的延迟调整。

(4)第11行:创建称为“GainControl”的滑动条,下限值是0,上限值是10,一次滚动增加1,一页滚动1,将这些信息赋给本地GEL整数变量mygainfactor。

(5)第13行:把mygainfactor的值先除以10然后赋给ISRs_C的C变量gain。这样得到0.0~1.0增量为0.1的增益调整。但是,如上所述,我们希望避免代价太大的除法运算,所以我们将其乘以1/10。注意,“0.1F”中的大写字母F强迫编译器将该数作为浮点数而不是双精度数处理,这样效率更高而且可得到我们所需的足够高的精度。然后,编译器自动将整数mygainfactor变成浮点数,使得第13行的浮点分配事实上变成多余的。但是这个分配可以改进代码可读性。

要使用GEL文件,首先改变项目去掉ISRs_B并加入ISRs_C(方式和从ISRs_A变到ISRs_B一样)。GEL文件也要加到项目里。使用”File”,“Load GEL”,或者简单地在左边的项目窗口树上单击”GEL files”,然后单击“Load GEL”。选择要加载的“Echo.gel”。重新构建,重新加载,然后和前面一样运行程序。要激活GEL控制,单击代码编辑器的GEL下拉菜单,选择“Echo Control”和“Delay Control”。对“GainControl”进行同样操作。滑动条可能会彼此叠加,出现这种情况时,把一个往旁边拖动,以露出下面的另一个。激活两个GEL滑动条时,屏幕上可以看到与图10.18类似的画面。滑动条在控制的下面显示整数GEL变量而不是变量C的值。图中,延迟滑动条设为44108,增益滑动条设为6。这等于延迟为44108/48000≈919ms,增益为0.6。

978-7-111-33881-9-Part02-39.jpg

图10.18 带有ISRs_C的GEL滑动条控制器

如你所见,GEL文件允许交互改变代码中的变量值而不会停止并重新编译程序。GEL文件仅在编译后的程序的DEBUG版本下运行,要注意从DEBUG子目录下加载程序。注意,将DEBUG链接用于GEL文件传送会临时中断处理器,同时GEL文件控制改变变量。这会使输出信号暂时丢失,在移动一个滑动条时,发出听起来像“滴答”或“砰”的声音。如果你愿意多花点时间和精力,通过利用本书CD中名为Windows Control Applications的函数,就可以避免GEL文件的这个弊端,同时依然获得增益交互控制。这些函数使得可以运行编译程序的完全优化发行版本,避免控制程序时的任何处理器暂停。用类似技术创建winDSK6应用程序,具体信息参见本书附录E。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈