NTC 10K 温度传感器快速读取(arduino自定义库)区间线性回归(升级版)(Github开源下载)
(上一版本的区间线性回归原理请移步↓)
NTC10K 温度传感器快速读取(C程序)区间线性回归
升级之后的用法
-
可以安装在arduino内直接使用,并且制作了arduino使用例程
-
从原来的函数调用改为arduino自定义库
#include <NTC10K.h>
//分压电阻为 4.7K
//连接方式:GND----|4.7K|--|--|NTC10K|---+5V
// |-A0→读取AD值
NTC10K T0(A0);
//NTC10K T1(A1);
//NTC10K T2(A2);可新增对象
//NTC10K T3(A3);
float T[8];
int AD;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
T[0] = T0.AD_to_temp();
AD = analogRead(A0);
Serial.print("AD value is:");
Serial.print(AD);
Serial.print(" ");
Serial.print("temperature is:");
Serial.println(T[0],2);
delay(100);
}
效果演示
一、上一代缺陷
1. 函数调用不方便
× 原来的文件要调用还要将整个库添加到项目文件夹中;
√ 升级后直接将库文件复制进arduino安装根目录下库文件夹 直接在arduino中打开示例。
2. 温度解算效率低
× 原来的文件解算时是以温度的最高位作为索引,在解算时执行太多的switch case
float AD_to_temp(int AD)
{
float T0,K_Value,b_Value;
if(AD > index[0]) {AD = index[0];}
if(AD < index[12]){AD = index[12];}
switch(AD/100)
{
// 百位 索引值
case 9: K_Value = K[0];b_Value = b[0];break;
case 8: if(AD <index[1]){K_Value = K[0];b_Value = b[0];}else{K_Value = K[1];b_Value = b[1];}break;
case 7: if(AD <index[2]){K_Value = K[1];b_Value = b[1];}else{K_Value = K[2];b_Value = b[2];}break;
case 6: if(AD <index[3]){K_Value = K[2];b_Value = b[2];}else{K_Value = K[3];b_Value = b[3];}break;
case 5: if(AD <index[4]){K_Value = K[3];b_Value = b[3];}else{K_Value = K[4];b_Value = b[4];}break;
case 4: if(AD <index[5]){K_Value = K[4];b_Value = b[4];}else{K_Value = K[5];b_Value = b[5];}break;
case 3: if(AD <index[6]){K_Value = K[5];b_Value = b[5];}else{K_Value = K[6];b_Value = b[6];}break;
case 2: if(AD <index[7]){K_Value = K[6];b_Value = b[6];}else if(AD <index[8]){K_Value = K[7];b_Value = b[7];}else{K_Value = K[8];b_Value = b[8];}break;
case 1:
if(AD > index[9]) {K_Value = K[8];b_Value = b[8];}
else if(AD > index[10]){K_Value = K[9];b_Value = b[9];}
else if(AD > index[11]){K_Value = K[10];b_Value = b[10];}
else{K_Value = K[11];b_Value = b[11];} break;
case 0: K_Value = K[11];b_Value = b[11];break;
}
T0 = b_Value - K_Value*AD;
return T0;
}
√升级后的解算方式为差值排序算法,排序后进入区间内进行线性回归。
float NTC10K::AD_to_temp()
{
float T;
int AD_value;
char i;
AD_value = analogRead(this->Analog_pin);
if(AD_value < index[0] && AD_value > index[10])
{
for(i=0;i<=9;i++)
{
if(AD_value<=index[i] && AD_value>index[i+1]) //排序
{
if(i == 8) //特例二项拟合
{
T = AD_value*AD_value;
T = 0.0013*T;
T = T+189.37;
T = T-0.7403*AD_value;
}
else{ //线性拟合
T = b[i] -K[i]*AD_value;
}
break; //跳出循环
}
}
}
else{
if(AD_value >index[0]) {T = -30;}
if(AD_value <=50) {T = 168;}
}
return T;
}
3. 程序可读性低
× 原来的文件 switch case中还有多重分支结构难于理解
√ 升级后解算方式改为排序→易于理解
4.解算温度的范围变宽
× 原来的由于分压电阻原因温度只能支持-20℃–100℃;
√ 升级后分压电阻在10位AD转换下采用4.7K可以达到-20℃–167℃。(之后的AD采样值就不为一对一函数关系)
5. 程序使用麻烦(“长”得不官方)
× 原来使用方式为个人库
√ 升级后为arduino自定义库。(arduino库格式 有高亮Keywords设置)
二、更新内容介绍
1、索引方式
索引方式是按AD值百位 划分区间 每个区间开头为索引值 ;
之后将区间线性回归取得区间内的线性回归斜率和截距。
2、解算方式
首先找到当前温度下读取的AD值所处的区间;这一步采用类似插值排序的方式
if(AD_value < index[0] && AD_value > index[10])
{
for(i=0;i<=9;i++)
{//对比区间两侧的值
if(AD_value<=index[i] && AD_value>index[i+1]) //排序
{
;//
}
}
}
3、查看误差
由于Excel解算出的区间线性回归与当前区间内的原有值存在偏差,选取偏差比较大的区间进行误差对比
偏差求解原理:偏差 = 测量温度-(AD值*区间斜率+区间截距)
从表中可以看出即使线性回归较差的“800”区间段偏差也在±0.5℃之内
特例:
此区间线性拟合的之后的结果偏差太大 遂采用二项拟合
百度百科: 二项多项式
二项拟合回归:将曲线近似用二项式所绘制的曲线进行拟合的方式
可以看出在“100”区间内经过二项拟合之后的偏差勉强可以接受。
4、EXCEL参数化修改
之后又在原有的基础上添加修改NTC相关参数 和 ADC相关参数的参数区
5、NTC 理论最大测温范围计算
(由计算表格结算出最大不失真对应区间)
10bit 的ADC(0-1023) (arduino C51等类型单片机)
NTC100K
分压电阻 2K ---- 20-300℃
分压电阻4.7K ---- 0-250℃
分压电阻 10K ---- 20-210℃
NTC10K
分压电阻 2K ---- -20-182℃
分压电阻4.7K ---- -20-154℃
分压电阻 10K ---- -20-130℃
12bit 的ADC(0-4095) (STM32等)
NTC100K
分压电阻 2K: -12 - 416℃
分压电阻4.7K : -20 - 356℃
分压电阻 10K : -20 - 297℃
NTC10K
分压电阻 2K : -20 - 267℃
分压电阻4.7K : -20 - 214℃
分压电阻 10K : -20 - 179℃
(其他参数可通过 Excel参数化解算 参数可调NTC 区间线性回归文件下载后自行调试得出)