数学之美:嵌入式编程凹凸性之妙用(附C代码)
扫描二维码
随时随地手机看文章
[导读] 咦,你已被成功吸引进来了,不是你想的那样哈~~~
皮一下哈,言归正传,今天遇到一个网友问一个问题,他有一个传感器测量一个物理量,需要判断其变化趋势,我给了一些建议,这里将这个建议展开做些深入分析,并分享给大家。
本文想借此表达一下个人的一个观点,做开发如果遇到无法解决的难题,可以试着从数序的角度出发,看能否找到答案。
注:文中配图只为阅读轻松一点,本人数学也是半吊子,有错误帮忙指正。
一个项目中用到一个传感器测量一物理量,这里假定测量温度吧。需要判断其变化趋势,利用这个变化趋势去做一些应用。
那么要怎么判断一个物理量的变化趋势呢?我们能自然能想到去求取该随机序列的变化率。这里涉及到一些数序定义。
这样将S(t)信号转换为离散信号序列S(n),那么对于当前时刻其斜率怎么求取呢?(这里忽略中间的过度态,仅将其看为线段相连,当然现实应用中如果有更高要求,可以做曲线拟合)
但是如果只判断,斜率极容易误判,比如下面这样的情况:
则称函数f为l上凹函数,有的书上也称为下凸函数。
如果把上述条件中的“≥”改成“>”,则叫做严格上凹函数,或叫做严格下凸函数。
上面是一维函数情况,这里来个2维函数的图,刚方便理解
设f为定义在区间I上的函数,若对I上的任意两点x1
可见,凹凸是相对的,如f(x)在某区间为凹,则-f(x)则在该区间为凸。
证明,这里就不推导了,可以利用拉格朗日中值定理可以推导出上面这个性质。
来看一下会动的图,加深一下理解:
函数 从 到 切线为蓝色,曲线向上凹,绿色表示曲线是向下凹的,红色表示曲线的拐点。
是否可以利用离散序列的求导数来判断传感器的变化趋势?
S[n]表示当前测量点,S[n-1]表示前一个测量点,S[n-2]表示前第2个测量点。
利用excel生成曲线:
再进一步:
一阶导数与二阶导数结合起来看,就可以看出测量值变化趋势的趋势,比如在前1/4周期,此区间变换趋势为增,也即一阶导数为正,而其二阶导数为负,也可以看出递增的趋势是逐渐减小到0的。
如果只是做定性判断,上述函数,完全没必要与采样周期做除法,只需要考察其增量即可,代码可优化如下:
这里意外引入一个可能很多人没注意的知识点NaN,在计算中,NaN代表非数字,是数字数据类型的成员,可以将其解释为不确定的或无法表示的值,尤其是在浮点运算中。1985年,IEEE 754浮点标准引入了NaN的系统使用,并表示了其他无限量(如无穷大)。
前述函数返回0x7FBFFFFF,也就是表示无穷大。
不同的操作系统和编程语言可能具有NaN的不同字符串表示形式:
实际上,由于编码的NaN具有符号,因此通常也可以在NaN的字符串表示中找到它们,例如:
这里给出我的建议方案:
将传感器信号经由电路处理,模数采样,在进入前级数字滤波器,滤除不必要的噪声,在进行一阶/二阶求导。对于一阶和二阶求导再做一级移动平均滤波,最后在按照上面描述进行判别变化趋势,则个人认为基本就比较健壮了。实际移动均值滤波长度不宜选择过长,否则响应就比较滞后了。不能对传感器的变化趋势做出实时的判别。加了后级均值滤波器,则会消除由于波形忽上忽下的随机噪声干扰影响,使得系统判别更为健壮,实际滤波器长度需根据不同的场合进行调试优化。或者也可以选择别的IIR/FIR滤波器形式实现。
具体实现可参考(点击可阅读):
做为嵌入式er编程,有时候有必要去看看数学书,了解一下数学原理的背后故事,可能会给你带来意想不到的作用哦。
本文辛苦原创,也是为了帮助网友,如有错误之处,也请联系我指出。希望大家不吝点个赞,随心打个赏也是可以的,哈哈。也请帮忙转发分享支持一下~~~
—END—
是个啥坑?
函数的凹凸性
凹函数
凹函数是一个定义在某个向量空间的凸集C(区间)上的实值函数f。设f为定义在区间I上的函数,若对I上的任意两点x1
凸函数
性质
回到坑里
上代码
#include
代码优化
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
NaN%
NAN
NaNQ
NaNS
qNaN
sNaN 1.#SNAN 1.#QNAN -1.#IND
-NaN
NaN12345
-sNaN12300
-NaN(s1234)
工程应用
总结一下
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!