最小二乘法计算传感器灵敏度
在传感器的设计与应用过程中,如何准确评估传感器的灵敏度和非线性误差是至关重要的。灵敏度代表了传感器对外部应变的响应程度,而非线性误差则反映了传感器在整个量程范围内与理想线性响应的偏离程度。为此,最小二乘法提供了一种高效而且简单的方法,能够通过拟合传感器输出数据,准确计算这些关键参数。这篇文章将通过一段简单的 Python 代码,介绍如何利用最小二乘法计算应变式传感器的灵敏度和非线性误差。
1. 准备工作:数据与精度处理
首先,我们需要处理应变传感器的输入(应变值)与输出(电压或电阻值)的数据。为了确保计算的精确性,我们使用 Python 的 decimal
模块,该模块允许我们进行高精度的数值计算,避免因四舍五入带来的计算误差。
from decimal import Decimal, getcontext
# 设置计算精度为28位,确保结果的高精度
getcontext().prec = 28
# 定义输入数据(应变值)和输出数据(传感器测量值)
x = [Decimal('0'), Decimal('10'), Decimal('20'), Decimal('50'), Decimal('100'), Decimal('150'),
Decimal('200'), Decimal('300'), Decimal('350'), Decimal('400')]
y = [Decimal('28.14'), Decimal('27.16'), Decimal('26.17'), Decimal('23.19'), Decimal('18.24'),
Decimal('13.34'), Decimal('8.32'), Decimal('-1.59'), Decimal('-6.37'), Decimal('-11.5')]
在这里,我们定义了输入 x
(应变值)和输出 y
(传感器测量值)作为待拟合的两个变量。这些数据点来源于实际测量,表示传感器在不同应变条件下的输出。
2. 最小二乘法的核心计算
接下来,我们通过最小二乘法来拟合传感器的输出曲线。最小二乘法的核心思想是通过最小化数据点与拟合直线之间的距离平方和,来确定最佳的斜率 k和截距 b。计算公式如下:
斜率 k:
截距 b:
其中,实现该公式的代码为:
n = len(x) # 数据点的数量
# 计算 ∑x, ∑y, ∑x^2, ∑xy
sum_x = sum(x)
sum_y = sum(y)
sum_x2 = sum([xi ** 2 for xi in x])
sum_xy = sum([xi * yi for xi, yi in zip(x, y)])
# 计算斜率 k 和截距 b
k = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
b = (sum_y - k * sum_x) / Decimal(n)
# 输出斜率和截距
print(f"斜率 k = {k}")
print(f"截距 b = {b}")
3. 误差分析与非线性误差计算
一旦拟合直线方程确定,我们可以计算出每个数据点的预测值 ypredy_{pred}ypred,然后通过原始数据 yyy 与预测值的差异计算误差。此外,我们可以通过以下步骤计算最大误差和非线性误差:
误差计算:每个数据点的误差为其真实值与拟合值之差。
最大误差:误差中的最大值表示拟合曲线的最严重偏差。
满量程输出(MLC):表示传感器从最大到最小输出的差值。
非线性误差:定义为最大误差与满量程输出的比值,是衡量传感器非线性性能的重要指标。
代码展示如下:
# 计算预测值 y_pred
y_pred = [k * xi + b for xi in x]
# 计算误差
errors = [yi - y_predi for yi, y_predi in zip(y, y_pred)]
# 计算最大误差和满量程输出
max_error = max([abs(ei) for ei in errors])
MLC = max(y) - min(y)
# 计算非线性误差
nonlinear_error = max_error / MLC
# 输出非线性误差
print(f"最大误差 = {max_error}")
print(f"满量程输出 MLC = {MLC}")
print(f"非线性误差 = {nonlinear_error}")
4. 可视化结果
import matplotlib.pyplot as plt
import matplotlib
# 设置中文字体支持
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
matplotlib.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 转换为浮点数以便绘图
x_float = [float(xi) for xi in x]
y_float = [float(yi) for yi in y]
y_pred_float = [float(yp) for yp in y_pred]
# 绘制数据点和拟合直线
plt.scatter(x_float, y_float, color='blue', label='原始数据')
plt.plot(x_float, y_pred_float, color='red', label=f'拟合直线: y = {float(k):.4f}x + {float(b):.4f}')
plt.legend()
plt.grid(True)
plt.title('传感器数据拟合曲线')
plt.xlabel('应变')
plt.ylabel('传感器输出')
plt.show()
5.结果分析
最后,可视化结果为:
计算结果为:
6.完整代码
###——————最小二乘法计算应变式传感器的灵敏度和非线性误差——————###
#导入所需的函数库
from decimal import Decimal, getcontext
import matplotlib.pyplot as plt
import matplotlib
# 设置中文字体支持以便用于图例中文显示
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体
matplotlib.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 设置计算过程的精度(由于在计算过程中会由于四舍五入而导致计算过程出错)
getcontext().prec = 28
# 定义数据类型
x = [Decimal('0'), Decimal('10'), Decimal('20'), Decimal('50'), Decimal('100'), Decimal('150'),
Decimal('200'), Decimal('300'), Decimal('350'), Decimal('400')]
y = [Decimal('28.14'), Decimal('27.16'), Decimal('26.17'), Decimal('23.19'), Decimal('18.24'),
Decimal('13.34'), Decimal('8.32'), Decimal('-1.59'), Decimal('-6.37'), Decimal('-11.5')]
# 数据点数量
n = len(x) #可以直接定义为10
# 计算过程
sum_x = sum(x) # ∑x
sum_y = sum(y) # ∑y
sum_x2 = sum([xi ** 2 for xi in x]) # ∑x^2
sum_xy = sum([xi * yi for xi, yi in zip(x, y)]) # ∑xy
# 输出计算结果
print(f"∑x = {sum_x}")
print(f"∑y = {sum_y}")
print(f"∑x^2 = {sum_x2}")
print(f"∑xy = {sum_xy}")
# 计算斜率 k 和截距 b 的公式
k = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
b = (sum_y - k * sum_x) / Decimal(n)
# 输出斜率和截距
print(f"斜率 k = {k}")
print(f"截距 b = {b}")
# 计算预测值 y_pred
y_pred = [k * xi + b for xi in x]
# 计算误差
errors = [yi - y_predi for yi, y_predi in zip(y, y_pred)]
# 计算最大误差和满量程输出 (MLC,man_liang_cheng)
max_error = max([abs(ei) for ei in errors]) # 最大误差
MLC = max(y) - min(y) # 满量程输出
# 计算非线性误差
nonlinear_error = max_error / MLC
# 输出非线性误差
print(f"非线性误差 = {nonlinear_error}")
print(f"最大误差 = {max_error}")
print(f"满量程输出 MLC = {MLC}")
# 转换回浮点数
x_float = [float(xi) for xi in x]
y_float = [float(yi) for yi in y]
y_pred_float = [float(yp) for yp in y_pred]
#绘图准备
plt.title('高精度最小二乘法拟合曲线')
plt.xlabel('x')
plt.ylabel('y')
# 绘制数据点和拟合直线
plt.scatter(x_float, y_float, color='blue', label='原始数据') # 绘制原始数据点
plt.plot(x_float, y_pred_float, color='red', label=f'拟合直线: y = {float(k):.4f}x + {float(b):.4f}') # 绘制拟合的直线
plt.legend() # 显示图例
plt.grid(True) # 显示网格
plt.show() # 展示图像
# 最终输出灵敏度(斜率)和非线性误差
print(f"灵敏度(斜率 k)= {k}")
print(f"非线性误差 = {nonlinear_error}")