多場景分布魯棒優(yōu)化調度方法)
先聊一個真實調度場景早上8點預測下午3點風大你按這個預測排好了機組出力結果到了2點半風突然變小電鍋爐還在滿功率吃電儲熱罐可用熱量又快見底這時候再調整機組爬坡已經來不及了。做電熱綜合能源調度的人多少都經歷過這種“預測一時爽調度兩行淚”的時刻。純靠點估計做決策遲早被不確定性教做人但完全按最壞場景規(guī)劃成本高得離譜電廠和熱網公司都接受不了。于是這些年“數據驅動 分布魯棒優(yōu)化”這套思路越來越熱核心就是利用歷史數據構造場景再在場景周圍留一個“模糊集”來兜底最終在“經濟性”和“魯棒性”之間取一個可調的平衡點。這篇文章圍繞多離散場景分布魯棒Distributionally Robust Optimization, DRO方法聊聊怎么在電熱綜合能源系統(tǒng)里落地一套完整的Matlab調度程序。我會從問題建模、不確定性處理、模糊集構造、對偶轉化、代碼框架到踩坑實錄全部過一遍適合正在做綜合能源調度、園區(qū)能源管理相關課題的研究生以及想從確定性優(yōu)化轉向魯棒優(yōu)化的工程師參考。1. 先把問題說透電熱綜合能源系統(tǒng)為什么難優(yōu)化1.1 電和熱兩種能量耦合不是兩套獨立系統(tǒng)電熱綜合能源系統(tǒng)之所以讓人頭疼是因為電、熱本身就是強耦合的。典型園區(qū)系統(tǒng)里主要有這么幾類設備熱電聯(lián)產機組CHP這是電-熱耦合的核心。抽汽式CHP的發(fā)電量和供熱量必須在可行域內聯(lián)動發(fā)多了電往往熱也會多靈活性受限。電鍋爐EB把電轉化成熱相當于給系統(tǒng)增加了一條“電轉熱”的靈活路徑但它本質上是負荷會增加電網購電壓力。儲熱罐TES儲熱罐是解耦電-熱“強綁定”的關鍵緩沖裝置熱負荷高峰時放熱熱負荷低谷時充熱相當于給系統(tǒng)提供一個時間維度上的平移能力。常規(guī)火電/上級電網購電提供電功率平衡的兜底手段。風電/光伏這里是不確定性的主要來源也直接決定了為什么要做分布魯棒。電網側需要滿足CHP發(fā)電 風電實際出力 購電 電負荷 電鍋爐耗電。熱網側需要滿足CHP供熱量 電鍋爐供熱量 儲熱罐放熱 熱負荷 儲熱罐充熱 熱網損失。問題的難點不在方程多而在于CHP 的發(fā)電和供熱捆綁在一起風電又隨機波動。一旦風電預測不準系統(tǒng)只能通過快速調整CHP或者改變電鍋爐出力來平衡但這兩者又牽動著熱力平衡牽一發(fā)動全身。1.2 三種不確定性處理思路為什么我選分布魯棒對風電出力和負荷預測誤差的處理現在主流有三條路線它們之間存在本質區(qū)別方法不確定集合優(yōu)化目標對數據的依賴保守程度確定性優(yōu)化無直接使用預測值單場景經濟最優(yōu)只要預測值最低但容易失衡隨機規(guī)劃(SAA)若干離散場景及概率場景期望成本最小需要大量場景中低依賴場景質量傳統(tǒng)魯棒優(yōu)化盒式/橢球不確定域最壞情況下成本最小只需不確定變量的上下界高過于保守分布魯棒優(yōu)化(DRO)以歷史分布為中心的模糊集最壞概率分布下的期望成本最小需要歷史數據構造場景和模糊集可調的中間水平隨機規(guī)劃的問題是你給的場景概率分布是固定的但實際風電誤差分布可能跟假設偏差很大傳統(tǒng)魯棒的問題是它只關心最壞情況凡是落在盒式集合內的可能值都按最壞結果兜底最終調度成本可能比實際最優(yōu)貴20%以上。分布魯棒走的是中間路線——只假設真實分布落在經驗分布周圍的一個“模糊集”內然后優(yōu)化最壞分布下的期望成本。當歷史數據足夠多時模糊集半徑可以收得很小結果趨近隨機規(guī)劃當數據不充分或者你對分布沒信心時可以調大半徑結果向傳統(tǒng)魯棒靠攏。這個“可調”特性在工程里非常實用因為它讓你能用一套算法框架去適配不同數據質量的項目。1.3 多離散場景這個“多”字到底指什么標題里的“多離散場景”可以拆成兩個層面理解。第一層是用有限離散場景近似經驗分布把歷史風速、歷史負荷誤差數據通過聚類或者采樣歸納成幾十個代表性場景每個場景對應一組24小時的風電出力曲線。這樣隨機變量就從“連續(xù)分布”退化為“帶概率權重的離散點集”計算規(guī)??煽?。第二層是模糊集也按離散場景構造分布魯棒優(yōu)化不需要顯式描述連續(xù)分布而是以“這些離散場景組成的經驗分布”為中心向外擴一個半徑為alpha的距離球通常是Wasserstein距離。只要真實分布沒有超出這個球最壞情況下的期望成本就在模型掌控范圍內。這種“離散場景 模糊球”的組合既保留了隨機規(guī)劃對場景信息的利用又繼承了魯棒優(yōu)化對不確定性的兜底能力是這個方向近幾年成為熱點的關鍵。2. 分布魯棒優(yōu)化的建模與轉化怎么把min-max問題變成可求解問題2.1 先建立確定性調度主模型整套優(yōu)化模型可以表達為目標最小化系統(tǒng)總運行成本包括CHP燃料成本、向上級電網購電成本、棄風懲罰、切負荷懲罰。約束電功率平衡、熱功率平衡、CHP可行域約束、電鍋爐出力上下限、儲熱罐SOC連續(xù)性約束與容量約束、購電上下限、爬坡約束等。其中CHP運行可行域是關鍵約束通常用一組線性不等式圍成的多邊形描述即滿足P_chp_min P_chp_t P_chp_maxH_chp_min H_chp_t H_chp_maxP_chp_t c1 * H_chp_t c2c3 * H_chp_t - P_chp_t c4這四個不等式基本可以刻畫抽汽式CHP的可行域。如果你的CHP是背壓式可以直接簡化為P c * H那電熱耦合更緊調度難度更大。儲熱罐模型相對簡單但要注意不能同時充放熱的約束S_t S_{t-1} eta_c * H_char_t - H_dis_t / eta_d - eta_loss * S_{t-1}0 H_char_t H_char_max * u_c_t0 H_dis_t H_dis_max * u_d_tu_c_t u_d_t 1這里的u_c_t和u_d_t是0-1變量一旦加進去模型就變成了MILP混合整數線性規(guī)劃。如果系統(tǒng)規(guī)模不大直接用YALMIP Gurobi求解沒問題如果規(guī)模大要考慮用啟發(fā)式或者滾動時域控制去壓規(guī)模。2.2 把不確定性裝進去從SAA到DRO引入風電不確定性后簡化的目標函數形式變成一個min-max雙層結構外層min是調度決策變量x機組出力、儲熱罐充放、購電等內層max是針對模糊集D中所有可能概率分布P最大化期望成本。DRO目標含義min_x max_{P in D} E_P[f(x, xi)]在“最壞的合理分布”下期望成本最小這里xi就是隨機變量比如風電誤差向量、負荷誤差向量D就是模糊集。模糊集最常見的構造方式是Wasserstein球D { P | W(P, P_hat) alpha }其中P_hat是歷史數據構造的經驗分布alpha是模糊集半徑。Wasserstein距離衡量兩個分布之間的“搬運成本”直觀理解就是要把經驗分布P_hat變成真實分布P最少需要“搬運”多少概率質量。alpha越大真實分布離經驗分布可以越遠模型越保守。工程實現中我用的是1-范數Wasserstein距離因為對偶轉化后能保持線性約束結構Gurobi和CPLEX可以直接吃下。如果上2-范數模型會帶二次約束求解器壓力明顯變大除非你確有必要我不太推薦。2.3 對偶轉化的三板斧直接求解min-max問題是不現實的實際做法是把它對偶成一個單層的min問題。以Wasserstein模糊集為例核心思路分三步第一步內層max對偶變換。在凸目標函數和凸模糊集條件下內層最大化問題可以等價地轉化為一個關于對偶變量lambda的最小化問題。這一步讓“最壞分布”消失換來的是對每個離散場景引入一組額外約束和輔助變量s_i。第二步引入場景級最優(yōu)值函數。每個離散場景xi_i都會產生一個“最壞成本”的支撐函數通過引入輔助變量s_i把對每個場景的max項線性化。第三步最終得到形如min_{x, lambda0, s_i} lambda * alpha (1/N) * sum(s_i)約束lambda 0對每個場景is_i f(x, xi_i) - lambda * d(xi_i, xi_j) 的某種線性化形式這里d是場景之間的Wasserstein距離項f是當前決策x在場景xi_i下的運行成本。這個公式寫出來可能有點抽象但在代碼里的操作其實很簡單不要自己手推全部對偶約束而是用小規(guī)模測試3個場景、3個時段去驗證對偶轉換后的目標值和暴力枚舉max結果一致。我一開始直接套大模型結果怎么都不對最后縮小規(guī)模一步步檢查才定位到是某個極端場景下的約束沒寫全。3. Matlab代碼實現從零搭一套分布魯棒調度程序3.1 代碼框架與文件規(guī)劃整個項目我分成五個文件維護結構清晰也方便復現項目目錄/ ├── main.m % 主程序入口 ├── set_parameters.m % 設備參數定義 ├── generate_scenarios.m % 歷史數據讀取 場景生成/聚類 ├── build_dro_model.m % YALMIP建模仿真 ├── plot_results.m % 結果可視化main.m 的結構就是典型的“參數-場景-建模-求解-畫圖”五段式%% main.m clc; clear; close all; % 1. 參數設置 param set_parameters(); % 2. 讀歷史風速數據生成離散場景 [scen, prob] generate_scenarios(param); % 3. 構建DRO模型并求解 [result, model] build_dro_model(param, scen, prob); % 4. 畫圖 plot_results(result, param);這里有一點值得強調場景生成和建模是解耦的。如果你后續(xù)想換數據、換聚類方法只需要動generate_scenarios這一個文件不需要碰主模型這個設計能給你后續(xù)調參省很多事。3.2 場景生成K-means聚類 拉丁超立方采樣場景生成模塊的核心目標是把大量歷史風電出力數據壓縮成幾十個代表性離散場景。我用的是兩步法。第一步拉丁超立方采樣(LHS)生成海量預測誤差樣本。為什么要用LHS而不是直接蒙特卡洛抽樣因為LHS能保證樣本點在概率空間內覆蓋更均勻同樣的樣本量下LHS構造的經驗分布更穩(wěn)定模糊集半徑alpha可以選得更小。第二步用K-means對樣本聚類取聚類中心作為代表場景按每個簇的樣本比例分配概率。聚類數N我一般取20~50之間。少于20個場景分布信息損失太嚴重模糊集半徑會被迫加大成本偏向保守多于50個場景模型規(guī)模膨脹明顯MILP求解時間會從幾分鐘漲到一個小時。核心代碼示意% generate_scenarios.m 片段 % 歷史誤差樣本: err_hist (N_hist x T) err_hist load_historical_data(); % LHS生成候選樣本 candidate lhsdesign(N_samp, T); % 將[0,1]區(qū)間的LHS樣本映射到經驗誤差分布 err_samp quantile(err_hist, candidate); % K-means聚類 [idx, C] kmeans(err_samp, N_scen, Replicates, 10); prob histcounts(idx, N_scen) / N_samp; % C就是N_scen x T的離散場景矩陣 scen C;一個容易忽略的坑聚類前要對數據進行歸一化尤其是風電和負荷量綱不同的時候。有的風電場裝機容量500MW負荷可能才50MW如果不歸一化聚類結果會完全被風電數據主導負荷誤差場景根本體現不出來。我通常對每個隨機變量單獨歸一化到[0,1]區(qū)間構造模糊集后再反歸一化回去。3.3 核心模型YALMIP寫DRO的關鍵代碼模型部分用YALMIP建模求解器接口用Gurobi或CPLEX。整個DRO模型在YALMIP里非常直白因為分布式魯棒轉化后的模型本質上是一個帶額外輔助變量的MILP。決策變量定義片段% build_dro_model.m 片段 T param.T; P_chp sdpvar(T, 1); % CHP電出力 H_chp sdpvar(T, 1); % CHP熱出力 P_eb sdpvar(T, 1); % 電鍋爐耗電 H_eb sdpvar(T, 1); % 電鍋爐供熱 P_buy sdpvar(T, 1); % 購電 SOC sdpvar(T1, 1); % 儲熱罐狀態(tài) H_char sdpvar(T, 1); % 充熱 H_dis sdpvar(T, 1); % 放熱 % 輔助變量DRO對偶變量和場景上界 lambda sdpvar(1); s_var sdpvar(param.N_scen, 1);目標函數的YALMIP寫法% 確定性成本部分 obj_det sum(param.c_fuel .* P_chp) sum(param.c_buy .* P_buy) ... sum(param.c_wind * (scen_forecast - P_wind_used)); % DRO最壞分布期望附加項 obj_dro lambda * param.alpha (1/param.N_scen) * sum(s_var); objective obj_det obj_dro;核心約束張力在場景環(huán)節(jié)。對每個離散場景is_var(i)要大于等于“當前決策在場景i下的成本 - lambda乘以場景距離調整項”。這個調整項是用來約束真實分布不能離經驗分布太遠的“軟約束”。constr []; constr [constr, lambda 0]; for i 1:param.N_scen % 提取場景i的風電出力 wind_i scen(i, :); % 該場景下的最壞成本上界簡化示意 cost_i sum(param.c_wind * (wind_i - P_wind_used)) ... % 棄風懲罰項 sum(param.c_pen * (P_load - P_supply_i)); % 切負荷懲罰項 % Wasserstein距離項簡化為場景差分的1-范數按需調整 dist_i sum(abs(scen(i,:) - scen_mean), 2) / T; constr [constr, s_var(i) cost_i - lambda * dist_i]; end注意這只是一個示意片段不同項目的目標函數、懲罰系數、場景維度差異很大代碼要根據自己系統(tǒng)的約束修改。模型組裝好后直接調求解器ops sdpsettings(solver, gurobi, verbose, 2); sol optimize(constr, objective, ops); % 檢查求解狀態(tài) if sol.problem 0 disp(求解成功); else disp(sol.info); end3.4 結果后處理與對比實驗計算結果別只看最優(yōu)成本一個數。我做這類項目時一般會畫三張圖第一張CHP、電鍋爐、購電、風電的24小時電功率平衡堆疊圖。重點看有沒有出現“CHP貼著下限運行還不得不棄風”的時段如果存在說明模糊集半徑或儲熱罐調度參數可能需要調整。第二張熱功率平衡圖疊加儲熱罐SOC曲線。這張圖能直觀看出儲熱罐有沒有起到“削峰填谷”作用。如果SOC曲線全程貼著上限或下限跑說明儲熱罐容量沒被合理利用可以考慮調整充放熱的價格參數。第三張成本對比條形圖。分別跑確定性模型、SAA隨機規(guī)劃模型、DRO模型畫出總成本再在DRO模型里取幾個不同的alpha值看成本是怎么隨著alpha增大而升高的。這張圖是論文或匯報里最有說服力的結果。我在實際項目中測下來alpha從0.05增大到0.3成本大約會上升5%-15%但系統(tǒng)的“實際失負荷小時數”會大幅下降。這個trade-off曲線建議你在匯報時重點展示比堆一堆公式更能讓導師或者甲方理解分布魯棒的工程價值。4. 調試排坑我在這個項目上踩過的五個坑4.1 對偶變量維度不匹配導致YALMIP報錯最常見的問題s_var定義成標量但場景循環(huán)里卻按向量索引使用。YALMIP對維度非常敏感一旦s_var(i)沒法索引直接報“Subscripted assignment dimension mismatch”。解決技巧在定義變量后用assert語句檢查維度assert(length(s_var) param.N_scen, s_var維度與場景數不匹配);這個檢查放在建模前能讓你第一時間定位是定義問題還是約束問題。4.2 模糊集半徑alpha不是我拍腦袋定的alpha太小模型形同虛設基本等價SAAalpha太大成本膨脹嚴重失去意義。理論上有經驗公式alpha和樣本量N的關系是alpha O(1/sqrt(N))但實際操作中我推薦交叉驗證法。把歷史數據切分成訓練集和驗證集。用訓練集構造經驗分布和模糊集求解調度決策再拿驗證集里沒參與建模的“真實場景”去回測看成本分布情況。選能覆蓋90%驗證場景不切負荷的最小alpha。這個方法雖然要多花一點時間但勝在可解釋性很強匯報時也容易被接受。4.3 熱功率平衡約束導致無解電鍋爐和儲熱罐同時參與熱平衡時很容易出現“熱量來源太多”導致熱功率過剩約束沖突無解。我排查過多次原因基本都出在儲熱罐的充放熱0-1約束沒寫完整充熱和放熱變量同時為正熱平衡被雙倍計入。一個排查技巧求解無解時先把儲熱罐的0-1約束和SOC約束單獨拿出來固定所有電出力變量只求解熱子系統(tǒng)。如果熱子系統(tǒng)仍有解再逐步加回電側約束用二分法鎖定沖突約束。4.4 場景數一多求解時間爆炸50個場景、24個時段決策變量里再帶上0-1儲熱變量Gurobi解一個MILP可能要20分鐘。后來我的處理方式是先用大場景數做預分析確定合適的alpha范圍正式求解時把場景聚類數量壓到30個左右同時給MILP設置一個相對最優(yōu)間隙(mipgap)比如5%很多情況下Gurobi能在5分鐘解決戰(zhàn)斗。實際工程決策場景下5%的間隙完全可接受花15分鐘追求0.1%的經濟提升其實意義不大。4.5 數據中心化處理不當導致模糊集失效這個坑比較隱晦。經驗分布P_hat在DRO中的位置非常關鍵一旦場景數據沒有按變量均值中心化Wasserstein距離計算出的alpha實際含義會偏離預期。解決方法是構造模糊集前的所有場景均做零均值、單位方差標準化等對偶轉化完成、得到決策結果后再把結果反標準化回實際物理量綱。我在這里吃過一次虧花了一周時間比對結果最后發(fā)現是歸一化以后忘了在距離項里乘回尺度系數導致alpha的實際幾何意義完全不對。5. 后續(xù)擴展這套框架還可以往哪走數據驅動分布魯棒這套框架的價值不局限于電熱綜合能源系統(tǒng)。我做完這個項目后發(fā)現同樣的“離散場景 Wasserstein模糊集 對偶轉化”三段式可以直接平移到很多相關問題上含氫儲能的綜合能源系統(tǒng)調度氫氣儲能的不確定性和儲熱罐很像但時間尺度更長電動汽車聚合商參與電力市場的投標策略充電行為的不確定性正好用場景描述園區(qū)級微電網與配電網的互動優(yōu)化分布式光伏出力波動比風電更劇烈分布魯棒的優(yōu)勢更能體現。如果想把項目做成真正的論文級別還可以加一套兩階段分布魯棒模型第一階段決定機組開停機和儲熱罐充放計劃第二階段在不確定性實現后做出力調整。兩階段的DRO模型更貼近真實調度流程但求解復雜度會顯著上升需要引入Benders分解或者割平面方法這是另一個值得寫一篇文章的話題了。我自己實際操作下來的體會是分布魯棒優(yōu)化最難的部分不是數學推導而是對不確定性數據的認知——你對數據越了解模糊集半徑就選得越準優(yōu)化結果也就越有說服力。如果一上來就追求復雜的模糊集和花哨的求解器反而容易忽略問題的本質。先把確定性模型吃透再把場景注入最后加模糊集兜底一步一個腳印這個方向其實沒有想象中那么高不可攀。