三相电压矢量合成原理与SVPWM基础:从Simulink建模到Matlab动态可视化 简介基于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 的初始相位填 0Ub 填 -2π/3Uc 填 2π/3。三者是“一前一后”的关系不是“一前两后”。生成 GIF 后如果发现矢量顺时针转第一步就该检查三相初相设置而不是检查变换公式。3. Simulink 搭建三相电压矢量合成模型Gain 参数与仿真配置3.1 模型结构和模块参数表Simulink 里搭这个模型不需要任何电气库只用基础数学模块就够了。常见做法是三个正弦源作为三相电压输入中间放一个“几何合成”子系统输出 u_alpha 和 u_beta再接 Scope 和 To Workspace。内部结构拆开看一共就三步Ua 乘 1、Ub 和 Uc 各乘 -0.5三者相加得 u_alphaUb 乘 √3/2、Uc 乘 -√3/2两者相加得 u_beta。Simulink 模块库路径关键参数Sine Wave ×3Simulink / SourcesAmplitude 311Frequency 2pi50Phase 0、-2pi/3、2pi/3Bias 0Gain ×4Simulink / Math Operations-0.5、-0.5、sqrt(3)/2、-sqrt(3)/2Sum ×2Simulink / Math Operations圆形图标默认加减号即可To Workspace ×5Simulink / SinksUa、Ub、Uc、Ualpha、UbetaSave format TimeseriesScope ×1Simulink / Sinks可看三相输入和合成矢量分量用 311 作幅值对应 220V 有效值系统方便后面验证 1.5 倍关系时直接看到 466.5V 半径。如果不关心实际电压等级也可以设成 1验证比例更方便。3.2 接线关系与为什么这里不提 2/3 系数模型里的数学关系要完全对应几何合成公式u_alpha Ua - 0.5·Ub - 0.5·Ucu_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 接 Gainsqrt(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.0009sGIF 播放起来旋转速度适中 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 保护范围设置。把这段代码接到模型里下一个需要扇区的模块扇区判断的输入输出就算闭环了。本文还有配套的精品资源点击获取