并网逆变器的控制回路里,锁相环(PLL)就是那个“报角度”的眼睛。做过新能源并机、APF或者微电网项目的人应该都有体会:电网电压稍微有点不平衡、有点谐波,普通的SRF-PLL角度就开始抖,电流波形跟着变形,严重时直接触发过流保护。DSOGI-PLL(双二阶广义积分器锁相环)就是解决这个问题的经典方案,它能把不对称、带畸变的电网电压先分解出正序分量再锁相,工程上非常实用。这篇博文就从原理讲起,带你在Simulink里一步步把模型搭起来,参数怎么算、模块怎么连、仿真怎么验证、调试踩过哪些坑,全部写清楚,代码包的结构也一并说明。
我自己做并网逆变器控制时,最早用的就是SRF-PLL,后来在一次电网模拟器测试中遇到单相电压跌落,锁相角度直接抖了十几度,从那以后DSOGI-PLL就成了我模型里的常驻模块。这篇文章适合正在做三相并网逆变器、PWM整流器、或者刚接触电网同步技术的人,你不需要有很深的理论基础,只要会用Simulink基本模块,跟着搭就能跑通。
1. 为什么并网控制离不开PLL?——从SRF-PLL的局限说起
1.1 锁相环在并网系统里的真实作用
并网逆变器要想把能量送进电网,核心要求是输出电流和电网电压保持同频同相,也就是功率因数接近1。但电网电压的相位不是静止的,频率会波动、相位会突变、幅值会跌落,逆变器必须实时知道当前电网电压的相位角,才能控制桥臂输出电压矢量。这个“实时报相位”的工作就是锁相环干的。
很多人把PLL简单地理解成一个“测频率”的工具,其实它是闭环控制:把估计出来的角度送去做Park变换,然后调节角频率让q轴电压强制为0,稳态时角度就锁定在电网电压的相位上。这个过程本质上是一个非线性跟踪系统,设计得好不好直接决定了并网电流的质量和系统的稳定性。
1.2 SRF-PLL的理想与尴尬
传统SRF-PLL(同步旋转坐标系锁相环)结构很简单:三相电压先做Clark变换得到αβ分量,再根据PLL输出的角度做Park变换得到dq分量,把vq送给PI调节器,PI输出作为角频率偏差叠加到额定角频率上,最后积分得到角度。
在三相平衡、电压无谐波的理想工况下,SRF-PLL表现非常好,动态快、实现简单,这也是它至今仍是工业主流的原因。但实际电网哪有那么乖?当发生单相接地故障或者大负载投切时,电压会出现负序分量。负序分量在Park坐标系下表现为2倍频纹波,PI调节器压不掉这个纹波,锁相角度就会跟着波动,最终反映到电流指令上就是谐波和冲击。
你可能想,把PI带宽压低一点,让环路把2倍频滤掉不就行了?问题在于PLL带宽降低,动态响应变慢,电网频率突变时锁相环半天跟不上,反而更容易失稳。这就是SRF-PLL的根本矛盾:滤波性能和动态性能互相打架。DSOGI-PLL的思路不是去“压”2倍频,而是从源头上把负序分量直接分离掉,锁相环只盯着正序分量看,问题自然就解决了。
1.3 为什么选择DSOGI而不是其他锁相方案
现在工程上可选的正序锁相方案有好几种:解耦双同步坐标系锁相环(DDSRF-PLL)、基于陷波器的PLL、基于延迟信号消除的PLL等等。DDSRF-PLL通过两个旋转坐标系解耦负序,性能也不错,但参数调起来更繁琐;陷波器方案设计简单,但陷波频率偏离真实频率时就失效。DSOGI-PLL最大的优势是把“频率自适应”和“滤波”结合在SOGI结构里,既能提取正序,又能通过二阶广义积分器的带通特性抑制谐波,配合FLL甚至能在频率偏移时无静差跟踪,工程实现上模块化程度高,特别适合Simulink搭模型和后续代码生成。
2. DSOGI-PLL原理逐层拆解:从数学到框图
2.1 单个SOGI-QSG:滤波器和正交信号发生器两件事一起干
SOGI的全称是Second Order Generalized Integrator,二阶广义积分器。它接收一个输入信号,输出两个信号:一个与输入同相的分量,一个与输入正交的分量。以α轴电压vα为例,SOGI-QSG的传递函数写成这样:
D(s) = vα' / vα = k·ω0·s / (s² + k·ω0·s + ω0²)
Q(s) = qvα / vα = k·ω0² / (s² + k·ω0·s + ω0²)
其中D输出是同相分量,Q输出是滞后90度的正交分量,k是阻尼因子,ω0是SOGI的中心角频率。从传递函数形式能看出来,D(s)是一个带通滤波器,在中心频率ω0处幅值增益为1、相位为0;Q(s)是一个低通滤波器,在ω0处幅值增益为1、相位滞后90度。这两个滤波器配合在一起,就能在电网电压畸变的情况下,把基波分量提出来,并生成正交信号。
这里k的取值很关键。把D(s)的分母写成标准二阶系统形式s² + 2ξω0s + ω0²,就能看出阻尼比ξ = k/2。工程上最常用的取法是k = √2,对应的ξ = 0.707,也就是临界阻尼状态,滤波效果和响应速度比较均衡。k越大,SOGI带宽越宽,动态响应快但滤波能力弱;k越小,滤波能力强但动态慢,而且对频率偏移更敏感。我在实际调试中一般先用√2,如果谐波抑制还不够,再往小调到1.5左右,但很少低于1.2,否则频率阶跃时锁相环会明显拖沓。
2.2 正序分量计算:利用正交信号做对称分量分离
三相不平衡电压经过Clark变换后,αβ坐标系里同时包含正序和负序分量。正序负序在αβ坐标系里的区别在于旋转方向不同:正序旋转方向是α→β,负序旋转方向是β→α。利用SOGI生成的正交信号,可以通过下面的公式提取出正序分量:
vα+ = 0.5 · (vα' - qvβ)
vβ+ = 0.5 · (qvα + vβ')
这里的vα'是α轴SOGI的同相输出,vβ'是β轴SOGI的同相输出,qvα是α轴SOGI的正交输出,qvβ是β轴SOGI的正交输出。为什么能剔除负序?因为负序分量在αβ里表现为β分量超前α分量90度,而正交信号恰好把这个超前关系反转,做加减之后负序就被抵消了。
这个公式很多资料里直接给出,但新手容易抄错符号。负号位置、加减顺序都影响最终结果,一旦弄反,负序会变成正序叠加在信号上,锁相环反而更糟糕。我的建议是搭完模型后先做一次不平衡电压仿真,把正序分量和理论值对一下,确认无误再往下接PLL。
2.3 从正序αβ到锁相角度:经典SRF-PLL闭环
拿到正序αβ分量后,后面的结构和SRF-PLL完全一样:Park变换、PI调节器、积分器。控制目标是让q轴电压分量为0,PI调节器输出的是角频率修正量,叠加到额定角频率ω0上,再积分就得到角度θ。
这个闭环系统在忽略耦合的情况下可以化简成一个二阶系统:
θ_out(s) / θ_in(s) = (kp·s + ki) / (s² + kp·s + ki)
其中kp、ki分别是PI调节器的比例和积分系数。从特征方程s² + kp·s + ki可以看出,这正是标准的二阶系统形式,因此可以用带宽和阻尼比来设计PI参数,这是后面参数整定的基础。DSOGI-PLL整体结构简单说就是“前置滤波+正序分离+传统锁相”三件套,每一级各干各的活,逻辑非常清晰。
3. Simulink建模前的准备:参数计算与文件清单
3.1 参数计算:SOGI与PLL的关键数值从哪里来
在打开Simulink之前,先把参数算清楚。SOGI部分需要两个参数:k = √2,ω0 = 2π·50 = 314.159 rad/s。如果仿真中要模拟电网频率偏移,可以把SOGI的ω0做成一个外部输入,这就是后面DSOGI-FLL的内容,本文的模型先用固定50Hz,这样更容易理解。
PLL部分需要设计PI参数。按带宽ωn = 2π·20 rad/s,阻尼比ζ = 0.707来设计:
kp = 2·ζ·ωn = 2·0.707·125.66 ≈ 177.7
ki = ωn² = 125.66² ≈ 15791
我把这些参数整理成一张表,方便对照:
| 参数 | 数值 | 说明 |
|---|---|---|
| k | √2 ≈ 1.414 | SOGI阻尼因子,对应阻尼比0.707 |
| f0 | 50 Hz | 电网基波频率 |
| ω0 | 314.159 rad/s | SOGI中心角频率 = 2πf0 |
| ωn | 125.66 rad/s | PLL环路带宽 = 2π×20 |
| ζ | 0.707 | PLL阻尼比 |
| kp | 177.7 | PLL比例系数 |
| ki | 15791 | PLL积分系数 |
有一个细节值得提醒:这里的PI参数是直接对vq(单位V)作用输出的角频率修正量(单位rad/s)。如果电压幅值不同,或者在模型里做了标幺化处理,PI参数要相应调整。实际工程中我一般会把vq除以额定电压幅值做标幺化,这样PI参数在不同电压等级的系统中可以复用,不容易踩坑。
3.2 代码包结构:下载之后怎么开始用
按照标题的承诺,这里把配套代码包的文件结构列清楚。下载解压之后应该有这几个文件:
- DSOGI_PLL_params.m:参数初始化脚本,所有参数都在这里定义,运行一次即可
- DSOGI_PLL_demo.slx:完整的Simulink模型,包含DSOGI-QSG、正序计算、SRF-PLL三部分
- SOGI_sfunction_demo.m:SOGI环节的S-Function参考实现,方便后续嵌入到DSP或生成代码
- DSOGI_PLL_analysis.m:仿真结果绘图脚本,可以快速对比三相电压、正序分量和锁相角度
使用步骤很简单:先打开DSOGI_PLL_params.m运行一遍,参数加载到工作区,再打开DSOGI_PLL_demo.slx,直接点仿真就能看到波形。如果不先运行参数脚本,模型会报错,因为Gain模块里的变量k、w0、kp这些都是来自工作区的变量。我把初始化的核心代码贴出来:
%% DSOGI-PLL 参数初始化 clc; clear; close all; % 电网参数 f0 = 50; % 额定频率 Hz w0 = 2*pi*f0; % 额定角频率 rad/s % SOGI参数 k_sogi = sqrt(2); % SOGI阻尼因子 % PLL参数 wn_pll = 2*pi*20; % 锁相环带宽 rad/s zeta_pll = 0.707; % 阻尼比 kp_pll = 2*zeta_pll*wn_pll; % 比例系数 ki_pll = wn_pll^2; % 积分系数 % 仿真时间 T_sim = 0.2; % 仿真时长 s3.3 连续模型和离散模型的选择建议
很多人在Simulink里搭模型时,直接用连续模块搭完了事,但实际嵌入式实现时模型必须是离散的,这就涉及连续模型到离散模型的转换问题。对于学习阶段,先用连续模型跑通逻辑,用变步长求解器ode45,理解原理最重要;等到了要出代码或者做硬件在环仿真时,再用手动方式做离散化,采样频率一般选10kHz到20kHz。
如果一开始就打算做离散仿真,SOGI的传递函数需要先离散化。以10kHz采样频率、Tustin双线性变换为例,离散化后的SOGI传递函数系数可以提前用MATLAB的c2d函数算出来,然后在Simulink里用Discrete Transfer Fcn模块实现。这样做的优点是仿真速度更快,更接近实际代码行为;缺点是需要理解采样和离散化带来的相位误差。我个人的建议是:先搭连续模型把问题研究清楚,再转离散,不要一上来就两头抓。
4. 手把手Simulink建模:逐步搭建DSOGI-QSG与正序分离
4.1 第一步:建立三相电压源与Clark变换
打开Simulink,新建一个空白模型,先把模型的名字存成DSOGI_PLL_demo,避免后面占用中文字符导致的问题。三相电压源我用Simulink自带的Three-Phase Programmable Voltage Source最省事,它能设置不平衡、谐波和频率变化,非常贴合锁相环测试场景。
放好电源模块后,接一个Three-Phase V-I Measurement模块测量电压,然后要把三相电压从abc坐标变换到αβ静止坐标。Clark变换公式是:
vα = (2/3)·(va - 0.5·vb - 0.5·vc)
vβ = (2/3)·(√3/2·vb - √3/2·vc)
在Simulink里可以直接用Fcn模块或者Gain加Sum模块实现。Fcn模块最简单,直接在表达式里写公式就行,但要注意每相电压的单位是V,表达式里用的变量名要和上游信号一致。我习惯用Gain和Sum模块搭,这样以后改成DSP代码时更容易对应到矩阵运算。搭完Clark变换后,建议先接一个Scope看一眼vα和vβ波形,确认是幅值正确的正弦波再往下走。
4.2 第二步:SOGI-QSG模块的两种搭建方法
SOGI-QSG是整个模型中最重要的环节,搭法比较多,我推荐两种。方法一是直接用Transfer Fcn模块拖两个传递函数,D输出和Q输出各一个,分子分母填好系数,优点是搭建速度快、不容易出错,适合快速验证。D(s)的分子填[k_sogiw0, 0],分母填[1, k_sogiw0, w0^2];Q(s)的分子填[0, k_sogi*w0^2],分母相同。
方法二是用积分器搭SOGI的状态方程实现,这个方式更接近控制理论里的状态空间描述,也方便理解SOGI的内部结构。关联积分器的方式是:第一个积分器输出x1,第二个积分器输出x2,x2同时作为D输出;反馈回路上,x1乘以-w0²、x2乘以-k_w0、输入u乘以k_w0,三者相加后作为第二个积分器的输入。逻辑是:
dx1/dt = x2
dx2/dt = -ω0²·x1 - k·ω0·x2 + k·ω0·u
D输出 = x2
Q输出 = ω0·x1
两种方法本质上完全等价,区别只在于可读性和后续可维护性。第一次学习我建议用积分器搭一遍,把SOGI的内部动态看清楚;如果只是赶项目,直接用Transfer Fcn就行。
4.3 第三步:搭建DSOGI和正序分量计算模块
DSOGI就是把两个SOGI-QSG分别接在vα和vβ上,α轴的D输出叫vα',Q输出叫qvα,β轴的D输出叫vβ',Q输出叫qvβ。搭完之后用Goto和From模块整理信号线,把四个信号引到一块,正序分量计算公式需要这四个信号同时参与。
正序分量计算用Fcn模块最直观,新建一个Fcn模块,输入是一个四维向量,我定义u(1) = vα',u(2) = qvα,u(3) = vβ',u(4) = qvβ,表达式写成:
vα+ = 0.5 * (u(1) - u(4))
vβ+ = 0.5 * (u(2) + u(3))
这里特别要提醒,u(4)是β轴的正交输出qvβ,符号是负号;u(2)是α轴的正交输出qvα,符号是正号。我见过好几次有人把这两个符号搞反,锁相结果会出问题。保险起见,搭完这两行Fcn后接一个Scope,把不平衡电压输入下得到的vα+和vβ+跟理论值对比一下,确认正序分量没有明显2倍频成分,再继续。
4.4 第四步:搭建SRF-PLL闭环,重点是角度取模
得到正序αβ分量后,剩下就是把经典的SRF-PLL接上。Park变换我建议直接用MATLAB Function模块,输入是vα+、vβ+和当前角度θ,内部写两行三角函数计算:
vd = cos(theta) * v_alpha + sin(theta) * v_beta;
vq = -sin(theta) * v_alpha + cos(theta) * v_beta;
这里vq作为Park变换的q轴分量,稳态时应该为0。PI调节器用PID Controller模块,P和I参数填工作区变量kp_pll和ki_pll,注意把D项设为0,同时限制积分器的输出范围,我一般限制角频率偏差在±20 rad/s,防止启动瞬间积分饱和。PI输出的角频率偏差加上ω0后进积分器,积分出来的角度需要做2π取模,用Modulo模块,Constant模块设置为2π,或者用Fcn模块写mod(u, 2*pi)。取模这个操作很重要,如果不做,仿真时间长后角度数值越来越大,可能导致数值精度问题,而且Scope上看角度波形也会很乱。
5. 仿真验证:三个工况测试模型是否靠谱
5.1 工况一:三相平衡带5次谐波
第一个工况先做最简单的。设置三相平衡电压311V峰值,叠加上5%的5次谐波,仿真时长0.2秒。这个工况主要是验证SOGI的滤波能力。观察锁相角度和参考角度之间的误差,理论上稳态相位误差应该在正负1度以内。
我的仿真结果里,相位误差大约是0.3度左右,主要是谐波在SOGI输出端残留了一点点纹波,这是正常的。对比一下直接用SRF-PLL的模型,同样是5%的5次谐波,SRF-PLL的角度纹波能达到2到3度,差距很明显。这个对比能直观说明DSOGI-PLL在谐波工况下的优势。
5.2 工况二:单相电压跌落,验证负序分离能力
第二个工况模拟A相电压跌落50%,这是电网不对称故障里最常见的形态。用Three-Phase Programmable Voltage Source设置A相电压幅值从311V跌到155V,持续0.05秒后恢复。这个工况下三相电压明显不平衡,SRF-PLL的角度会随2倍频纹波剧烈抖动,而DSOGI-PLL锁出来的相位依然平直。
从波形上看,DSOGI正序分量计算模块输出的vα+和vβ+保持了三相对称的特性,没有明显的100Hz纹波,锁相角度的最大动态误差大概在2度左右,故障切除后能快速回到稳态。这说明正序分离切实解决了负序扰动问题。需要注意的是,电压跌落瞬间正序分量幅值也会变化,PLL的PI输出会产生一个瞬态调节过程,这属于正常现象,只要阻尼比设计合理,不会出现振荡。
5.3 工况三:频率阶跃,暴露SOGI固定中心频率的局限
第三个工况做频率从50Hz阶跃到52Hz。这个工况很重要,因为它能暴露固定ω0的DSOGI-PLL的局限性。PLL环路部分由于PI调节器的作用,最终能跟踪上52Hz,锁相角度的稳态值没有问题。但SOGI的中心频率仍然固定在50Hz,输入是52Hz信号时,SOGI的输出幅值不再等于输入幅值,相位也不再严格滞后90度,正序分量计算会出现幅值和相位误差。
仿真实测下来,52Hz时锁相角度虽然能锁定,但角度波形上会叠加一个小的正弦纹波,大概1到2度,这就是SOGI失谐引起的。这个现象不是模型搭错了,而是固定中心频率DSOGI-PLL的原理性缺陷。解决思路有两个:一是让SOGI的中心频率跟随锁相环输出的频率实时调整,也就是DSOGI-FLL结构;二是把频率偏差控制在较小范围内,仅用于电网频率波动不大的工况。做项目时一定要清楚自己面对的频率工况,不要把一个只能在50Hz附近工作的模型硬用在宽频域场合。
6. 常见问题与排错技巧实录
6.1 模型运行报代数环错误
不少人在搭SOGI的时候,把D输出和Q输出直接接到后面的运算,然后又把锁相输出的角度反馈回Park变换,模型运行时就报出“Algebraic Loop”的提示。代数环的本质是某条信号路径在同一时刻存在直接馈通,即输出依赖当前时刻的输入,Simulink需要迭代求解,容易导致仿真变慢甚至发散。
我排查代数环的经验是先看一下反馈路径上有没有纯增益或直接馈通模块。SOGI用积分器搭的状态空间实现不会产生代数环,但如果你用了Transfer Fcn模块并且某个路径上存在直接馈通,就要注意。PLL闭环里的三角运算和Park变换也会引入代数环,最简单的解决办法是在Park变换的角度输入端加一个Memory模块或者Unit Delay模块,把反馈路径切断一个采样周期。连续仿真里加Memory模块基本不影响结果,但要注意会引入一个步长的延时,在离散仿真里要换成Unit Delay。
6.2 锁相角度一直在跳,锁不住
锁不住相位大概有五成是正序分量计算公式的符号搞反了,三成是角度没有正确取模,剩下的就是PI参数和反馈方向问题。先检查正序分量计算模块里的符号,把模型暂停在稳态时刻,看看vq是否接近于0。如果vq不为0,那就是稳态静差,说明PI积分项有问题或者前馈频率不对。如果vq在0附近但角度在跳,多半是角度取模环节做得不对,或者sin/cos函数的输入参数单位搞错。
还要检查PID Controller模块的极性。我习惯让vq经过PI调节器后输出正值对应角度增大,如果模型里Park变换用的是另外一套符号约定,PI输出极性就要反过来。一个实用的调试技巧:在SOGI和PLL之间加一个手动开关,先断开PLL,给一个固定频率的正弦波作为角度输入,观察Park变换的vd和vq波形,确认正序分量模块输出正确后,再接回PLL闭环。这能帮你快速定位问题出在前级还是后级。
6.3 仿真步长对结果影响很大,波形毛刺多
连续模型用变步长求解器时,如果步长控制不好,波形上会有很多毛刺,尤其是SOGI这种带通特性比较尖锐的环节,对步长更敏感。我一般先用ode45,相对误差设为1e-4,模型跑通后再尝试ode23tb或者固定步长。离散模型的话,采样时间选10us到100us都可以,太大会导致离散化误差累积,太小则仿真速度慢。一个简单的判断标准:把仿真步长减半,如果锁相角度的波动变化在0.1度以内,说明步长已经足够。
还有一个很隐蔽的坑是Scope的采样率设置。Scope默认会以变步长的每个计算点都记录数据,波形看起来全是噪声,其实可能是显示粒度过细。在Scope设置里把Decimation设为合适值,或者用To Workspace模块把数据按固定采样率保存到工作区再用脚本绘图,波形就会干净很多。
6.4 从Simulink模型到嵌入式代码需要注意什么
模型搭好以后,很多项目需要用Simulink Coder生成C代码部署到DSP或单片机里。这里有一个容易被忽略的问题:连续域模块无法直接生成代码,必须先把模型全部改造成离散域。坐标变换、PI调节器、积分器都要用离散版本,SOGI的传递函数也要先离散化再放到Discrete Transfer Fcn或者S-Function里。
我在代码包里附带了一个SOGI_sfunction_demo.m,就是给准备做代码生成的人一个参考。它用S-Function实现了SOGI的状态方程,内部用差分方程离散化,采样周期作为参数传入。这样在Simulink里和最终DSP上运行的算法是一致的,不会出现仿真和实物行为不一样的问题。离散化方法推荐Tustin双线性变换,二阶系统用Tustin离散后依然能保持稳定的频率响应特性。
写在最后
DSOGI-PLL这个方案我从学习到工程落地用了差不多一个月,最大的感受是:原理书上的框图看着简单,真正搭起来才发现细节全在反馈路径、信号极性、取模和参数整定这些地方。如果只是照抄一个模型跑通不难,但要理解为什么这样做,最好还是自己从积分器那一层搭一遍,再对照传递函数仿真结果,收获会大很多。
调试这个小技巧很值得分享:把SOGI这一级单独拿出来,给一个带谐波的不平衡电压,用Scope对比D输出和Q输出,确认波形正交、幅值一致,再把正序分量模块和PLL接上去,这样每一步都有独立的验证依据。我身边不少同事直接一把梭搭完,出问题后到处找原因,反而更慢。这个内容后续还可以往两个方向扩展,一个是我前面提到的DSOGI-FLL,把SOGI中心频率做成自适应,频率偏移工况下的表现会更好;另一个是把模型离散化后用Simulink Coder生成代码,往实际控制器上移植。到时候可以再写一篇实操记录。