2 定点小数表达方式
为了精确构造数字滤波器,经常要用到浮点数据和系统。在进行浮点数乘法运算时,针对AVR单片机设计的C编译器例如AVR-GCC,需要加入额外的数学库函数进行编译。而这会使编译后程序的代码量增加、处理时间加长、处理器的开销也随之增加。为了更大限度地降低系统开销,提高程序效率,采用定点小数表示形式进行乘法运算是最佳选择。
AVR单片机是一种8位精简指令集(RISC)单片机。其中megaAVR系列内部都带有一个硬件乘法器,计算一次8位乘8位的定点乘法只需2个时钟周期。因此采用8位定点采样数据乘以8位系数的定点乘法方式完成滤波器算法是最高效的。
低通滤波处理涉及的运算形式为一个纯小数系数和一个已知数据相乘再相加。因此将系数采用定点小数的表示形式,对于提高算法速度是至关重要的。
可以定义一种8位定点小数表示形成——Q8,其各位权系数如下:
Q8数的表示范围从0到1-2 -8=0.99609375,每两个数之间的间隔是2 -8(0.00390625),其所能表示的纯小数共有2 8=256个。例如11011000就表示2 -1+2 -2+2 -4+2 -5=0.84375,而11011001就是表示2 -1+2 -2+2 -4+2 -5+2 -8=0.84765625,因此0.84375和0.84765625之间的纯小数只能用这两个数中的一个近似表示了。这对于乘法计算的精度有一定的影响,但是由于滤波公式(3)中的系数a和(1-a)都是常数,在整体性能稳定的情况下,系数微小的不确定性对滤波器整体性能并没有太大的影响。
3 分配系数法原理
从(3)式可知,滤波算法可以用迭代计算实现,为保证每个新的输出值都可以作为下次计算的输入值,必须使输出值和输入值的位宽度一致。必须使输出值和输入值的位宽度一致。AVR单片机内部硬件乘法器的输出结果为16位,两次乘法运算的结果还要进行加法运算,其结果很有可能超过16位宽度。如果要进行迭代计算,就要将乘加运算的结果转化成8位表示方式。一种解决方法是用查表法实现乘法计算,这样运算结果就直接表达成8位定点数形式,不用进行表示方式的转化,但是这种方案要占用额外的硬件在座空间构造一张查找表。
可以从逆向进行思考:由(3)式可知,每个新的输出值y(k)都与上一次的输出值y(k-1) 和新的输入值x(k)有关。y(k-1)和x(k)都是8位的,因此最大值为0xFF。为了使a×y(k-1)+(1-a) ×x(k)不超过0xFFFF,两个系统a和(1-a)的和不能超过0xFFFF/0xFF=0x101。实际上,a+(1-a)等于"1",因此这里的0x101就可以看作“1”。如果取a=0.9,那么对应地将0x101平均分成10份,取其中的9份,即0x101×0.9近似等于0xE7,相应地0.1就等于0x101-0xE7=0x1A。这里的0xE7可以近似被认为是0.9的一种定点Q8数表示形式,而0.1的定点Q8数表示形式就是0x1A。由于滤波器系数a和(1-a)采用了Q8数的表示形式这种将16位乘加运算结果转化为8定点数表示形式的工作就变得各简单了,只需通过移位运算,取y(k)的高8位即可,对应的C语言代码为:
y(k)=(char)(y(k)>>8)
在C语言编程处理中,并不需要建立一个数组来存储y(k)的值,而只需定义两个unsigned char型的变量分别存储y(k-1)和x(k)。当乘加计算a×y(k-1)+(1-a)×x(k)完成后,将结果转化为8位定点数形式,再将其赋值给y(k-1)所对应的变量即可。因此采用迭代方式进行乘加运算后,整个运算过程只需要两个变量和两个常数参加即可。
通过这种处理,y(k)就可以作为计算下一次输出值y(k+1)的一个已知量,并继续与Q8数形式的滤波器系数相乘,得到新的输出值。这种处理方式简化了乘加运算的完成过程,节省了系统硬件资源,并降低了处理器开销。
4 采样时间的控制
采用单片机进行数字信号处理,一种有效而准确的数据采集方式就是通过计数器中断服务程序(ISR)控制AD对输入信号进行精确采样。但是(图2)中断服务程序(ISR)的开销影响了AD采样时间间隔的精确度,同时如果中断服务程序(ISR)的开销过大,必然导致AD的最高采样频率的降低。因此,要想获得精确的采样频率,就必须在尽量减少中断服务程序开销的前提下,适当调整计数器中断的时间间隔。这可以通过调整OCR0的预置数来完成。
5 算法流程图
滤波算法是通过中断服务程序(ISR)来完成的,整个应用程序的主函数main()主要负责初始化计数器中断,并处理其它应用。整个程序的流程图如图3所示。
本算法的C语言代码(附录A)经过AVR-GCC编译器的编译后,“.text”段只有310个字节,大大节省了单片机的flash空间。