尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Matlab的微电网日前-日内两阶段优化调度与敏感性分析实现

基于Matlab的微电网日前-日内两阶段优化调度与敏感性分析实现 做微电网优化调度的时候最让人头疼的往往不是模型本身有多复杂而是“算完一个结果”和“结果真的敢用”之间隔着一道鸿沟。今天想聊的这个项目就是一个典型的“日前-日内两阶段优化调度”框架外加对电价、光伏、风电、负荷四个参数的独立敏感性分析全部基于Matlab代码实现。这套东西我断断续续跑了大半个月中间踩了不少坑也把很多细节理清了写出来分享给正在做微电网调度、储能优化、或者要交竞赛报告的各位希望能帮你们少走点弯路。先把这个项目能解决什么问题说清楚。微电网里接了光伏、风电、储能还要和主网进行购售电交易但光伏和风电出力天生不稳定负荷预测也不可能百分之百准确。如果只做一次性的“日前计划”到了第二天实际运行往往会偏离计划如果完全靠实时调整又容易让储能频繁充放、成本失控。两阶段调度的思路就是日前先根据预测数据做一次全局规划确定储能的充放电计划、购售电策略日内再根据超短期预测和实测数据做滚动修正把偏差掰回来。这个思路在业界和学术界都是主流非常适合处理可再生能源接入后的不确定性问题。而敏感性分析这部分很多人会忽略但它恰恰是项目价值最大的地方。电价、光伏、风电、负荷这四个参数决定了调度方案的边界条件但哪个参数对系统运行成本的影响最大储能策略在什么情况下会“质变”这些问题如果不做敏感性分析心里就没底。这套代码里对四个参数分别做独立扰动固定其他参数不变观察目标函数和决策变量的变化幅度找到系统的薄弱环节从而指导电价政策制定、储能容量配置、预测精度要求设定。下面我从整体思路、模型细节、代码实现到排查经验一步步拆开讲。1. 项目定位与整体思路拆解1.1 为什么是“两阶段”而不是单阶段优化单阶段优化就是“一锤子买卖”基于一组预测数据把未来24小时的调度计划全部排出来。这种做法的最大问题在于预测误差全部靠计划本身“硬扛”。举个例子日前预测明天中午光伏出力是100 kW实际到了第二天中午只有60 kW那么按照日前计划安排的储能放电量和购电量必然偏少系统只能临时从主网购高价电或者被迫削减负荷成本一下就上去了。两阶段调度的本质是“先定大局再修细节”。日前阶段以1小时为间隔有时候也用15分钟对全天24个时段做全局优化目标是让全天总运行成本最低同时满足所有约束。这个阶段用的预测数据是“中长期预测”精度可能只有80%左右但它决定了储能什么时候充、什么时候放什么时候多买电、什么时候少买电是一个整体框架。日内阶段则类似模型预测控制MPC每15分钟或每1小时滚动一次基于最新的超短期预测精度可以到95%以上和实际测量数据只优化未来几个小时内的决策同时尽量不偏离日前计划太远避免储能动作频繁、购售电曲线剧烈抖动。用一个生活化的类比来说日前计划就像你出门前做的旅行攻略大致确定哪天去哪个城市、住哪家酒店日内修正就像是到了当地后根据天气和交通情况临时调整打车路线但不会轻易推翻整体行程。如果把攻略做得太死遇到突发情况就抓瞎如果完全不做攻略走一步看一步又会多花冤枉钱。两阶段调度就是把“计划”和“修正”结合起来兼顾全局最优和局部应变。1.2 四个敏感性参数的选取逻辑为什么偏偏选电价、光伏、风电、负荷这四个参数做敏感性分析而不是储能效率、电池容量、联络线功率上限这些因为前四个是系统的“外部输入条件”后几个是“系统自身属性”。外部输入条件在真实运行中是不可控的电价由市场或政策决定光伏和风电由天气决定负荷由用户的用电行为决定。这些参数每天都在变而且变化幅度可能很大。系统属性则相对固定储能容量装了多少就是多少充放电效率在短期内基本不变。所以要评估一个调度策略在不同外部环境下的适应能力最有效的办法就是对外部输入参数做扰动观察系统响应。这就像测试一辆车的性能你会改变路况外部条件来试而不是拆掉轮胎换座椅内部属性来试。另外这四个参数的“不确定性来源”也各不相同。电价的不确定性来自于市场波动或政策调整光伏来自于云层遮挡风电来自于风速随机变化负荷来自于用户行为随机性。它们分别代表了市场类、气象类、行为类的不确定性覆盖了微电网面临的主要风险来源做出来之后分析视角会很全面。1.3 整体技术路线与数据流转这套代码的整体流程可以概括成五个环节数据准备、日前优化、日内修正、敏感性分析、结果可视化。数据准备阶段需要输入光伏预测出力曲线、风电预测出力曲线、负荷预测曲线、分时电价信息、储能系统参数容量、功率上限、SOC上下限、充放电效率、联络线功率上限。这些数据在代码里统一整理成列向量或矩阵方便后续调用。需要特别说明的是如果手上没有真实的微电网数据可以用典型日数据或者直接构造测试数据不影响方法验证。日前优化阶段调用求解器计算出各时段的储能充放电功率、购售电功率、SOC变化轨迹并保存为“日前计划”。日内修正阶段按时间窗滚动推进读取新预测数据以“尽量贴近日前计划”为附加目标求解当前窗口内的最优调整量然后将第一时段的控制指令下发窗口后移。敏感性分析阶段则是把所有参数恢复到基准场景循环执行“单参数扰动-重跑优化-记录结果”最后用曲线和表格展示不同参数对总成本和调度策略的影响程度。这套流程里数据传递是整个工程的“血管”。我建议从一开始就把输入数据结构化统一用结构体struct或者表格存别东一个变量西一个变量否则后面做批量循环的时候会非常痛苦。后面我在踩坑环节还会详细讲这个问题。2. 日前阶段建模与核心实现细节2.1 目标函数与约束条件设计日前阶段的目标函数我采用的是“运行成本最小化”模式核心包含三项与主网交互的购售电成本、储能充放电造成的折算损耗成本、弃风弃光的惩罚成本。购售电成本是最主要的部分计算公式是每个时段购电价格乘以购电量减去售电价格乘以售电量再累加全天。这里有个坑购电和售电不能同时发生否则就会出现“一边买一边卖”的荒谬场景。为了处理这个市场约束我引入了两个互斥的二进制变量分别表示购电状态和售电状态并强制二者之和不大于1。储能损耗成本采用充放电功率的绝对值乘以一个等效成本系数用来抑制储能过于频繁地充放因为实际运行中电池是有寿命损耗的。弃风弃光惩罚成本则是给“允许丢弃一部分可再生能源”留了一个口子保证模型在某些极端场景下有可行解而不是因为必须全额消纳而导致无解。约束条件这块最重要的几条我列一下功率平衡约束每个时段光伏出力、风电出力、储能放电功率、购电功率之和等于负荷功率、储能充电功率、售电功率之和。这是整个模型的核心等式约束。储能SOC递推约束下一时段的SOC等于当前SOC加上充电电量乘以充电效率减去放电电量除以放电效率再除以电池容量。效率参数不能省它直接决定了储能的“盈利空间”。储能运行边界充放电功率各有上限且不能同时充放用二进制变量互斥SOC保持在设定范围内比如0.2到0.9。联络线传输功率约束购电和售电功率都不能超过联络线允许的最大值。SOC始末衔接约束为了体现“日循环”特性我设定了调度周期结束时SOC不小于初始SOC相当于储能在一个周期内不能把电“偷吃”掉这在实际应用中更合理。目标函数的数学表达可以写成如下形式min ∑ [ c_buy(t) * P_buy(t) - c_sell(t) * P_sell(t) γ * (P_ch(t) P_dis(t)) ξ * (P_pv_curtail(t) P_wind_curtail(t)) ] * Δt其中 P_ch 和 P_dis 分别表示储能充电和放电功率P_pv_curtail 和 P_wind_curtail 分别表示弃光和弃风功率γ 是储能损耗系数ξ 是弃能惩罚系数。这里需要注意的是所有功率量纲统一用kW时间单位用小时最后算出来的成本单位就是元。如果是15分钟一个时段Δt要填0.25别填1这个细节我见过很多人栽跟头。2.2 二进制变量与线性化处理在Matlab里用Yalmip工具箱建模时最难处理的其实是各种“互斥逻辑”。储能不能同时充放电、联络线不能同时购售电这些都是典型的互斥约束需要引入二进制变量。以储能为例我定义了两个连续变量 P_ch 和 P_dis再配合一个二进制变量 δ_storage。充电时 δ1放电时 δ0反过来也可以只要逻辑自洽。约束写成0 ≤ P_ch ≤ δ * P_ch_max 0 ≤ P_dis ≤ (1 - δ) * P_dis_max这里有个小技巧如果你用的是Gurobi或Cplex这类支持混合整数规划的求解器可以直接这样写但如果你手上的工具箱只有 linprog纯线性规划那就麻烦了因为二进制变量带来的是混合整数线性规划MILP。这种情况下要么换用 intlinprog要么把问题做一些松弛处理但松弛之后“互斥”就不再严格成立结果可能有瑕疵。我建议直接上Yalmip加Gurobi的搭配稳定又省心后面我会细说环境配置。购售电的互斥处理逻辑类似区别在于购售电不是系统的物理设备而是市场规则。有些场景下你甚至可以通过设置“售电价永远低于购电价”来让模型自动不出现同时买卖但这个方法只在分时电价结构简单时有效。如果分时电价峰谷差很大而售电价又高于某些时段的购电价模型就可能出现“低价时段买入、高价时段卖出”的套利行为——这不是bug而是储能套利的一种形式是合理的。只是要保证同一时段不能同时买入又卖出所以互斥约束仍然需要加不能省。2.3 Matlab代码框架与关键变量说明下面这段代码是日前优化部分的骨干逻辑我做了简化重点展示变量定义和约束构建方式。我用的是Yalmip工具箱求解器选择Gurobi也可以用Cplex语法几乎一致。% 参数定义 T 24; % 时段数 dt 1; % 时间间隔单位小时 E_cap 500; % 储能容量 kWh P_ch_max 100; % 最大充电功率 kW P_dis_max 100; % 最大放电功率 kW eta_ch 0.95; % 充电效率 eta_dis 0.92; % 放电效率 SOC_min 0.2; SOC_max 0.9; SOC_init 0.3; P_line_max 200; % 联络线功率上限 kW % 预测数据示例实际从外部读取 P_pv [...]; % 光伏预测出力1x24 P_wind [...]; % 风电预测出力1x24 P_load [...]; % 负荷预测1x24 c_buy [...]; % 分时购电价1x24 c_sell [...]; % 分时售电价1x24 P_pv_hat P_pv * 0.95; % 实际可用光伏考虑损耗 % 决策变量 P_buy sdpvar(1, T); % 购电功率 P_sell sdpvar(1, T); % 售电功率 P_ch sdpvar(1, T); % 储能充电功率 P_dis sdpvar(1, T); % 储能放电功率 SOC sdpvar(1, T1); % 荷电状态比功率多一个点 delta_storage binvar(1, T); % 储能充放电互斥二进制 delta_grid binvar(1, T); % 购售电互斥二进制 % 约束集合 C []; C [C, SOC(1) SOC_init]; for t 1:T % 功率平衡 C [C, P_pv_hat(t) P_wind(t) P_dis(t) P_buy(t) ... P_load(t) P_ch(t) P_sell(t)]; % 储能递推 C [C, SOC(t1) SOC(t) (eta_ch * P_ch(t) - P_dis(t) / eta_dis) * dt / E_cap]; % 储能边界 C [C, 0 P_ch(t) delta_storage(t) * P_ch_max]; C [C, 0 P_dis(t) (1 - delta_storage(t)) * P_dis_max]; C [C, SOC_min SOC(t1) SOC_max]; % 购售电边界 C [C, 0 P_buy(t) delta_grid(t) * P_line_max]; C [C, 0 P_sell(t) (1 - delta_grid(t)) * P_line_max]; end % 周期末SOC回收约束 C [C, SOC(T1) SOC_init]; % 目标函数 objective sum((c_buy .* P_buy - c_sell .* P_sell ... 0.02 * (P_ch P_dis)) * dt); % 求解 ops sdpsettings(solver, gurobi, verbose, 0); optimize(C, objective, ops); % 提取结果 P_buy_opt value(P_buy); P_sell_opt value(P_sell); P_ch_opt value(P_ch); P_dis_opt value(P_dis); SOC_opt value(SOC);这里的 sdpsettings 里 verbose 设为 0 是为了不让求解器刷屏调试时可以设成1能看到求解进度。初始步数多的时候Gurobi的日志能看到gap下降过程比较有参考价值。还有一点SOC(1) 对应0点的初始荷电SOC(T1) 对应24点的荷电维度上比功率多一个建模的时候容易搞错索引建议在代码旁边加注释标注清楚哪个变量对应哪个时刻。3. 日内阶段滚动修正与两阶段衔接3.1 日内修正的出发点很多第一次接触两阶段调度的人会问既然日前已经优化出全天计划了为什么日内还要再算一次直接用日前计划不就行了问题的关键在于预测误差。日前用的光伏预测是前一天做出的第二天云一来预测可能就偏了30%负荷的日前预测也常常在高峰时段低估。如果坚持使用日前计划储能可能因为SOC不够而无法应对突发事件或者光伏突然多发了、储能还在按原有计划充电导致弃光。日内修正就是干这个用的。日内修正的典型做法是滚动时域优化我在代码里采用了1小时滚动、4小时预测时域的配置相当于在每一个新时刻基于最新的超短期预测重新求解未来4小时的调度策略但只执行第一时段的决策然后下一时刻窗口继续往前推。这样既利用了超短期预测的高精度又不至于因为计算耗时太长而丧失实时性。3.2 与日前计划的偏差惩罚机制日内模型在结构上跟日前模型基本一致但目标函数里多了一项“对日前计划的偏差惩罚”。这个设计非常重要如果没有这一项日内优化很可能为了追求局部最优而让储能大幅偏离日前计划的SOC轨迹结果就是所有时段都在大幅度调整设备出力虽然单个时段看起来是“最优”的但整个系统在设备层面缺乏稳定性储能和联络线的磨损也大。我在目标函数中加入的偏差项是这样的形式λ_soc * (SOC(t) - SOC_dayahead(t))² λ_grid * (P_grid(t) - P_grid_dayahead(t))²其中 λ_soc 和 λ_grid 是权重系数P_grid 是购售电净功率购正售负。权重系数我建议调成比运行成本项小一个数量级让模型“优先保证成本最优其次兼顾计划稳定”否则修正性能被牺牲太多。实际调参时我试过 λ_soc 取0.1、λ_grid 取0.05效果比较平衡。如果发现日内结果和日前计划差异太大就调大系数如果发现SOC轨迹虽然稳定但总成本明显上升就调小系数。这里需要说明一下二次项平方项会让模型变成二次规划QPGurobi和Cplex都能直接处理但如果你用的是纯线性规划求解器可以把它近似成绝对值项λ * |SOC(t) - SOC_dayahead(t)|然后用引入辅助变量的线性化方法处理。实际效果差不多但求解速度更快。3.3 滚动窗口的数据更新方式滚动优化的代码实现核心是“循环”。下面是我在Matlab里写的一个简化滚动流程for k 1:T_roll % 当前时刻 k % 获取未来 H 时段的预测数据超短期 P_pv_pred P_pv_ultra(k:min(kH-1, T)); % 其他预测数据同理 % 构建日内滚动优化模型约束条件继承当前实际状态 % 例如 SOC 初值取上一个时刻实际SOC而不是日前计划的SOC % 求解 optimize(C_IN, objective_in, ops); % 只执行第一个时段的决策 P_grid_actual(k) value(P_grid(1)); P_ch_actual(k) value(P_ch(1)); % 更新系统实际状态 SOC_actual(k1) SOC_actual(k) ...; end滚动里面最容易出错的地方是“预测数据的取数范围”和“窗口边界的推进方式”。如果你在第k时刻要用未来4小时的数据预测序列的索引就是 k 到 k3但实际执行只执行第k时刻执行完以后把系统状态更新到第k1时刻然后进入下一轮循环。这个逻辑看起来很简单但涉及数组切片和状态传递稍不注意就会“越界”或者“索引对不上”。我建议单独写一个“状态更新”函数把储能递推、实时功率平衡都放在里面减少主循环体的复杂度。另外日内阶段获取“当前实际状态”时切记不要直接用日前计划的SOC值而要根据上一个时段的实际充放电功率更新SOC这样才能真正把“反馈校正”的思路落地。很多初学者在这里偷懒直接用计划值那日内修正就名存实亡了。4. 四参数敏感性分析的完整方案4.1 敏感性分析的实验设计与实现流程敏感性分析的目的是回答一个问题当某个外部参数发生变化时系统的优化结果会发生多大变化为了单独“提取”每个参数的影响我采用的是标准的单因素扰动法以某一组典型数据为基准场景固定其他三个参数不变只把目标参数乘以一个扰动系数0.7到1.3步长0.1重新跑一遍完整的“日前-日内”两阶段优化记录目标函数值总运行成本、储能充放电总电量、平均购电价、弃风弃光率等关键指标。四个参数都这样跑完就得到四组“参数-指标”关系曲线。这套实验设计看起来简单但有几个细节必须注意第一扰动系数是对“整条曲线”做缩放还是对“每个时段”做独立扰动我选择的是前者即整条光伏曲线乘以0.8模拟的是“辐射量整体下降”的场景如果要做“云层遮挡导致午间短时骤降”的场景就需要对特定时段扰动那是另一种实验设计。做报告时一定要写清楚否则结果会出现认知混淆。第二电价扰动比较特殊不能简单整条乘以一个系数。电价是和分时结构强相关的现实中的电价变化更多是“峰谷比变化”或者“整体价格水平变化”。我做了两种扰动一种是整体缩放0.8倍、0.9倍、1.1倍、1.2倍模拟市场化改革导致的整体价格波动另一种是峰段电价单独扰动谷段电价不动模拟尖峰电价政策。这两种扰动方式的结论往往不同整体缩放主要影响成本绝对值峰段电价扰动则会影响储能“低充高放”的套利积极性。第三记录结果的数据结构要统一。我在代码里用一个 table 来存放敏感性分析的中间结果每一行对应一个扰动系数每一列对应一个输出指标。这样画图的时候直接调用即可不用反复从工作区找变量。建议格式如下扰动对象扰动系数总成本(元)储能放电总量(kWh)平均购电价(元/kWh)弃光弃风率(%)基准1.03264.54860.4122.3电价0.82712.34500.3982.1光伏0.83568.75300.4214.8针对这类数据我会在画图时用两条线一条是总成本变化曲线另一条是成本变化百分比曲线。后者更直观可以直接比出“哪个参数对成本影响最大”。4.2 电价敏感性分析与储能套利行为电价的敏感性分析是最有意思的。因为电价直接决定了储能“低买高卖”套利是否划算。当电价整体水平提高时总成本上升是必然的但储能放电总量不一定是单调变化的。我跑出来的典型结果是电价整体从0.8倍抬升到1.2倍时储能放电总量呈现先增后稳的趋势。原因是电价低时充放价差小储能套利赚不了多少钱系统更倾向于直接用市电电价升高后峰谷价差变得更有吸引力储能就被激活了多充多放但电价再继续升高到某个阈值后储能的充放电主要受到功率上限和SOC边界约束放电量就不再明显增加了。这个“阈值效应”如果不做敏感性分析你是很难直观想到的。还有一种情况值得注意如果只把峰段电价调高而谷段电价不动储能的放电高峰时段会往后移动或者集中在峰段。这种“跨时段套利”的响应行为直接影响到配电网侧的负荷峰谷形态。做敏感性分析时建议把每个扰动场景下的储能SOC曲线叠加画在一张图上能很清楚看到策略迁移的过程。4.3 光伏与风电敏感性分析的差异对比光伏和风电虽然同属可再生能源在做敏感性分析时表现出来的特征差异很大。光伏出力具有明显的“时间同步性”——中午出力大早晚约等于零。所以光伏出力整体下降时系统主要受影响的是午间时段的功率平衡。因为午间原本可以靠光伏多发电、少购电甚至有余电卖出光伏一旦下降午间购电量立刻上升总成本响应非常灵敏。但有意思的是如果光伏出力上升系统反而可能增大弃光率因为储能和联络线都有限度多余的光电只能放弃。这时候敏感性曲线会出现一个“平台段”光伏再增加成本几乎不变因为成本瓶颈已经被储能容量和联络线容量卡住了。风电的特性和光伏不一样风电出力的“削峰”和“填谷”作用比较随机一天24小时都可能有大风或小风。风电出力减少时系统面临的是全天候的供电压力储能需要更早地充电、更晚地放电SOC曲线整体会变得“紧绷”。风电的敏感性分析曲线通常没有光伏那种明显的平台段而是近似线性这是因为风电对全天各时段的贡献相对均匀不像光伏那样集中在特定时段。这两组曲线的对比能说明一个很实际的问题系统对光伏参数的瞬态变化更敏感对风电参数的持续变化更敏感。如果要做预测精度投资应该优先提高午间时段的辐射预测精度如果想提升系统抗风风险能力则需要留出更充足的储能备用。4.4 负荷敏感性分析与系统薄弱环节识别负荷参数的变化反映的是用户用电行为的变化。负荷整体放大时系统势必要增加购电或者增加储能放电。但在分时电价下负荷增加的时段不同系统响应也不一样。如果负荷增加发生在谷段比如电动汽车夜间充电需求增加系统可以用很便宜的电来满足成本增加幅度较小。但如果负荷增加发生在峰段比如夏季空调负荷猛涨系统被迫在峰段高价购电或者把储能放电量提前耗尽成本增加幅度会非常大。敏感性分析时不应该只对整条负荷曲线做统一缩放还应该做“时段局部扰动”——只把峰段负荷提高10%、只把谷段负荷提高10%分别观察总成本变化。这样能找到系统的“压力测试”场景。我在实际项目里发现一个规律负荷敏感性曲线的斜率在峰时段系数大于1.0以后会明显变陡说明系统在高负荷场景下的成本压力是超线性的。原因在于峰段高价购电和储能容量饱和同时发生系统的调节手段捉襟见肘。这种识别结果在后续做需量管理、需求响应项目时非常有参考价值。4.5 结果综合对比与关键结论提炼做完四组敏感性分析之后我习惯用一张综合对比表把所有结果汇总在一起核心指标是“参数变化±20%时总成本的变化幅度”。按敏感性从高到低排序通常是电价 负荷 光伏 风电但这个排序在不同电价结构、不同储能配置下会发生变化。我跑的一个典型算例结果是电价扰动±20%引起总成本约±16%的变化负荷扰动±20%引起约±12%的变化光伏扰动±20%引起约±5%的变化风电扰动±20%引起约±4%的变化。这个结果说明在这套参数下系统对市场价格波动最敏感对风电出力波动相对最不敏感。但也正是这种“不敏感”才更值得警惕——一旦超过某个阈值风电的断崖式下降可能导致系统失去平衡因为常规调节手段已经用尽。这种分析的价值在于它能把“拍脑袋觉得重要”的参数真正排出来一个优先序。比如如果你预算有限只能在光伏预测和负荷预测上选一个提高精度那敏感性分析会告诉你选负荷预测如果你在和售电公司谈电价合同你也会知道自己能承受多大的电价波动范围。5. 常见问题与排查技巧实录5.1 求解器选择与运行环境配置Matlab里做优化调度我最推荐的工具组合是 Yalmip 建模工具箱加 Gurobi 求解器其次才是 Cplex 和 intlinprog。Yalmip本身不是一个求解器它是一个建模语言层让用户用类似自然语言的方式描述优化问题然后自动转换成求解器能识别的格式。安装时最容易踩的坑是路径设置不对。Yalmip下载解压后要在Matlab里面“Set Path”把文件夹加进去Gurobi除了要装Python接口还要把Matlab接口文件夹也加到路径里并配好许可证文件。如果你没有Gurobi的学术许可证用 intlinprog 也能求解小规模问题但速度会慢不少。对于24时段的模型还好一旦扩展到96时段或者加入多场景intlinprog 可能几分钟都算不完而 Gurobi 只需要几秒钟。此外还有一个常见问题Yalmip 有时会自动选择求解器但默认选的不一定是你想要的。所以在 sdpsettings 里一定要显式指定 solver比如sdpsettings(solver,gurobi)否则可能悄悄用了linprog而报错特别是含有二进制变量的模型linprog根本解不了。5.2 模型无解或结果异常的排查思路两阶段模型里最麻烦的就是“无解”。我遇到过的无解原因主要有三类第一类是约束矛盾。比如SOC初始值设了0.3但区间下限设了0.5这直接无解或者SOC(T1) SOC_init 这个约束和SOC上限冲突在极端条件下也可能无解。排查方法是先用optimize返回的solvertime和solve退出码如果退出码不是0再用checkset(C)检查哪些约束不满足。这个方法能定位到具体是哪条约束导致无解非常实用。第二类是数值问题。储能容量是500 kWhSOC约束是0.2到0.9对应的电量范围是100到450 kWh量级在百级而购售电功率可能是2 MW量级在千级两者相乘之后再放进约束里矩阵条件数会变差。解决办法是对所有变量做归一化或者把单位统一后再建模。我一般把功率单位统一用MW、能量单位用MWh成本单位用万元这样数值范围比较友好。第三类问题是“看起来有解结果却不符合常识”。比如储能既不充电也不放电明明有分时电价差也完全不套利。这个大概率是目标函数漏了储能损耗项的同时又把充放电效率设得太低导致“存1度电只能放出0.85度还要被算上损耗”经济上就不划算了。如果希望储能被激活把损耗系数调小或者把峰谷价差调大再观察结果。5.3 敏感性分析批量循环时的效率优化敏感性分析需要反复调用优化模型每次重跑一次优化。如果不做优化循环80次4个参数每个参数6个扰动级别加上基准场景大约25次其实还好但如果你把时间粒度降到15分钟、96个时段每次求解可能需要几秒到十几秒加起来就非常慢了。我的做法是在批量循环之前把所有模型常量预先算好不要在每次循环里重复初始化Yalmip对象循环内部只修改变量的参数不重复创建整个模型每次求解后清空旧的sdpvar对象用assign给变量赋初值做热启动。热启动对MILP求解很有帮助Gurobi可以利用上次的解作为初始可行解大幅缩短求解时间。另外循环里尽量用预分配的矩阵存结果不要在循环体内动态增加矩阵维度Matlab在动态扩维时真的慢到让人抓狂。5.4 结果可视化与报告输出技巧敏感性分析的结果我通常用两种图来展示第一种是总成本随扰动系数变化的折线图四组参数画在一张图上纵轴用百分比表示成本变化率一眼就能看出敏感性排序第二种是选定某个参数扰动到0.8倍和1.2倍时储能SOC和购售电功率的时序对比图用来展示策略层面的响应。画图的时候有个小建议把不同参数的曲线用不同线型区分同时加粗基准点扰动系数1.0处的标记。这样报告里截图出来即使黑白打印也能分清谁是谁。输出表格时如果用的是Matlab的table可以直接用writetable导出CSV或Excel再导入Word或LaTeX里排版比自己手动做表靠谱得多。最后再分享一个我自己的习惯跑敏感性分析时我会把基准场景的结果单独存成一个mat文件每次扰动场景跑完自动加载基准场景数据做对比。这个习惯帮我避免了很多次“改了参数却拿错基准”的低级错误。做这类项目数据管理比建模能力更影响最终产出质量。两阶段优化调度加四参数敏感性分析这套方案我从头到尾用Matlab完整实现了一遍整体跑通后最大的感受是模型本身并不神秘难的是把每个细节做扎实——二进制变量别漏、单位别混、索引别错、批量循环别偷懒、报告图表别糊弄。其中任何一个环节出了小问题结果都会差之毫厘谬以千里。如果你正在做微电网相关的竞赛、课题或者工程方案我建议按这个框架先搭一套基准场景再逐项增加细节不要一上来就追求复杂的模型先把日前的24时段模型算通再扩展日内滚动最后加敏感性分析每一步都能有清晰的验证结果项目推进起来会踏实很多。
返回列表