news 2026/10/15 17:12:31

反馈线性化与Backstepping:非线性控制设计与Simulink仿真对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
反馈线性化与Backstepping:非线性控制设计与Simulink仿真对比

做非线性控制这些年,我见过太多人一上来就被Backstepping那一串递推公式劝退,又被反馈线性化里“相对阶”“零动态”这些名词绕晕。其实这两套方法,本质上都在回答同一个问题:线性系统里那套“配置极点、设计状态反馈”的思路,能不能搬到非线性系统上?答案是可以,但需要一些额外的功夫。这篇文章不扯太深的数学,就用一个具体的三阶非线性系统,把反馈线性化和Backstepping的设计流程完整走一遍,再用Simulink把两种控制律都跑起来做对比,代码逻辑我会拆开讲清楚,适合正在学《非线性控制理论》或准备做课程设计、面试相关岗位的读者。

先说清楚适用范围:如果你手头的系统能写成严格的反馈形式(后面会说),或者你能比较精确地写出模型中的非线性项,这篇文章的方法就能直接套。如果模型本身就一团黑,那这两个方法都不合适,得先去做系统辨识。本文所有内容我会尽量用大白话讲原理,同时保留必要的数学推导,保证你能照着实现。

1. 从线性到非线性,问题到底难在哪

1.1 线性控制器的“天花板”

先聊聊我最早接触非线性控制时的困惑。本科阶段学自动控制原理,天天跟传递函数、根轨迹、Bode图打交道,感觉一切都在频域里安排得明明白白。控制一个线性系统,几乎是有标准答案的:看性能指标,找闭环极点位置,设计控制器参数,完事。

但稍有工程经验的人就会碰到一个尴尬场景:把线性控制器放到真实对象上,工作点一变,效果就拉胯。举个最常见的例子,控制一个摆臂系统。在竖直位置附近线性化,模型就是个小阻尼的二阶系统,PID调得漂漂亮亮;可一旦摆臂大幅摆动,模型里的正弦项就不能再近似成线性项了,此时线性控制器要么响应迟钝,要么干脆失稳。

问题根子在于:线性化本质是在某个工作点附近做一阶泰勒近似,工作点一挪远,近似就不成立了。增益调度是一种工程上的补救办法,把工作区间切成多段,每段做一次线性化,再用LPV或切换逻辑串起来,但调度表的维护成本极高,而且切换瞬间的抖动也让人头疼。

于是在系统本身能写出精确非线性模型的情况下,更合理的思路是:别把非线性当成敌人去近似掉,而是直接在非线性层面设计控制律,用反馈把非线性补偿掉,或者利用非线性的结构逐步构造稳定化控制器。这就是反馈线性化和Backstepping登场的直接动机。

1.2 两大思路的定位关系

很多初学者会把反馈线性化和Backstepping当成两个互相竞争、二选一的方法,实际上它们更多是互补关系,甚至经常结合使用。

反馈线性化的核心哲学是“以非线性治非线性”:既然模型里有一项非线性动力学,我就在控制律里构造一个一模一样的非线性项把它抵消掉,剩下的系统就退化成一个线性积分器链,之后再舒服地配极点。

Backstepping的哲学则更“递推”:它把多阶系统拆成一串首尾相接的子系统,从最靠近输出的那个状态开始,把下一个状态当作虚拟控制量,逐步往回设计,每一步都构造一个Lyapunov函数保证当前误差子系统的稳定,最后得到真实控制律。

本文后面会用同一个系统分别施加这两种方法,对比它们的共同点和差异。你会发现,在很多标准严格反馈系统上,这两种方法得到的控制律最终长得很像,但推导路径和心理模型完全不同。

1.3 为什么选三阶严格反馈系统

为了演示方便,我选了一个三阶严格反馈系统:

x1_dot = x2

x2_dot = x3

x3_dot = sin(x1) + x2^2 + u

这里x = [x1, x2, x3]^T是系统状态,u是控制输入。第一个方程里x1的导数直接由x2决定,第二个方程里x2的导数由x3决定,第三个方程里x3的导数里既有非线性项又有输入u。这种“状态依次做导数、输入最后才出现”的结构,就是严格反馈形式,也叫下三角结构。

选择三阶而不是常见的二阶,原因很简单:二阶系统的Backstepping只递推一次,体现不出反推法的精髓;三阶系统需要设计两次虚拟控制,才能完整展示递推过程。而且这个系统里的sin(x1) + x2^2非线性项,恰好覆盖了状态之间相互耦合的典型情况,做仿真时能明显看到反馈线性化把非线性对消后的效果。

2. 反馈线性化:用反馈把非线性“吃掉”

2.1 核心思想与相对阶

反馈线性化并不神秘,它做的事情和传递函数里的零极点对消在思想上很像:与其让非线性项继续在我的闭环系统里添乱,不如在控制量里反着加一项,让它从我推导的动态方程中消失。

关键概念是先搞清楚“相对阶”。通俗理解,就是输出y要连续求导多少次,控制输入u才会显式出现在导数表达式中。本文系统取输出y = x1,则:

y_dot = x2

y_ddot = x3

y_dddot = sin(x1) + x2^2 + u

可以看到,求导到第三次时u才出现,所以相对阶是3。系统状态本身就是一条积分链,从y到y_ddot都不含u,这就是最理想的反馈线性化对象:没有内动态,不需要处理零动态稳定性问题。

相对阶这个概念的价值在于,它决定了系统能不能通过反馈精确线性化。如果有些状态在求导过程中始终没有进入u的通道,那些状态就构成了零动态或内动态,后面必须额外检查稳定性,否则整个设计是危险的。

2.2 非线性对消与线性极点配置

接下来就直观了。既然y_dddot的表达式中包含非线性项f(x) = sin(x1) + x2^2,我直接设:

u = -f(x) + v

代入原系统得:

x3_dot = v

整个闭环从外部看就是一条纯净的三重积分器链:y_dddot = v。此时v就是一个虚拟输入,可以随便用线性控制手段来收拾。

定义跟踪误差:

e1 = x1 - yd

e2 = x2 - yd_dot

e3 = x3 - yd_ddot

其中yd是期望轨迹。把v设计为:

v = yd_dddot - k1e1 - k2e2 - k3*e3

代入后得到误差动态:

e1_ddot = e3

e1_ddot = e3

e1_dddot = -k1e1 - k2e2 - k3*e3

即:

e1_dddot + k3e1_ddot + k2e1_dot + k1*e1 = 0

特征方程是s^3 + k3s^2 + k2s + k1 = 0。经典极点配置问题,让三个极点都落在s = -1,也就是(s+1)^3 = s^3 + 3s^2 + 3s + 1,得到k1 = 1, k2 = 3, k3 = 3。此时误差按指数收敛,无超调,调节时间约4秒。

这就是反馈线性化的完整流程:非线性对消,把系统拉回线性域,再配极点。整个推导不难,真正难的其实在建模和相对阶判断上。

2.3 别忘了前提:内动态与模型精度

前面说这个系统没有内动态,属于最幸运的情况。如果系统里有一个状态始终不在输入通道的求导链上,比如某些机械系统里位置和速度可测但弹性力动态不可控,那线性化后剩下的那一部分就是零动态。此时即使外部误差系统收敛得再漂亮,内部状态也可能悄悄发散,最终表现为整个系统失控。所以做反馈线性化时,算完控制律必须回头验证零动态稳定性。

另一个容易被忽略的问题是模型精度。反馈线性化对模型中的f(x)有极强的依赖,控制律里用到的f(x)必须和真实对象完全一致,一旦模型有偏差,补偿就不完全,残留的非线性会直接影响误差动态。这也是它在工程实践中常常被吐槽“太理想化”的原因。后面仿真对比时会专门体现这一点。

3. Backstepping:反推法的递推设计过程

3.1 一个画面:虚拟控制在“诱敌深入”

Backstepping的设计思路,我习惯用一句不太严谨但好理解的话概括:既然真实控制量u在最外层,我一时够不到,那就先把每个状态前一个状态当作“假的控制器”来设计,让系统一层层稳定下去。

本系统里,第一个方程x1_dot = x2,如果x2是我可以随便指定的虚拟输入,那我希望x1怎么走?当然希望误差z1 = x1 - yd按指数收敛。于是先设计:

alpha1 = -c1*z1 + yd_dot

这个alpha1就是第一步想要的“x2参考值”。因为x2不可能瞬间跳到alpha1,实际存在偏差z2 = x2 - alpha1,那么继续把x3当虚拟输入,设计alpha2让z2变小,最后真实输入u要来让z3变小。整个过程就像从输出端一步步往回“递推”,所以叫Backstepping。

3.2 从误差系统推导虚拟控制

下面直接上完整数学推导,这是全文的核心干货,建议跟着笔算一遍。

定义误差:

z1 = x1 - yd

设计虚拟控制:

alpha1 = -c1*z1 + yd_dot

注意这里第一步因为x1_dot中不包含f(x),所以虚拟控制里不需要加模型项。接着定义:

z2 = x2 - alpha1

则第一个误差子系统:

z1_dot = x2 - yd_dot = z2 + alpha1 - yd_dot = z2 - c1*z1

这里有一项z2来自尚未稳定的下一个误差,符合预期。继续设计alpha2,目标是让z2快速收敛:

alpha2 = -z1 - c2*z2 + alpha1_dot

注意第一步Lyapunov函数V1 = 0.5z1^2求导后会出现z1z2项,所以alpha2里要带回一个-z1,这就是递推过程中消除交叉耦合项的关键。alpha1_dot的计算是Backstepping最容易出错的地方,后面专门讲。

再定义z3 = x3 - alpha2,那么z2_dot = x3 - alpha1_dot = z3 + alpha2 - alpha1_dot = z3 - z1 - c2*z2。

最后设计真实控制律,让z3_dot = x3_dot - alpha2_dot = f(x) + u - alpha2_dot = -z2 - c3*z3,于是:

u = -f(x) - z2 - c3*z3 + alpha2_dot

整个闭环误差系统:

z1_dot = -c1*z1 + z2

z2_dot = -z1 - c2*z2 + z3

z3_dot = -z2 - c3*z3

写成矩阵形式会发现这是一个反对称结构加对角阻尼项,构造全局Lyapunov函数V = 0.5*(z1^2 + z2^2 + z3^2),求导得到:

V_dot = -c1z1^2 - c2z2^2 - c3*z3^2 < 0

也就是说,只要c1、c2、c3都大于零,全局渐进稳定。这就是Backstepping最漂亮的部分:整个过程没有依赖消去非线性后的线性系统,而是直接给出了一个Lyapunov函数,稳定性证明和控制设计是一体的。

现在把alpha1_dot拆开算清楚:

alpha1_dot = -c1x2 + c1yd_dot + yd_ddot

alpha2_dot = -z1_dot - c2*z2_dot + alpha1_ddot

其中z2_dot = x3 - alpha1_dot,alpha1_ddot = -c1x3 + c1yd_ddot + yd_dddot。逐项代入就能得到alpha2_dot的解析表达式。很多人在这一步漏项,建议全程用符号推导软件辅助验证。

3.3 与反馈线性化的对比

看到这里你会发现,本文例子里Backstepping的最终控制律和反馈线性化其实高度相似,都包含一个非线性对消项-f(x)和一个线性阻尼项,差别在于Backstepping的误差系统是一个递推结构,而不是直接配成特征多项式。为了让你在选型时有清晰判断,我列一张对比表:

对比项反馈线性化Backstepping
适用结构相对阶明确、可精确线性化严格反馈/下三角结构
设计思路非线性对消+线性极点配置递推虚拟控制+构造Lyapunov函数
对内动态必须额外检查零动态稳定标准严格反馈下无内动态问题
模型精度依赖强烈依赖精确f(x)同样依赖f(x),但误差项可逐步吸收
调参方式极点位置直观,一次到位c1、c2、c3分别影响流形收敛速度
排序思考难度相对阶判断有时困难符号导数容易出错
扩展能力自适应/鲁棒结合较绕容易扩展自适应和鲁棒项

一句话总结我的经验:如果你的问题能干净地建模、相对阶也清楚,反馈线性化更直接;如果系统是长链结构、还带有参数不确定性,Backstepping往往更容易扩展。

4. Simulink仿真实现与结果对比

4.1 Simulink模型总体架构

理论推导再漂亮,不上Simulink跑一遍,心里总是不踏实。这次仿真的目标只有一个:把上面两套控制律都用起来,在一个三阶非线性对象上跟踪正弦参考信号,看谁跟踪更准、控制量更合理。

模型结构不复杂,由四部分组成:

  • 被控对象:三个积分器串联,最后一个积分器前加入非线性项sin(x1) + x2^2和输入u
  • 控制器:MATLAB Function模块,分别实现ctrl_ff和ctrl_bs两种逻辑
  • 参考信号:由Clock模块生成时间t,再用Fcn模块计算yd及其一阶、二阶、三阶导数
  • 数据记录:To Workspace模块保存时间、状态、控制量,方便后处理画图

参考信号我取yd = 0.5sin(0.5t),这个信号幅值适中、变化不剧烈,适合观察跟踪效果。它的导数是手写解析式,不建议在Simulink里直接用Derivative模块做数值微分,否则噪声会污染控制器输出。

被控对象的搭建顺序建议这样:放三个Integrator模块,第一个输出x1、第二个输出x2、第三个输出x3;用Fcn模块算f(x) = sin(u(1)) + u(2)^2,加到第三个积分器输入端;控制器算出的u也加到这个输入端。注意这里需要把x1、x2、x3同时反馈给控制器模块,所以也得把积分器输出接到MATLAB Function的输入口。

初始条件方面,我设置x1(0)=0.2,x2(0)=0,x3(0) = 0,目的就是让系统一开始就有一个可见的跟踪误差,方便观察收敛过程。如果全设零,参考信号也从零开始,画面会平淡很多。

4.2 控制器代码实现

MATLAB Function模块里直接写函数就行。先看反馈线性化控制器:

function u = ctrl_ff(x1, x2, x3, yd, dyd, ddyd, dddyd) % 反馈线性化控制器,期望闭环极点均位于 -1 f = sin(x1) + x2^2; % 注意这里必须与对象模型一致 e1 = x1 - yd; e2 = x2 - dyd; e3 = x3 - ddyd; k1 = 1; k2 = 3; k3 = 3; % (s+1)^3 展开系数 v = dddyd - k1*e1 - k2*e2 - k3*e3; u = -f + v; % 先对消非线性,再线性反馈 end

这段代码逻辑非常短,就是上一节推导的直接翻译。唯一要求是f这一行必须跟被控对象一模一样,模型稍有偏差,控制效果立刻变差。

再看Backstepping控制器:

function u = ctrl_bs(x1, x2, x3, yd, dyd, ddyd, dddyd) % Backstepping 控制器,严格反馈系统 c1 = 2; c2 = 2; c3 = 2; % 三阶误差通道的阻尼系数 f = sin(x1) + x2^2; z1 = x1 - yd; alpha1 = -c1*z1 + dyd; % 第一步虚拟控制 z2 = x2 - alpha1; dalpha1 = -c1*(x2 - dyd) + ddyd; % alpha1 对时间的导数 alpha2 = -z1 - c2*z2 + dalpha1; % 第二步虚拟控制 z3 = x3 - alpha2; % 计算 alpha2 的导数 z1_dot = x2 - dyd; z2_dot = x3 - dalpha1; ddalpha1 = -c1*(x3 - ddyd) + dddyd; dalpha2 = -z1_dot - c2*z2_dot + ddalpha1; % 注意这里没有漏项 u = -f - z2 - c3*z3 + dalpha2; % 最终控制律 end

注意区别:反馈线性化是一步到位把非线性对消掉,Backstepping则是把对消项分散在每一步的递推里,最后的控制律也多了一堆alpha的导数项。这些导数项其实就是我在3.2节花力气推导的东西,代码里的每个变量名都对应推导中的一项,调试时对着公式查特别方便。

还有一个细节:MATLAB Function模块的输入端口顺序和你传参顺序要一一对应,踩过不少次坑,建议信号线的标签名字跟函数参数名保持一致。

4.3 仿真参数与被控对象实现

对象搭建时注意不要直接用一个S函数写全套,用基础模块搭更有教学感。具体做法是:

  • 第三个积分器输入端接一个Sum模块,两个输入分别是u和f(x)
  • f(x)用Fcn模块,表达式写 sin(u(1)) + u(2)^2,其中u(1)接x1、u(2)接x2
  • 三个积分器依次串联:第一个积分器输入是x2,输出x1;第二个输入x3,输出x2;第三个输入是u+f,输出x3

这里的初始条件在Integrator模块的Initial condition里分别填[0.2; 0; 0]。

参考信号生成部分,用Clock模块接四个Fcn模块,分别写:

  • 0.5sin(0.5u)
  • 0.25cos(0.5u)
  • -0.125sin(0.5u)
  • -0.0625cos(0.5u)

注意四个表达式的次序分别是yd、dyd、ddyd、dddyd。u就是Clock输出的t。如果用MATLAB Function生成这四个量也可以,但Fcn模块更直观。

求解器设置上,我用定步长ode4,步长0.001秒,仿真时间20秒。系统本身是光滑的非线性系统,步长0.001足够稳定。如果你用变步长ode45也问题不大,但做对比实验时建议统一定步长,保证控制量曲线的可比性。

为了对比控制器对模型失配的鲁棒性,我还额外做一个变体:把对象里的sin(x1)改成0.9*sin(x1),但控制器里仍然写sin(x1),模拟“模型误差”场景。这个对比很值得跑一下,能直观理解反馈线性化为什么怕模型失配。

4.4 结果观察与对比分析

理想模型下,反馈线性化和Backstepping都能让跟踪误差在几秒内收敛到很小。仔细看还是能看出区别:反馈线性化的误差收敛曲线接近线性系统的指数衰减,没有明显过冲;Backstepping的收敛形态则更像三条误差通道依次建立,z1先被约束住,z2紧随其后,最后z3才稳定,整体过渡更平滑。

控制量方面,反馈线性化在初始阶段会输出一个较大的正向控制脉冲,因为它需要一次性补偿掉初始误差对应的全部加速度项;Backstepping由于c1、c2、c3分级作用,控制量峰值会温和一些,但调节时间会稍微拉长。如果你把c1、c2、c3全部调大,Backstepping的控制量峰值也会抬升,性能和控制量之间的权衡在这个例子里体现得很清楚。

最值得关注的是模型失配场景。把对象中的sin(x1)系数改成0.9后,反馈线性化因为对消项不精确,闭环误差动态里会残留0.1*sin(x1)的扰动,表现为周期性跟踪误差,误差波形和参考信号同频。Backstepping在同样的失配下,底部误差也会被激发,但因为递推结构里每一层都带阻尼项,扰动在递推中被进一步衰减,肉眼看上去误差要小一些。这并不是说Backstepping更鲁棒,而是它的阻尼结构意外地提供了更多余度。真要在工程里用,还是得配自适应机制或扰动观测器。

5. 常见问题与调试经验

5.1 模型一跑就发散,先查这几处

仿真发散是初学非线性控制最高频的翻车现场,而且绝大多数时候不是控制器原理错,而是下面几个细节:

  • 符号导数算错。Backstepping的alpha2_dot推导一旦漏项,控制律里就存在一个不小的符号错误,误差会以振荡形式放大。强烈建议用符号计算工具把alpha1_dot、alpha2_dot展开后再抄进代码。
  • 步长太大。非线性系统的闭环可能比线性系统更“硬”,步长0.01秒有时就是稳定的临界点。直接用0.001秒起步,等模型没问题了再尝试放大步长。
  • 代数环报警。MATLAB Function模块输入端如果又接回自身输出,Simulink会提示代数环。遇到时往信号路径上插一个Memory模块或Unit Delay打破环路,治标也治本的是检查信号连接是否接错了。

5.2 控制量峰值太高,怎么压下来

一上来就用大增益,初始误差又大,控制量很容易冲到几十上百,看起来吓人。调试习惯上我建议从“低增益+小初始误差”开始,先把逻辑跑通,再逐渐加增益逼近期望性能。

对于参考信号,如果目标轨迹加速度跳跃太猛,也会在控制端激起尖峰。一个实际技巧是在目标轨迹生成后加一个平滑滤波器,或者在规划轨迹时直接约束二阶导数的幅值。控制量峰值和跟踪精度本质上是矛盾的,工程上必须做取舍。

还有一个小技巧:初始误差的符号和控制量的方向会导致第一个瞬间的峰值。比如x1(0)=0.2而yd(0)=0.5,控制量会在开头抢误差,如果对象模型里还有sin项,峰值会更明显。可以做参考信号“软启动”,让yd从当前状态附近开始变化。

5.3 跟踪误差一直消不掉

如果误差不是不收敛,而是收敛完还有周期性波动,第一个怀疑对象是模型补偿项f(x)和对象不一致。把对象的非线性项抄到控制器时,少个系数、多个平方,都会留下周期性残差。解决办法是把对象里的f(x)和控制器里的f(x)全部抽成同一个参数变量,例如f_nom,改模型时只改一处,减少人为不一致。

另一个可能原因是执行器饱和。Simulink里如果不加饱和,计算出的u再大也会被当作真实输入代入对象,一旦你实际用的是带饱和的执行器,一定要在u进对象前加Saturation模块,并考虑抗饱和措施,否则误差和积分项会互相打架。

如果误差表现为缓慢漂移,那往往是没有积分作用。反馈线性化配极点时没有自动引入积分,模型低频失配就会形成常值偏差。可以在误差通道上加入积分项,例如把v的表达式改成带e1积分的形式,代价是系统阶数加一,相位滞后会让相位裕度下降,需要重新调极点。

5.4 两种方法到底该选谁

最后聊聊我自己在实际项目里的选型习惯。如果系统的状态方程能写成标准严格反馈形式,而且模型参数相对可信,我更倾向Backstepping,因为每一步都有明确的Lyapunov函数兜底,往里面加自适应、加鲁棒项都顺手,调试时每层误差的收敛情况也容易观察。

如果系统的相对阶结构更复杂,或者你希望用极点位置直接控制过渡过程波形,反馈线性化更清晰。它的最大问题在于“对消”两个字本身:对消的前提是模型绝对精确,噪声环境下这个前提往往不成立。因此真做工程时,我通常会在反馈线性化外面再包一层鲁棒项,或者用扩张状态观测器在线估计那部分对消残差。

有一说一,这两个方法都不是“万能药”。系统不确定性大、建模困难时,滑模控制、自适应控制、模型预测控制往往表现更好。但把本文这两个方法彻底学透,你会建立一套“如何利用模型结构设计控制律”的直觉,这比套各种高级方法模板重要得多。

我个人实际调试中的体会是,Backstepping代码写完第一件事永远是验证alpha的导数,别嫌麻烦。把中间量z1_dot、alpha1_dot、alpha2_dot全部用To Workspace导出,跟手推公式逐项对,能省下大量比眼睛瞪代码的时间。反馈线性化则一定要先检查相对阶算对没有,相对阶错了,后面全白做。最后一个小技巧:把参考信号各阶导数作为独立输入送给控制器,永远不要在控制器内部做数值微分,这是让控制量不发抖的第一原则。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 17:12:12

非线性控制实战:反馈线性化与Backstepping原理及Simulink仿真对比

做控制工程的这两年&#xff0c;我最大的感受是&#xff1a;教科书上干干净净的线性假设&#xff0c;到了现场往往第一个顶不住。摩擦死区、伺服阀流量非线性、气动执行机构的饱和&#xff0c;任何一个环节的非线性都能让精心调好的线性控制器在工况切换时突然“失忆”。所以当…

作者头像 李华
网站建设 2026/10/15 17:12:11

制造业项目管理软件有哪些?从BOM到生产计划全覆盖

多品种、小批量、变更频繁&#xff0c;是当前制造企业研发与生产协同最典型的痛点&#xff1a;设计变更传导不到产线&#xff0c;生产计划反复调整。 围绕从BOM到生产计划这条主线&#xff0c;本文整理制造业常用的八款项目管理软件&#xff0c;按研发管理与产品数据、生产计划…

作者头像 李华
网站建设 2026/10/15 17:11:34

分数阶滑模控制算法:从抖振抑制到Simulink实现的工程实战

简介&#xff1a;分数阶滑模控制算法的MATLAB/Simulink实现资料包&#xff0c;面向控制工程、自动化及相关专业的学生与研究人员&#xff0c;解决非线性、时变及不确定性系统的鲁棒控制建模与仿真问题。包内共24个文件&#xff0c;包括12个.m脚本&#xff08;实现控制律、轨迹规…

作者头像 李华