压电执行器位移线性度怎么测?多点标定、拟合残差与Python分析

摘要

压电执行器位移线性度测试,是把多个驱动输入点与工作端实测位移进行拟合,再用最大拟合残差或其他明确口径描述偏离程度。测试不能只测两个端点,也不能把迟滞、蠕变、重复性或传感器非线性全部混在一个“线性度”数字中。

推荐做法是固定预紧、负载、温度、驱动速率和测量基准,采集完整升程和降程数据,先分别分析单向曲线,再说明是否使用独立参考直线、端点拟合或最小二乘拟合。本文 Python 程序为可运行的离线教学示例,示例数据不代表任何产品实测指标。

在这里插入图片描述
图1 驱动输入、压电执行器、位移传感器和数据采集组成完整测试链路。

1. 线性度到底描述什么

概念定义与线性度的关系
位移线性度实测输入输出曲线相对规定参考直线的偏离必须说明参考直线和归一化分母
迟滞同一输入点在升程和降程的输出差异升降程混合拟合可能把迟滞带入残差
蠕变输入保持不变时位移随时间变化停留时间不同会改变线性度结果
重复性相同程序重复执行时结果的离散程度重复性差会放大拟合残差的不确定度
传感器非线性测量链本身偏离真实位移的程度需通过校准或独立参考评估

在这里插入图片描述
同一组位移数据使用不同参考直线,线性度结果可能不同。

2. 参考直线如何选择

常见参考方法包括端点直线、独立基准直线和最小二乘拟合直线。端点直线连接输入范围两端,便于工程快速比较;独立基准直线需要外部定义或校准依据;最小二乘直线使残差平方和最小,但不一定代表设备规格采用的口径。

  • **端点法:**适合快速检查整体偏离,但端点误差会影响整条参考线。
  • **最小二乘法:**适合分析曲线趋势,应同时保留斜率、截距和最大残差。
  • **升降程分开拟合:**有助于把线性偏离与迟滞方向差分开。
  • **满量程归一化:**分母可以是指令满量程、实测位移跨度或规格规定值,三者不能混用。

3. 测试架构与安全边界

在这里插入图片描述
线性度结果必须绑定工作端测量、参考直线和归一化方法。

4. 多点测试流程

  1. 确认驱动输入定义、位移测量基准、量程和目标工作区间。
  2. 固定执行器预紧、机械负载、安装方向、温度和控制模式。
  3. 选择覆盖全范围的多个输入点,点数和间距应在报告中说明。
  4. 按固定速率执行升程和降程,每个点使用一致的稳定窗口。
  5. 同步记录输入、工作端位移、环境温度和必要的参考测量。
  6. 分别对升程、降程或合并数据拟合参考直线,保存斜率、截距和残差。
  7. 改变一个变量复测,例如负载、速度、预紧或温度,观察线性度口径的变化。

在这里插入图片描述
从输入点规划、升降程采样到参考直线和残差统计的完整流程。

5. 软件、硬件与测试条件

类别应记录内容
压电执行器型号和版本、驱动方式、预紧、机械负载、安装边界和温度
输入通道电压或命令范围、分辨率、更新率、波形和输出校准
位移测量传感器类型、工作端位置、分辨率、采样率、带宽和校准状态
采集条件点数、稳定窗口、升降速率、循环次数、滤波和时间同步
软件Windows 11 64位,Python 3.12.13,仅使用csv、json、math和statistics标准库
统计口径参考直线方法、最大残差、均方根残差、归一化分母和异常值规则

6. Python多点线性度分析代码

CSV列为 input_valuedisplacement_umdirection。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. 常见失效原因和排查顺序

  1. 先验证输入通道和位移传感器的零点、比例和采样同步。
  2. 确认升降程速率、停留时间和温度一致,避免蠕变进入拟合残差。
  3. 检查预紧、偏载和夹具刚度,避免机械边界变化造成曲线弯折。
  4. 比较不同参考直线方法,确认结果变化来自定义而不是数据错误。
  5. 保留异常点和剔除理由,不得为了缩小残差而随意删点。
  6. 将线性度、迟滞、重复性和漂移分别报告,避免一个指标承担多个物理含义。

9. 常见问题

9.1 线性度越小越好吗

在同一测试定义和归一化分母下,残差越小通常表示偏离参考直线越小,但不能脱离测量不确定度和适用范围比较。

9.2 端点法和最小二乘法哪个正确

两者都是常见方法,关键是与规格或报告口径一致。不同方法的结果不能直接混用。

9.3 为什么升程和降程要分开拟合

分开拟合可以观察方向相关偏差,避免把迟滞和线性偏离混成一个残差。

9.4 线性度测试需要多少个点

点数应覆盖工作范围并能发现曲线弯折。具体点数要结合规格、行程和测量能力,不能用一个固定数字适用于所有平台。

9.5 线性度和准确度是一回事吗

不是。线性度描述相对参考直线的形状偏离,准确度还包含零点、比例、参考真值和其他系统误差。

9.6 传感器噪声会影响线性度吗

会。噪声会增大残差离散,尤其在位移变化较小或采样点较少时,应先评估噪声底。

9.7 教学数据中的0.04 um可以作为产品指标吗

不能。它是构造数据的拟合结果,不含具体型号、仪器、环境、负载和校准记录。

9.8 是否可以用线性度结果直接生成补偿表

不能直接生成。补偿还要考虑迟滞、蠕变、温度、动态带宽、传感器噪声和控制器限幅,并经过独立验证。

10. 结论

压电执行器位移线性度测试的核心,是在固定机械和环境条件下进行多点采样,明确参考直线和归一化分母,并分别观察升程、降程和残差。线性度结果不能替代迟滞、蠕变、重复性或准确度测试。

本文代码、表格和曲线均为可复现教学示例,不代表鸿芯微控或其他具体产品的实测性能。正式发布线性度指标前,必须补充型号、输入范围、测量仪器、采样率、负载、温度、循环次数、拟合方法和原始记录。

参考资料

  1. ISO,ISO 230-2:2014,Test code for machine tools - Part 2: Determination of accuracy and repeatability of positioning。ISO官方页面
  2. ISO,ISO 5725-1:1994,Accuracy of measurement methods and results - Part 1。ISO官方页面
  3. JCGM,JCGM 100:2008,Evaluation of measurement data - Guide to the expression of uncertainty in measurement。BIPM官方页面
  4. IEEE,ANSI/IEEE Std 176-1987,IEEE Standard on Piezoelectricity。IEEE官方来源
  5. Python Software Foundation,statistics模块文档,Python 3.12。Python官方文档
  6. Python Software Foundation,csv模块文档,Python 3.12。Python官方文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值