任务说明
现在手上有个使用热敏电阻读取体温的小项目,我使用一个基本的 “adc” 读取工程,它串口的输出是这个样子的:
返回的是电压值,而热敏电阻的读取只能通过查表,而且这个表就…很特别,它是温度-电阻的散点图,精度大到 1℃。
所以我的任务出来了:
首先,我需要设计个电路,让我能从电压值算出电阻值。
其次,根据 电阻 - 温度 散点图表,做一个非线性回归,以便能算出温度。
最后,获取串口数据,将其进行处理,以便直接丢入非线性回归方程,返回温度。
设计电路
设计个分压电路,那他的电阻就好读取了。
算出电阻
非线性回归
首先,提取出 电阻 - 温度 散点数据,存进excel,画出散点图。
代码:
# 读取散点图
data = pd.read_excel(r'E:\Data\电阻—温度表.xlsx')
x_data = data.iloc[:, 1]
y_data = data.iloc[:, 0]
# 画出电阻-温度散点图
plt.rcParams['font.family'] = 'SimHei' # 解决中文字体
plt.scatter(x_data, y_data)
data.corr()
plt.scatter(x_data, y_data)
plt.xlabel('电阻中心值(kΩ)')
plt.ylabel('温度')
plt.show()
结果如下:
基本是一条直线,略微有点弧度,选择2次、3次函数拟合都行。
上完整代码:
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures as pf
# 按照标准电阻-温度散点图得到的非线性回归模型
def Read_temp(Vol):
a = int(Vol)
# 计算电阻值
resistance = 10 / ((3300 / a) - 1)
if resistance >= 33.898:
print('体温小于 34 ℃,已经凉透了')
elif resistance <= 24.4515:
print('体温大于 42 ℃,可以沏茶了')
else:
# 读取散点图
data = pd.read_excel(r'E:\Data\电阻—温度表.xlsx')
x_data = data.iloc[:, 1]
y_data = data.iloc[:, 0]
pf_function = pf(degree=2) # 选择什么函数进行拟合,‘degree=3’代表三次函数
x1 = pf_function.fit_transform(x_data.values.reshape(-1, 1))
ir_modle = LinearRegression()
ir_modle.fit(x1, y_data)
# a = ir_modle.score(x1, y_data)
# print('模型拟合度:', a)
b = pf_function.fit_transform([[resistance]])
tem = ir_modle.predict(b)
print('体温:', tem)
Python读取串口数据
为了方便计算,我稍微修改了一下串口的打印格式,效果如下:
左边是寄存器原始值,右边是计算出来的电压值,中间用 ‘/’ 隔开,这样就清爽多了。
这里唯一需要注意的就是字符类型,无非就是多几次处理,问题不大,直接上代码:
import time
import pandas as pd
import serial.tools.list_ports
from codecs import getincrementaldecoder
from regression import rf
portx = "COM3" # 设置串口号
bps = 115200 # 设置波特率
timex = 5 # 设置超时时间
ser = serial.Serial(portx, bps, timeout=timex) # 创建串口对象
df_load = pd.DataFrame()
new_path = r'E:\Data\温度test.xlsx'
while True:
data = ser.readline() # 读取一行数据
decoder = getincrementaldecoder('gb2312')('replace') # 创建解码器
data_dc = decoder.decode(data) # 解码读取到的数据
print(data_dc) # 数据为字符串类型,且中间以“/”号隔开
data_dc1 = data_dc.strip() # 删除开头结尾的空白字符
data_dc2 = data_dc1.split('/') # split函数仅对‘str’处理
df_data = pd.DataFrame(data_dc2) # dataframe型
Vol = df_data.iloc[1, 0] # 提取电压值
rf.Read_temp(Vol)
# t = time.ctime()
df_load = df_load.append(df_data) # ‘append’函数对Dataframe格式操作
if data_dc == "": # 若读取到的数据为空,则跳出本次循环
break
# time.sleep(5)
df_load.to_excel(new_path)
打印结果:
结束