光伏UI与PU特性曲线:基于Simulink的建模与批量仿真实践

发布时间:2026/9/10 3:31:57
光伏UI与PU特性曲线:基于Simulink的建模与批量仿真实践 简介面向光伏系统研究者和Simulink初中级用户这份资料演示了如何搭建光伏电池模型并绘制不同温度、光照强度下的UI电压-电流与PU功率-电压特性曲线帮助快速定位最大功率点MPP并分析环境因素对发电效率的影响。压缩包内共2个文件含1个slx格式Simulink模型和1个m格式MATLAB主脚本模型负责光伏阵列仿真脚本用于参数扫描、数据采集与绘图包体仅24KB结构精简便于二次开发。已有3119人学习下载。通过案例可掌握光伏模型参数设置、光照与温度变量调整、plot绘图及结果解读等关键环节并能基于同一流程开展扩展实验例如比较不同光伏材料或不同工况下的输出差异为课程设计、毕业设计及光伏系统MPPT控制与性能优化提供直接参考。 做光伏发电研究的人几乎都免不了要和UI特性曲线、PU特性曲线打交道。这里提到的UI可不是用户界面而是电压U和电流I的关系曲线PU则是功率P和电压U的关系曲线。这两条曲线直接决定了一块光伏组件在什么工作点能交出最大功率也决定了MPPT控制策略该怎么设计。用Simulink把光伏模型搭起来在不同温度、不同光照强度下批量跑仿真然后把UI、PU曲线一次性画出来这件事听起来简单真正做的时候还是有不少门道的。这篇文章就按我自己的实操流程从建模思路、模型搭建到批量绘图和常见坑位完整走一遍。1. 建模思路从物理方程到Simulink仿真1.1 光伏电池模型单二极管等效电路光伏电池本质上就是一个大面积PN结。光照进来之后光子把价带电子激发到导带产生电子-空穴对在内建电场作用下分离形成光生电流。所以电气上等效起来就是一个电流源并联一个二极管再考虑实际损耗还会串联一个小电阻、并联一个大电阻。这个等效电路对应的电流-电压方程就是光伏仿真领域最经典的“单二极管模型”[ I I_{ph} - I_0 \left[ \exp\left(\frac{V I R_s}{n V_t}\right) - 1 \right] - \frac{V I R_s}{R_{sh}} ]其中 (I_{ph}) 是光生电流(I_0) 是反向饱和电流(R_s) 是串联电阻(R_{sh}) 是并联电阻(n) 是二极管理想因子(V_t kT/q) 是热电压。如果直接把完整方程搬进Simulink会遇到一个麻烦等号右边也出现了电流 (I)这是一个隐式方程容易触发代数环。我实现在模型里的方式是对教学场景做一点简化忽略 (R_s)把 (R_{sh}) 当作无穷大于是方程变成[ I I_{ph} - I_0 \left( \exp\left(\frac{V}{n V_t}\right) - 1 \right) ]这个简化模型对展示曲线趋势完全够用曲线形状、最大功率点位置都和实际组件对得上。工程上如果非要考虑 (R_s) 的压降建议直接换Simscape的PV Array模块而不是在基础Simulink里硬解隐式方程后面我会对比这两种路线。1.2 什么是UI和PU特性曲线UI曲线也就是伏安特性曲线横轴是电压U纵轴是电流I。一块组件在特定光照和温度下电压从0一直增加到开路电压 (V_{oc})电流一开始几乎不变、接近短路电流 (I_{sc})到接近开路电压时快速跌到0。这个“膝盖”附近就是最大功率点MPP。PU曲线则是把同一组数据里的功率 (P U \times I) 放到纵轴上横轴依然是电压U所以它的形状是从0上升到峰值再掉回0峰值就是最大输出功率。温度、光照对这两条曲线的影响规律我在第3节会结合结果详细讲先记住两个大方向光照主要改变电流大小温度主要改变电压高低。1.3 技术路线选择手动搭建 vs Simscape PV Array刚开始用Simulink做光伏仿真的人通常会问不是有个现成的PV Array模块吗为什么还要自己搭两条路线各有适用场景我列个表说明对比项手动搭建数学模型Simscape PV Array建模透明程度高方程、参数全部可见低封装成物理模块与后续电路级联需要自己搭电气接口直接连接电阻、逆变器等教学演示效果适合讲原理适合做系统仿真隐式方程处理需简化或特殊处理内部已处理批量绘制UI/PU曲线方便也方便但需要额外获取电气信号如果你的目标是理解光伏电池本身或者论文里需要解释模型参数那我建议手动搭数学模型如果目标是做MPPT算法验证、并网逆变器控制那就直接用PV Array省时间。我这篇文章主要按手动建模路线走因为它的信号流更清晰而且后面接MPPT算法也不难。2. Simulink模型搭建一次搭好任意工况可扫2.1 模型结构与模块清单整个模型核心思路很简单用Ramp模块产生一个从0线性增加到 (V_{oc}) 的扫描电压把它和温度、光照一起送进MATLAB Function模块函数内部用单二极管方程计算出电流I电流I再乘上电压V得到功率P。最后把V和I用To Workspace送到工作区方便脚本批量出图。我在R2020a里实测过这套结构模型文件很小运行速度很快。模块清单如下模块名称主要作用RampScan Voltage产生0~(V_{oc})的线性扫描电压ConstantG光照强度输入单位 W/m²ConstantT温度输入单位 ℃MATLAB FunctionPV Model单二极管方程计算电流ProductPower计算功率 (P V \times I)To WorkspaceVout导出电压数据To WorkspaceIout导出电流数据ScopeScope在线观察曲线趋势模型里的Constant模块值不要写死数字而是填工作区变量名比如G_work和T_work。这样脚本里每次仿真前用assignin(base, G_work, G)给变量赋新值Simulink模型就会自动用最新的光照和温度运行不需要频繁打开模型改参数这是批量扫描的核心技巧。2.2 MATLAB Function核心代码MATLAB Function模块是实现光伏方程最关键的地方。代码如下function I pv_curve(V, G, T) % 光伏组件简化单二极管模型 % 输入 % V: 输出电压单位 V % G: 光照强度单位 W/m^2 % T: 电池温度单位 ℃ % 输出 % I: 输出电流单位 A % 物理常数 q 1.602176634e-19; % 电子电荷C k 1.380649e-23; % 玻尔兹曼常数J/K % 组件参数可按实际组件datasheet修改 n 1.2; % 二极管理想因子 Isc0 8.21; % STC条件下短路电流A Voc0 32.9; % STC条件下开路电压V Gref 1000; % STC光照W/m^2 Tref 25; % STC温度℃ % 温度换算与热电压 Tk T 273.15; Trefk Tref 273.15; Vt n * k * Tk / q; % 当前温度下的等效热电压 % 光生电流随光照和温度修正 Iph Isc0 * (G / Gref) * (1 0.0006 * (T - Tref)); % 反向饱和电流 Vtref n * k * Trefk / q; I0ref Isc0 / (exp(Voc0 / Vtref) - 1); Eg 1.12; % 硅的带隙能量eV I0 I0ref * (Tk / Trefk)^3 * exp((Eg / (n * k)) * (1 / Trefk - 1 / Tk)); % I-V关系加入截断防止数值溢出 I_temp Iph - I0 * (exp(V / Vt) - 1); I max(0, I_temp); end这段代码里几个地方值得注意第一温度单位。Simulink里Constant填的是摄氏温度函数内部要先加273.15转成开尔文再算热电压很多人一开始就直接用25去算结果开路电压差得离谱。第二反向饱和电流 (I_0) 随温度是按 (T^3) 和指数项变化的不能当成常数。上面用的公式是从半导体物理里的 (I_0 \propto T^3 \exp(-E_g/(nkT))) 推出来的实际仿真下来温度从15℃升到45℃时(V_{oc}) 的下降量和我查到的组件datasheet基本一致。第三最后用max(0, I_temp)做截断。因为在 (V) 超过 (V_{oc}) 后指数项会让电流变成负值这在物理上对应反向漏电流对画曲线没有帮助而且可能让后续计算功率出现小负数直接截掉更干净。2.3 关键参数设置与温度光照输入Ramp模块的参数这样设置仿真时长我习惯设5秒Ramp斜率就填 (V_{oc0}/5 32.9/5 6.58)初值0。这样仿真结束后Ramp正好从0扫到32.9V能看到完整的开路过程。如果扫描范围想再宽一点可以设成1.2倍的 (V_{oc0})对应斜率约7.9方便观察曲线在超过开路电压后的走势。两个Constant模块的值分别填G_work和T_work然后到MATLAB Function的输入端口。To Workspace模块的参数里变量名分别设成Vout和IoutSave format选Array采样时间格式选这个最方便脚本处理Sample Time统一设成0.001。采样时间如果不统一Vout和Iout的数据长度可能不一样后面绘图时直接报维度不匹配我踩过一次这个坑这里先提醒你。仿真器设置保持默认的ode45就行。模型搭完后先在模型里把G_work设成1000、T_work设成25跑一遍Scope里应该能看到一条从 (I_{sc}) 平滑跌到0的UI曲线以及一个先升后降的PU曲线。确认形状对了再进入批量仿真环节。3. 多工况批量仿真与曲线绘制3.1 批量仿真脚本模型搭好之后手动改温度光照再点运行也能出图但那只能看一两组。要拿到论文里那种“一条图里画好几条不同光照曲线”的效果必须用脚本批量仿真。核心思路是在工作区给G_work和T_work赋值然后反复调用sim函数。%% 批量仿真脚本 clear; close all; clc; % 光照工况 W/m^2 G_list [200 400 600 800 1000]; % 温度工况 ℃ T_list [15 25 35 45]; % 预存结果 results struct(G, [], T, [], V, [], I, [], P, []); idx 1; for T T_list for G G_list % 将变量写入基本工作区Simulink模型自动读取 assignin(base, G_work, G); assignin(base, T_work, T); % 运行仿真 sim(pv_curve_model); % 读取To Workspace导出的数据 V Vout.Data; I Iout.Data; P V .* I; % 保存结果 results(idx).G G; results(idx).T T; results(idx).V V; results(idx).I I; results(idx).P P; idx idx 1; end end这里用嵌套循环把所有温度光照组合都跑了一遍。如果工况更多说实话会比较慢但基本都够用了。还有一点每次仿真前最好执行一下clear或至少把上一次的Vout、Iout从工作区清掉否则如果Simulink模型因为某个原因没把新数据覆盖到变量里脚本会读到上一次的数据造成工况与曲线对不上的诡异问题。3.2 UI/PU曲线绘图与后处理批量仿真结束后结果都存在results结构体里了。绘图时我习惯分成两个视角固定温度、变化光照固定光照、变化温度。每个视角画一幅图上下两个子图分别放UI和PU曲线。%% 绘制固定温度25℃时不同光照下的UI/PU曲线 figure(Position, [100 100 900 700]); % 筛选25℃的数据 idxT find([results.T] 25); subplot(2, 1, 1); hold on; grid on; for k idxT plot(results(k).V, results(k).I, LineWidth, 1.5); end xlabel(电压 U (V)); ylabel(电流 I (A)); title(UI特性曲线 (T25℃, 不同光照)); legend(arrayfun((x) sprintf(G%d W/m^2, x.G), results(idxT), UniformOutput, false), ... Location, best); subplot(2, 1, 2); hold on; grid on; for k idxT plot(results(k).V, results(k).P, LineWidth, 1.5); end xlabel(电压 U (V)); ylabel(功率 P (W)); title(PU特性曲线 (T25℃, 不同光照)); legend(arrayfun((x) sprintf(G%d W/m^2, x.G), results(idxT), UniformOutput, false), ... Location, best); % 保存图片格式推荐PDF或TIF saveas(gcf, IV_PV_curves_T25.pdf);固定光照1000 W/m²、变化温度的那组图代码结构完全一样只需筛选results里G等于1000的数据标题和legend改成温度就行我这里不重复贴了。还有个实用技巧如果曲线数据点比较密plot时会觉得图很平滑但如果你想找最大功率点的精确位置不能直接从离散点里取最大值完事因为扫描步长是0.00658V左右真正的MPP很可能落在两个采样点之间。我通常的做法是在MPP附近取一小段数据用polyfit做二次多项式拟合然后对拟合多项式求导令导数为0得到更精确的最优工作点电压和功率。这个细节写论文的时候很有用。3.3 结果怎么解读曲线画出来之后要能看出物理规律不然图就是一堆线。固定温度、改变光照时可以看到短路电流 (I_{sc}) 几乎和光照成正比200 W/m²时电流约1.6A1000 W/m²时约8.2A这就是光生电流 (I_{ph}) 随光强线性增大的结果。开路电压 (V_{oc}) 变化很小光照从200增加到1000(V_{oc}) 只增几个伏特因为 (V_{oc}) 和光电流是自然对数关系。PU曲线的峰值随光照显著增大最大功率点从低光强的几十瓦涨到高光强两百多瓦这就是为什么光伏系统在阴天发电量骤降。固定光照、改变温度时可以看到(V_{oc}) 明显随温度升高而下降温度每升高10℃开路电压大约降2V这是反向饱和电流 (I_0) 随温度指数增大导致的。(I_{sc}) 略微上升但幅度很小肉眼看去几乎不变。PU曲线的峰值随温度升高而下降说明高温对光伏发电是不利的。这也是实际电站里高温天组件反而发不了最高功率的一个重要原因。拿着这四条规律去对照自己的曲线如果趋势对不上大概率是模型参数或者单位出了问题往下看排查方法。4. 常见问题与避坑经验4.1 代数环和数值发散如果不想用我给的简化模型非要在Simulink里完整实现含 (R_s) 的隐式方程第一个遇到的就是代数环。典型症状是模型运行极慢、报“Algebraic loop”警告或者曲线明显震荡。避免手段有三种加Memory模块打断代数环但可能引入延迟误差用MATLAB Function里自己迭代求解最省事的是直接不用基础Simulink换Simscape物理建模。我自己的观点是如果只是为了画UI/PU曲线没必要冒这个风险。简化模型已经能反映所有关键趋势做MPPT算法验证也够用。真要精确到和datasheet毫厘不差那就上PV Array模块里面已经处理好了所有数值问题。4.2 曲线不平滑和采样点过少曲线出现锯齿状、或者MPP附近明显“拐硬弯”多数情况下不是模型错了而是扫描步长太粗。解决办法把仿真时长拉长比如从5秒改成10秒同时Ramp斜率减半或者把To Workspace采样时间从默认值改到0.0005。采样点越多曲线越平滑代价是导出的数组更大对一台普通电脑来说几百KB的数据完全没压力放心加密度。另外如果Ramp斜率设置得过快扫描电压变化的速率接近光伏电池内部动态过程的响应速度曲线也会失真。所以Ramp斜率宁慢勿快我通常保持5秒扫完整段。4.3 命名、单位和其他低级的坑有几个问题不属于物理建模但卡住人的概率极高我整理成一个表格现象原因解决办法模型加载报错或识别不了路径文件名或路径含中文全部用英文字母命名路径也建议英文输出电流比预期大/小很多温度单位没用开尔文函数内部先转K再用Vout和Iout数据长度不一致To Workspace采样时间没设统一两个模块Sample Time都填0.001数字很大时有NaNexp指数溢出用max(0, I_temp)截断限制V范围曲线最后一段电流变成负数扫描电压超过了 (V_{oc})已经用了截断则不会出现否则缩小Ramp斜率或仿真时间批量仿真结果全是同一组工况工作区变量赋值后没重新编译模型确认Constant模块值填的是变量名而不是数字常量排查的时候先挂Scope在线看波形再用disp(结果)把G_work和T_work打出来确认工况是否正确传了进去。数据显示永远是最诚实的不要上来就怀疑公式不对。4.4 向更高精度扩展的方向如果电容性负载、局部阴影遮挡、MPPT动态响应这类问题被提上日程简化模型就不够用了。我觉得最合理的升级路径是保留目前的MATLAB Function作为“原理演示单元”同时在同一个Simulink工程里再放一个Simscape PV Array作为“系统仿真单元”两个互不干扰。需要展示原理时跑前者需要联调逆变器时用后者数据都导出到工作区绘图脚本可以完全复用。我在实际项目里还有一个习惯把建模得到的MPP、(V_{oc})、(I_{sc}) 和厂家datasheet表对比偏差控制在5%以内就认为模型可信。这样后面无论是做MPPT算法对比还是整机系统级仿真都有底气说自己用的光伏模型是可靠的。最后再分享一个操作习惯每次搭完这类模型我会把仿真时间、Ramp斜率、采样时间记在脚本注释里因为这个三件套互相牵连改一个就得同步改另外两个。下次你隔了几个月再打开这个模型如果注释没写清楚大概率要花至少半小时重新调这些参数。画UI/PU曲线本身不复杂真正体现功力的地方是你能不能一次性把这些边界细节都处理好。本文还有配套的精品资源点击获取