lihui_mc 发表于 2010-9-16 17:00:29

关于IIR高通滤波器,个人认为AVR应用笔记AVR465中的程序有问题

最近需要检测交流电有效值,因此借用了AVR465中IIR高通滤波器以去掉采样数据中的直流成分

相关原版的代码是这样的:
计算公式:y = 0.996*y + 0.996*x - 0.996*x

Sample.PreviousFiltered=Sample.Filtered;// y <- y
TempL=255*(long)Sample.Filtered;
TempL=TempL>>8;
TempI=Sample.Fresh-Sample.Previous;
TempL=TempL+255*(long)TempI;
Sample.Filtered=TempL;

这段代码有2个问题:
1,第5句 TempL=TempL+255*(long)TempI; 我怎么看都觉得与公式不同,因为TempI没有除以256;
2,我认为,以定点计算代替浮点计算,需要有若干小数位参加计算,而该算法没做到这点。因此无法对小数点后的有效数字进行累积。我的实验也证明这点,
当电源电压是220伏时,测量结果完全正确,这是突然撤掉220伏,则测量结果会在56伏左右跳动,无法回零。
因此我认为是相邻采样点的差值接近零时,0.996的乘法的小数部分被抛弃了。下面是我自己的代码:
s32 templ;
s16 tempi;
templ = (s32)ADC_Last_Result*255;
templ >>= 8;
tempi = pbuf - ADC_Buf_Last;
tempi *= 255;
tempi >>= 8;
templ += (s32)tempi;
ADC_Last_Result = templ;//乘以0.996
显然我的代码也是有定点小数位被舍弃的问题。
程序正在调试中,稍后吧带16位定点小数运算的算法贴上,以表明结论是否正确,也欢迎高手指正。

lihui_mc 发表于 2010-9-16 18:02:13

问题已解决,贴上修改后的代码,11位定点小数的:
s32 templ;
templ = (s32)ADC_Last_Result;
templ += (s32)pbuf<<11;//11位小数
templ -= (s32)ADC_Buf_Last<<11;//11位小数
templ *= 255;
templ >>= 8;//乘以0.996
ADC_Last_Result = templ;

haimaod 发表于 2011-7-7 16:31:20

回复【楼主位】lihui_mc软硬兼施
-----------------------------------------------------------------------

请问一下,avr单片机的AD:输入是多少时它的内部寄存器从0-1023变化?

zhengjf 发表于 2011-8-20 15:16:23

make

albert_w 发表于 2011-8-20 15:19:34

回复【2楼】haimaod
回复【楼主位】lihui_mc软硬兼施
-----------------------------------------------------------------------
请问一下,avr单片机的ad:输入是多少时它的内部寄存器从0-1023变化?
-----------------------------------------------------------------------

输入0到1023/1024vref的时候

xad74 发表于 2017-12-8 16:33:41

楼主能说说这个公式的含义吗y = 0.996*y + 0.996*x - 0.996*x,频率点是怎么定的

xad74 发表于 2017-12-13 16:37:53

补上公式不知道对不对
*
*      X= exp(-2.0 * pi * Fc)
*      A0 = (1 + X) / 2
*      A1 = -(1 + X) / 2
*      B1 = X
*      Fc = cutoff freq / sample rate
*
* Mimics an RC high-pass filter:
*
*      || C
*    ----||--------->
*      ||    |
*            <
*            > R
*            <
*            |
*            V
页: [1]
查看完整版本: 关于IIR高通滤波器,个人认为AVR应用笔记AVR465中的程序有问题