三相电压矢量合成原理与SVPWM基础:从Simulink建模到Matlab动态可视化
2026/9/16 12:12:55 网站建设 项目流程

简介:基于Matlab和Simulink实现三相电压矢量合成图的辅助学习包,面向电子信息工程、计算机及数学专业的学生,适用于课程设计、期末大作业或毕业设计的参考。压缩包共6个文件,包含3个.m源码脚本、1个.slx仿真模型和2个.gif效果演示图,整体仅1.46MB,便于下载与解压。源码实现了三相电压矢量的合成计算与可视化,Simulink模型可直观观察矢量合成过程,GIF图片则展示了动态运行效果,方便快速理解三相电压矢量合成的物理意义。已有759人学习/下载,内容清晰、结构紧凑,适合具备一定Matlab基础、需要动手改造代码的读者作为参考资料。

1. 三相电压矢量合成图:把“圆”画出来,才算看懂三相电

做电机控制和并网逆变器的人,几乎都会在 SVPWM 那章卡一下。“三相正弦波”长什么样,示波器上一看便知;可一旦把它们合成为一个“电压矢量”,为什么轨迹偏偏是个圆?这个圆转一圈,为什么刚好对应一个工频周期?答案不在时域波形里,而在三相坐标到 αβ 坐标的映射关系里。标题里的“三相电压矢量合成图”,本质就是把每一时刻的 Ua、Ub、Uc 画在各自绕组轴线上,再按平行四边形法则相加,观察合成矢量末端扫过的轨迹。把轨迹保存成 GIF 图片后,旋转方向、幅值大小、相位变化全都动起来了。本文从变换系数讲起,再落到 Simulink 模型、Matlab 出图脚本和验证方法,适合刚接触 FOC/SVPWM 的工程师,也适合需要给学生或客户演示三相平衡电压空间效果的人。

2. 三相电压矢量合成的数学基础:坐标系选择和半径推导

2.1 三相到两相的变换系数有几种版本,先选对再建模

画三相电压矢量合成图,第一步要决定用什么比例把三相值映射到两相平面上。常见做法有三种,区别只在系数上,但合成矢量的半径会差出 1.5 倍甚至更多:

变换/画法系数平衡三相时的合成矢量模典型使用场景
三相矢量直接相加(几何合成)不乘系数1.5 × 相电压幅值 Um电机学空间矢量图、动画演示
等幅值 Clarke 变换2/3UmFOC 控制量、SVPWM 逐周期计算
等功率 Clarke 变换√(2/3)√(3/2)·Um功率计算、谐波分析

标题里的“矢量合成图”通常采用第一种,也就是把 A、B、C 三相绕组轴线固定在空间互差 120° 的位置,每相瞬时电压值沿各自轴线取长度,再矢量相加。这样画出来的合成矢量半径正好是 1.5 倍相电压幅值,和教科书里“三相绕组磁势合成为单相 1.5 倍”的结论一致。如果换成等幅值 Clarke 变换,相当于整体乘了 2/3,合成半径会变成 1.0 倍 Um,动画里箭头会短一截,演示效果不如几何合成直观。

在 Matlab 里用矩阵实现这三种变换非常直接:

% 三相瞬时值(示例:220V 有效值系统) Um = 220 * sqrt(2); w = 2 * pi * 50; t = 0:1e-4:0.04; Ua = Um * sin(w*t); Ub = Um * sin(w*t - 2*pi/3); Uc = Um * sin(w*t + 2*pi/3); % 几何合成(无系数,半径 = 1.5*Um) u_alpha_geo = Ua - 0.5*Ub - 0.5*Uc; u_beta_geo = sqrt(3)/2 * (Ub - Uc); % 等幅值 Clarke(乘 2/3,半径 = Um) u_alpha = 2/3 * u_alpha_geo; u_beta = 2/3 * u_beta_geo;

这里 u_alpha_geo、u_beta_geo 就是 Simulink 模型里要算的两个量。注意 u_beta 的系数是 √3/2,不是 √3/3,很多初学的人会把等幅值 Clarke 里 2/3 和 √3/2 拆错。同一组三相数据,从没乘系数的版本换到等幅值版本,只差一个 2/3 缩放,画出来的圆形状完全一样,只是刻度变了。

2.2 平衡三相正弦的合成矢量为什么是个圆

把三相正弦代入几何合成公式,可以直接看到圆的来源。设 Ua = Um·sin(ωt),Ub = Um·sin(ωt - 120°),Uc = Um·sin(ωt + 120°):

u_alpha_geo = 1.5·Um·sin(ωt)

u_beta_geo = -1.5·Um·cos(ωt)

所以合成矢量可以写成复数形式:

Us = u_alpha_geo + j·u_beta_geo = -j·1.5·Um·e^(jωt)

这个式子的含义很直观:模长恒为 1.5·Um,相角以 ωt 的速度匀速旋转,角速度等于三相电压的角频率,旋转一圈就是一个工频周期。对应到 GIF 里,你会看到黑色合成矢量始终指向圆周上的一点,而三个彩色分量沿着各自的轴线不断伸缩,无论怎么变,合成末端都落在同一个圆上。

“为什么是圆”的另一个直观解释是:Ua、Ub、Uc 三个值时刻在变,但它们满足 Ua + Ub + Uc = 0,只在一个二维平面内运动。再加上相位彼此差 120°,这个平面运动又满足圆方程,投影出来必然是个圆。若三相不平衡或存在直流偏置,这个结论就不成立,后面会讲怎么从图形反推问题。

2.3 相序决定 GIF 里矢量的旋转方向

合成矢量转的方向由三相的相序决定。按 Ua → Ub → Uc 依次滞后 120° 接法,旋转方向是数学正方向(逆时针);如果把 Uc 的初相填错成 -120°,或者把 Ub 和 Uc 两根信号线接反,旋转方向就反过来了。

在 Simulink 里具体表现为:Ua 的初始相位填 0,Ub 填 -2π/3,Uc 填 +2π/3。三者是“一前一后”的关系,不是“一前两后”。生成 GIF 后如果发现矢量顺时针转,第一步就该检查三相初相设置,而不是检查变换公式。

3. Simulink 搭建三相电压矢量合成模型(Gain 参数与仿真配置)

3.1 模型结构和模块参数表

Simulink 里搭这个模型不需要任何电气库,只用基础数学模块就够了。常见做法是三个正弦源作为三相电压输入,中间放一个“几何合成”子系统,输出 u_alpha 和 u_beta,再接 Scope 和 To Workspace。

内部结构拆开看,一共就三步:Ua 乘 1、Ub 和 Uc 各乘 -0.5,三者相加得 u_alpha;Ub 乘 √3/2、Uc 乘 -√3/2,两者相加得 u_beta。

Simulink 模块库路径关键参数
Sine Wave ×3Simulink / SourcesAmplitude = 311,Frequency = 2pi50,Phase = 0、-2pi/3、+2pi/3,Bias = 0
Gain ×4Simulink / Math Operations-0.5、-0.5、sqrt(3)/2、-sqrt(3)/2
Sum ×2Simulink / Math Operations圆形图标,默认加减号即可
To Workspace ×5Simulink / SinksUa、Ub、Uc、Ualpha、Ubeta,Save format = Timeseries
Scope ×1Simulink / Sinks可看三相输入和合成矢量分量

用 311 作幅值对应 220V 有效值系统,方便后面验证 1.5 倍关系时直接看到 466.5V 半径。如果不关心实际电压等级,也可以设成 1,验证比例更方便。

3.2 接线关系与为什么这里不提 2/3 系数

模型里的数学关系要完全对应几何合成公式:

u_alpha = Ua - 0.5·Ub - 0.5·Uc

u_beta = √3/2·(Ub - Uc)

这两个式子没有乘 2/3,和 FOC 里常用的等幅值 Clarke 矩阵差了比例。这是故意保留的:画三相电压矢量合成图时,用“无系数”版本才能让合成半径显示为 1.5 倍相电压幅值,跟教材上的空间矢量图习惯一致。如果后续要把同样的 Ualpha、Ubeta 送进 SVPWM 调制器做占空比计算,再整体乘 2/3 即可,GIF 动画本身不受影响。

接线时最容易乱的是负数处理。推荐做法:Ua 接 Sum 的正输入,Ub 先接一个 Gain(-0.5),再接到求和符号为负的输入端口;Uc 同样接 Gain(-0.5)再进 Sum。u_beta 那一路则让 Ub 接 Gain(sqrt(3)/2)进正输入,Uc 接 Gain(-sqrt(3)/2)进负输入。两个 Sum 再分别接到 To Workspace。若想减少模块数量,也可用 Fcn 模块直接写表达式,但不方便后续改成标准 Clarke 变换,我一般不建议。

为了确认接线,可以给出一段等价于子系统内部逻辑的 Matlab Function 代码:

function [u_alpha, u_beta] = vector_synthesis(Ua, Ub, Uc) % 几何合成:不乘 2/3,合成半径 = 1.5 * 相电压幅值 u_alpha = Ua - 0.5*Ub - 0.5*Uc; u_beta = sqrt(3)/2 * (Ub - Uc); % 若做等幅值 Clarke,取消下面注释,输出半径会变为 1.0 * 幅值 % u_alpha = 2/3 * u_alpha; % u_beta = 2/3 * u_beta; end

这里的输出顺序、正负号都按 3.1 的接法对应。u_beta 如果出现相反数,说明 Ub 和 Uc 的 Gain 符号接反了。

3.3 仿真步长与数据导出设置

三相正弦不需要特别小的步长,但后面要生成 GIF,轨迹点太少会让圆看起来像多边形。常见做法是固定步长 1e-4 秒,跑 0.04 秒,也就是两个工频周期,能拿到 401 个点。这样 GIF 里的圆足够圆,文件体积也可控。

在命令行里可以直接用 set_param 完成配置:

mdl = 'svc_geometry_model'; open_system(mdl); % 固定步长仿真:ode4 即经典 RK4 set_param(mdl, 'Solver', 'ode4'); set_param(mdl, 'FixedStep', '1e-4'); set_param(mdl, 'StopTime', '0.04');

To Workspace 块的 Save format 一定要选 Timeseries,这样 sim 返回的结果才是带时间戳的 timeseries 对象,方便第四章直接用 .Time 和 .Data 索引。三个 Sine Wave 的 Sample time 可以保持 0(连续采样),也可以手动设为 1e-4,对仿真结果没有实质影响。若用变步长,Scope 里曲线正常,但 To Workspace 保存的时间点不均匀,做 GIF 抽帧时可能出现前后帧速度突变的观感,所以这里建议固定步长。

4. Matlab 脚本绘制矢量合成轨迹并输出 GIF 图片

4.1 从仿真结果里取数:Timeseries 的两种取法

Simulink 模型跑完,数据已经在工作区里了。R2016b 之后,sim 函数返回的是 Simulink.SimulationOutput 对象,To Workspace 里定义的变量名就是它的属性名:

out = sim(mdl); % 时间直接取自任何一个输出通道,避免自己构造时间轴 t = out.Ua.Time; Ua = out.Ua.Data; Ub = out.Ub.Data; Uc = out.Uc.Data; u_alpha = out.Ualpha.Data; u_beta = out.Ubeta.Data;

如果你的 Matlab 版本较老,没有 out.Ua 这种访问方式,可以用:

Ua = out.get('Ua'); t = Ua.Time;

这里 Ua、Ub、Uc 是三个正弦源的瞬时值,u_alpha、u_beta 是 Simulink 里 Sum 模块输出的合成分量。取出后第一步先做数值检查,确认没有 NaN、长度一致、起始时刻为 0,再做动画。

4.2 绘制三相矢量合成动画并写 GIF 的完整源码

下面是完整可跑的脚本。三个彩色箭头表示 Ua、Ub、Uc 在各自绕组轴线上的瞬时分量,黑色箭头是合成矢量,黑线是它到当前时刻为止扫过的轨迹。每帧取一个时间点,画完直接追加写入 GIF:

% 取 45 帧,一帧约 0.0009s,GIF 播放起来旋转速度适中 N = round(linspace(1, numel(t), 45)); % 三相绕组轴线:A 轴 0°,B 轴 120°,C 轴 240° axis_deg = [0, 2*pi/3, 4*pi/3]; colors = [0.8500 0.3250 0.0980; % A 橙 0.4660 0.6740 0.1880; % B 绿 0.3010 0.7450 0.9330]; % C 蓝 % 坐标范围略大于 1.5 倍相电压幅值 R = 1.15 * max(hypot(u_alpha, u_beta)); fig = figure('Color','w','Position',[80 100 680 620]); for k = 1:numel(N) idx = N(k); % 三相瞬时矢量在各自轴线上 vA = [Ua(idx), 0]; vB = Ub(idx) .* [cos(axis_deg(2)), sin(axis_deg(2))]; vC = Uc(idx) .* [cos(axis_deg(3)), sin(axis_deg(3))]; vS = [u_alpha(idx), u_beta(idx)]; cla; hold on; grid on; axis equal; xlim([-R R]); ylim([-R R]); % 三条固定轴线 for j = 1:3 quiver(0, 0, R*cos(axis_deg(j)), R*sin(axis_deg(j)), 0, ... 'Color', [0.8 0.8 0.8], 'LineWidth', 0.8, 'MaxHeadSize', 0.4); end % 三相瞬时分量 for j = 1:3 vec = [vA; vB; vC]; quiver(0, 0, vec(j,1), vec(j,2), 0, ... 'Color', colors(j,:), 'LineWidth', 1.4); end % 平行四边形辅助线:A 和 B 先合成,再叠加 C 的效果 plot([vA(1), vA(1)+vB(1)], [vA(2), vA(2)+vB(2)], '--', 'Color', [0.6 0.6 0.6]); plot([vB(1), vA(1)+vB(1)], [vB(2), vA(2)+vB(2)], '--', 'Color', [0.6 0.6 0.6]); plot([vA(1)+vB(1), vS(1)], [vA(2)+vB(2), vS(2)], ':', 'Color', [0.4 0.4 0.4]); % 合成矢量与已扫过的轨迹 quiver(0, 0, vS(1), vS(2), 0, 'k', 'LineWidth', 2.0, 'MaxHeadSize', 0.9); plot(u_alpha(1:idx), u_beta(1:idx), 'Color', [0.2 0.2 0.2], 'LineWidth', 1.5); % 当前矢量的电角度 th_deg = rad2deg(atan2(vS(2), vS(1))); text(vS(1)*1.10, vS(2)*1.10, sprintf('%.0f°', th_deg), ... 'FontSize', 9, 'HorizontalAlignment', 'center'); title(sprintf('t = %.4f s', t(idx)), 'FontSize', 10); drawnow; % 写 GIF:第 1 帧指定循环,后续帧追加 rgb = frame2im(getframe(gcf)); [I, cmap] = rgb2ind(rgb, 256); if k == 1 imwrite(I, cmap, 'three_phase_vector.gif', 'gif', ... 'LoopCount', Inf, 'DelayTime', 0.05); else imwrite(I, cmap, 'three_phase_vector.gif', 'gif', ... 'WriteMode', 'append', 'DelayTime', 0.05); end end

这段脚本的要点有三个:一是 quiver 的第 5 个参数传 0,表示不自动缩放箭头,否则矢量长短会被 Matlab 按比例改变,动画看起来就会忽长忽短;二是 cla 只清内容不清坐标范围,所以 xlim、ylim 在每帧循环里都要重新设置,防止坐标轴自动缩放导致圆上下抖动;三是 rgb2ind 用 256 色就能覆盖 GIF 的全部常见场景,不需要调更多色。

4.3 GIF 参数调节与性能优化

我把每帧间隔设成 0.05 秒,45 帧放完大约 2.25 秒,符合“一圈工频周期”的视觉节奏。想让它转得慢一点,把 DelayTime 改成 0.08 或 0.10;太快则用 0.03。留意 DelayTime 单位是秒,Matlab 的 GIF 写入不支持毫秒,别把 0.05 写成 50。

脚本每帧都执行 cla 重绘全部对象,数据量小的时候没问题。如果你把仿真时间延长到了 1 秒,动态轨迹会积累几千个点,重绘开销就很明显。更快的做法是提前创建好 quiver 和 plot 对象,每帧只更新坐标数据:

hVec = quiver(0, 0, 0, 0, 0, 'k', 'LineWidth', 2.0); hTrace = plot(nan, nan, 'Color', [0.2 0.2 0.2], 'LineWidth', 1.5); for k = 1:numel(N) idx = N(k); set(hVec, 'UData', u_alpha(idx), 'VData', u_beta(idx)); set(hTrace, 'XData', u_alpha(1:idx), 'YData', u_beta(1:idx)); drawnow; % 其余写 GIF 的代码不变 end

这样 CPU 占用小很多,GIF 帧间隔也更均匀。

5. 合成结果验证与 SVPWM 扇区衔接

5.1 用数值检查半径,别只看图形像圆

Scope 和 GIF 里看起来都是圆,不代表数值一定对。Simulink Scope 默认自动缩放,就算合成半径少了一半,图还是圆的。用 max + hypot 直接算半径最可靠:

radius = max(hypot(u_alpha, u_beta)); fprintf('合成矢量半径 = %.2f V\n', radius); fprintf('相电压幅值倍率 = %.3f\n', radius / max(abs(Ua)));

按几何合成模型,相电压幅值为 311V 时,半径应为 466.5V 左右,倍率接近 1.500。如果倍率是 1.000,说明模型里不小心用了等幅值 Clarke 的 2/3 系数;如果倍率是 0.866,说明可能把 √3/2 错写成了 √3/3。这一步能帮你确认生成的 GIF 到底用的哪一套系数。

5.2 图形失真的快速定位表

GIF 图一旦出现椭圆、偏心、抖动等异常,按下面表格排查最快:

异常现象最常见原因检查方式
轨迹明显是椭圆三相幅值不相等,或某相初相不是 120° 间隔分别 max(Ua)、max(Ub)、max(Uc)并对比
圆心不在原点Sine Wave 模块 Bias 不是 0,叠加了直流分量检查三个正弦源的 Bias 参数
矢量旋转方向反Ub、Uc 相位互换,或初相符号填反看 GIF 第一秒的箭头偏转方向
圆边缘呈锯齿固定步长过大把 FixedStep 改到 5e-5 或 1e-4
箭头长度忽大忽小quiver 自动缩放箭头检查 quiver 第五个参数是否为 0
合成矢量末端跟不上轨迹抽帧索引 N 跨度过大把帧数从 45 提高到 60

常见误用是把 Scope 里的自动缩放当成“波形正常”,然后拿着比例错误的 GIF 去加标注。建议每次改完参数,都跑一遍 5.1 的半径倍率语句,比肉眼判断可靠。

5.3 把 u_alpha、u_beta 直接接到 SVPWM 扇区判断

合成矢量图生成的 u_alpha 和 u_beta,不只是用来做动画的。SVPWM 的第一步扇区判断,用的正是这两个值。根据合成矢量角度除以 60° 取整,就能得到当前所在扇区:

% 合成矢量电角度:atan2 返回 [-pi, pi] theta_v = atan2(u_beta, u_alpha); % 扇区编号 1~6,适用于七段式 SVPWM 的常规判断 sector = floor(mod(theta_v + pi/6, 2*pi) / (pi/3)) + 1;

这个 sector 可以和 GIF 里标注的电角度对应起来验证:当合成矢量位于 0° 附近时扇区应为 3 或 4,按常规三相坐标定义略有差异,以你后续调制器的坐标轴定义为准。用这份结果去和 Simulink 里的 SVPWM 模块输出做对比,能快速定位角度偏差是来自变换系数还是 from 保护范围设置。把这段代码接到模型里下一个需要扇区的模块,扇区判断的输入输出就算闭环了。

本文还有配套的精品资源,点击获取

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

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

立即咨询