简介:这份资源是一套完整的单相单管PFC Simulink仿真模型,面向电力电子、电源设计与功率因数校正方向的学习者和工程师,尤其适合希望在低成本MCU上落地PFC算法的开发者。模型采用新颖的电流前馈算法,省去电流环PI控制器,计算量小,可直接应用于实际产品;控制部分包含电压外环,母线电压可主动控制,输入电流谐波能抑制到3%以下,控制效果优秀。压缩包共9个文件,约73KB,以slx与slxc仿真模型、m脚本、mat数据文件为主,另含xml配置与docx说明文档,无需修改即可在MATLAB 2023a及以上版本直接运行。目前已有83人学习下载,读者可借此理解单相Boost升压PFC的拓扑搭建、前馈控制实现与谐波抑制思路,并对照脚本与数据文件快速复现仿真、验证算法性能。
1. 单相单管 PFC 仿真:为什么一个开关管也能把功率因数拉到 0.99
很多人第一次接触功率因数矫正,脑子里浮现的是图腾柱 PFC 或者四开关 buck-boost 那种多管拓扑,觉得单管 boost 早就过时了。但如果你拆过小功率电源适配器、LED 驱动或者几百瓦以内的充电器,会发现里面清一色是「整流桥 + 单管 boost + 一个二极管」的结构。原因很直接:单相单管 PFC 的器件最少、驱动最简单、成本最低,而在 300W 以内的场景里,它的性能完全够用。这份 Simulink 仿真资源就是围绕这个拓扑展开的,核心目标是把输入电流波形修成跟输入电压同相的正弦,让功率因数从整流桥后的 0.6 左右拉到 0.99 以上,同时把输出电压稳定在设定值。它适合正在做课程设计、准备电源类项目、或者想搞懂 PFC 电流环和电压环到底怎么配合的人。你不需要有硬件也能跑,但需要 MATLAB/Simulink 环境,并且愿意花时间理解每个模块背后的控制逻辑,而不是拖几个块连起来看波形就完事。
2. 单管 boost PFC 的主电路搭建:从整流桥到输出电容的参数计算
2.1 主电路拓扑选择与器件参数
单相单管 PFC 的主电路说白了就是四个部分:交流输入、整流桥、boost 升压级、输出负载。交流输入经过整流桥之后变成脉动直流,这个脉动直流的包络就是正弦的绝对值。boost 级的作用是在每个开关周期内,通过控制开关管的占空比,让电感电流跟踪这个脉动电压的波形,从而实现输入电流正弦化。
在 Simulink 里搭这个电路,我一般用 Simscape Electrical 里的模块,而不是 Simulink 自带的理想开关。原因很简单:Simscape 的模块自带导通电阻、二极管正向压降这些非理想特性,仿真出来的波形更接近真实电路,尤其是电流环的过零畸变,用理想器件根本看不出来。
关键参数怎么定?先看输入:220V 交流有效值,50Hz,那峰值就是 311V。输出电压必须高于输入峰值,否则 boost 电路无法工作,一般取 400V。输出功率假设 500W,那输出电流就是 1.25A。电感的选择直接决定电流纹波大小,常见做法是让电感电流纹波不超过额定电流的 20%。开关频率取 50kHz,那电感值大概在 1mH 左右。输出电容的选择看保持时间要求,一般按每瓦输出功率 1 到 2 微法来估算,500W 的话取 470μF 到 1000μF 之间。
下面这段代码是在 MATLAB 脚本里先算好参数,再往 Simulink 模型里赋值,避免每次改参数都要手动点模块:
% 单相单管 PFC 主电路参数计算 Vac_rms = 220; % 交流输入有效值 (V) f_line = 50; % 电网频率 (Hz) Vout_ref = 400; % 输出电压参考值 (V) Pout = 500; % 输出功率 (W) fsw = 50e3; % 开关频率 (Hz) Vac_peak = Vac_rms * sqrt(2); % 输入峰值电压 Iout = Pout / Vout_ref; % 输出电流 Iin_rms = Pout / (Vac_rms * 0.99); % 假设效率接近 1,功率因数 0.99 Iin_peak = Iin_rms * sqrt(2); % 输入电流峰值 % 电感计算:纹波系数取 0.2 ripple_ratio = 0.2; L = Vac_peak * (Vout_ref - Vac_peak) / (ripple_ratio * Iin_peak * fsw * Vout_ref); % 输出电容计算:保持时间取 20ms hold_up_time = 20e-3; Cout = 2 * Pout * hold_up_time / (Vout_ref^2 - 0.8*Vout_ref^2); fprintf('电感 L = %.2f mH\n', L*1e3); fprintf('输出电容 Cout = %.2f uF\n', Cout*1e6);这段代码的逻辑是先根据功率和电压算出电流有效值和峰值,再用 boost 电感的纹波公式反推电感值。公式里的(Vout_ref - Vac_peak)是电感两端电压在开关管关断时的差值,这个值越小,电感需要的值越大。输出电容的公式用的是能量守恒,保持时间取 20ms 是为了覆盖一个电网周期,保证输出电压不会掉太多。跑完这段脚本,你会得到具体的 L 和 C 数值,直接填到 Simulink 模块里就行。
2.2 整流桥与 boost 级的 Simulink 连接
在 Simulink 里搭主电路,我习惯从 Simscape 的库浏览器里拖模块,顺序是:AC Voltage Source → Diode Bridge → Inductor → MOSFET → Diode → Capacitor → Resistor。这里有个细节:MOSFET 的驱动信号来自控制部分,所以主电路和控制电路之间需要一个 Simulink-PS Converter 把 Simulink 信号转成 Simscape 物理信号。
整流桥用四个二极管搭,或者直接用 Simscape 里的 Universal Bridge 模块,设置成 Diode 模式。电感模块要设置串联电阻,一般取 0.1Ω 左右,模拟实际电感的铜损。MOSFET 的导通电阻设 0.1Ω,二极管的正向压降设 0.7V。输出电容的等效串联电阻设 0.05Ω,这些非理想参数会让波形更真实,尤其是电流过零点的畸变。
连接的时候注意:整流桥的输出正极接电感的一端,电感的另一端接 MOSFET 的漏极和二极管阳极的公共点,二极管的阴极接输出电容正极,MOSFET 的源极和输出电容负极接整流桥的输出负极。这个连接方式就是标准的 boost 升压结构,只不过输入是脉动直流而不是纯直流。
提示:Simscape 的求解器步长要设小一点,我一般用 ode23t,最大步长设 1e-6,否则开关频率 50kHz 的时候波形会失真。
3. 电流环与电压环的双闭环控制:让输入电流跟踪正弦参考
3.1 平均电流控制策略的原理
单管 boost PFC 最常用的控制策略是平均电流控制,也叫电流模式控制。它的核心思想是:电压环输出一个电流参考幅值,这个幅值乘以整流后的电压波形,就得到电流参考信号。然后电流环让电感电流跟踪这个参考信号。这样输入电流就自然跟输入电压同相了,因为参考信号本身就是电压的缩放版本。
为什么不用峰值电流控制?因为峰值电流控制的输入电流会有明显的尖峰,总谐波失真大,功率因数只能做到 0.95 左右。平均电流控制可以把 THD 压到 5% 以内,功率因数做到 0.99 以上。代价是需要一个乘法器和一个电流调节器,但在 Simulink 里这些都是现成的模块,不增加复杂度。
电压环的带宽要设得很低,一般 10 到 20Hz,因为输出电压的二次谐波纹波很大,如果电压环带宽太高,这个纹波会调制电流参考信号,导致输入电流畸变。电流环的带宽要高,一般取开关频率的十分之一到五分之一,也就是 5kHz 到 10kHz,这样才能快速跟踪参考电流。
3.2 Simulink 里搭建双闭环的步骤
先搭电压环。输出电压采样之后,跟参考值 400V 比较,误差送进一个 PI 控制器。PI 的输出就是电流参考的幅值。这个幅值再乘以整流后的电压采样值(归一化到 0 到 1),得到电流参考信号。注意这里要除以输入电压的峰值平方,或者用有效值平方,目的是让电流参考的幅值跟输入电压的幅值无关,只跟输出功率有关。
% 电压环 PI 参数设计 % 电压环带宽取 15Hz f_vbw = 15; % 输出电容已知,计算 PI 参数 Kp_v = 2 * pi * f_vbw * Cout; Ki_v = Kp_v * 2 * pi * f_vbw / 10; % 电流环带宽取 8kHz f_ibw = 8e3; Kp_i = 2 * pi * f_ibw * L; Ki_i = Kp_i * 2 * pi * f_ibw / 10; fprintf('电压环 Kp = %.4f, Ki = %.4f\n', Kp_v, Ki_v); fprintf('电流环 Kp = %.4f, Ki = %.4f\n', Kp_i, Ki_i);这段代码里,电压环的 Kp 是根据输出电容和带宽算的,Ki 取 Kp 乘以带宽再除以 10,这是一个经验公式,让零点放在带宽的十分之一处。电流环的 Kp 是根据电感和带宽算的,原理类似。这些参数不是唯一的,但作为起点很靠谱,跑出来波形不对再微调。
在 Simulink 里,电压环的 PI 控制器用 Discrete PID Controller 模块,采样时间设 1e-4 秒,也就是 10kHz。电流环的 PI 控制器采样时间跟开关频率一致,设 1e-5 秒。电流环的输出是占空比信号,跟一个 50kHz 的三角波比较,生成 PWM 驱动信号。三角波的幅值设 1,频率 50kHz,相位从 0 到 1 变化。
注意:电流环的参考信号在过零点附近会有畸变,因为整流桥的二极管在低压差时导通能力差。常见做法是在电流参考上叠加一个小的偏置,或者用软启动让输出电压慢慢升到 400V,避免冲击电流。
3.3 仿真参数设置与波形观察
仿真时间设 0.5 秒,足够看到稳态波形。求解器用 ode23t,最大步长 1e-6,相对容差 1e-3。这些设置是为了兼顾精度和速度,步长再小会跑得很慢,再大波形会失真。
跑完之后看几个关键波形:输入电压和输入电流是不是同相的正弦,输出电压是不是稳定在 400V 附近,电感电流是不是跟踪参考信号。如果输入电流在过零点有平顶或者畸变,说明电流环带宽不够或者电压环带宽太高。如果输出电压有大幅低频振荡,说明电压环带宽太低或者 PI 参数太激进。
我一般会把输入电压和输入电流放在同一个示波器里,用不同的颜色区分,这样一眼就能看出相位差。功率因数可以用 Simulink 里的 Powergui 模块计算,或者自己用傅里叶分析算基波相位差。THD 用 FFT 分析工具看,重点关注 3 次和 5 次谐波。
4. 仿真跑不通?这几个坑我替你踩过了
4.1 电流波形过零畸变严重
现象:输入电流在过零点附近明显偏离正弦,出现平顶或者台阶,THD 超过 10%。
原因:整流桥的二极管在输入电压接近零时无法正常导通,因为此时电感电流也接近零,二极管的反向恢复特性导致电流断续。另外,电流环的 PI 控制器在误差很小时积分作用太强,输出饱和。
解决:在电流参考信号上叠加一个小的直流偏置,让电流在过零点也有一定的跟踪能力。或者把电流环的积分分离阈值调低,误差小于 0.1A 时只用比例控制。我一般还会在整流桥后面并一个小电容,帮助二极管在过零点导通,但电容不能太大,否则会引入额外的相位滞后。
4.2 输出电压振荡不收敛
现象:输出电压在 400V 附近来回振荡,幅度超过 20V,而且频率很低,大概 10Hz 左右。
原因:电压环的带宽设得太高,跟输出电容的二次谐波纹波耦合了。单相 PFC 的输出电压天然有 100Hz 的纹波,如果电压环带宽接近 100Hz,就会把这个纹波放大。
解决:把电压环带宽降到 10Hz 以下,或者用陷波器把 100Hz 的分量滤掉。我一般直接把电压环的 Kp 减小一半,Ki 也相应减小,牺牲一点动态响应换稳定性。另外,输出电压的采样要加一个低通滤波器,截止频率设 30Hz 左右。
4.3 开关管驱动信号异常
现象:MOSFET 的驱动信号在应该导通的时候没有导通,或者占空比突然跳到 0 或 1。
原因:PWM 比较器的三角波幅值和电流环输出的范围不匹配。如果电流环输出超过三角波的峰值,占空比就会饱和到 1,反之饱和到 0。另外,Simulink 里的代数环也会导致驱动信号异常。
解决:在电流环输出后面加一个饱和模块,上限设 0.95,下限设 0.05,防止占空比进入极端值。三角波的幅值设 1,偏置设 0,这样占空比就是电流环输出的值。如果还有代数环,在反馈路径上加一个单位延迟模块。
4.4 仿真速度慢到无法接受
现象:跑 0.1 秒的仿真要等好几分钟,波形还卡顿。
原因:求解器步长太小,或者用了变步长求解器但容差设得太紧。Simscape 的物理网络求解本身就比纯 Simulink 慢,如果模型里还有大量理想开关,速度会更慢。
解决:把最大步长从 1e-6 放宽到 5e-6,相对容差从 1e-3 放宽到 1e-2。如果波形还能接受,就继续用。另外,把不用的示波器和显示模块关掉,减少数据记录量。我一般会在跑正式仿真之前,先用 0.05 秒的短时间试跑,确认参数没问题再跑全程。
4.5 功率因数计算出来只有 0.9 左右
现象:波形看起来已经同相了,但用 Powergui 算出来的功率因数只有 0.9 出头。
原因:功率因数的定义是有功功率除以视在功率,如果电流波形有谐波,视在功率会变大,功率因数就上不去。另外,如果输入电压本身有畸变,也会影响计算结果。
解决:先看 THD,如果 THD 超过 5%,先把电流环带宽提高,或者把电压环带宽降低。如果 THD 没问题,检查输入电压源是不是纯正弦,Simulink 里的 AC Voltage Source 默认是纯正弦,但如果加了谐波模块就会畸变。最后,功率因数的计算要用一个电网周期的数据,不要用瞬态数据。
5. 从仿真到代码生成:把模型变成可移植的算法验证平台
仿真跑通之后,很多人就停在这里了。但这份资源真正的价值在于,它可以作为算法验证平台,往嵌入式代码生成的方向走。Simulink 的 Embedded Coder 可以把电流环和电压环的 PI 控制器直接生成 C 代码,烧到 DSP 或者 MCU 里。我一般会先把控制部分单独拎出来,做成一个原子子系统,设置成可重入,然后用 Embedded Coder 生成代码。
生成代码之前,要把所有模块的采样时间显式设置好,不要用继承采样时间。电压环的采样时间设 1e-4,电流环设 1e-5,PWM 模块设 1e-5。数据类型也要显式指定,不要用 double,改成 single 或者定点。我一般先用 single 跑一遍仿真,确认波形跟 double 差不多,再生成代码。
% 配置 Embedded Coder 生成代码 cfg = coder.config('lib'); cfg.TargetLang = 'C'; cfg.GenerateReport = true; cfg.LaunchReport = 'force'; % 指定子系统名称 subsys = 'pfc_control/PI_Controller'; % 生成代码 rtwbuild(subsys);这段代码的作用是把pfc_control模型里的PI_Controller子系统生成 C 代码。coder.config('lib')表示生成静态库,TargetLang设成 C,GenerateReport打开报告方便检查。生成出来的代码里,PI 控制器的积分和比例部分会变成独立的函数,输入输出都是结构体,方便集成到现有的工程里。
生成代码之后,我习惯做一件事:把生成的 C 代码跟 Simulink 里的仿真结果做对比。具体做法是在 Simulink 里跑一遍,记录输入输出数据,然后在 C 代码里用同样的输入跑一遍,看输出是不是一致。如果不一致,大概率是数据类型转换或者采样时间的问题。这个步骤能帮你提前发现定点化带来的精度损失,避免烧到硬件上才发现问题。
从那以后我每次做 PFC 仿真,都会先把控制部分做成可生成代码的子系统,哪怕暂时不用,也留个后路。希望帮到你。
本文还有配套的精品资源,点击获取