一种ADC采样算法,中位值平均滤波+递推平均滤波

news2024/11/20 4:26:17

前言

在实际AD采集场景中,会出现周期性变化和偶然脉冲波动干扰对AD采集的影响

这里使用中位值平均滤波+递推平均滤波的结合

参考前人写好的代码框架,也参考博主GuYH_下面这篇博客,在此基础上稍作修改,写出这篇博客,能应用于实际项目。常用ADC采样数字滤波算法最全汇总!!!【❤️建议收藏❤️】_adc滤波算法_GuYH_的博客-CSDN博客

以后有机会,搞个上位机对比几种算法的优劣。

有纰漏请指出,转载请说明。

学习交流请发邮件 1280253714@qq.com

算法讲解

中位值滤波:采样10次,去掉最大和最小的值,求和再除8,对脉冲波有抑制作用。

递推平均滤波:把连续取N个采样值看成一个队列,队列的长度固定为N,每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则), 把队列中的N个数据进行算术平均运算,就可获得新的滤波结果。对周期性干扰有良好的抑制作用,平滑度高;适用于高频振荡的系统。

优点:适用于周期性变化和偶然脉冲波动干扰的AD采集。

缺点:灵敏度低;对偶然出现的脉冲性干扰的抑制作用较差,不适于脉冲干扰较严重的场合。

代码

因为项目用的是比51还low的单片机,所以不能进行太高频的AD采样,否则会大量占用CPU;采样次数也不能设置太高,否则占用大量RAM空间。

每10ms进行一次中位值滤波

每100ms进行一次递推平均滤波

adc.h

#ifndef __ADC_H
#define	__ADC_H

#include "sys.h"


#define AD_Channel_Num  4 	// ADC的通道数
#define AD_Sample_Num   4 	// 采样次数

void AdcInit(void);
u16 ADC_Sample(u8 adch);
void AdcLoopTask(void);

typedef struct {
    u16 V_Chip_0V6;
    u16 V_Bat;
    u16 V_In;
    u16 I_Cur;
    u8  sampleCnt;                      //采样计数
    u8  bSampleInit;					// 去除前几次的采样值的标志位,0为去除,1为开始滤波
    u8  u8ArraryIndex;					// 当前采样的索引			
	u16 u16SampleValue[AD_Channel_Num];	// 规则转换时DMA搬运的目标数组
	u16 u16ValueSum[AD_Channel_Num];	// ADC采样值的总和
	u16	u16Value[AD_Channel_Num];		// 平均滤波后的AD值	
} ADC_S;

extern ADC_S stAdc;

#endif	//__ADC_H

adc.c

#include "sys.h"

ADC_S stAdc;
/********************************************
*	@函数名	AdcInit
*	@描述	ADC循环任务
*	@参数	无
*	@返回值	无
*	@注意	无
********************************************/
void AdcInit(void)
{
	TRISA0 = 1;		//将RA0设置为输入
	TRISA2 = 1;		//将RA2设置为输入
	TRISA5 = 1;		//将RA5设置为输入
}

/********************************************
*	@函数名	AD_Sample
*	@描述	AD采样
*	@参数	adch - 检测通道
*	@返回值	ad_result - 8次AD平均值 
*	@注意	采样通道需自行设置为模拟口,采样10次,取中间八次的平均值为采样结果存于adresult中
********************************************/
u16 ADC_Sample(u8 adch)
{
	u32 adsum = 0;
	u16 admin = 4096,admax = 0;
	u8 adtimes = 0;
	u16 ad_temp,adresult;
	u8 j;
	ADCON1 = 0B00000101;			//左对齐,选用VDD 2.0V做AD基准
	ADCON0 = 0X81 | (adch << 2);	//ADCclk = Fosc/32
	asm("nop");
	asm("nop");

	for(j=0;j<10;j++)
	{
		GODONE = 1;						//开始转换
		u8 i = 64;
		
		while(GODONE)
		{
			__delay_us(100);	//延时100us(编译器内置函数)
			if(0 == (--i))		//延时6.4ms仍没有AD转换结束,跳出程序
				return;
		}
		
		ad_temp=(ADRESH<<4)+(ADRESL>>4);	//计算12位AD值
		adresult = ad_temp;
		
		if(ad_temp > admax)
			admax = ad_temp;				//AD采样最大值
		else if(ad_temp < admin)
			admin = ad_temp;				//AD采样最小值
		
		adsum += ad_temp;
	}
	adsum = adsum - admax - admin;
	adresult = adsum >> 3;		//8次平均值作为最终结果
	return adresult;
}

/********************************************
*	@函数名	AdcSampleAllChanel
*	@描述	对所有ADC通道都进行采样
*	@参数	无
*	@返回值	无
*	@注意	无
********************************************/
static void AdcSampleAllChanel(void)
{
	stAdc.u16SampleValue[0] 	= ADC_Sample(0x0F);		//芯片内部0.6V电压
	IO_Vbat_Sample_Ctrl = 1;	
	stAdc.u16SampleValue[1] 	= ADC_Sample(0x00);		//电池电压
	IO_Vbat_Sample_Ctrl = 0;
	stAdc.u16SampleValue[2] 	= ADC_Sample(0x05);		//输入电压
	stAdc.u16SampleValue[3] 	= ADC_Sample(0x02);		//电流采样电压
}

/********************************************
*	@函数名	AdcMoveAverageFilter
*	@描述	ADC递推平均滤波法
			把连续取N个采样值看成一个队列,队列的长度固定为N
			每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则)
			把队列中的N个数据进行算术平均运算,就可获得新的滤波结果
			优点:对周期性干扰有良好的抑制作用,平滑度高;试用于高频振荡的系统
			缺点:灵敏度低;对偶然出现的脉冲性干扰的抑制作用较差,不适于脉冲干扰较严重的场合
*	@参数	无
*	@返回值	无
*	@注意	无
********************************************/
static void AdcMoveAverageFilter(void)
{
	u8 i = 0;
/******************************* u16ValueSum加上最新的值并剔除最旧的值 *******************************/
	for (i=0; i<AD_Channel_Num; i++)
	{
		stAdc.u16SampleValue[i] &= 0x0FFF;
		stAdc.u16ValueSum[i] += stAdc.u16SampleValue[i];
		stAdc.u16ValueSum[i] -= stAdc.u16ValueArray[i][stAdc.u8ArraryIndex];
	}

/******************************* 最近采样的AD_Sample_Num个数取平均 *******************************/	
	if ( 0 == stAdc.bSampleInit )
	{
		for (i=0; i<AD_Channel_Num; i++)
		{
			stAdc.u16Value[i] = stAdc.u16SampleValue[i];
		}
	} 
	else
	{
		for (i=0; i<AD_Channel_Num; i++)
		{
			stAdc.u16Value[i] = stAdc.u16ValueSum[i]>>2;	//在均值滤波的基础上进行递推均值滤波
		}
	}

/******************************* u16ValueArray添加最新的值 *******************************/	
	for (i=0; i<AD_Channel_Num; i++)
	{
		stAdc.u16ValueArray[i][stAdc.u8ArraryIndex] = stAdc.u16SampleValue[i];
	}	

/******************************* AD游标更新 *******************************/	
    stAdc.u8ArraryIndex++;
    if( stAdc.u8ArraryIndex >= AD_Sample_Num ) {
        stAdc.u8ArraryIndex = 0;
        stAdc.bSampleInit = 1;
    }	
}

typedef struct {
	u16 V_Chip_0V6;
    u16 V_Bat;
    u16 V_In;
    u16 I_Cur;
} ADC_TEST_S;
ADC_TEST_S stAdc1;
/********************************************
*	@函数名	AdcLoopTask
*	@描述	ADC循环任务
*	@参数	无
*	@返回值	无
*	@注意	无
********************************************/
void AdcLoopTask(void)
{
	
	AdcSampleAllChanel();
	stAdc.sampleCnt++;
	if (stAdc.sampleCnt > 10)
	{
		stAdc.sampleCnt = 0;
		AdcMoveAverageFilter();
		stAdc.V_Chip_0V6 = stAdc.u16Value[0];
		stAdc.V_Bat		 = stAdc.u16Value[1];
		stAdc.V_In		 = stAdc.u16Value[2];
		stAdc.I_Cur		 = stAdc.u16Value[3];
	}	
}

改进递推平均滤波占用大量RAM空间的方法

减去的不是队首的值,而是上一次得到的平均值

如果有10个通道,递推平均滤波个数为10个,那么,改进后,可以省去10*10*2=200byte个字节

这里我采集了4个通道,递推平均滤波个数为4个(8个在改进前RAM溢出了 哭笑 )

改进前

改进后:

省去了4*4*2=32byte个字节的空间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1195915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于超宽带技术的人员定位系统源码,spring boot+ vue+ mysql定位系统源码

​UWB定位技术源码 超宽带技术的人员定位系统源码 UWB人员定位系统是一种基于超宽带技术的人员定位系统&#xff0c;它通过发送和接收超短脉冲信号&#xff0c;在测距方面可以达到微米级精度。这种系统通常需要具备高精度的定位能力&#xff0c;通常需要达到微米级别&#xff0…

ceph-deploy bclinux aarch64 ceph 14.2.10

ssh-copy-id&#xff0c;部署机免密登录其他三台主机 所有机器硬盘配置参考如下&#xff0c;计划采用vdb作为ceph数据盘 下载ceph-deploy pip install ceph-deploy 免密登录设置主机名 hostnamectl --static set-hostname ceph-0 .. 3 配置hosts 172.17.163.105 ceph-0 172.…

局部路由守卫component守卫

局部路由守卫component守卫 component守卫&#xff08;beforeRouteEnter、beforeRouteLeave&#xff09; 代码位置&#xff1a;在路由组件中&#xff0c;代码是写在component当中的&#xff08;XXX.vue&#xff09;beforeRouteEnter、beforeRouteLeave都有三个参数&#xff1…

python Flask框架,调用MobileNetV2图像分类模型,实现前端上传图像分类

python Flask框架&#xff0c;调用MobileNetV2图像分类模型&#xff0c;实现前端上传图像分类 今天博主介绍一个图像分类的小项目 基于flask 和mobileNetV2模型的前端图像分类项目 环境配置如下&#xff1a; python版本3.7.6 安装库的版本如下&#xff1a; tensorflow 2.11.…

单挑特斯拉,华为智选车迈入第二阶段

文丨刘俊宏 编丨王一粟 华为智选车的节奏越来越快。 11月9日&#xff0c;华为跟奇瑞打造的首款C级纯电轿车智界S7发布&#xff0c;预售价为25.8万起。 在发布会上&#xff0c;华为常务董事、终端BG CEO、智能汽车解决方案BU董事长余承东采取手机以往最惯用的对标营销手法&a…

蓝桥杯算法心得——拼数(排列型回溯dfs)

大家好&#xff0c;我是晴天学长&#xff0c;排列型的dfs&#xff0c;在一些需要暴搜的题中很中很重要&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .拼数 2) .算法思路 超级递归 1.遍历数组&#…

想要和猫妹一起学Python吗?快进群吧

这是一篇2024年猫妹学Python新同学召集令&#xff0c;感兴趣的朋友可以看下。 初始Python 猫爸第一次被Python惊艳&#xff0c;是几年前的一个风格迁移程序。 国外某大学的一篇博士论文&#xff0c;为风格迁移提供了理论支撑。 下载到模型之后&#xff0c;就可以用简单的Py…

Linux的基本指令(1)

目录 快速认识的几个指令 pwd指令 mkdir指令 touch指令 cd指令 clear指令 whoami指令 ls指令 ls -l ls -la ls 目录名 ls -ld 目录名 文件 路径 路径是什么&#xff1f; 路径的形成 ​ 怎么保证路径必须有唯一性&#xff1f; ls -la隐藏文件 隐藏文件的是什…

UnRaid安装安装仓库管理系统GreaterWMS

文章目录 0、前言1、安装流程1.1、克隆GreaterWMS项目到UnRaid本地目录1.2、修改项目前后端端口1.3、修改baseurl1.4、修改Nginx.conf配置文件1.5、安装依赖插件1.5.1、Docker Compose Manager插件1.5.2、Python3环境 1.6、创建GreaterWMS容器1.6.1、为前后端启动脚本赋执行权限…

C++ static关键字

C static关键字 1、概述2、重要概念解释3、分情况案例解释3.1 static在类内使用3.2 static在类外使用案例一&#xff1a;案例二&#xff1a;案例三 1、概述 static关键字分为两种情况&#xff1a; 1.在类内使用 2.在类外使用 2、重要概念解释 &#xff08;1&#xff09;翻译…

keepalived+Nginx+邮件

实验场景&#xff1a; 我使用keepalived保证nginx的高可用&#xff0c;我想知道什么时候ip发生漂移&#xff0c;可以让ip发生漂移的时候 我的邮箱收到消息. 如果对keepalived不了解&#xff0c;这有详细解释&#xff1a;keepalived与nginx与MySQL-CSDN博客https://blog.csdn.ne…

在Spring Boot中使用JTA实现对多数据源的事务管理

了解事务的都知道&#xff0c;在我们日常开发中单单靠事务管理就可以解决绝大多数问题了&#xff0c;但是为啥还要提出JTA这个玩意呢&#xff0c;到底JTA是什么呢&#xff1f;他又是具体来解决啥问题的呢&#xff1f; JTA JTA&#xff08;Java Transaction API&#xff09;是…

思维模型 梅拉宾法则

1 梅拉宾法则的应用 1.1 演讲口才中的梅拉宾法则应用 苹果公司的演讲&#xff1a;苹果公司的演讲一直以来都以其独特的风格和效果著称。苹果公司的演讲者在演讲中注重运用肢体语言和声音等非语言因素&#xff0c;如手势、表情和语调等&#xff0c;来增强演讲的效果。例如&am…

Linux文件类型与权限及其修改

后面我们写代码时&#xff0c;写完可能会出现没有执行权限什么的&#xff0c;所以我们要知道文件都有哪些权限和类型。 首先 就像我们之前目录结构图里面有个/dev,它就是存放设备文件的&#xff0c;也就是说&#xff0c;哪怕是一个硬件设备&#xff0c;例如打印机啥的&#xf…

Linux学习教程(第一章 简介)3

第一章 简介 七、Linux系统的优缺点 前面章节提到&#xff0c;相比 Windows 系统&#xff0c;Linux 系统有更好的稳定性&#xff0c;那么除此之外&#xff0c;Linux 系统还有那些优点&#xff08;或者不足&#xff09;呢&#xff1f;本节带领大家详细了解一下。 1、大量的可…

【Kurbernetes集群】Pod资源、Pod资源限制和Pod容器的健康检查(探针)详解

Pod资源 一、Pod概述1.1 Pod的定义1.2 一个Pod能包含几个容器&#xff1f;1.3 Pod的分类1.3.1 控制器管理的Pod1.3.2 自主式Pod1.3.3 静态Pod 1.4 Pod中容器的分类1.4.1 Pause容器1.4.2 初始化容器1.4.3 应用容器 1.5 Pod常见的状态 二、Pod中的策略2.1 镜像拉取策略2.2 Pod中容…

另辟奚径-Android Studio调用Delphi窗体

大家都知道Delphi能调用安卓SDK&#xff0c;比如jar、aar等&#xff0c; 但是反过来&#xff0c;能在Android Studio中调用Delphi开发的窗体吗&#xff1f; 想想不太可能吧&#xff0c; Delphi用的是Pascal&#xff0c;Android Studio用的是Java&#xff0c;这两个怎么能混用…

AI时代如何提升自己晋升力

要在AI时代提升职场晋升力&#xff0c;采取以下详细策略&#xff1a; 终身学习的实践&#xff1a; 专业课程&#xff1a; 定期参加在线课程或研讨会&#xff0c;如Coursera、edX等&#xff0c;学习最新的AI技术和行业动态。行业资讯&#xff1a; 订阅相关的行业杂志、博客&…

通过海康私有协议Ehome/ISUP协议将海康摄像头、录像机等设备统一接入到LiveNVR Web流媒体平台实现统一汇聚及Web播放等的配置说明,

LiveNVR海康摄像头海康NVR通过EHOME协议ISUP协议接入支持转GB28181级联 1、海康 ISUP 接入配置2、海康设备接入2.1、海康EHOME接入配置示例2.2、海康ISUP接入配置示例 3、通道配置3.1、直播流接入类型 海康ISUP3.2、海康 ISUP 设备ID3.3、启用保存3.4、接入成功 4、相关问题4.1…

初识RabbitMQ - 安装 - 搭建基础环境

RabbitMQ 各个名词介绍 Broker&#xff1a;接收和分发消息的应用&#xff0c;RabbitMQ Server 就是 Message Broker Virtual host&#xff1a;出于多租户和安全因素设计的&#xff0c;把 AMQP 的基本组件划分到一个虚拟的分组中&#xff0c;类似于网络中的 namespace 概念。当…