電價(jià)機(jī)制的家庭能量管理策略優(yōu)化:從MILP建模到MATLAB實(shí)現(xiàn))
獨(dú)立做這個(gè)“MATLAB下基于分時(shí)電價(jià)機(jī)制的家庭能量管理策略優(yōu)化”項(xiàng)目時(shí)我遇到最多的問題不是“模型怎么建”而是大家不知道這套東西做完到底能干什么。有人以為是讓家電自動斷電有人以為只是給儲能寫一個(gè)定時(shí)充電程序其實(shí)都不對。分時(shí)電價(jià)給家庭側(cè)創(chuàng)造了真正的“套利窗口”而家庭能量管理要做的是如何在一個(gè)有光伏、儲能、電動汽車、多個(gè)可轉(zhuǎn)移負(fù)荷的復(fù)雜場景里把每一度電的使用時(shí)刻盡量對準(zhǔn)低電價(jià)時(shí)段。MATLAB剛好是把這個(gè)過程從“拍腦袋”變成“可計(jì)算、可對比、可復(fù)現(xiàn)”的絕佳工具。這篇文章我會從機(jī)制、建模、求解、代碼實(shí)現(xiàn)、結(jié)果分析一直講到落地時(shí)容易踩的坑適合正在做畢業(yè)設(shè)計(jì)、研究生課題或者準(zhǔn)備做能碳管理方向產(chǎn)品的朋友參考。1. 分時(shí)電價(jià)機(jī)制背后的“套利空間”是家庭能量管理的經(jīng)濟(jì)驅(qū)動力1.1 峰谷價(jià)差到底能制造多少收益不先把經(jīng)濟(jì)賬算清楚后面的優(yōu)化策略很容易變成自嗨。分時(shí)電價(jià)的原則其實(shí)特別樸素電網(wǎng)在白天和傍晚用電高峰時(shí)發(fā)電側(cè)、輸電側(cè)壓力都大所以用較高的電價(jià)引導(dǎo)用戶少用電到了夜里電網(wǎng)負(fù)荷率不足發(fā)電機(jī)組又不能輕易停機(jī)于是用很低的電價(jià)鼓勵(lì)用戶把用電需求挪到谷時(shí)。這種“峰高谷低”的結(jié)構(gòu)本質(zhì)就是把稀缺的輸配電容量成本通過價(jià)格信號傳導(dǎo)給用戶。國內(nèi)很多地區(qū)的典型工商業(yè)和居民分時(shí)電價(jià)峰段價(jià)差能達(dá)到0.6元/kWh到0.9元/kWh。以常見的家庭儲能系統(tǒng)為例如果用一塊10kWh的磷酸鐵鋰電池充放電綜合效率按90%算實(shí)際一個(gè)充放循環(huán)可用的電量大約是9kWh。假設(shè)你每天晚上在谷段充電白天峰段放電用于家庭負(fù)載那么每個(gè)完整循環(huán)的價(jià)差收益大約是9×0.87.2元。如果全年這樣操作300天對應(yīng)的收益就是2160元。這個(gè)數(shù)字放到單戶家庭角度看著不多但家庭能量管理研究真正的價(jià)值在于“規(guī)模復(fù)制”和“多資源協(xié)同”。一旦家里有電動汽車每天通勤需要充10~20kWh再把空調(diào)、熱水器、洗衣機(jī)這些負(fù)荷全部納入?yún)f(xié)調(diào)單戶一年的節(jié)省達(dá)到3000~4000元并不夸張。所以家庭能量管理系統(tǒng)本質(zhì)上做的事情就是在保證用戶用電體驗(yàn)不下降的前提下通過自建儲能、光伏自消納、電器運(yùn)行時(shí)刻平移、EV充電時(shí)間重排等手段去最大化利用峰谷價(jià)差。而“策略優(yōu)化”研究的目標(biāo)就是從數(shù)學(xué)上嚴(yán)謹(jǐn)?shù)亟o出“每個(gè)時(shí)刻每臺設(shè)備應(yīng)該處于什么狀態(tài)”的最優(yōu)解而不是憑經(jīng)驗(yàn)定幾條if-else規(guī)則。1.2 先盤清楚家里有哪些“聽話”的負(fù)荷在做建模之前我建議你先把自己研究場景里的家庭負(fù)荷分一下類。不是所有電器都適合被調(diào)度有些負(fù)荷你動它時(shí)間用戶就會覺得體驗(yàn)變差。按可控程度我一般把家庭負(fù)荷分成四類負(fù)荷類型典型設(shè)備可控性調(diào)度難度與舒適度影響基礎(chǔ)固定負(fù)荷冰箱、路由器、電視、燈具基本不可控只能作為必須滿足的功率需求可轉(zhuǎn)移負(fù)荷洗衣機(jī)、洗碗機(jī)、熱水器時(shí)間可平移只需在用戶允許窗口內(nèi)完成即可可中斷/可調(diào)節(jié)負(fù)荷空調(diào)、暖氣、電熱水器狀態(tài)可周期開關(guān)或功率可調(diào)需保證溫度維持在舒適范圍內(nèi)儲能型資源家庭電池儲能、電動汽車充電功率和時(shí)間都可控放電時(shí)還可能影響出行電量需設(shè)下限這里最容易被初學(xué)者忽略的是“可轉(zhuǎn)移負(fù)荷”的建模細(xì)節(jié)。比如洗衣機(jī)程序不是簡單地允許它“任意一個(gè)時(shí)間點(diǎn)功率不為零”而是要求它一旦開始運(yùn)行就連續(xù)運(yùn)行完整的工作周期中間不能斷——更準(zhǔn)確地說一個(gè)洗衣程序包含洗滌、漂洗、脫水等階段總持續(xù)時(shí)間固定。所以優(yōu)化時(shí)要約束它的“啟動時(shí)刻”是唯一決策變量一旦啟動在后續(xù)duration_i個(gè)時(shí)間段內(nèi)都必須運(yùn)行??芍袛嘭?fù)荷則不一樣??照{(diào)在保持室內(nèi)溫度區(qū)間的過程中是可以周期性啟停的因此建模時(shí)通常用一個(gè)0-1變量表示某個(gè)時(shí)段是否開啟并另加約束相鄰時(shí)段的狀態(tài)不能變化得太頻繁或者一天內(nèi)總啟停次數(shù)不能超過設(shè)備限制。這樣既得到經(jīng)濟(jì)性最優(yōu)又不會把壓縮機(jī)和風(fēng)機(jī)折騰壞。把這些設(shè)備放進(jìn)同一個(gè)優(yōu)化問題里你會發(fā)現(xiàn)家庭能量管理不是讓電器“少用”而是讓電器“在對的時(shí)間用”。這個(gè)視角一旦建立后面所有數(shù)學(xué)約束都順理成章。2. 把“家”變成可計(jì)算對象負(fù)荷、儲能、光伏和電網(wǎng)交互建模2.1 為什么先定時(shí)間粒度和調(diào)度邊界寫代碼前我建議先冷靜想清楚一個(gè)問題你是用1小時(shí)間隔做日級調(diào)度還是用15分鐘粒度做日內(nèi)滾動優(yōu)化這會直接決定優(yōu)化模型的決策變量個(gè)數(shù)。以一天24小時(shí)、1小時(shí)間隔為例一個(gè)家庭里如果包含儲能、EV、光伏和幾臺可轉(zhuǎn)移負(fù)荷決策變量總數(shù)通常在200到300個(gè)之間MILP求解器處理這種規(guī)模非常輕松。如果改成15分鐘粒度變量數(shù)翻四倍但精度并不會提升那么多因?yàn)榧彝ヘ?fù)荷曲線本身在分鐘級的隨機(jī)波動非常大精確到15分鐘的策略未必能完美執(zhí)行。對于第一版研究我強(qiáng)烈建議先用1小時(shí)步長做完整天的確定性優(yōu)化。這個(gè)粒度足夠看清楚負(fù)荷平移、儲能充放、EV充電的經(jīng)濟(jì)規(guī)律而且畫出來的結(jié)果圖在論文或匯報(bào)中特別直觀。等這套框架跑通后再在實(shí)時(shí)控制層用15分鐘粒度做滾動修正。另外調(diào)度“邊界”也很重要。家庭能量管理系統(tǒng)通常以電表關(guān)口為邊界電網(wǎng)側(cè)看進(jìn)來是一個(gè)凈負(fù)荷。光伏出力、儲能放電、EV放電如果允許V2H都可以讓關(guān)口凈負(fù)荷下降甚至反向送電家庭負(fù)荷、儲能充電、EV充電則是關(guān)口向電網(wǎng)取電的原因。把邊界畫清楚后每個(gè)設(shè)備的功率方向不會搞混。2.2 儲能模型與避免同時(shí)充放電儲能是家庭能量管理中最靈活的調(diào)節(jié)資源它的模型也最需要仔細(xì)推敲。我用離散時(shí)間動態(tài)方程描述SOC(t) SOC(t?1) (η_ch × P_ch(t) ? P_dis(t) / η_dis) × Δt / E_bess其中SOC(t)是t時(shí)段結(jié)束時(shí)的荷電狀態(tài)P_ch(t)是充電功率非負(fù)P_dis(t)是放電功率非負(fù)η_ch是充電效率η_dis是放電效率E_bess是電池額定容量。用這個(gè)式子時(shí)單位必須統(tǒng)一如果功率用kW、時(shí)間用h那么P×Δt單位是kWh要和E_bess一致。除了動態(tài)方程儲能至少還有四個(gè)基本約束充電功率上限0 ≤ P_ch(t) ≤ P_ch_max放電功率上限0 ≤ P_dis(t) ≤ P_dis_maxSOC上下限SOC_min ≤ SOC(t) ≤ SOC_max一般鋰電池建議0.1~0.9調(diào)度周期始末SOC相等SOC(0)SOC(T)這是為了保證“今天用的電不能是昨天偷偷留下來的”讓方案具有可持續(xù)性還有一個(gè)隱藏約束新人經(jīng)常漏掉同一時(shí)刻不能既充電又放電。如果模型里有 η_ch 小于1、η_dis 小于1優(yōu)化器會聰明地讓儲能同時(shí)充放電來套利嗎答案是即使不出現(xiàn)這種“白嫖損耗”的荒唐結(jié)果在物理上也絕不允許同時(shí)充放。處理辦法是引入一個(gè)0-1變量u_bess(t)P_ch(t) ≤ u_bess(t) × P_ch_maxP_dis(t) ≤ (1 ? u_bess(t)) × P_dis_max這樣u_bess(t)1時(shí)只能充電u_bess(t)0時(shí)只能放電完美互斥而且因?yàn)榧s束全是線性的MILP可以直接處理。2.3 可轉(zhuǎn)移負(fù)荷建模連續(xù)運(yùn)行邏輯別寫錯(cuò)可轉(zhuǎn)移負(fù)荷洗衣機(jī)、洗碗機(jī)建模我見過很多同學(xué)直接用“全天某幾個(gè)時(shí)段可以運(yùn)行”來約束結(jié)果求出來的方案是“洗10分鐘停20分鐘再洗10分鐘”完全不符合物理實(shí)際。正確建模思路是用“開始時(shí)刻”作為決策變量。假設(shè)第 i 臺可轉(zhuǎn)移設(shè)備運(yùn)行持續(xù)時(shí)間為duration_i允許開始時(shí)段為[α_i, β_i]。令s_i(t)為0-1變量表示第i臺設(shè)備是否在t時(shí)段“開始運(yùn)行”。由于每臺設(shè)備一天最多啟動一次一般場景所以Σ s_i(t) 1, t ∈ [α_i, β_i]設(shè)備在t時(shí)刻是否處于運(yùn)行狀態(tài)y_i(t)可以從之前若干個(gè)時(shí)刻的啟動狀態(tài)推導(dǎo)出來。這個(gè)關(guān)系如果用矩陣形式表達(dá)會比較繞但在MATLAB里可以直接寫成一個(gè)循環(huán)填充絕對約束for t 1:T for i 1:n_app for tau 0:duration_i?1 if t?tau 1 y_i(t) s_i(t?tau) end end end end這套約束的邏輯是如果設(shè)備在t?duration_i1到t之間任何時(shí)刻啟動了那它在t時(shí)刻都必須處于運(yùn)行狀態(tài)。因?yàn)槎嗯_啟動變量互斥且時(shí)間窗約束存在倒推出來的運(yùn)行狀態(tài)自然連續(xù)。要注意的是這個(gè)寫法產(chǎn)生的約束偏多對24小時(shí)、三五臺設(shè)備來說完全夠用如果粒度變得更小可以改用開始時(shí)間位置的累計(jì)變量來壓縮約束數(shù)量。2.4 光伏的數(shù)據(jù)輸入方式光伏是家庭能量管理中典型的“看天吃飯”資源。在確定性優(yōu)化研究中通常直接用一條預(yù)測曲線P_pv(t)它相當(dāng)于家庭內(nèi)部的“負(fù)負(fù)荷”——發(fā)出來的電優(yōu)先自用用不完再賣給電網(wǎng)。但如果做實(shí)物或做魯棒調(diào)度研究就需要考慮晴轉(zhuǎn)多云時(shí)出力陡降的情況。我建議代碼里把光伏曲線單獨(dú)放在數(shù)據(jù)文件中不要寫死在程序里。后面做敏感性分析時(shí)把輸入曲線乘一個(gè)縮放在0.4到1.1之間的系數(shù)就能快速看不同天氣條件下策略的表現(xiàn)。2.5 電網(wǎng)交互買電和賣電要分開建模并加互斥家庭和電網(wǎng)之間的交互通常需要區(qū)分兩個(gè)變量從電網(wǎng)買電P_buy(t)和向電網(wǎng)賣電P_sell(t)。如果家里的光伏有“余電上網(wǎng)”政策賣電電價(jià)c_sell(t)通常會低于買電電價(jià)c_buy(t)甚至有的地區(qū)是固定上網(wǎng)電價(jià)不隨時(shí)間變化。這里有一個(gè)新手很容易踩的坑如果模型里允許同一時(shí)間既買電又賣電優(yōu)化器會干出“用1元/kWh買進(jìn)再用0.4元/kWh賣出”賠本買賣嗎它不會。但如果把某些電價(jià)政策設(shè)置成賣電電價(jià)在某時(shí)段高于買電電價(jià)它可就真的會瘋狂雙向套利。所以在建模時(shí)要么直接用互斥變量P_buy(t) ≤ M × v(t)P_sell(t) ≤ M × (1 ? v(t))其中v(t)是0-1變量M是一個(gè)足夠大的數(shù)。要么比較穩(wěn)妥地接受一個(gè)近似反正結(jié)論上賣電價(jià)低于買電價(jià)時(shí)可以不設(shè)置互斥約束優(yōu)化器自然避免賠本買賣。但誰也不能保證你的研究以后不會換一套電價(jià)參數(shù)建議一開始就把互斥約束寫上一勞永逸。3. 把“省電費(fèi)”翻譯成一個(gè)MILP問題為什么選型數(shù)學(xué)規(guī)劃而不是啟發(fā)式3.1 決策變量選取與目標(biāo)函數(shù)拆解把家庭能量管理寫成優(yōu)化模型時(shí)我習(xí)慣按“連續(xù)變量 離散變量”兩條線來列。以1小時(shí)分辨率的24小時(shí)日調(diào)度為例連續(xù)變量儲能充電功率P_ch(1:24)、儲能放電功率P_dis(1:24)、從電網(wǎng)購電P_buy(1:24)、向電網(wǎng)售電P_sell(1:24)離散變量儲能充放電互斥標(biāo)志u_bess(1:24)、每臺可轉(zhuǎn)移設(shè)備的啟動時(shí)段標(biāo)志s_i(1:24)、EV充電狀態(tài)u_ev(1:24)等目標(biāo)函數(shù)非常直觀就是最小化一天的凈購電成本min J Σ_t [ c_buy(t) × P_buy(t) ? c_sell(t) × P_sell(t) ] × Δt這里c_buy(t)和c_sell(t)是t時(shí)段的購電、賣電電價(jià)。家庭負(fù)荷的用電成本已經(jīng)隱含在P_buy(t)里儲能和EV的損耗已經(jīng)體現(xiàn)在效率系數(shù)里所以不需要額外加“用電費(fèi)用”項(xiàng)。當(dāng)然如果目標(biāo)里還要考慮電池壽命損耗可以在這個(gè)目標(biāo)函數(shù)后加一個(gè)懲罰項(xiàng)比如每次充放電單位能量折算的損耗成本c_degrad乘以充放電電量之和。這部分我在后面落地章節(jié)會詳細(xì)說。3.2 功率平衡等式模型的靈魂約束所有設(shè)備最后必須滿足一條功率平衡等式。在家庭關(guān)口處這一時(shí)刻所有流入家庭的功率等于所有流出并在內(nèi)部消耗的功率P_buy(t) P_pv(t) P_dis(t) P_load_base(t) ΣP_app(t) P_ch(t) P_ev(t) P_sell(t)公式里每一項(xiàng)都能翻譯成自然語言左側(cè)是外部和儲能供過來的總功率右側(cè)是家里所有設(shè)備和賣給電網(wǎng)的總功率。這個(gè)等式保證系統(tǒng)任何時(shí)刻不能憑空多出電也不能莫名少掉電。寫代碼時(shí)它就是一個(gè)Aeq × x beq等式矩陣24個(gè)時(shí)段對應(yīng)24行把所有變量按順序歸組、系數(shù)填1或?1。有個(gè)實(shí)用技巧這些約束行中光伏、基礎(chǔ)負(fù)荷這些輸入量屬于已知參數(shù)放在beq側(cè)決策變量全部放在左側(cè)。具體實(shí)現(xiàn)時(shí)可以先生成Aeq zeros(T, n_vars)然后逐個(gè)時(shí)段往里填。不要在循環(huán)里反復(fù)拼接矩陣預(yù)分配能快非常多。3.3 MILP為何是首選遺傳算法別隨便當(dāng)主角很多朋友一上來就想用粒子群、遺傳算法做“智能優(yōu)化”因?yàn)槁犉饋砀呒?。但我要說句實(shí)在話家庭能量管理問題本質(zhì)上是一個(gè)混合整數(shù)線性規(guī)劃目標(biāo)函數(shù)和約束條件幾乎全是線性的這種情況下MILP能用分支定界法在幾十秒內(nèi)找到全局最優(yōu)解。用遺傳算法找同一道題可能要跑幾十次才收斂到接近最優(yōu)而且每次結(jié)果還帶一點(diǎn)隨機(jī)性寫論文時(shí)“全局最優(yōu)性”這張牌完全打不出來。除非你的模型引入了非線性的儲能效率曲線、空調(diào)熱力學(xué)方程或非線性電池老化模型那時(shí)才需要考慮把問題線性化后再用MILP或者實(shí)在線性化不了再用啟發(fā)式。我的建議是第一版研究應(yīng)該先用MILP跑出一個(gè)“理想最優(yōu)解”當(dāng)作基準(zhǔn)之后如果要對比啟發(fā)式算法的性能也有一個(gè)標(biāo)準(zhǔn)答案可以參考。實(shí)際調(diào)用的MATLAB函數(shù)就是intlinprog內(nèi)置在Optimization Toolbox里不需要額外裝其他求解器。3.4 intlinprog求解時(shí)最容易翻車的細(xì)節(jié)把問題寫成MATLAB可求解的形式有幾個(gè)細(xì)節(jié)特別容易讓人抓狂。第一是intcon索引。intlinprog要求你告訴它哪些變量是整數(shù)變量傳入的是“在完整決策向量x里的下標(biāo)”。如果你把變量按順序拼成一個(gè)長向量比如x [P_ch(1:24), P_dis(1:24), P_buy(1:24), P_sell(1:24), ..., s_i(1:24*n)]那么前96個(gè)是連續(xù)變量后面跟的全部0-1變量。這時(shí)intcon應(yīng)該是97:length(x)的某個(gè)范圍。真正寫代碼時(shí)別手動數(shù)用變量分組長度動態(tài)拼接n_ch 24; n_dis 24; n_buy 24; n_bess_01 24; n_app_start n_app * 24; intcon (n_ch n_dis n_buy 1):(n_ch n_dis n_buy n_bess_01 n_app_start);第二bounds 和 0-1 變量別沖突。有些人不小心把0-1變量在 lb/ub 里已經(jīng)設(shè)成 [0,1]又額外加了線性不等式約束讓它們大于等于0這其實(shí)沒問題但會造成很多冗余約束增加求解時(shí)間。第三不可行問題定位。如果你的模型一跑就返回 infeasible不要一句“模型有問題”就卡住。實(shí)操中最有效的排查辦法是從簡單到復(fù)雜慢慢加約束。先只用儲能和功率平衡跑通再逐步加入可轉(zhuǎn)移負(fù)荷、EV、電網(wǎng)賣電等加到哪一步不可行問題就在哪一步新增的約束里。我早期做這個(gè)項(xiàng)目時(shí)因?yàn)榭赊D(zhuǎn)移負(fù)荷的窗口設(shè)置成“最晚必須在20點(diǎn)前開始”但洗衣機(jī)程序運(yùn)行2小時(shí)后和晚高峰的另一個(gè)固定負(fù)荷疊加后功率超過了關(guān)口容量上限導(dǎo)致最優(yōu)解不存在——這類沖突不逐個(gè)排查根本發(fā)現(xiàn)不了。4. MATLAB工程目錄與核心代碼實(shí)現(xiàn)套路4.1 別把參數(shù)寫死在腳本里用結(jié)構(gòu)體統(tǒng)一管理MATLAB科研代碼最常見的壞味道就是一打開腳本看到幾十行散落的T24; price...; P_load...;。這種代碼跑一次沒問題但你要做多場景對比時(shí)魔改成本極高。我會建議你把項(xiàng)目的關(guān)鍵輸入全部裝進(jìn)一個(gè)結(jié)構(gòu)體paramsparams.T 24; % 調(diào)度時(shí)段數(shù) params.dt 1; % 單位小時(shí) params.E_bess 10; % kWh params.P_ch_max 3; % kW params.P_dis_max 3; % kW params.SOC_min 0.1; params.SOC_max 0.9; params.SOC_0 0.5; params.eta_ch 0.95; params.eta_dis 0.95; params.P_buy_max 10; % 關(guān)口容量 params.P_sell_max 5; params.P_ev_max 7; % EV充電功率上限 params.EV_target 20; % EV次日所需電量kWhprice_buy zeros(24,1); price_buy(1:7) 0.42; % 低谷時(shí)段 price_buy(8:10) 1.12; % 早高峰 price_buy(11:17) 0.75; % 平段 ... params.price_buy price_buy; params.price_sell 0.45 * ones(24,1); % 固定上網(wǎng)或平段售電價(jià)你可以在一個(gè)setup_params.m函數(shù)里返回這個(gè)結(jié)構(gòu)體之后仿真腳本需要什么參數(shù)都從params里取。這樣做的好處非常明顯后面做敏感性分析時(shí)寫一個(gè) for 循環(huán)每個(gè)循環(huán)改的是params.E_bess這種字段而不是到一堆腳本里去改常量的引用位置。4.2 組裝約束矩陣的通用套路用intlinprog時(shí)目標(biāo)向量f的長度由決策變量個(gè)數(shù)決定。我先說明一下完整決策向量的排列方式方便對照代碼理解x [P_ch(1:24) % 儲能充電功率 P_dis(1:24) % 儲能放電功率 P_buy(1:24) % 電網(wǎng)購電 P_sell(1:24) % 電網(wǎng)售電 u_bess(1:24) % 0-1 充放電互斥 s_app(1:n_app*24) % 可轉(zhuǎn)移負(fù)荷啟動標(biāo)志按設(shè)備逐段排 ];目標(biāo)函數(shù)系數(shù)向量 f 就很好寫了f [zeros(1,24), zeros(1,24), params.price_buy.*params.dt, -params.price_sell.params.dt, zeros(1,24), zeros(1,n_app24)];注意儲能充放電本身在目標(biāo)函數(shù)里不直接扣錢它通過功率平衡影響購電和售電所以f里對應(yīng)位置是0。接下來核心工作是構(gòu)建等式約束矩陣 Aeq 和不等式約束矩陣 A。我用一個(gè)函數(shù)build_constraints(params)來干這件事結(jié)構(gòu)大概如下function [Aeq, beq, A, b, lb, ub, intcon] build_constraints(params) T params.T; n_basic 4 * T; % 連續(xù)變量數(shù)量 n_bess_01 T; n_app length(params.app_duration); n_app_var n_app * T; n_vars n_basic n_bess_01 n_app_var;Aeq zeros(T, n_vars); % 功率平衡 beq zeros(T,1); for t 1:T idx_ch t; idx_dis T t; idx_buy 2*T t; idx_sell 3*T t; Aeq(t, idx_ch) 1; % P_ch 移到右側(cè)其實(shí)等價(jià)于左側(cè)為負(fù) Aeq(t, idx_dis) -1; Aeq(t, idx_buy) 1; Aeq(t, idx_sell) -1; beq(t) params.P_load(t) - params.P_pv(t); end ...end上面這段代碼只是為了說明思路功率平衡式左右側(cè)正負(fù)號在寫的時(shí)候一定要再推一遍否則符號反了結(jié)果會變成“越用越省”。我的建議是最后用一個(gè)小型實(shí)例手動驗(yàn)算比如把儲能、光伏都去掉只留負(fù)荷和購電看 Aeq 能否正確返回“購電量等于負(fù)荷量”的結(jié)論。4.3 儲能SOC遞推約束的矩陣寫法SOC遞推式含SOC(t?1)也就是說下一時(shí)刻的狀態(tài)和上一時(shí)刻的狀態(tài)相互耦合。這個(gè)約束同樣要寫成矩陣形式才能喂給intlinprog。整理一下SOC(t) SOC(t?1) (η_ch · P_ch(t) ? P_dis(t) / η_dis) · Δt / E_bess但等等這里有個(gè)小坑SOC(t)本身在基礎(chǔ)決策變量里其實(shí)沒有直接出現(xiàn)它是由儲能充放電功率和時(shí)間累積出來的內(nèi)部狀態(tài)。所以我們可以把SOC寫成一個(gè)輔助變量soc(0:T)加入決策向量也可以用消元方式去掉SOC變量。消元方式比較優(yōu)雅更適合代碼量少的腳本。如果用輔助變量決策變量會變長約束也更直觀。我建議精力尚可的讀者采用“含SOC輔助變量”的寫法。具體排列順序是x [P_ch(1:24), P_dis(1:24), P_buy(1:24), P_sell(1:24), SOC(0:24), u_bess(1:24), ...]這時(shí) SOC 的上下界直接寫到 lb 和 ub 中。SOC(0) 是初值SOC(24) 是末值如果有始末相等約束就在 Aeq 中加一行對應(yīng)變量系數(shù)為1和?1。構(gòu)建遞推約束時(shí)對于 t1:24寫 soc(t) ? soc(t?1) ? (η_ch·Δt / E_bess) · P_ch(t) (Δt / (η_dis·E_bess)) · P_dis(t) 0 把系數(shù)填進(jìn)對應(yīng)矩陣。這部分你只要耐心對齊好索引一次寫對就不容易出bug。4.4 用intlinprog求解并處理結(jié)果目標(biāo)、約束、邊界都準(zhǔn)備好后調(diào)用求解器非常輕松opts optimoptions(intlinprog, Display, iter, MaxTime, 300); [x_opt, fval, exitflag] intlinprog(f, intcon, A, b, Aeq, beq, lb, ub, opts);fval就是最小化后的凈購電成本exitflag 1表示收斂到全局最優(yōu)解。拿到x_opt后再從長向量里把各段變量切出來。我喜歡立刻把結(jié)果轉(zhuǎn)成結(jié)構(gòu)體res.P_ch x_opt(1:T); res.P_dis x_opt(T1:2T); res.P_buy x_opt(2T1:3T); res.P_sell x_opt(3T1:4T); soc_all x_opt(4T1:4TT1); % SOC(0)到SOC(24) u_bess x_opt(4TT2:4T2T1);之后做指標(biāo)計(jì)算和數(shù)據(jù)可視化時(shí)只和res這個(gè)結(jié)構(gòu)體打交道。保持代碼模塊化是我能給出的最實(shí)用建議之一。4.5 把電價(jià)和調(diào)度結(jié)果畫成一張好看的圖結(jié)果圖是給導(dǎo)師、評委或讀者看的第一印象。我習(xí)慣用兩種圖畫結(jié)果第一種是“功率平衡堆疊面積圖”把光伏出力、負(fù)荷曲線、儲能充放電、電網(wǎng)交互畫在同一張圖里用不同顏色區(qū)分可以看到儲能什么時(shí)候充電什么時(shí)候放電第二種是“SOC曲線電價(jià)分段背景圖”用來展示儲能策略和電價(jià)之間的跟隨關(guān)系。電價(jià)分段背景可以這樣處理figure; area(1:24, P_pv, FaceColor, [1 0.85 0.6], EdgeColor,none); hold on; ... xline(8, --, 峰段開始); xregion(8, 11); % 需要 MATLAB R2023a 以上才支持 xregion 如果版本支持不夠可以用patch畫一個(gè)半透明背景塊for k 1:2:length(edge_idx) patch([edge_idx(k) edge_idx(k1) edge_idx(k1) edge_idx(k)], [yl(1) yl(1) yl(2) yl(2)], [0.9 0.9 0.9], FaceAlpha, 0.3, EdgeColor,none) end這段代碼是示意實(shí)際運(yùn)行時(shí)記得先把坐標(biāo)范圍記下來不然patch會改變坐標(biāo)軸范圍。畫圖部分雖然不影響優(yōu)化結(jié)果但直接決定讀者能不能一眼看出“優(yōu)化策略是在谷段充電、峰段放電”的規(guī)律值得花心思。5. 別急著下結(jié)論用三組對照仿真講清楚策略價(jià)值5.1 對照實(shí)驗(yàn)怎么設(shè)才有說服力單獨(dú)看一條優(yōu)化后的功率曲線圖誰也不知道它到底好在哪里。做研究或者項(xiàng)目匯報(bào)必須有對照組。我建議至少跑三個(gè)方案方案0無優(yōu)化按用戶原始習(xí)慣用電沒有儲能、EV到家就充方案1固定時(shí)段策略儲能每天0點(diǎn)到6點(diǎn)谷段充電8點(diǎn)到11點(diǎn)/18點(diǎn)到21點(diǎn)峰段放電EV到家后固定22點(diǎn)開始充電方案2MILP優(yōu)化策略用前面構(gòu)建的優(yōu)化模型對負(fù)荷、儲能、EV聯(lián)合調(diào)度。方案1的設(shè)計(jì)要盡量貼近實(shí)際工程中常用的規(guī)則策略不讓它顯得太蠢才有對比價(jià)值。我之前見過有人把方案1設(shè)成“隨機(jī)充電”結(jié)果當(dāng)然是優(yōu)化方案完勝但這種對比別人看一眼就知道不公平。合理的固定時(shí)段策略恰恰能幫你說明“MILP優(yōu)化帶來的收益不是全靠峰谷價(jià)差躺著賺而是來自多設(shè)備協(xié)調(diào)的時(shí)序安排比固定規(guī)則又高出一截”。5.2 從曲線到指標(biāo)如何解讀優(yōu)化后的調(diào)度行為跑完仿真主要盯著幾個(gè)數(shù)字就夠了日凈購電成本、峰段購電量比例、谷段購電占比、儲能循環(huán)次數(shù)、光伏自消納率。以一戶典型居民為例假設(shè)夏季典型日基礎(chǔ)負(fù)荷峰值約4kW日用電量約30kWh光伏日發(fā)電量約20kWhEV日充電需求20kWh10kWh儲能。仿真結(jié)果可能長這樣方案購電費(fèi)用元售電收入元凈成本元峰段購電比例無優(yōu)化28.65.123.542%固定時(shí)段充放24.76.218.518%MILP優(yōu)化22.36.815.59%這個(gè)表格里的數(shù)字是我為示意編的不同電價(jià)和負(fù)荷場景數(shù)值會變但趨勢很一致優(yōu)化策略最大的貢獻(xiàn)不是把總用電量省了而是把購電行為大量遷移到谷段同時(shí)提高了光伏自消納。你去看SOC曲線通常會發(fā)現(xiàn)夜間谷段可能是“EV和儲能都在充”到上午光伏出力起來后如果負(fù)荷低光伏多余電量會存進(jìn)儲能傍晚峰值電價(jià)到來時(shí)儲能光伏一起供電把購電功率壓到很低的水平。解讀仿真結(jié)果時(shí)還有一件事值得做把MILP解出來的若干“非直觀規(guī)則”提煉出來。比如優(yōu)化器在某個(gè)場景中會選擇讓EV在中午光伏大發(fā)時(shí)小電流補(bǔ)一點(diǎn)電而不是晚上才充滿。這種小反直覺行為恰恰說明多資源協(xié)同優(yōu)化比固定規(guī)則更有價(jià)值。5.3 三因素敏感性分析價(jià)格、容量、光伏條件單日的優(yōu)化結(jié)果只能說明一天的情況。要回答“這套策略對一個(gè)家庭一年能省多少錢”這種問題就得做敏感性分析。我做的第一輪敏感性分析包含三個(gè)維度峰谷價(jià)差從0.4元/kWh到1.2元/kWh變化儲能容量從5kWh到20kWh變化光伏曲線按晴、多云、陰三種典型日縮放。實(shí)現(xiàn)代碼其實(shí)就是最外層套兩層for循環(huán)或直接用表格枚舉配置把參數(shù)寫入params然后調(diào)用同一個(gè)求解腳本把fval、SOC數(shù)據(jù)、購電數(shù)據(jù)收集到結(jié)果表里。跑完后畫出來的折線圖能非常清晰地展示“容量越大收益越高是否線性”“價(jià)差低到多少策略就失去意義”這類結(jié)論。以我的經(jīng)驗(yàn)結(jié)果通常是價(jià)差高于0.5元/kWh之后優(yōu)化收益開始明顯爬升儲能容量從5增加到10kWh時(shí)收益提升最顯著10再增加到20收益增長放緩邊際遞減效應(yīng)很明顯。做這個(gè)分析才能讓人看懂“10kWh配儲是當(dāng)前戶用市場主流”不是拍腦袋定的。6. 從MATLAB仿真到真實(shí)落地我踩過的坑和工程化建議6.1 不要再讓儲能“免費(fèi)打工”壽命損耗必須進(jìn)目標(biāo)函數(shù)前面提過MILP模型會讓儲能每天只做對自己最劃算的事。如果電價(jià)曲線的峰谷差足夠大優(yōu)化器可能讓儲能做“一天兩充兩放”上午充下午放晚上再充晚高峰再放。可問題是每一次充放電循環(huán)都在消耗電池壽命。鋰電池的循環(huán)壽命不是無限的典型的磷酸鐵鋰電芯循環(huán)壽命在4000~6000次左右日歷壽命和放電深度也會影響老化速度。如果把電池當(dāng)成“零成本”資源優(yōu)化的日套利收益看著很漂亮但實(shí)際折算到全生命周期內(nèi)頻繁深度充放可能會讓電池提前退役錢等于換了個(gè)方式虧掉。一個(gè)工程上可接受的近似做法是把每次充放電的壽命損耗成本化加進(jìn)目標(biāo)函數(shù)。假設(shè)電池更換成本是C_battery元/kWh總循環(huán)次數(shù)是N_cycle單次“全充滿全放空”的等效循環(huán)損耗成本約為c_degrad C_battery / N_cycle元/kWh比如電池系統(tǒng)單價(jià)1200元/kWh循環(huán)壽命5000次那單次深度循環(huán)的損耗大約0.24元/kWh。于是目標(biāo)函數(shù)變成J Σ [ c_buy(t)·P_buy(t) ? c_sell(t)·P_sell(t) ] c_degrad · (Σ P_ch(t) Σ P_dis(t))·Δt / 2這里的除以2是因?yàn)橐粋€(gè)循環(huán)內(nèi)充進(jìn)去的和放出來的電量基本相等求和后總量是循環(huán)吞吐量的兩倍不過如果你直接用總充電量或總放電量乘以損耗系數(shù)也可以只是系數(shù)標(biāo)定要對齊。加入這個(gè)懲罰項(xiàng)后優(yōu)化器會在“套利收益”和“電池消耗”之間自動做權(quán)衡你也會看到SOC曲線變得克制很多——不會動不動來一次深度循環(huán)。6.2 負(fù)荷和光伏預(yù)測誤差為什么開環(huán)結(jié)果往往“好看不好用”確定性優(yōu)化把所有輸入當(dāng)成已知但真實(shí)家庭的負(fù)荷曲線和光伏曲線都是“預(yù)測值”。如果早上做完日級調(diào)度后下午突然來一片云光伏出力驟降一半原定“光伏充電、支撐晚高峰”的計(jì)劃很可能當(dāng)場破產(chǎn)。對付這個(gè)問題業(yè)界標(biāo)準(zhǔn)做法是模型預(yù)測控制MPC滾動優(yōu)化不是跑一次24小時(shí)計(jì)劃就結(jié)束而是每個(gè)控制步長比如1小時(shí)都重新求解一次未來N小時(shí)的子問題只執(zhí)行第一步指令到下一個(gè)小時(shí)再基于最新量測和預(yù)測刷新計(jì)劃。在MATLAB里模擬MPC非常自然外層套一個(gè)for循環(huán)遍歷仿真時(shí)間每個(gè)循環(huán)調(diào)用intlinprog或提前在外部用YALMIP建模求解后只保留下一個(gè)時(shí)段的控制量。滾動優(yōu)化的價(jià)值在于它能把“預(yù)測誤差”和“狀態(tài)偏移”不斷修正回來。如果你在論文里只做確定性日優(yōu)化通常會被審稿人追問“你的誤差場景下結(jié)果還健壯嗎”這時(shí)拿MPC結(jié)果對比開環(huán)結(jié)果基本是標(biāo)準(zhǔn)答案。6.3 把控制指令下發(fā)到真實(shí)設(shè)備還存在“最后一公里”策略層的輸出是“每小時(shí)建議功率/開關(guān)狀態(tài)”但要真正執(zhí)行還需要本地控制器去跟智能插座、逆變器、充電樁通信。這個(gè)層面做過實(shí)際項(xiàng)目的人都知道坑遠(yuǎn)不止算法本身通信協(xié)議不統(tǒng)一空調(diào)、熱水器用Wi-Fi智能模塊儲能逆變器往往走M(jìn)odbusEV充電樁很多只開放廠商私有API要統(tǒng)一接入數(shù)據(jù)中臺需要不少協(xié)議適配工作控制延遲下發(fā)指令到設(shè)備響應(yīng)之間可能有幾秒到幾十秒的延遲所以執(zhí)行層通常需要一個(gè)小型狀態(tài)機(jī)做防錯(cuò)安全兜底無論策略怎么說都必須保證電池不過充過放、用戶手動優(yōu)先級最高、停電后設(shè)備狀態(tài)能安全恢復(fù)。我的建議是如果你目前的階段是做研究或畢設(shè)重點(diǎn)先把策略層的MATLAB框架打磨扎實(shí)如果后續(xù)想接實(shí)物可以保留一個(gè)“策略輸出接口”比如把每個(gè)時(shí)段的目標(biāo)狀態(tài)寫成一個(gè)CSV或通過MATLAB的TCP/IP發(fā)送給本地網(wǎng)關(guān)這樣模型層和硬件層解耦出問題也容易區(qū)分是誰的鍋。6.4 代碼可復(fù)用性換個(gè)電價(jià)機(jī)制或換套負(fù)荷數(shù)據(jù)得能在十分鐘內(nèi)跑起來項(xiàng)目做到中后期多組實(shí)驗(yàn)、多個(gè)電價(jià)版本、多套典型日負(fù)荷曲線并存是常態(tài)。我強(qiáng)烈建議你從一開始就嚴(yán)格區(qū)分“配置文件”、“數(shù)據(jù)驅(qū)動代碼”和“結(jié)果分析腳本”。例如把每種電價(jià)政策放在一個(gè)data/price_2025_summer.m里返回params結(jié)構(gòu)體把典型家用負(fù)荷曲線、光伏曲線也做成可獨(dú)立調(diào)用的函數(shù)。這樣當(dāng)你想換一套電價(jià)機(jī)制比如加上尖峰電價(jià)、季節(jié)電價(jià)或者換一個(gè)城市的典型負(fù)荷曲線只需要改數(shù)據(jù)文件優(yōu)化主程序完全不用動。我自己曾經(jīng)踩過的坑是第一版代碼把電價(jià)序列寫在主程序頭部后來又復(fù)制了主程序去做多場景對比結(jié)果一個(gè)數(shù)值改了另一個(gè)沒改整整浪費(fèi)兩天去查為什么結(jié)果對不上。后來吸取教訓(xùn)所有運(yùn)行參數(shù)由配置文件統(tǒng)一生成主程序只負(fù)責(zé)讀取和求解不做任何參數(shù)硬編碼?,F(xiàn)在無論做參數(shù)掃描還是換場景都是在寫循環(huán)和改數(shù)據(jù)文件再也不會把一個(gè)分支改漏。最后分享一個(gè)我實(shí)際的體會家庭能量管理這個(gè)課題難的不是intlinprog調(diào)用也不是畫圖漂亮而是把每個(gè)約束的物理意義想透再把這些物理意義準(zhǔn)確轉(zhuǎn)成數(shù)學(xué)約束和矩陣代碼。仿真里跑通一天只能證明模型沒寫錯(cuò)要真正讓人信服至少得覆蓋不同季節(jié)、不同電價(jià)、不同家庭行為的多組實(shí)驗(yàn)。第一次跑這個(gè)項(xiàng)目建議老老實(shí)實(shí)按“簡化模型 → 日級MILP → 固定時(shí)段對照 → 敏感性分析 → MPC滾動”這條路線走一遍。過程中每加一個(gè)約束就重新驗(yàn)證一次別一上來就追求把所有家電和復(fù)雜約束塞進(jìn)去一步步來結(jié)果會遠(yuǎn)遠(yuǎn)超出預(yù)期。