
去年底我在一个园区微电网项目上做类似工作发现很多人一听到日前经济调度就觉得这是纯理论研究但其实把它落到Matlab代码里、考虑风光储和需求响应之后可操作性和坑点比想象中多得多。这篇文章我就围绕风力、光伏、储能和需求响应DR参与日前经济调度的建模与Matlab实现讲一遍从问题拆解、数学建模、代码框架到实跑结果逐层展开。如果你正打算做微电网优化调度的毕设、课题或者生产环境的初版方案这篇文章能帮你省下不少查资料的时间。我尽量把每一步为什么这样设计也讲清楚而不是直接扔给你一堆公式和Cplex指令。1. 微电网日前经济调度的本质一个带约束的多时段资源分配问题1.1 日前调度到底在优化什么微电网的日前经济调度简单说就是提前一天通常按15分钟或1小时一个时段共24或96个时段把第二天的发电计划、储能充放电计划、可调负荷控制策略全部算出来在满足负荷需求的前提下让系统总运行成本最低。但成本不是只有火电煤耗那么简单。在含风光储的微电网里真正要决策的对象包括可控机组如果有柴油机或燃气轮机的启停与出力储能的充放电功率和每个时段的荷电状态SOC风电、光伏的处理方式——全消纳还是允许一部分弃风弃光需求响应资源的调用量与调用时间——哪些负荷在哪些时段被削减或转移。我习惯把这种问题理解成一个多时段资源分配问题每个时段都在做一个该让谁出力、让谁休息的决策而各个时段之间又通过储能SOC和机组爬坡约束紧紧耦合在一起。所以你不能一个时段孤立地寻优必须拉着全部时段一起算。1.2 为什么风光储和DR要放进同一个模型很多初学者只看风电光伏的装机容量认为风光越多成本越低但真正做过运行模拟的人都清楚风电光伏是零边际成本电源可它同时也是不可控电源出力的不确定性会传导到系统平衡上。没有储能和需求响应配合时要么出现弃风弃光要么必须在负荷高峰动用昂贵的备用机组。把储能和DR放进来之后调度模型发生的关键变化有两个储能给出了时间上的平移能力低谷充电、高峰放电把风电光伏的过剩电量搬到晚上用。需求响应给出了负荷侧跟随电源的能力原本刚性不可变的负荷一部分变得可以削减或转移相当于给系统增加了虚拟调节容量。这两样东西叠加日前调度就从单纯的机组组合问题变成了包含源、荷、储三类资源协同的优化问题。这正是这类题目近年在论文和工程里热度很高的原因。实际写代码时风光储和DR并不是各自单独建模然后拼起来而是共享同一组功率平衡变量互相耦合——所以建模时先画清楚变量关系非常重要。2. 目标函数与约束条件的数学化把运行规则翻译成优化模型2.1 目标函数哪些成本真正需要计入日前调度的目标函数一般写成下面这种形式[ \min \sum_{t1}^{T} \left[ C_{\text{gen}}(P_t) C_{\text{OM}}(P_t^{DG}, P_t^{chr}, P_t^{dis}) C_{\text{DR}}(\Delta P_t) C_{\text{grid}}(P_t^{buy}) \right] ]具体拆开看每项成本都要考虑清楚可控机组发电成本通常用二次函数 ( C(P) aP^2 bP c ) 描述很多Matlab实现里为了用线性规划求解会用分段线性化处理这条二次曲线。运行维护成本风机、光伏、储能的运维成本常按发电量/充放电量的比例系数折算这部分很小但不能漏。需求响应调用成本不同类型的DR资源补偿价格不同。可中断负荷可能是1元/kWh可转移负荷因为要影响用户的生产流程补偿可能到2~3元/kWh。这一项决定了DR资源是不是会被优先调用。向大电网购电成本微电网和外部配网有联络线时购电按分时电价计。这也是为什么峰谷价差越大、储能和DR的价值越突出的原因。需要特别说明的是弃风弃光一般不直接进目标函数而是通过在约束中允许切除一定比例的风光出力来间接表达的。如果你把风光必须全额消纳设成硬约束那储能和DR根本来不及发挥作用模型很容易无解这不符合实际情况。2.2 约束条件少了哪一条模型都会跑出离谱结果我总结过日前调度模型能否真的可用就看下面几个约束有没有写全第一个是功率平衡约束。每个时段都要满足[ P_t^{wind} P_t^{PV} P_t^{DG} P_t^{dis} P_t^{buy} P_t^{load} P_t^{chr} P_t^{sell} \Delta P_t^{DR} ]这里最容易被忽略的是储能充放电不能同时进行以及DR调用后负荷其实是减少的符号方向别搞反。第二个是储能约束。包括充放电功率上下限、SOC递推关系、SOC日终回位约束。[ SOC_t SOC_{t-1} \frac{\eta_c P_t^{chr} - P_t^{dis}/\eta_d}{E_{\text{rated}}} \Delta t ]SOC递推公式看起来简单但离散化和充放电效率放置的位置充电时效率在分子、放电时效率在分母写错的话算出来的储能收益会严重失真。第三个是可控机组爬坡约束。很多初版代码里没有爬坡约束结果机组出力在相邻时段跳变几千千瓦物理上根本做不到。爬坡约束的典型写法是[ -R^{\text{down}} \le P_{t1}^{DG} - P_t^{DG} \le R^{\text{up}} ]第四个是DR可调用量约束。这要区分DR类型可削减负荷通常有最大削减比例比如不超过该时段总负荷的20%可转移负荷要满足全天转移电量守恒——你让用户把10点的高峰负荷挪到14点那么14点必须能多收下这些电量不能只减不加。第五个是联络线功率约束。扣除向大电网购电的功率上限。如果不设这个上限DR和储能的经济价值会大幅降低因为系统会倾向于无限从电网买电。我在跑模型时有个习惯写完所有约束后把每一条约束的名称/行数打印出来逐条核对物理意义。优化模型最怕的不是求解器收敛不了而是约束写漏了模型还能正常求解只不过结果是一堆违背物理常识的数值。3. 需求响应建模弹性负荷如何变成可计算的决策变量3.1 可削减负荷与可转移负荷是两套写法需求响应是这类模型里看起来最软的部分但恰恰是最需要精细处理的。我强烈建议把DR分成两大类分别建模不要用一个笼统变量糊弄过去。可削减负荷interruptible load指的是用户允许调度系统在特定时段切除一部分负荷切除的负荷当天不再补回来。它建模最简单[ 0 \le \Delta P_t^{cut} \le \alpha \cdot P_t^{load}, \quad \forall t ]对用户来说这是以补偿换舒适度中断适合空调、照明、部分生产线等负载。它的成本项就是削减电量乘以单位补偿价。可转移负荷shiftable load则是某一类负荷的总用电量不变但用电时间可以被移动比如洗衣机、蓄热式电锅炉、部分工业搅拌工序。约束要加一个电量守恒条件[ \sum_{t} P_t^{shift_out} \sum_{t} P_t^{shift_in} ]然后对每个时段的转移量也设一个上限防止模型把负荷任意搬移导致结果不可执行。3.2 价格型DR与激励型DR的实现区别在Matlab里实现DR还要想清楚你用的是价格型还是激励型价格型DR负荷弹性体现在电价变化后负荷自然变化一般通过价格-需求弹性矩阵描述。这种做法适合做仿真分析但不太适合作为日前优化问题的决策变量因为负荷不再是一个外部参数而是跟电价耦合的非线性关系。激励型DR调度系统直接决定调用哪部分DR资源并按调用量付补偿费。这种模式天然适合优化模型——DR调用量就是决策变量单位补偿价格就是目标函数系数。实话说真正落到MatlabYalmip这类框架里的绝大部分是激励型DR因为线性或混合整数表达式好写、求解快、结果也容易对用户解释。价格型DR更多用于后续的市场影响分析可以等基础调度模型跑通之后再做扩展。4. Matlab日前调度代码的核心框架从数据准备到求解器调用4.1 完整流程与代码架构下面给出我习惯的Matlab代码组织方式这个结构已经帮我在三个项目里快速复用过了case_study_day_ahead_scheduling/ |-- load_data.m // 读入负荷、风光预测曲线、电价 |-- build_model.m // 用Yalmip构建优化模型 |-- solve_case.m // 调用求解器并保存结果 |-- plot_results.m // 结果可视化 |-- params.m // 所有参数集中定义 -- data/ |-- load_profile.xlsx |-- wind_forecast.xlsx |-- pv_forecast.xlsx -- tariff_structure.xlsx调用关系也很直接solve_case.m先执行load_data把数据装入工作区接着执行params初始化参数结构体然后build_model生成模型变量、约束和目标函数最后调用optimize求解。为什么要把数据和模型分开因为做敏感性分析时你大概率要反复调整负荷曲线或者风电预测数据如果数据和模型混在一个脚本里那每次修改都要小心翼翼翻代码。数据文件放在外部Excel里模型代码一行都不用改只需要替换数据文件再重跑一遍。4.2 Yalmip模型表达的核心代码Matlab生态里做这种优化调度问题最方便的工具组合是Yalmip Cplex/Gurobi。Yalmip提供建模语法求解器负责真正算。下面给出build_model.m里的关键片段示意性质但结构完整可用。%% 决策变量定义 P_wind sdpvar(T, 1); % 风电出力 P_pv sdpvar(T, 1); % 光伏出力 P_dis sdpvar(T, 1); % 储能放电功率 P_chr sdpvar(T, 1); % 储能充电功率 SOC sdpvar(T1, 1); % 储能荷电状态 P_buy sdpvar(T, 1); % 向电网购电功率 P_dg sdpvar(T, 1); % 燃气轮机出力 P_dr sdpvar(T, 1); % 需求响应调用量 u_dg binvar(T, 1); % 机组启停状态看到binvar就应该意识到带机组启停的日前调度属于混合整数线性规划MILP问题。这也是为什么我建议用求解器而不是用fmincon硬解——fmincon处理整数变量非常吃力而且很容易陷入局部最优。约束部分的表达方式Constraints []; % 功率平衡约束 Constraints [Constraints, ... P_wind P_pv P_dg P_dis P_buy ... P_load - P_dr P_chr]; % 储能SOC递推 Constraints [Constraints, ... SOC(2:end) SOC(1:end-1) ... (eta_c * P_chr - P_dis / eta_d) * dt / E_rated]; % SOC上下限及日终回位 Constraints [Constraints, ... 0.1 SOC 0.9, SOC(1) 0.5, SOC(end) 0.5]; % 需求响应调用量限制 Constraints [Constraints, ... 0 P_dr 0.2 * P_load];最后是目标函数Objective sum(P_dg .* c_dg) ... % 发电成本二次曲线需先分段线性化 sum(P_dr .* c_dr) ... % DR补偿成本 sum(P_buy .* c_tariff) ... % 购电成本 sum(P_chr .* c_om_storage) ...% 储能运维成本 sum(P_wind .* c_om_wind) ... sum(P_pv .* c_om_pv); ops sdpsettings(solver, gurobi, verbose, 1, showprogress, 1); optimize(Constraints, Objective, ops);4.3 求解器选择没有一把钥匙能开所有锁求解器选型是模型能不能顺利跑通的另一个关键点。我这里给个经验总结Gurobi综合能力最强工业界用得最多。支持大规模MILPMIP gap收敛速度快。教育版有使用限制但做课程设计和一般项目完全够用。Cplex老牌求解器和Yalmip兼容性同样很好。如果你是学校实验室有正版licenseCplex是稳妥的选择。开源求解器CBC、SCIP免费但求解速度和数值稳定性差一截。模型规模在几百个变量以内可以试试变量上千且带很多整数变量时求解时间可能陡增。单纯用Matlab内置的linprog/intlinprog适合教学演示。去掉机组启停和储能同时性约束的纯线性规划版本可以用linprog跑出来但扩展性有限。我个人的底线是凡是模型里出现binvar就优先考虑Gurobi或Cplex。但要注意目标函数里的二次成本曲线如果直接用二次项问题会变成MIQP求解难度比MILP高一截。工程上更常见的做法是分段线性化把二次成本曲线分成3~5段用一组线性变量替代问题就退回MILP了求解快很多。5. 仿真案例与结果分析同样一套模型加不加DR差别有多大5.1 测试系统参数设计为了验证模型的效果我自己搭了一个算例参数细节如下方便你复现并给自己当基准测试项目参数值调度周期24h时间分辨率 1h风电装机600 kW光伏装机400 kW储能容量500 kWh / 250 kW燃气轮机200 kW爬坡限 60 kW/h负荷峰值800 kWDR类型激励型可削减负荷最大削减比例20%补偿 0.8 元/kWh分时电价峰时1.1平时0.65谷时0.25 元/kWh负荷曲线采用典型的工商业双峰形状风电预测按夜间大风、白天减小的趋势设定光伏预测则用晴天正弦模型。5.2 基准方案与含DR方案的系统性对比我跑了三个方案方案A是无储能无DR的纯风光火模式方案B是风光储能但无DR方案C是风光储能DR。结果挺有意思的方案总运行成本元弃风弃光电量kWh峰时购电kWhA风光火电48601801320B储能394045510C储能DR354530330看到三个关键变化一是储能的加入大幅削减了峰时购电因为低谷时期充电、高峰时段放电的经济套利空间实在太大储能一天就能把一部分购电成本挪走。方案B比A成本降低接近19%。二是加DR后又进一步降了10%的成本。DR最直接的贡献其实是替代了储能的一部分高峰放电职责。储能容量有限遇到晚间高峰时可能已经放空了此时DR可以补上最后一段调节缺口。三是弃风弃光量明显下降。DR在凌晨风电大发时段增加了用电相当于给风电找到了额外的消纳空间这也验证了DR作为虚拟储能的说法。成本结构拆分还有一个细节值得注意方案C的DR补偿成本虽然增加了920元但购电成本下降了约1500元抵消之后净收益仍有600元左右。这说明DR并不是省了但没省多少的概念它确实能把峰谷价差的红利吃进系统里。5.3 储能SOC曲线的典型形态把方案C的SOC曲线画出来看典型形态会很清晰0点到6点低电价夜间风电大储能顶着功率上限充电SOC从0.3爬到0.8左右8点到11点光伏出力上升、电价进入平段储能停止充电SOC基本平走下午高峰时段SOC迅速下降储能在16到20点持续放电22点之后SOC已经回到低位为第二天的充电腾出空间。这条曲线如果出现锯齿状上下波动多半是约束出问题了比如没限制同时充放电、SOC上下限写错这是排查结果时最直接的检查依据。6. 实操中的坑与细节优化跑通模型之后的六个问题6.1 SOC初值与日终回位的处理技巧很多人的模型跑出来储能会偷懒原因就出在SOC初值设置上。如果你把SOC初值设成0.9并把日终回位也设在0.9那储能一天下来的总充放电量空间只有很小一段调度模型自然不敢多用储能。我建议的做法是初值设在中位0.5同时加一个日终回位约束如要求SOC(24)在0.4~0.6区间这比强行固定SOC(24)0.5更合理给优化器留一点余量如果做连续多日滚动调度则把前一天算出的SOC末值直接作为下一天初值传入不能每天无脑重置0.5。6.2 可转移负荷电量守恒实现时的线性化细节可转移负荷的电量守恒约束本身是线性的但工程现实更复杂用户的负荷不是在任何时段都能接受转入。比如某些时段就算电价更低用户也接不了电因为产线没人看守。所以我在模型里额外加了一个可转入时段集合% 只有允许的时段才能转入负荷 for t allowed_transfer_in_hours Constraints [Constraints, ... 0 P_shift_in(t) P_shift_max]; end for t setdiff(1:T, allowed_transfer_in_hours) Constraints [Constraints, P_shift_in(t) 0]; end这个约束看起来微不足道但它直接决定了DR结果能不能真正执行。如果忽略它模型会建议把负荷转移到半夜2点理论上成本最优但实际没有哪个用户愿意配合。6.3 风光出力的弃置建模什么时候该用软约束初学者喜欢写死约束P_wind P_wind_forecast意思是风电预测多少就必须发多少。这在模型里确实简单但实际调度时由于系统消纳能力有限弃风弃光才是常态。强制全额消纳会导致两个问题一是模型可能无解。凌晨风电大发、负荷低谷、储能已满、又没法向外卖电时功率平衡根本没有可行解。二是就算凑出解成本也会因为大量储能损耗而膨胀结果不可信。我推荐用软约束的写法让风电出力在0到预测值之间可调把弃风量作为结果统计项而不是直接禁掉% 风电/光伏可以在预测值以下任意调节 Constraints [Constraints, 0 P_wind P_wind_forecast]; Constraints [Constraints, 0 P_pv P_pv_forecast]; % 弃风弃光量 预测值 - 实际出力事后统计 curtailment_wind P_wind_forecast - value(P_wind);这样既保留了模型的可行性又能从结果里看出系统在哪些时段消纳压力最大还能进一步分析储能扩容或DR扩大的收益空间。6.4 求解器数值问题量纲一定要统一这是个看起来低级、但几乎每个初次实现者都会踩的坑。目标函数里的成本系数用元/kWh储能容量用kWh但功率是kW时间步长是h这三者组合起来的单位经常算错。我建议全模型统一基准值比如功率统一用kW能量统一用kWh成本统一用元时间步长统一用h。如果模型里出现了MWh和kW混用的情况Cost项就会大出1000倍目标函数的梯度完全失真求解器最终给出的最优解也会偏离物理实际。调试时可以先看算出来的总成本量级是否合理比如一个几百kW的微电网日运行成本一般在几千到一万多元突然蹦出上百万就说明单位或系数出问题了。6.5 用确定性场景起步再逐步加不确定性现在的毕业论文和课题普遍喜欢把风光不确定性也放进来做鲁棒优化或随机优化。我建议初学者不要一上来就叠这个buff。原因是确定性的日前调度问题本身已经把源、荷、储、DR的所有逻辑串起来了如果你连确定性问题都调不出合理结果引入不确定性只会让你分不清问题到底出在建模还是场景生成上。正确路径是先跑通确定性MLP模型确认成本量级、SOC曲线、DR调用量都合理再加不确定性分析比如用多个风光场景做随机优化最后对比确定性方案与随机方案的期望成本差异作为结论输出。只有走到第2、3步才算真正把调度从仿真推进到可靠性评估层面。6.6 结果可视化的三个必要图我每次做完一个算例必画下面三张图这能帮你在汇报时省掉大量口头解释第一张是功率平衡堆叠图风电、光伏、储能充放电、购电、负荷、DR削减量都画在同一张图里可以直接看出每个时段的供给来源与负荷构成第二张是SOC曲线图确认储能行为是否合理第三张是成本累积曲线各成本项随时间累积的走势能直观展示DR和储能分别在哪个时段贡献了最大收益。这三张图画完哪怕别人不看你的数学公式也能理解你的模型比传统方案好在哪。最后说点实在的我实际跑这类模型的最大体会是代码常不是瓶颈模型意识和数据质量才是。Matlab代码部分Yalmip语法半天就能上手真正花时间的是反复推敲约束条件是不是完备、数据曲线是否可信、结果是否具备物理解释力。这套模型后续还有几条很自然的扩展路线把风光出力的不确定性场景由确定性改为多场景随机优化、将DR从单体聚合改为多用户聚合、把优化周期从日前延伸到实时滚动修正甚至和碳交易成本结合起来做双碳目标下的调度。每条路线的核心框架都以本文这套Matlab实现为基础改目标函数和约束条件即可。希望这篇文章能让你少走几步弯路把时间花在真正值得深挖的问题上。