当前位置:首页 > 公众号精选 > 嵌入式微处理器
[导读]今天遇到一个网友问一个问题,他有一个传感器测量一个物理量,需要判断其变化趋势,我给了一些建议,这里将这个建议展开做些深入分析,并分享给大家。 本文想借此表达一下个人的一个观点,做开发如果遇到无法解决的难题,可以试着从数序的角度出发,看能否找

今天遇到一个网友问一个问题,他有一个传感器测量一个物理量,需要判断其变化趋势,我给了一些建议,这里将这个建议展开做些深入分析,并分享给大家。

本文想借此表达一下个人的一个观点,做开发如果遇到无法解决的难题,可以试着从数序的角度出发,看能否找到答案。

注:文中配图只为阅读轻松一点,本人数学也是半吊子,有错误帮忙指正。

是个啥坑?

一个项目中用到一个传感器测量一物理量,这里假定测量温度吧。需要判断其变化趋势,利用这个变化趋势去做一些应用。

那么要怎么判断一个物理量的变化趋势呢?我们能自然能想到去求取该随机序列的变化率。这里涉及到一些数序定义。随机序列有很多可能的来源,最为常见是我之前在<<模数转换知多少>>中介绍的模数采样。

这样将S(t)信号转换为离散信号序列S(n),那么对于当前时刻其斜率怎么求取呢?(这里忽略中间的过度态,仅将其看为线段相连,当然现实应用中如果有更高要求,可以做曲线拟合)

但是如果只判断,斜率极容易误判,比如下面这样的情况:

其斜率一会儿正,一会儿负,但是其总体趋势又是在增加的,所以只考察斜率显然不可取,获取需要在代码在加各种复杂的条件或者限值去判断。即使加这么多条件系统仍然可能表现的非常不健壮。

对于模拟信号2而言,趋势又在不断变化。那么怎么做才能稳定呢?先卖个关子?

函数的凹凸性

凹函数

凹函数是一个定义在某个向量空间的凸集C(区间)上的实值函数f。设f为定义在区间I上的函数,若对I上的任意两点x1<x2和任意的实数t属于(0,1),总有,

则称函数f为l上凹函数,有的书上也称为下凸函数。

如果把上述条件中的“≥”改成“>”,则叫做严格上凹函数,或叫做严格下凸函数。

上面是一维函数情况,这里来个2维函数的图,刚方便理解

凸函数

设f为定义在区间I上的函数,若对I上的任意两点x1<x2和任意的实数t属于(0,1),上面不等式变成大于等于,则在该区间为凸函数。

可见,凹凸是相对的,如f(x)在某区间为凹,则-f(x)则在该区间为凸。

性质

  • 若一个函数在某区间二阶可导且大于0,则函数在该区间为凹函数
  • 若一个函数在某区间二阶可导且小于0,则函数在该区间为凸函数

证明,这里就不推导了,可以利用拉格朗日中值定理可以推导出上面这个性质。

来看一下会动的图,加深一下理解:

函数 切线为蓝色,曲线向上凹,绿色表示曲线是向下凹的,红色表示曲线的拐点。

sin(2x)的一阶导数为:

sin(2x)的二阶导数为:

装逼结束,也可能没装对~~~

回到坑里

通过上面装逼,是否可以利用离散序列的求导数来判断传感器的变化趋势。啥?导数?又要开始表演了?

前面说了一阶导数是这样的:

那么二阶导数是哪样捏?

化简一下:

其中S[n]表示当前测量点,S[n-1]表示前一个测量点,S[n-2]表示前第2个测量点。

上代码

#include <stdio.h>
#include <math.h>
#include <string.h>
typedef struct _T_2ND_DRV
{

    float xn1;
    float xn2;
}t_2ND_DRV;
typedef struct _T_1ST_DRV
{

    float xn1;
}t_1ST_DRV;

void init_second_derivative(t_2ND_DRV *pSndDrv)
{
    pSndDrv->xn1 = 0;
    pSndDrv->xn2 = 0;
}

float second_derivative(t_2ND_DRV *pSndDrv, float xn,float T)
{
     float result=0.0f;
     if(T<=0)
         return 0x7FBFFFFF/*非法数据*/
     result = (xn-2*pSndDrv->xn1-pSndDrv->xn2)/T/T;
     pSndDrv->xn2 = pSndDrv->xn1;
     pSndDrv->xn1 = xn;
    
     return result;
}

void init_fisrt_derivative(t_1ST_DRV *p1stDrv)
{
    p1stDrv->xn1 = 0;
}

float fisrt_derivative(t_1ST_DRV *p1stDrv, float xn,float T)
{
     float result=0.0f;
     if(T<=0)
         return 0x7FBFFFFF/*非法数据*/
     result = (xn-p1stDrv->xn1)/T; 
     p1stDrv->xn1 = xn;
    
     return result;
}
#define PI 3.1415f
#define SAMPLE_RATE 500.0f
#define SAMPLE_T (1/SAMPLE_RATE)
#define SAMPLE_SIZE (100)
int main()
{
    float sim1[SAMPLE_SIZE];
    float sim2[SAMPLE_SIZE];
    float out1[SAMPLE_SIZE];
    float out2[SAMPLE_SIZE];
    t_2ND_DRV sndDrv;
    t_1ST_DRV frtDrv;
    init_fisrt_derivative(&frtDrv);
    init_second_derivative(&sndDrv);
    
    FILE *pFile=fopen("./simulationSin.csv","wt+");
    if(pFile==NULL)
    {
        printf("simulationSin.csv opened failed");
        return -1;
    }
    
    for(int i=0;i<SAMPLE_SIZE;i++)
    {
        sim1[i]=10*sin(2*PI*10*i/500);
    } 
    for(int i=0;i<SAMPLE_SIZE;i++)
    {
        out1[i]=fisrt_derivative(&frtDrv,sim1[i],SAMPLE_T);
        out2[i]=second_derivative(&sndDrv,sim1[i],SAMPLE_T);
        fprintf(pFile,"%f,%f,%f\n",sim1[i],out1[i],out2[i]);
    }

    fclose(pFile);

    return 0;
}

利用excel生成曲线:

从图中可看出:
  • 一阶导数为正时,函数递增趋势;
  • 一阶导数为负时,函数递减趋势;
  • 二阶导数为0时,出现拐点,趋势改变;此时如果左右两侧的一阶导符号相反,则出现极值。
  • 二阶导数为负时,其一阶导数也即原函数斜率规律单调减,二阶导数为正时,其一阶导数也即原函数斜率规律单调增。

再进一步:

一阶导数与二阶导数结合起来看,就可以看出测量值变化趋势的趋势,比如在前1/4周期,此区间变换趋势为增,也即一阶导数为正,而其二阶导数为负,也可以看出递增的趋势是逐渐减小到0的。

代码优化

如果只是做定性判断,上述函数,完全没必要与采样周期做除法,只需要考察其增量即可,代码可优化如下:

typedef struct _T_2ND_DRV
{

    float xn1;
    float xn2;
}t_2ND_DRV;
typedef struct _T_1ST_DRV
{

    float xn1;
}t_1ST_DRV;

void init_second_derivative(t_2ND_DRV *pSndDrv)
{
    pSndDrv->xn1 = 0;
    pSndDrv->xn2 = 0;
}

float second_derivative(t_2ND_DRV *pSndDrv, float xn)
{
     float result=0.0f;
     result = xn-2*pSndDrv->xn1-pSndDrv->xn2;
     pSndDrv->xn2 = pSndDrv->xn1;
     pSndDrv->xn1 = xn;
    
     return result;
}

void init_fisrt_derivative(t_1ST_DRV *p1stDrv)
{
    p1stDrv->xn1 = 0;
}

float fisrt_derivative(t_1ST_DRV *p1stDrv, float xn)
{
     float result=0.0f;
     result = xn-p1stDrv->xn1; 
     p1stDrv->xn1 = xn;
    
     return result;
}

意外收获

这里意外引入一个可能很多人没注意的知识点NaN,在计算中,NaN代表非数字,是数字数据类型的成员,可以将其解释为不确定的或无法表示的值,尤其是在浮点运算中。1985年,IEEE 754浮点标准引入了NaN的系统使用,并表示了其他无限量(如无穷大)。

前述函数返回0x7FBFFFFF,也就是表示无穷大。

不同的操作系统和编程语言可能具有NaN的不同字符串表示形式:

nan
 NaN
 NaN%
 NAN
 NaNQ
 NaNS
 qNaN
 sNaN
 1.#SNAN
 1.#QNAN
 -1.#IND

实际上,由于编码的NaN具有符号,因此通常也可以在NaN的字符串表示中找到它们,例如:

 -NaN
  NaN12345
 -sNaN12300
 -NaN(s1234)

工程应用

这里给出我的建议方案:

将传感器信号经由电路处理,模数采样,在进入前级数字滤波器,滤除不必要的噪声,在进行一阶/二阶求导。对于一阶和二阶求导再做一级移动平均滤波,最后在按照上面描述进行判别变化趋势,则个人认为基本就比较健壮了。实际移动均值滤波长度不宜选择过长,否则响应就比较滞后了。不能对传感器的变化趋势做出实时的判别。加了后级均值滤波器,则会消除由于波形忽上忽下的随机噪声干扰影响,使得系统判别更为健壮,实际滤波器长度需根据不同的场合进行调试优化。或者也可以选择别的IIR/FIR滤波器形式实现。


本文授权转载自公众号“嵌入式客栈”,作者逸珺


-END-




推荐阅读



【01】单片机学习笔记,三个步骤教你学!
【02】来,看看你的单片机程序有多大!
【03】为什么要学习单片机?如何开始上手学习单片机?
【04】详论单片机固件模块化架构设计(精华)
【05】真实案例:再论做单片机两三年后为什么转学嵌入式


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

嵌入式ARM

扫描二维码,关注更多精彩内容

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

学好电子技术基础知识,如电路基础、模拟电路、数字电路和微机原理。这几门课程都是弱电类专业的必修课程,学会这些后能保证你看懂单片机电路、知道电路的设计思路和工作原理;

关键字: 单片机 编程 电路设计

单片机编程需要使用专门的软件工具,这些工具能够帮助程序员编写、调试和烧录程序到单片机中。以下是一些常用的单片机编程软件:

关键字: 单片机 编程 软件工具

Java语言和C语言是两种不同的编程语言,它们在语法、特性和应用领域上有许多差别。下面将详细介绍Java语言和C语言之间的差异以及它们各自的技术特点。

关键字: Java语言 C语言 编程

嵌入式系统是现代生活中无处不在的一部分。它们包括了我们的家电、汽车、智能手机、医疗设备等等。这些系统的工作必须高效、可靠,因为它们往往控制着生活中的关键方面。而C语言作为一种广泛用于嵌入式系统开发的编程语言,其质量和稳定...

关键字: 嵌入式系统 C语言 编程

在嵌入式系统开发领域中,C语言是使用最广泛的编程语言之一。它具有高效、灵活和可移植的特点,成为嵌入式系统设计师的首选语言。本文将介绍C语言编程的基本概念、特点以及在嵌入式系统开发中的应用。

关键字: 嵌入式系统 C语言 编程

在编程和计算中,运算符优先级是解释和计算表达式的一个关键因素。本文旨在阐述运算符优先级的概念、规则及其在表达式中的应用,以帮助读者更好地理解和运用运算符优先级。

关键字: 表达式 运算符 编程

泰克科技组合软件总经理Rick Khulman:“激发孩子们——尤其是女孩们对STEM的兴趣,对我本人乃至广大工程界都至关重要。”

关键字: 编程 机器人 示波器

PIC单片机采用精简指令集,例如对于PIC16F716单片机,只有35条单字节指令。要用这么少的指令实现复杂的控制或计算,显然要在程序设计上多做文章,以下就程序设计需要注意的问题谈一些看法。 美国微芯公司开发的CMOS工...

关键字: 单片机 控制 编程

PLC编程是一种数字运算操作的电子系统,专为在工业环境下应用而设计。它采用可编程序的存储器,用来在其内部存储执行逻辑运算、顺序控制、定时、计数和算术运算等操作的指令,并通过数字式、模拟式的输入和输出,控制各种类型的机械或...

关键字: plc 编程 plc编程

初学PLC梯形图编程,应要遵循一定的规则,并养成良好的习惯。下面以西门子PLC为例,简单介绍一下PLC梯形图编程时需要遵循的规则,希望对大家有所帮助。

关键字: 西门子 plc 编程
关闭
关闭