数学的应用 - y=kx+b处理嵌入式设备的校准数据

文摘   科技   2023-03-12 18:12   广东  

Keep Moving 

保持·热爱

应用方案

方案分析

嵌入式

设备校准表格



一元一次方程处理设备校准数据

后台回复开源获取源代码



关于校准

设备校准的一般方案

一般来说,设备未校准前,电压、电流的测量与控制,与实际值存在偏差,校准就是找到实际值的数学关系式 f(x)。


针对电压、电流的测量:

  • 市面上ADC芯片的基本都是线性的

  • 对ADC量程分段,基本能满足精度要求

  • 被测量也可分段,如万用表的量程


针对其输出控制:

  • 软件闭环控制方案,只要ADC测量精度高即可

  • 硬件闭环控制,一般DAC输出参考量,与反馈信号综合控制输出


那么这里头:

  • 写入DAC的值、从ADC读出的值,称为原始值 x

  • 实际的待测量、控制量,称为真实值 y

  • 也就有 y = k x + b


校准表格的由来

上面我们找到了关系式,一元一次方程,我们校准就是:

  • 限定定义域,依据线性度打断点,进行分段

  • 每一小段套用 y = k x + b

  • 断点是坐标点,作为校准点

  • 坐标点可用Excel拉一个表格

表格的概念出来,形式如下:


结构体描述Excel表格

我们设想,若MCU内部维护一个表格,那么我们就可以愉快地使用校准数据。


尝试用结构体描述上述表格:

typedef struct{    int32_t     actual;      /* 实际的目标值 */    uint32_t    original;    /* 原始值 */}CalPoint_t;typedef struct{    uint16_t    start_addr; /* EEPROM上的存储地址 */    uint8_t     point_size; /* 校准点的大小 */    uint8_t     number;     /* 校准点数 */    uint8_t     ch;         /* 通道 */    uint8_t     linkage_ch; /* 联动通道 */    CalPoint_t  *point;     /* 校准点 */}CalTable_t;typedef struct{    uint8_t     ch_number;  /* 通道数 */    CalTable_t  *table;     /* 校准表格 */}CalObj_t;

接着定义宏列表,具体参考上篇 宏列表批量定义结构体数组、枚举 ,结构上基本与Excel表格一致:



校准驱动

接口实现             

              驱动设计

概述

上篇 宏列表批量定义结构体数组、枚举 已设计好校准表格

/* 用户校准表格控制块。结构已固定 */static CalObj_t __userCalTable[] = {  CAL_TABLE(TABLE_USER_REG, __NULL, __NULL, __NULL, __NULL)};

现在需要从“__userCalTable”中获取真实值、原始值,包括从存储器加载校准数据等等。


获取真实值

“ry_get_actual”函数是一个分段函数,扔3个变量给它,它吐出结果

  • cal_table:告诉它是哪个校准表格

  • ch:告诉它通道号

  • val:原始值 x

/* 获取实际电压值、电流值 */float ry_get_actual(uint8_t cal_table, uint8_t ch, uint32_t val){  uint8_t pos, number;  int32_t prev, next;  float   k;  CalPoint_t *CalPoint;  CalObj_t   *obj;  __IS_CHANNEL(cal_table, ch, 0);  CalPoint = obj->table[ch].point;  number   = obj->table[ch].number;  /* 找出在哪个区间内 */  for(pos = 0; pos < number; pos++)  {    if(val <= CalPoint[pos].original)    {      if(val == CalPoint[pos].original)        return (float)CalPoint[pos].actual;      if(pos == 0)        pos = 1;//        return ((float)CalPoint[0].actual) / CalPoint[0].original * val;      break;    }  }  if(pos >= number)    pos = number - 1;  /* y = k * x + b */  /* k = (y2 - y1) / (x2 - x1) */  /* b = y1 - k * x1 */  /* f(data) = k(data - x1) + y1 */  prev = CalPoint[pos-1].actual;  next = CalPoint[pos].actual;  k  = (float)(next - prev) / (float)(CalPoint[pos].original - CalPoint[pos-1].original);  return (float)((float)((int32_t)val - (int32_t)CalPoint[pos-1].original) * k + prev);}


加载校准数据

从存储器中加载校准数据,放入表格中:

/* 获取校准状态,并加载校准数据 */uint8_t ry_get_device_cal_status(void){  uint8_t pos;  uint8_t buf[1];  ry_eeprom_read(DEVICE_CAL_DATA_ADDR, buf, 1);  if(buf[0] == DEVICE_CAL_FINISH)  {    /* 加载校准数据 */    for(pos = 0; pos < __CAL_TABLE_NUMBER; pos++)    {      __DeviceCalFlag = ry_cal_table_upload(pos);    }    return __DeviceCalFlag;  }  __DeviceCalFlag = DEVICE_CAL_NO;  return __DeviceCalFlag;}



应用举例

举例

对照校准表格:

编写主函数:

运行结果如下:

可以看到校准表格:

  • 一元一次方程正常运转

  • 能找点,能转换出正数、负数






-END-


碎片聚合
求真务实
 最新文章