单片机常用算法设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(NOT2POW(len)) return NULL; //如果失败,返回空指针 for(;!(t&1);t>>=1) ex++; //len应该等于2的ex次方 y=(my_complex*)malloc(len*sizeof(my_complex)); if(!y) return NULL; //变址计算,库里-图基算法 for(i=0;i<len;i++){k=i; j=0; =ex; while((t--)>0){ j<<=1; j|=k&1; k>>=1; } if(j>=i){ y[i]=x[j]; y[j]=x[i]; } } //用变址后的y向量进行计算 for(i=0;i<ex;i++){t=1<<i; for(j=0;j<len;j+=t<<1){ for(k=0;k<t;k++) {ti=-MYPI*k/t; rr=cos(ti); ri=sin(ti); tr=y[j+k+t].r; ti=y[j+k+t].i; yr=rr*tr-ri*ti; yi=rr*ti+ri*tr; tr=y[j+k].r; ti=y[j+k].i;
FFT变换算法的基本思想:利用WN的周期性 和对称性,把一个N项序列(设N=2k,k为正整 数),分为两个N/2项的子序列,每个N/2点 DFT变换需要(N/2)^2次运算,再用N次运 算把两个N/2点的DFT变换组合成一个N点的 DFT变换。这样变换以后,总的运算次数就 变成N+2(N/2)2=N+N^2/2。其程序片段如 下所示:
y[j+k].r=tr+yr; y[j+k].i=ti+yi; y[j+k+t].r=tr-yr; y[j+k+t].i=ti-yi;}}} return y;} //以下为测试 int main() {int i,DATA_LEN; my_complex *x,*y; printf("基二FFT测试\n输入生成序列长度:"); scanf("%d",&DATA_LEN); x=(my_complex*)malloc(DATA_LEN*sizeof(my_complex)); for(i=0;i<DATA_LEN;i++){x[i].r=i; x[i].i=i-1; } printf("处理前...\n实部\t\t虚部\n"); for(i=0;i<DATA_LEN;i++) printf("%lf\t%lf\n",x[i].r,x[i].i); y=fft(x,DATA_LEN); if(!y){ printf("序列长度不为2的整数次方!\n"); return 0; }
第7章 单片机常用算法设计
7.1 7.2 7.3 7.4 7.5 7.6 单片机滤波算法的设计 信号处理的FFT变换 SPWM正弦逆变算法的设计 PID控制算法 51单片机PID算法程序 模糊控制算法
7.1 单片机滤波算法的设计
电路的滤波分为模拟滤波与数字滤波。 其中数字滤波器具有精度高、高可靠性和高 稳定性的特点 ,因此被广泛应用。用数字滤波 算法克服随机误差主要有如下优点: 数字滤波由软件程序实现 ,不需要硬件 ,因 此 不存在阻抗匹配的问题; 对于多路信号输入通道 ,可以共用一个软件 “滤波器”,降低仪表的设计成本; 只要改变滤波器程序或元算参数 ,就能方便 的改变滤波特性。
7.2 信号处理的FFT变换
快速傅里叶变换(Fast Fourier Transfonn,FFT) 是为了减少离散傅里叶变换(Discrete Fourier Transform,DFT)计算次数的一种快速有效的 算法。它是根据离散傅氏变换的奇、偶、虚、 实等特性,对离散傅立叶变换的算法进行改进 获得的。
下面是中位值滤波程序:
#define N 11 char filter() { char value_buf[N], count,i,j,temp; for ( count=0;count<N;count++) { value_buf[count] = get_ad(); delay(); } for (j=0;j<N-1;j++) { for (i=0;i<N-j;i++) { if ( value_buf[i]>value_buf[i+1] ) {temp = value_buf[i]; value_buf[i] = value_buf[i+1]; value_buf[i+1] = temp; } } } return value_buf[(N-1)/2]; }
#define N 12 char filter() {int sum = 0,count; for ( count=0;count<N;count++) { sum+=get_ad(); delay();} return (char)(sum/N); }
D.递推平均滤波法
基本方法:采用队列作为测量数据存储器 , 设队列的长度为 N ,每进行一次测量 ,把测量 结果放于队尾 ,而扔掉原来队首的一个数据 , 这样在队列中始终就有 N 个 “最新” 的数 据。当计算平均值时 ,只要把队列中的 N 个 数据进行算数平均 ,就可得到新的算数平均值。 这样每进行一次测量 ,就可得到一个新的算术 平均值。
下面我们介绍几种主要的数字滤波法:
A.限幅滤波法
对于随机干扰 , 限幅滤波是一种有效的方法; 基本方法:比较相邻n 和 n - 1时刻的两个采 样值y(n)和 y(n – 1),根据经验确定两次采样 允许的最大偏差。如果两次采样值的差值超过 最大偏差范围 ,认为发生可随机干扰 ,并认为后 一次采样值y(n)为非法值 ,应予删除 ,删除y(n) 后 ,可用y(n – 1) 代替y(n);若未超过所允许的 最大偏差范围 ,则认为本次采样值有效。
ห้องสมุดไป่ตู้
C.算术平均滤波法
算术平均滤波法适用于对一般的具有随机 干扰的信号进行滤波。这种信号的特点是信 号本身在某一数值范围附近上下波动 ,如测量 流量、 液位; 基本方法:按输入的N 个采样数据 ,寻找这 样一个 Y ,使得 Y 与各个采样值之间的偏差 的平方和最小。
编写算术平均滤波法程序时严格注意: 一.为了加快数据测量的速度 ,可采用先测 量数据 存放在存储器中 ,测完 N 点后 ,再对 N 个数据进行平均值计算; 二.选取适当的数据格式 ,也就是说采用定 点数还是采用浮点数。其程序如下所示:
printf("处理后...\n实部\t\t虚部\n"); for(i=0;i<DATA_LEN;i++) printf("%lf\t%lf\n",y[i].r,y[i].i);
free(y); free(x); return 0; }
7.3 SPWM正弦逆变算法的设计
PWM的全称是Pulse Width Modulation(脉 冲宽度调制),它是通过改变输出方波的占空 比来改变等效的输出电压,广泛地用于电动机 调速和阀门控制; SPWM是在PWM的基础上改变了调制脉冲方 式,脉冲宽度时间占空比按正弦规率排列,这 样输出波形经过适当的滤波可以做到正弦波输 出,它广泛地用于直流交流逆变器等; SPWM理论基础:冲量相等而形状不同的窄 脉冲加在具有惯性的环节上时, 其效果基本相同。
下面是限幅滤波程序:( A 值可根据实际情况调 整,value 为有效值 ,new_value 为当前采样值 滤波程序返回有效的实际值 )
#define A 10 char value; char filter() { char new_value; new_value = get_ad(); if ( ( new_value - value > A ) || ( value - new_value > A )) return value; return new_value; }
B.硬件调制法
方案原理:把所希望的波形作为调制信号, 把接受调制的信号作为载波,通过对载波的调 制得到所期望的PWM波形.用等腰三角波作 为载波,当调制信号波为正弦波时,所得到的 就是SPWM波形; 优点:实现方法简单,可以解决等面积法 计算繁琐的缺点; 缺点:模拟电路结构复杂,难以实现精确的 控制。
实现SPWM法的几种方案:
A.等面积法
该方案是用同样数量等幅而不等宽的矩形 脉冲序列代替正弦波,然后计算各脉冲的宽度 和间隔,并把这些数据存于微机中,通过查表 的方式生成PWM信号控制开关器件的通断, 以达到预期的目的; 优点:可准确计算出各开关器件的通断时 刻,所得的波形很接近正弦波; 缺点:计算繁琐,数据占用内存大,不能实时 控制。
B.中位值滤波法
中位值滤波法能有效克服偶然因素引起的 波动或采样不稳定引起的误码等脉冲干扰; 对温度 液位等缓慢变化的被测参数用此法 能收到良好的滤波效果 ,但是对于流量压力等 快速变化的参数一般不宜采用中位值滤波法; 基本方法:对某一被测参数连续采样 n次 (一般 n 取奇数) ,然后再把采样值按大小排列 , 取中间值为本次采样值。
程序如下: #define N 12
char value_buf[N],i=0; char filter() { char count; int sum=0; value_buf[i++] = get_ad(); if ( i == N ) i = 0; for ( count=0;count<N;count++) sum = value_buf[count]; return (char)(sum/N); }
用面积法实现SPWM正弦波逆变换的程序片段:
void CalcSpwmWithArea(float32 a/*调制比*/,Uint16 w_Hz/* 调制频率*/,Uint32 z_Hz/*载波频率*/) { //Uint16 tmp_PR; //T1周期值 volatile Uint16 i,n,*p; float32 m,n1,n2; m = z_Hz/w_Hz ; //求出载波比 g_SPWM_Table.SpwmSize =(Uint16)m; //tmp_PR = g_T1_Clk /(2*z_Hz); //计算出其周期值 p=g_SPWM_Table.p_HeadTable; //得到数据表头指针 n=m; m/=2; //除去一半 计算半波 n1=(float32)g_T1_Clk/(8.0*m*w_Hz); // 计算首相 n2=(float32)g_T2_Clk/(8.0*PI*w_Hz)*a; for(i=0;i<n;i++) {*p=n1-n2*(cos(i*PI/m)-cos((i+1)*PI/m)); p++;} }
E.一阶滞后滤波法
优点:对周期性干扰具有良好的抑制作用, 适用于波动频率较高的场合; 缺点:相位滞后,灵敏度低.滞后程度取决 于a值大小.不能消除滤波频率高于采样频率 的1/2的干扰信号。程序如下:
#define a 50 char value; char filter() { char new_value; new_value = get_ad(); return (100-a)*value + a*new_value; }
#include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct{ double r; double i; }my_complex; //检查a是否为2的整数次方数 #define NOT2POW(a) (((a)-1)&(a)||(a)<=0) #define MYPI 3.14159265358979323846//pi my_complex* fft(const my_complex* x, unsigned int len){ unsigned int ex=0,t=len; unsigned int i,j,k; my_complex *y; double tr,ti,rr,ri,yr,yi;