资讯动态

MATLAB实现压电陶瓷Preisach模型:迟滞辨识与逆补偿

发布时间:2026/9/17 17:55:04 来源:尧图企业网站定制
简介围绕压电陶瓷Preisach建模与迟滞补偿的Matlab仿真资料包面向压电执行器方向的研究者、工程师与高年级学生可用于解决Preisach正逆模型数值实现、迟滞非线性仿真与补偿控制等关键问题也适用于传感器、执行器、MEMS等压电应用场景的特性分析与优化。包内共有49个文件压缩包大小10.97MB以m脚本、PDF论文为主另含dat数据、fig图形、mat变量等类型m源码用于模型实现与算法运行PDF文档提供理论推导与补偿控制方法dat、mat文件辅助实验数据管理与加载。目前已有1218人学习下载。内容涵盖经典Preisach模型及改进数值实现方法、逆模型双线性插值算法、GUI交互程序、迟滞逆模型补偿控制等资料并配有readme说明与相关文献便于读者从理论推导、代码编写到仿真验证系统掌握压电陶瓷迟滞建模与动力学仿真流程。1. 压电陶瓷Preisach模型在MATLAB里到底要怎么落地压电陶瓷的位移响应不是一条静态曲线就能描述的同一个电压从低到高到达和从高到低到达位移能差出百分之十几到几十。更麻烦的是如果中间停过一段时间再走一小段位移还会绕着另一条小环走。做微纳米定位时这种迟滞会直接变成定位误差。Preisach模型之所以在压电陶瓷驱动领域被反复提起是因为它不用假设迟滞环是多项式还是圆弧而是用大量滞回算子的加权叠加去逼近任意形状的迟滞环。下面的做法在MATLAB里把Preisach的权重辨识、状态计算和逆补偿串成一份可以自己改的代码。新手可以按步骤复现有经验的人可以直接把手里的 stairsh7w 这类实测数据套进辨识流程里验证。2. Preisach模型的数据结构和状态计算先让MATLAB认识迟滞环2.1 从积分公式到权重向量经典Preisach模型把输出写成[ y(t)\iint_{\alpha \ge \beta} \mu(\alpha,\beta)\ \gamma_{\alpha\beta}[u(t)]\ d\alpha d\beta ]其中 (u(t)) 是压电陶瓷驱动电压(\gamma_{\alpha\beta}) 是一个滞回开关算子当输入从下方穿越 (\alpha) 时这个算子输出 1当输入从上方穿越 (\beta) 时输出回到 0输入停留在两者之间时输出保持上一次的翻转结果。这样一来历史信息就通过算子状态被保留下来迟滞环的“记忆”就体现在这里。实际使用中不会直接算二重积分而是把电压范围离散成 (N) 个阈值点。设(\alpha) 取一组升序的电压阈值(\beta) 取同一组电压阈值每个阈值对 ((\alpha_i,\beta_j)) 对应一个权重 (\mu_{ij})因为有效区域必须满足 (\alpha \ge \beta)所以真正需要辨识的权重只在矩阵下三角。把所有下三角权重拉平成一个列向量就得到mu_vec长度是 (N(N1)/2)。这就是后续最小二乘里的未知数。2.2 网格参数怎么定网格大小 (N) 直接决定模型表达能力和辨识开销。取得太小迟滞环上的细节会被平均掉取得太大权重矩阵病态程度上升而且状态计算的时间成平方增长。参数建议取值说明N32 到 64定位精度要求高时取 64初步验证用 32u_min,u_max按实际驱动电压范围设置不要超出实测数据范围否则权重外推不可靠mu_vec初值全 0不要随机初始化后面用线性最小二乘求解采样点数每个电压分支至少 20 个点用于捕捉穿越阈值的精确时刻一个常见的错误是把 (N) 设成 256 以上然后发现辨识矩阵病态严重。压电陶瓷的迟滞环并不需要那么多自由参数64 已经能描述绝大多数驱动器的次环行为。2.3 MATLAB结构体与算子状态序列在MATLAB里我习惯用一个结构体保存模型model.N 32; model.u_min 0; model.u_max 100; model.alpha linspace(model.u_min, model.u_max, model.N); model.beta model.alpha; model.mu_vec zeros(model.N * (model.N 1) / 2, 1);这里alpha和beta是相同的列向量。mu_vec按行优先顺序保存下三角权重长度与后面生成的状态矩阵列数一致。接下来是整篇文章最核心的函数给定一段电压历史算出每个算子在这段历史中每个时刻的输出状态。我按“下三角列优先”顺序生成状态矩阵每一行对应一个采样时刻每一列对应一个 ((\alpha_i,\beta_j)) 算子function states preisach_states(model, V) alpha model.alpha(:); beta model.beta(:); N numel(alpha); T numel(V); ncols N * (N 1) / 2; states zeros(T, ncols); col 0; for i 1:N for j 1:i col col 1; s V(1) alpha(i); states(1, col) s; for k 2:T u_prev V(k-1); u_now V(k); if ~s u_prev alpha(i) u_now alpha(i) s 1; elseif s u_prev beta(j) u_now beta(j) s 0; end states(k, col) s; end end end end逻辑说明对每个算子单独追踪状态。s为 1 表示该算子当前导通贡献权重为 0 表示关断。判断条件分别捕捉“向上穿越 (\alpha)”和“向下穿越 (\beta)”这样即使电压在一拍内从范围一端跳到另一端也能正确判定最终状态。这个写法不是性能最优版本但 (N32)、(T3000) 时在普通PC上可以接受追求速度时可以把内层循环改成矩阵运算先用cumsum找到最后一次穿越时刻再批量赋值。3. 用压电陶瓷实测数据辨识Preisach权重一阶回转曲线与最小二乘3.1 辨识输入序列为什么选一阶回转曲线Preisach权重能不能辨识出来取决于输入电压是否把 ((\alpha,\beta)) 平面上的下三角区域充分激励。只给正弦波迟滞环只会经过有限几条轨迹大部分算子从未翻转过权重无法被观测到。常见做法是给一组阶梯式“一阶回转曲线”序列从最小电压出发升到某个上限再落回最小电压每次升到的上限递增重复多次。这样每个算子都被反复翻转观测数据里包含足够多的迟滞信息。v_lo model.u_min; v_hi model.u_max; levels 12; pts_per_level 25; V v_lo; for level 1:levels peak v_lo (v_hi - v_lo) * level / levels; upward linspace(v_lo, peak, pts_per_level); downward linspace(peak, v_lo, pts_per_level); V [V, upward, downward]; end这段代码生成一个电压序列第一段从 0 到 1/12 满量程再回 0第二段从 0 到 2/12 满量程再回 0依此类推。注意V的初始值取v_lo对应压电陶瓷的零电压位置。生成后先看一遍min(V)和max(V)确保没有超出实际驱动范围。实际测量时把这段电压命令送给压电陶瓷驱动电源同步采集位移。如果数据已经存在stairsh7w.mat这种文件里先用load读进来确认命令向量和位移向量长度一致再统一去掉位移的直流偏置load stairsh7w.mat; cmd stairsh7w.cmd; disp stairsh7w.disp; disp disp - disp(1); cmd cmd(:); disp disp(:);cmd是施加给压电陶瓷的电压disp是对应位移。把位移初值归零是为了让模型输出从 0 开始避免常数项干扰权重辨识。如果数据里还有缓慢的蠕变漂移先做高通滤波或者去掉首尾均值不要让直流分量进入最小二乘。3.2 把输出方程改写成线性回归前面已经定义了算子状态矩阵。模型输出可以写成[ y_k \sum_{m1}^{M} \mu_m , s_{k,m} ]其中 (MN(N1)/2)。把所有采样时刻放到一起就是[ \begin{bmatrix} y_1\ y_2\ \vdots\ y_T \end{bmatrix}\begin{bmatrix} s_{1,1} \cdots s_{1,M}\ s_{2,1} \cdots s_{2,M}\ \vdots \ddots \vdots\ s_{T,1} \cdots s_{T,M} \end{bmatrix} \begin{bmatrix} \mu_1\ \vdots\ \mu_M \end{bmatrix} ]用preisach_states生成状态矩阵后辨识就变成标准线性方程组求解。经典Preisach模型的权重物理上应该非负所以优先用lsqnonneg它比无约束最小二乘更符合迟滞模型states preisach_states(model, cmd); mu_vec lsqnonneg(states, disp); model.mu_vec mu_vec;如果MATLAB里没有优化工具箱也可以用mu_vec states \ disp代替。这种情况下可能出现负权重但只要预测误差可控、不要求严格物理解释工程上也能用。需要注意的是lsqnonneg要求states是数值矩阵不能包含NaN。如果电压序列里有过零电位或者采样中断先把对应行删除。3.3 辨识结果的自检方式拿到mu_vec后第一件事是用同一组电压命令回代算模型输出和实际位移的误差y_hat states * model.mu_vec; e y_hat - disp; rms_error sqrt(mean(e.^2)); max_error max(abs(e)); fprintf(RMS error: %.4f um\n, rms_error); fprintf(Max error: %.4f um\n, max_error);如果rms_error与位移量级相比超过 1%先不要急着调网格。常见原因有三个输入电压命令没有经过功率放大器带宽限制导致实际电压与命令电压不一致采集到的位移没对齐时间戳存在相位滞后激励序列没有从同一个初始磁化状态出发。相位问题只要把位移整体前移或后移几拍重新算一次误差就能看出来。4. Preisach正模型预测与逆补偿从fzero到前馈PID4.1 正模型给定任意电压轨迹预测位移有了权重向量之后正模型预测很简单用同一套preisach_states算出状态矩阵再乘权重向量。function y preisach_predict(model, V) states preisach_states(model, V); y states * model.mu_vec; end调用时可以传入完整历史轨迹V_test [0; 20; 40; 60; 80; 100; 80; 60]; y_test preisach_predict(model, V_test);注意V_test的第一个点会被当作初始状态的一部分。如果正模型要模拟的是从零电压、零位移开始的实际过程第一点就必须是u_min。如果直接从某个非零电压开始最好把前一段历史也接进去否则算子初始状态和实际情况对不上。4.2 逆补偿把期望位移反解成电压Preisach逆模型可以直接用“正模型求根”的方式做。对于期望位移序列y_ref在每个控制周期里给定当前电压历史找一个新的电压使得正模型输出等于y_ref(k)u_history []; u_prev model.u_min; u_feed zeros(size(y_ref)); options optimset(TolX, 1e-4); for k 1:numel(y_ref) fun (uu) preisach_predict(model, [u_history; uu]) - y_ref(k); try u_feed(k) fzero(fun, u_prev, options); catch u_feed(k) fzero(fun, [model.u_min, model.u_max], options); end u_history [u_history; u_feed(k)]; u_prev u_feed(k); end这里的思路是每次把候选电压uu追加到历史末尾用正模型算出对应位移再和期望位移比较。fzero在这个问题里是可靠的因为模型输出对当前输入单调目标位移落在模型输出范围内时存在唯一解。u_prev作为初始猜测可以减少迭代次数。fzero的容差不要设得太小压电陶瓷驱动电压经过DAC输出后本身有量化误差TolX取 1e-3 到 1e-4 就够。过小的容差会让fzero在噪声水平上反复迭代白白增加计算时间。4.3 前馈加PID的复合控制纯逆模型前馈在模型误差为零时效果最好但实际压电陶瓷还有蠕变、温度漂移和负载变化。工程上更常见的做法是前馈提供主要电压PID反馈补偿剩余误差。下面是一个仿真用闭环循环Kp 0.5; Ki 0.02; Kd 0.001; err_sum 0; e_prev 0; u_applied []; y_sim zeros(size(y_ref)); for k 1:numel(y_ref) if k 1 e y_ref(k) - y_sim(k-1); else e y_ref(k); end err_sum err_sum e; u_pid Kp * e Ki * err_sum Kd * (e - e_prev); u_total u_feed(k) u_pid; u_total min(max(u_total, model.u_min), model.u_max); u_applied [u_applied; u_total]; y_sim(k) preisach_predict(model, u_applied); e_prev e; end这个循环把u_applied当作实际历史正模型用它产生仿真位移。前馈项u_feed(k)已经补偿了主要迟滞PID只需要处理残余误差。参数调整顺序是从零开始加Kp看到稳态误差后加Ki最后加一点Kd抑制超调。Ki不要一开始就设大压电陶瓷的蠕变会让积分项累积过快导致电压饱和。参数作用调试建议Kp比例项快速反映误差从 0.1 开始逐步增大Ki消除稳态误差从 0 开始出现稳态误差后加Kd抑制超调只在响应有振荡时加TolXfzero 搜索精度1e-4 足够u_total限幅防止电压越界必须限制在u_min到u_max5. 压电陶瓷Preisach模型参数调优边界外推、擦除特性和验证轨迹5.1 边界外推权重只在辨识范围内有效Preisach模型没有外推能力。alpha和beta的范围一旦固定输入电压超出u_max时所有阈值都已经被翻过模型输出会停在饱和值上低于u_min时同理。这个现象在仿真中表现为预测曲线在极值附近变平但实际压电陶瓷可能还有非线性伸缩。因此辨识前必须测量驱动电压的真实上下限并在模型里留出 2% 到 5% 的余量。例如实际电压范围是 0 到 100V就把u_min设为 -2u_max设为 102。这样边界附近的算子也能被激活避免在两端出现权重空洞。5.2 擦除特性不要混用不同初始历史Preisach模型的核心是擦除特性当输入形成新的主导极值时旧的次级极值被遗忘。这带来了一个实际约束训练数据和预测数据的初始状态必须一致。用stairsh7w辨识时如果序列从 0V 开始那么预测轨迹开头也必须从 0V 开始或者先把从 0V 到当前电压的历史段补进模型。很多人在验证时直接给一段从 50V 开始的轨迹模型输出完全不对原因就在这里。5.3 最终验证用未参与辨识的轨迹检查泛化能力辨识误差低不代表模型能用。必须准备一段和训练序列形状不同的电压轨迹比如随机多频叠加正弦作为验证集。我常用的验证指标有两个峰值误差和 RMS 误差。RMS 误差反映整体逼近能力峰值误差反映最差位置控制精度。V_val v_lo (v_hi - v_lo) ... * (0.5 0.4 * sin(2*pi*1.3*(0:0.001:1.5)) ... 0.1 * sin(2*pi*7.7*(0:0.001:1.5))); y_val_true preisach_predict(model, V_val); noise 0.02 * randn(size(V_val)); y_val_meas y_val_true noise; y_val_pred preisach_predict(model, V_val); val_rms sqrt(mean((y_val_pred - y_val_meas).^2)); val_max max(abs(y_val_pred - y_val_meas)); fprintf(Validation RMS: %.4f\n, val_rms); fprintf(Validation Max: %.4f\n, val_max);验证用的电压序列最好覆盖到训练序列没有达到的小幅值范围。如果一味使用同一种阶梯波形辨识算法会把噪声也吸收进权重验证误差会明显高于训练误差。遇到这种情况优先减少pts_per_level对应分支上的采样重复次数或者把N从 64 降到 48降低模型自由度。最后一个实用技巧是正式辨识前先让压电陶瓷在最大电压下来回驱动几十次把材料内部的极化状态稳定下来再开始采集stairsh7w数据这样辨识出的权重更接近稳态迟滞环。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价