☰
三相PWM整流器直流母线电压环二阶离散自抗扰控制设计与Simulink实现
2026/10/24 4:41:36 网站建设 项目流程

做三相电压型PWM整流器这套系统时,最折磨我的环节就是直流母线电压环。负载一突加,母线电压“咣”地掉下去,PI调松了恢复太慢,调紧了又容易在启动和卸载时产生振荡,参数折衷折得人头皮发麻。后来我把电压外环改成非线性二阶离散自抗扰控制器(ADRC),并且坚持不用S函数,全部用Simulink模块搭出离散结构,配合内模控制的电流内环,整体抗扰动能力明显上了一个台阶。这篇文章就把这套方案从头到尾拆开讲,重点是如何用模块实现离散ADRC,电压环和电流环怎么配合,以及参数整定和调试时那些容易翻车的细节。适合正在做整流器、逆变器、并网变流器控制,或者刚接触ADRC想快速落地到仿真和样机的朋友。

1. 电压外环为什么难调:从PI困局到ADRC动机

1.1 直流母线电压对象的真实特性

三相电压型PWM整流器的直流侧,本质上是一个功率平衡节点。母线电容上的能量变化,等于交流侧输入的有功功率减去负载消耗的功率。在dq同步旋转坐标系下,忽略损耗后可以写成下面这种形式:

C * dUdc/dt = 1.5 * (edid + eqiq) / Udc - Udc/R

其中ed、eq是电网电压的d、q轴分量,id、iq是网侧电流的d、q轴分量,R是负载等效电阻。如果控制目标是单位功率因数,eq基本为零,这个方程还可以再简化。但不管怎么简化,有两点是绕不开的:

  • 这个系统自身是非线性的,因为方程里出现了电压乘电流、电压在分母上;
  • 负载等效电阻R是时变且不可预测的,你没办法提前知道负载什么时候会跳变。

把电流内环闭环之后,id对给定值id的跟踪可以近似成一阶惯性环节,时间常数就是电流环带宽的倒数。这样一来电压环被控对象从id到Udc就变成了一个带不确定参数和非线性耦合的二阶环节。传统PI在这里只能靠积分项慢慢消除稳态误差,面对突变负载时,积分器的滞后特性会让母线电压出现明显跌落和恢复拖尾。

1.2 ADRC给的是什么解题思路

ADRC的思路和PI完全不同。它不追求把对象模型建模得多精确,而是把“负载变化、参数偏差、建模误差、未建模动态”这些东西统一视为对系统的一个总扰动,用一个扩张状态观测器(ESO)把这个扰动实时估计出来,然后在控制量里反向补偿掉。

打个比方,PI像是驾驶员看到车速偏了就使劲踩油门,踩过头发动机咆哮,踩少了车速继续掉;ADRC则是车上装了一个能“预测路面坡度和风阻”的副驾驶,在上坡前就告诉你该给多少油。副驾驶本身不需要知道坡到底多大,他只需要通过观察车速偏差的变化,把这个“等效坡度”估算出来。

这个思路落到电压环上,控制动作就会变得非常直接:负载突然加重导致电压下跌,ESO立刻观察到一个持续性扰动存在,控制器不再依赖积分器慢慢“磨”,而是直接补一个前馈性质的补偿量,让id给定迅速提上去,母线电压跌落幅度小得多,恢复时间也短得多。

1.3 为什么选二阶离散ADRC

我见过不少文章把电压环当成一阶对象来做一阶ADRC,实际用起来效果也有,但超调相对大。原因在于整流器电压环背后还挂着一个电流内环,电流内环的闭环动态不可能无限快,它本身就给电压环引入了一个等效一阶惯性延迟。这个延迟和电容的积分特性,加起来让被控对象从输入到输出呈现出二阶特性。

所以我在这个项目里用的是二阶ADRC。它把电流环的延迟、电感参数偏差、负载波动都当成可观测扰动,由ESO统一估计。这样一来电压外环自己不需要去区分“这个扰动是负载带来的还是电流环带来的”,全部丢给扩张状态,控制律只负责没被补偿干净的那部分。

二阶ADRC的状态方程可以写成:

x1' = x2 x2' = f + b0 * u x3' = h

这里x1是母线电压Udc,x2是电压的变化率,x3就是扩张状态,即总扰动f。b0是对象增益的估计值,u是电压环输出的d轴电流给定。h是扰动变化率,按ADRC的假设它是有限的,不需要精确知道。控制器要做的事情就是构造一个三阶ESO,把x1、x2、x3都估计出来,然后用估计值做反馈和前馈补偿。

2. 离散ESO与非线性控制律的模块化拆解

2.1 离散化方式与递推式

既然标题强调“离散型”,那连续域的微分方程不能直接拿到Simulink里跑,必须转成差分递推式。离散化方法我推荐两种:前向欧拉和梯形法。

前向欧拉公式简单,嵌入式DSP和单片机里特别好移植,我这个项目为了后面把同一套代码搬到实物控制器上,最终用的就是前向欧拉。设采样周期为Ts,ESO的递推式如下:

e_eso = y(k) - z1(k) z1(k+1) = z1(k) + Ts * (z2(k) + β1 * e_eso) z2(k+1) = z2(k) + Ts * (z3(k) + β2 * e_eso + b0 * u(k)) z3(k+1) = z3(k) + Ts * β3 * e_eso

其中y(k)是当前采样到的母线电压Udc,u(k)是上一个控制周期算出的id*值。z1对应电压估计,z2对应电压变化率估计,z3对应总扰动估计。

这里有一个细节常见到让很多人翻车:ESO里拿来做反馈校正的是y(k) - z1(k),也就是“输出测量值 - 电压估计值”;而控制律里用的误差是“电压给定 - 状态估计值”,两个误差是完全不同的信号,连的时候一定别接错。

如果采样周期相对ESO带宽不算小,前向欧拉的离散误差会带来观测相位滞后。我实测下来,只要满足Ts小于1/(2ωo)左右,前向欧拉完全够用。梯形法精度更好,但模型里模块连线会复杂一些,后续移植到嵌入式代码时也不如欧拉直观,所以我没有采用。

2.2 fal函数:用MATLAB Function实现

ADRC的非线性控制律里,最核心的就是fal函数。它的定义分两段:

当|e| ≤ δ时,fal(e, α, δ) = e / δ^(1-α) 当|e| > δ时,fal(e, α, δ) = |e|^α * sign(e)

这个函数做的事情其实很朴素:误差小时用一个线性段,避免高频抖振;误差大时用幂函数段,让控制器“该狠时狠”。α越接近0,非线性越强,控制反应越快,但越容易抖;工程上α取0.5到0.75比较多,我做电压环用了两组参数,一组给比例项0.5,一组给微分项0.75。

Simulink里标准模块库没有现成的fal模块,S函数也不是必须的。我直接在模型里拖一个MATLAB Function块,把fal函数写进去:

function fx = fal(e, alpha, delta) ae = abs(e); if ae <= delta fx = e / (delta^(1 - alpha)); else fx = ae^alpha * sign(e); end end

注意这个函数会被同一个模型里多个地方调用,所以最好不要把它写成带副作用的脚本,而是定义成纯函数,输入输出就是误差、参数和结果。

还有一个数值层面的细节:如果delta设得太小,比如0.001,那么当e落在±δ区间时,1/delta^(1-α)会是一个非常大的数,相当于这一段的线性增益极大,很容易把采样噪声放大;如果delta设得太大,非线性特性又被抹平了。我的经验是,当Ts=100μs时,δ取0.05到0.2之间比较合适,后面调试微调。

2.3 ESO三通道的模块搭建

ESO如果完全用离散积分器加增益模块搭出来,连线会非常绕,而且容易产生代数环。原因在于z1、z2、z3三个状态彼此直接耦合,Simulink在求解这种代数环时很容易报错,或者算出来的结果和期望对不上。

所以我的做法是把整个ESO写进一个MATLAB Function块,输入是y、u和一组参数,输出是z1、z2、z3。虽然这样写出来也是代码,但从建模角度看它仍然是一个标准模块,比纯模块连线更“模块化”,也更方便后面生成代码。

function [z1, z2, z3] = eso_discrete(y, u, b0, beta1, beta2, beta3) persistent z1_prev z2_prev z3_prev if isempty(z1_prev) z1_prev = 0; z2_prev = 0; z3_prev = 0; end e_eso = y - z1_prev; z1 = z1_prev + Ts * (z2_prev + beta1 * e_eso); z2 = z2_prev + Ts * (z3_prev + beta2 * e_eso + b0 * u); z3 = z3_prev + Ts * (beta3 * e_eso); z1_prev = z1; z2_prev = z2; z3_prev = z3; end

这个代码块里的Ts在模型里是一个常数参数,可以在工作区定义,也可以做成模型参数对象。如果Ts变了但内部没有对应更新,ESO的估计会直接偏掉,这在调试的时候非常隐蔽,建议把Ts作为显式输入传进去,而不是写在函数内部。

β参数的取值按带宽法来:β1=3ωo,β2=3ωo²,β3=ωo³。ωo是观测器带宽,它决定了ESO跟踪真实状态的速度。注意这几个公式是连续域下的极点配置结果,离散化后仍然是很好的工程起点,不需要强行修正。

2.4 控制律通道与b0接线

控制律部分相对简单。设v是电压给定值,z1是电压估计,z2是电压变化率估计,z3是扰动估计,那么:

e1 = v - z1 e2 = 0 - z2 u0 = kp * fal(e1, 0.5, δ) + kd * fal(e2, 0.75, δ) u = (u0 - z3) / b0

这里e2我直接用“0 - z2”,因为电压给定在稳态时是常数,它的导数就是0。如果你做的是电压跟踪斜坡指令,那要给e2加上给定斜率项,不过整流器直流母线通常是定值控制,所以我按恒值来处理。

最后算出的u就是电压外环的输出,也就是d轴电流内环的给定id*。这里要特别注意b0的符号和量级,b0是整流器被控对象二阶输入增益的估计值。由于增大id会让母线电压上升,b0必须为正。如果调试中把b0符号搞反,ESO会立刻发散,z3会飞到一个离谱的值,控制量疯狂振荡。

b0的数值我不建议一上来就拍脑袋,而是通过一次简单的开环辨识实验来标定,具体方法放在第四章专门讲。

3. 与电流内环的时序配合和整体集成

3.1 电流环采用内模控制的理由

标题在“电流”后面断了,我补全一下自己用的方案:电流内环用的是内模控制(IMC),而不是传统PI加解耦。

三相电压型PWM整流器的电流环,在dq坐标系下存在交叉耦合项和电网电压前馈项。传统PI的做法是先把耦合项解耦,再对两个轴分别调PI。这种做法能用,但PI参数需要比较仔细地整定,而且电流环的动态特性和PI增益参数强耦合。内模控制的思路更直接:既然我们知道电感L和电阻R的大致数值,就可以把它们的模型信息直接写进控制器,让电流闭环的期望特性变成一个一阶惯性环节,时间常数由自己指定。

对一个一阶RL对象,内模控制器实际上可以化简成一个比例加积分再加上前馈的结构,比例系数和积分系数都直接由模型参数和目标闭环时间常数给定,不需要反复试凑:

Kp_imc = L / τi Ki_imc = R / τi

其中τi是期望电流环闭环时间常数。这个方法的工程好处是,调试时只需要改变τi一个参数,就能控制电流环的快慢,非常直观。

3.2 多速率采样的同步坑

电压外环和电流内环如果采样率不一致,离散ADRC很容易出现奇怪现象。常见的习惯是电压环用1kHz,电流环用10kHz,但这样至少有两个坑:

  • ESO的更新是1kHz,但u输出到电流环之前要经过零阶保持,相当于给控制通道又加了一个等效延迟;
  • 负载突变发生的时刻如果介于电压环两次采样之间,ESO要等到下一个采样点才能发现扰动,响应自然慢半拍。

我在这个项目里直接把两个环的采样率统一到10kHz,也就是和PWM开关频率一致。Simulink里建立一个离散求解器,采样步长设为1e-4s,所有离散模块和零阶保持器都在这个步长下更新。实测下来这样最省事,也最容易推到实物控制器上。

如果你确实想用多速率,那么电压环的采样周期最好设在电流环采样周期的整数倍,而且采样时刻要和电流环的更新对齐,不能在一个控制周期中段任意采。否则看起来都工作,实际上ESO会一直工作在错误的数据时间对齐上,调试时很难定位。

3.3 主电路参数与控制目标对照

为了让后面参数整定部分有据可依,我把这套系统的设计方案列在下面。这是一台5kW三相电压型PWM整流器,交流侧采用纯电感L滤波,直流侧为电容加阻性负载:

项目数值
额定功率5 kW
交流线电压380 V
交流侧电感L2 mH
直流母线电容C4700 μF
直流电压给定750 V
开关频率10 kHz
电流环闭环时间常数τi1 ms
电压环采样/控制频率10 kHz

在这个参数下,电流环闭环带宽大约是160Hz,电压环观测器带宽如果设得太高,比如4000rad/s以上,ESO就会疯狂放大采样噪声。后面调参的时候要反复记着这个约束。

整体模型的信号流可以这样梳理:电网三相电压进dq变换,电流采样进dq变换;电压外环输出id*,内模电流环比较id误差和iq误差,加上解耦前馈后生成U_d和U_q指令;U_d、U_q再进逆dq变换,生成三相调制波,进PWM发生器驱动桥臂。ADRC模块放在电压外环的位置,它的输入是Udc反馈和Udc给定,输出是id*。

4. 带宽整定、b0辨识与实物调试避坑

4.1 从电流环带宽倒推电压环ωc、ωo

ADRC的参数整定,最怕一上来就七个参数一起乱调。我的顺序是先定电流环,再定电压环,最后定ESO。

电流环内模控制的τi取1ms,得到电流环闭环带宽约160Hz。电压环的控制器带宽ωc应该明显低于电流环带宽,否则电压环会让电流环使唤不动。工程上一般取电流环带宽的1/5到1/10,我取的是ωc=100rad/s,差不多15Hz。这个看起来很低,但注意电压环的任务不是快,而是稳定和抗扰动,母线电容本身就是一个很大的惯性环节,不需要追求毫秒级电压响应。

控制器增益按二阶期望极点配置公式:

kp = ωc² kd = 2ωc

代入ωc=100,得到kp=10000,kd=200。这两个数看起来不小,但注意它们的单位不只是电压,还有前级fal函数的影响,仿真里要直接用,不要因为数字大就心惊胆战。

ESO带宽ωo取3到5倍的ωc,我最后用ωo=500rad/s左右。更好是试验几个值:把ωo从300往上加,观察z3波形的噪声水平和负载突变后的收敛速度,找一个“噪声可以被接受,收敛不太慢”的中间点。如果ωo超过8000rad/s,在这个采样率下基本没法看。

4.2 b0的实测校准方法

b0这个参数是ADRC里唯一和“模型”直接相关的量,也是最容易拍脑袋拍错的。我推荐一个简单的开环辨识流程:

第一步,断开电压外环,让电流内环单独工作,给一个固定的id常数。 第二步,在母线电压工作点附近,测量Udc的变化率dUdc/dt。 第三步,改变id,再测一次。两次的dUdc/dt之差除以id*之差,就是当前工作点下的二阶增益近似b0。

以一个简化估计为参考:在单位功率因数下,从功率平衡出发,Udc的二阶项增益大约正比于1.5ed/(CUdc)。代入ed峰值约310V、C=4700μF、Udc=750V,算出来数量级在几百左右。这个值会有偏差,但至少确定了正确的数量级和正负号。

b0比真实值偏大或偏小,系统都能工作,但不适合太大。偏大会让补偿过度,控制量出现高频抖动;偏小会让ESO输出的z3始终背着一个“常量扰动”工作,稳态上会有轻微的静差。动手调的时候,先在仿真里用±30%的偏差扫一圈,感受一下系统对b0的敏感性,这样心里有底。

4.3 四类典型故障的排查记录

调试期间我记录过几个很有代表性的问题,这里把现象、原因和处理方式列在一起,给你们参考。

问题一:启动瞬间母线电压冲到800V以上,然后慢慢回落。这个现象是典型的给定突变饱和。ADRC的抗饱和能力不如PI那么自然,参考值从0直接阶跃到750V时,e1巨大,fal函数输出巨大,控制量直接顶到限幅值,母线电容被过度充电。解决方法是把参考电压做成斜坡给定,比如设定150V/s的斜率。曲线太慢影响启动时间,太快又触发超调,我最终把斜坡时间定在2秒左右,效果比较稳。

问题二:轻载时母线电压波形出现明显纹波,放大之后看是两倍工频纹波叠加了高频抖动。ESO带宽太高或者δ太小的时候,采样噪声和纹波分量被观测器放大,z3会跟着抖动,控制量再把抖动传回电压。我先把ωo从800降到500,同时把δ从0.05提高到0.1,波形立刻干净很多。记住ESO不是越灵敏越好,它要的是“对真扰动敏感,对噪声迟钝”。

问题三:负载从空载突加到满载时,电压跌落比PI还大。这是最打击人自信的情况。后来逐段排查发现,电压外环输出的id*瞬间就被电流环的限幅值截断了,但ESO不知道限幅的存在,它仍然按未限幅的u来计算扰动补偿,于是越补越不对。解决方式是在限幅器前后做一个“限幅误差”信号,把这个误差也引入ESO的u输入,或者更简单一点,把ESO的输入u改成限幅前还是限幅后的选择,这里有多个可靠方案可取。

问题四:外环采样周期调成1kHz后,z3漂移。这个问题在第3.2节讲过,本质是零阶保持带来的延迟。最终我统一了采样周期,问题消失。

4.4 PI与ADRC的实测对比

我在这台5kW整流器样机上做了对比实验,控制器在同一个硬件平台上切换PI电压环和ADRC电压环,电流环保持不变。测试条件是:稳定带30%负载运行,然后突加负载到80%,观察直流母线电压的响应。

指标PI电压环ADRC电压环
电压跌落最大值42 V15 V
恢复到60%跌落的时间80 ms35 ms
恢复过程超调6 V2 V
稳态电压纹波峰峰值3.2 V2.8 V

这个结果不是PI不好,而是PI在“不振荡”和“抗冲击”之间必须折衷,ADRC则通过扩张状态补偿把这两件事解耦了。调PI可以调出媲美ADRC的抗冲击效果,但代价是临界振荡,在工程上几乎不可接受。

我个人在实际操作中的体会有两点。第一,离散ADRC用模块搭建并不比写S函数省太多事,但它的好处是每一块都能单独示波器观察,z1、z2、z3和最终控制量都能拉出来看曲线,调试时脑子非常清楚。第二,先把ESO单独调试好,确认z1能紧紧跟随实测Udc,z3在负载突变时能快速跳变到一个新值,再接上控制律。这一步走通,后面就不会陷入“到底是观测器问题还是控制律问题”的泥潭。

最后再分享一个小技巧:把ADRC这套参数整定完成后,Simulink里所有MATLAB Function块的代码都可以原样搬到一个嵌入式C文件里,只需要把persistent变量换成static变量,把Ts换成定时器中断周期。我后来在移植到DSP上的时候,几乎没有重新调试就跑起来了。如果你也在做整流器控制器,强烈建议先在仿真里把模块搭好,再用这套代码走一遍嵌入式移植,成功率会高很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询