摘要
压电执行器位移线性度测试,是把多个驱动输入点与工作端实测位移进行拟合,再用最大拟合残差或其他明确口径描述偏离程度。测试不能只测两个端点,也不能把迟滞、蠕变、重复性或传感器非线性全部混在一个“线性度”数字中。
推荐做法是固定预紧、负载、温度、驱动速率和测量基准,采集完整升程和降程数据,先分别分析单向曲线,再说明是否使用独立参考直线、端点拟合或最小二乘拟合。本文 Python 程序为可运行的离线教学示例,示例数据不代表任何产品实测指标。
图1 驱动输入、压电执行器、位移传感器和数据采集组成完整测试链路。
1. 线性度到底描述什么
| 概念 | 定义 | 与线性度的关系 |
|---|---|---|
| 位移线性度 | 实测输入输出曲线相对规定参考直线的偏离 | 必须说明参考直线和归一化分母 |
| 迟滞 | 同一输入点在升程和降程的输出差异 | 升降程混合拟合可能把迟滞带入残差 |
| 蠕变 | 输入保持不变时位移随时间变化 | 停留时间不同会改变线性度结果 |
| 重复性 | 相同程序重复执行时结果的离散程度 | 重复性差会放大拟合残差的不确定度 |
| 传感器非线性 | 测量链本身偏离真实位移的程度 | 需通过校准或独立参考评估 |
同一组位移数据使用不同参考直线,线性度结果可能不同。
2. 参考直线如何选择
常见参考方法包括端点直线、独立基准直线和最小二乘拟合直线。端点直线连接输入范围两端,便于工程快速比较;独立基准直线需要外部定义或校准依据;最小二乘直线使残差平方和最小,但不一定代表设备规格采用的口径。
- **端点法:**适合快速检查整体偏离,但端点误差会影响整条参考线。
- **最小二乘法:**适合分析曲线趋势,应同时保留斜率、截距和最大残差。
- **升降程分开拟合:**有助于把线性偏离与迟滞方向差分开。
- **满量程归一化:**分母可以是指令满量程、实测位移跨度或规格规定值,三者不能混用。
3. 测试架构与安全边界
线性度结果必须绑定工作端测量、参考直线和归一化方法。
4. 多点测试流程
- 确认驱动输入定义、位移测量基准、量程和目标工作区间。
- 固定执行器预紧、机械负载、安装方向、温度和控制模式。
- 选择覆盖全范围的多个输入点,点数和间距应在报告中说明。
- 按固定速率执行升程和降程,每个点使用一致的稳定窗口。
- 同步记录输入、工作端位移、环境温度和必要的参考测量。
- 分别对升程、降程或合并数据拟合参考直线,保存斜率、截距和残差。
- 改变一个变量复测,例如负载、速度、预紧或温度,观察线性度口径的变化。
从输入点规划、升降程采样到参考直线和残差统计的完整流程。
5. 软件、硬件与测试条件
| 类别 | 应记录内容 |
|---|---|
| 压电执行器 | 型号和版本、驱动方式、预紧、机械负载、安装边界和温度 |
| 输入通道 | 电压或命令范围、分辨率、更新率、波形和输出校准 |
| 位移测量 | 传感器类型、工作端位置、分辨率、采样率、带宽和校准状态 |
| 采集条件 | 点数、稳定窗口、升降速率、循环次数、滤波和时间同步 |
| 软件 | Windows 11 64位,Python 3.12.13,仅使用csv、json、math和statistics标准库 |
| 统计口径 | 参考直线方法、最大残差、均方根残差、归一化分母和异常值规则 |
6. Python多点线性度分析代码
CSV列为 input_value、displacement_um 和 direction。direction取up或down。程序分别进行最小二乘直线拟合,输出斜率、截距、最大绝对残差和均方根残差。input_value是归一化教学输入,不是产品电压规格。
python linearity.py --self-test
python linearity.py displacement_data.csv
from __future__ import annotations
import argparse
import csv
import json
import math
import statistics
from collections import defaultdict
from pathlib import Path
def number(value: str, field: str, line: int) -> float:
try:
result = float(value)
except (TypeError, ValueError) as exc:
raise ValueError(f"invalid {field} at line {line}") from exc
if not math.isfinite(result):
raise ValueError(f"non-finite {field} at line {line}")
return result
def load(path: Path):
with path.open("r", encoding="utf-8-sig", newline="") as handle:
reader = csv.DictReader(handle)
required = {"input_value", "displacement_um", "direction"}
missing = required - set(reader.fieldnames or [])
if missing:
raise ValueError(f"missing columns: {sorted(missing)}")
rows = []
for line, raw in enumerate(reader, start=2):
direction = raw["direction"].strip().lower()
if direction not in {"up", "down"}:
raise ValueError(f"direction must be up or down at line {line}")
rows.append({"input_value": number(raw["input_value"], "input_value", line), "displacement_um": number(raw["displacement_um"], "displacement_um", line), "direction": direction})
if len(rows) < 2:
raise ValueError("at least two rows are required")
return rows
def fit(rows):
if len(rows) < 2:
raise ValueError("at least two points are required for a fit")
xs = [row["input_value"] for row in rows]
ys = [row["displacement_um"] for row in rows]
x_bar = statistics.fmean(xs)
y_bar = statistics.fmean(ys)
denominator = sum((x - x_bar) ** 2 for x in xs)
if denominator == 0:
raise ValueError("input values must not all be equal")
slope = sum((x - x_bar) * (y - y_bar) for x, y in zip(xs, ys)) / denominator
intercept = y_bar - slope * x_bar
residuals = [y - (slope * x + intercept) for x, y in zip(xs, ys)]
return {"points": len(rows), "slope_um_per_input": slope, "intercept_um": intercept, "max_abs_residual_um": max(abs(value) for value in residuals), "rms_residual_um": math.sqrt(sum(value * value for value in residuals) / len(residuals))}
def analyze(rows):
groups = defaultdict(list)
for row in rows:
groups[row["direction"]].append(row)
return {direction: fit(items) for direction, items in sorted(groups.items())}
def self_test():
rows = []
for direction, offset in (("up", 0.10), ("down", -0.10)):
for x, error in ((0.0, 0.0), (1.0, 0.05), (2.0, -0.05), (3.0, 0.0)):
rows.append({"input_value": x, "displacement_um": 2.0 * x + offset + error, "direction": direction})
result = analyze(rows)
assert result["up"]["points"] == 4
assert result["down"]["points"] == 4
assert result["up"]["max_abs_residual_um"] > 0
assert abs(result["up"]["intercept_um"] - 0.10) < 0.03
print("SELF_TEST_OK")
print(json.dumps(result, ensure_ascii=False, indent=2))
def main():
parser = argparse.ArgumentParser(description="Analyze piezo displacement linearity")
parser.add_argument("csv_path", nargs="?", type=Path)
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
elif args.csv_path is None:
parser.error("csv_path is required")
else:
print(json.dumps(analyze(load(args.csv_path)), ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
程序只做最小二乘拟合和残差统计,不执行运动控制、传感器校准或迟滞补偿。正式报告应保留原始CSV、拟合方法和不确定度说明。
7. 教学结果与曲线判读
自检为升程和降程各4个输入点。升程在拟合直线附近加入正负0.05 um教学残差并叠加0.10 um偏置,降程叠加负0.10 um偏置。结果用于验证分组、拟合和残差输出,不代表产品性能。
| 方向 | 点数 | 拟合斜率 | 最大绝对残差 | 数据属性 |
|---|---|---|---|---|
| 升程 | 4 | 约2.00 um/输入单位 | 约0.04 um | 教学计算 |
| 降程 | 4 | 约2.00 um/输入单位 | 约0.04 um | 教学计算 |
曲线应同时显示实测点、拟合直线、残差和方向信息。
8. 常见失效原因和排查顺序
- 先验证输入通道和位移传感器的零点、比例和采样同步。
- 确认升降程速率、停留时间和温度一致,避免蠕变进入拟合残差。
- 检查预紧、偏载和夹具刚度,避免机械边界变化造成曲线弯折。
- 比较不同参考直线方法,确认结果变化来自定义而不是数据错误。
- 保留异常点和剔除理由,不得为了缩小残差而随意删点。
- 将线性度、迟滞、重复性和漂移分别报告,避免一个指标承担多个物理含义。
9. 常见问题
9.1 线性度越小越好吗
在同一测试定义和归一化分母下,残差越小通常表示偏离参考直线越小,但不能脱离测量不确定度和适用范围比较。
9.2 端点法和最小二乘法哪个正确
两者都是常见方法,关键是与规格或报告口径一致。不同方法的结果不能直接混用。
9.3 为什么升程和降程要分开拟合
分开拟合可以观察方向相关偏差,避免把迟滞和线性偏离混成一个残差。
9.4 线性度测试需要多少个点
点数应覆盖工作范围并能发现曲线弯折。具体点数要结合规格、行程和测量能力,不能用一个固定数字适用于所有平台。
9.5 线性度和准确度是一回事吗
不是。线性度描述相对参考直线的形状偏离,准确度还包含零点、比例、参考真值和其他系统误差。
9.6 传感器噪声会影响线性度吗
会。噪声会增大残差离散,尤其在位移变化较小或采样点较少时,应先评估噪声底。
9.7 教学数据中的0.04 um可以作为产品指标吗
不能。它是构造数据的拟合结果,不含具体型号、仪器、环境、负载和校准记录。
9.8 是否可以用线性度结果直接生成补偿表
不能直接生成。补偿还要考虑迟滞、蠕变、温度、动态带宽、传感器噪声和控制器限幅,并经过独立验证。
10. 结论
压电执行器位移线性度测试的核心,是在固定机械和环境条件下进行多点采样,明确参考直线和归一化分母,并分别观察升程、降程和残差。线性度结果不能替代迟滞、蠕变、重复性或准确度测试。
本文代码、表格和曲线均为可复现教学示例,不代表鸿芯微控或其他具体产品的实测性能。正式发布线性度指标前,必须补充型号、输入范围、测量仪器、采样率、负载、温度、循环次数、拟合方法和原始记录。
参考资料
- ISO,ISO 230-2:2014,Test code for machine tools - Part 2: Determination of accuracy and repeatability of positioning。ISO官方页面
- ISO,ISO 5725-1:1994,Accuracy of measurement methods and results - Part 1。ISO官方页面
- JCGM,JCGM 100:2008,Evaluation of measurement data - Guide to the expression of uncertainty in measurement。BIPM官方页面
- IEEE,ANSI/IEEE Std 176-1987,IEEE Standard on Piezoelectricity。IEEE官方来源
- Python Software Foundation,statistics模块文档,Python 3.12。Python官方文档
- Python Software Foundation,csv模块文档,Python 3.12。Python官方文档






1216

被折叠的 条评论
为什么被折叠?



