切换到宽版
  • 21174阅读
  • 45回复

关于单片机AD电压电流采样的软件滤波快被整疯了 [复制链接]

上一主题 下一主题
离线haigeer
 
发帖
145
M币
439
专家
5
粉丝
17
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2017-07-15
用单片机电压电流采样,单片机是STC15F104W,A/D转换芯片是普通的八位芯片,
硬件滤波已经做到位了,但软件滤波总是过不了,
参考坛友的这个贴:http://bbs.mydigit.cn/read.php?tid=668245
修改了,但没效果,也参考了网上一些例子,都没解决,欲哭无泪啊~


                                              更新 UPDATE                                                      
今天楼主特意只接了一路采样电压信号,不接采样电流信号,
发现,电压显示基本没有波动,而且只有纯硬件滤波,连软件滤波都不要,
分析原因可能两路信号发生了串扰,造成信号采样的异常,
看来,如10L的 @kreina   所说,PCB布局比较关健,对电路影响很大,
感谢楼下几位大师指点,回去我会好好学习软件滤波,
如果找到了更好的方法,我会分享给大家,互相学习!

存在问题描述:
显示电压会跳动,正常显示如截图1中  12.09 (伏特),
但有时就显示其他干扰值,比如截图2中的 04.21   。





亲们有啥好的软件滤波方法推荐一下,谢谢了~

截取的部分主要代码如下:
  1. /*---------------------------------获取采样数据---------------------------------*/        
  2. uchar ADC_result(uchar ad)
  3. {
  4. uchar result;
  5. ISendByte(ADDR,ad);
  6. result=IRcvByte(ADDR);
  7. return result;                         //返回转换结果
  8. }
  9. /*---------------------------------软件滤波------------------------------------*/        
  10. uchar U(uchar chx)                                              
  11. {
  12.     uchar i,U[10],min,max,R;
  13.     uint S;
  14.           
  15.     for(i=0,S=0;i<10;i++)              //测量电压10次去除最大最小求平均
  16.     {
  17.     U[i]=ADC_result(chx);  S+=U[i];      //获取通道ADC结果
  18.     }
  19.     for(i=1,min=U[0];i<=9;i++)
  20.     {
  21.      if(U[i]<min)  min=U[i];           //求最小值
  22.     }
  23.     for(i=1,max=U[0];i<=9;i++)
  24.     {
  25.      if(U[i]>max)  max=U[i];           //求最大值
  26.     }  
  27.      R=(S-min-max)/8;
  28.     return R;                     //返回计算结果
  29. }



电路PCB图:





测试的视频(时长:2分30秒):




[ 此帖被haigeer在2017-07-16 03:52重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖提到的人: @kreina
本帖最近打赏记录:共1条打赏M币+30
离线qjj2857

发帖
643
M币
532
专家
2
粉丝
12
只看该作者 1楼 发表于: 2017-07-15
干嘛求平均?!
你这种干扰极大的电路
应该用的是中位数
本帖最近打赏记录:共2条打赏M币+35
离线junyee

发帖
3937
M币
913
专家
11
粉丝
156
只看该作者 2楼 发表于: 2017-07-15
建议用 uart 来调试.

像你这种 从 12V跳到 4.XV ,波动太大了,应该是 运算溢出,或者采样到错误的数据.
本帖最近打赏记录:共1条打赏M币+5
离线zeze10000

发帖
2830
M币
8720
专家
34
粉丝
81
只看该作者 3楼 发表于: 2017-07-15
我之前也做过一个,数值也是跳动,我的是在两个数之间跳动。
我是采集5个,去掉最高和最低,然后中间的3个取平均。
本帖最近打赏记录:共2条打赏M币+5专家+1
离线ijelkam

发帖
535
M币
1236
专家
4
粉丝
12
只看该作者 4楼 发表于: 2017-07-15
12.09伏特, 4.21伏特,差距相当大,应该是比较好过滤的
楼主可以这样操作:
1,取一段时间内连续的N个数据放入数组
2,丢弃x个最大最小值,
3,取剩余值的平均

比如连续采样10个数据,丢弃最大和最小的1个数据,然后取其余值的平均
本帖最近打赏记录:共2条打赏M币+5专家+1

发帖
2812
M币
625
专家
19
粉丝
114
只看该作者 5楼 发表于: 2017-07-15
首先俺不得不说,下面俺给出的方法可以帮楼主剔除AD采样的异常子数据,但是慎用!数值稳定性是一个很复杂的东西,这个方法不能100%保证情况改善,原因有下:
楼主已经在程序里做了10次弃极值平均,这个算法非常厉害,但是仍出现了大幅波动,因此俺觉得,楼主的采样数据中应该存在多个异常值。就这一点而言,楼主是否更应该关注一下这些异常值的产生?异常值的出现是多方面的,比如ADC本身?程序问题?硬件设计问题?接触不良?电源自身的问题?建议楼主用电池、线性电源之类的采集几次试试,仔细检查检查程序有没有啥异常。硬件上ADC这玩意出问题也比较多,但是楼主用的这个ADC他不是闪速ADC(Flash ADC),出现真正意义上的闪码(Flash Code)几乎是不可能的,而硬件上出问题的概率似乎也不是很大。
因此,随便来个滤波,剃坏值貌似是不严谨,而且不负责任做法。
抛开上述问题不谈,对于某一两个坏值,这个方法还是挺好用的。
剔除坏值的方法有很多,肖维勒准则,格拉布斯准则都是可以的,当然还有其他方法。肖维勒准则对于n<10的情况处理还是不错的,而格拉布斯准则处理n>20效果较好,对于楼主的程序,不妨采用前者。
肖维勒准则说:|Vi|>|Xn-X平均|σZc,就是残差Vi的绝对值如果 大于 单次采样值与采样平均值之差绝对值的方差乘以Zc倍,那么该值为坏值。Zc可以通过查表得到,n为数据个数,大概如下
n=3Zc=1.38
41.54
51.65
61.73
71.80
81.86
91.92
101.96
112.00
122.03
132.07
142.10
152.13

至于格拉布斯准则,楼主可以自己了解一下。
在剔除坏值以后再求平均,效果较好,楼主可以写个程序试试。
俺还是坚持上面的看法,不检查出坏值产生的原因,啥滤波剃坏值都是不太好的,虽然最后出来的东西可能比较好看。俺看楼主的单片机有4K的程序空间,不如用打log的方式,写个串口通讯吧每一次采样值都发到上位机上,看看数据情况,以便分析。
最后,祝楼主早日解决问题,做个高高高高高高精度的电压电流表!楼主的视频做的也非常好!
[ 此帖被老孙和小孙在2017-07-15 23:17重新编辑 ]
本帖最近打赏记录:共4条打赏M币+48

发帖
6732
M币
1874
专家
1
粉丝
24
只看该作者 6楼 发表于: 2017-07-15
设计思路说一下吧
本帖最近打赏记录:共1条打赏M币+5
离线wanjinjie

发帖
206
M币
191
专家
2
粉丝
11
只看该作者 7楼 发表于: 2017-07-15
1.STC15自带的是10位ADC,所以如果你用的是片内ADC那么你需要定义int型变量按照10bit来采样处理!
2.采样10次去掉最大最小值然后向右移位三次就好了
3.计算电压的时候的小数点要放大后在计算,这种单片机尽量不要计算浮点数
参考我的例子带详细中文注释的电压采样http://bbs.mydigit.cn/read.php?tid=1683450&page=1
本帖最近打赏记录:共1条打赏M币+5
离线devcang

发帖
17670
M币
8523
专家
19
粉丝
93
只看该作者 8楼 发表于: 2017-07-15

建议保证测量的AD两端电容
本帖最近打赏记录:共1条打赏M币+5
能做自己喜欢的事情,会是最大的幸福
离线zhkrid

发帖
25778
M币
135579
专家
468
粉丝
372
只看该作者 9楼 发表于: 2017-07-15
讲的很专业,可惜不懂软件编程,我有这个单片机,也有ADC芯片,可惜不会用,但看你的讲解思路很好
本帖最近打赏记录:共1条打赏M币+5