規(guī)劃:Python實(shí)現(xiàn)經(jīng)濟(jì)性與可靠性雙目標(biāo)優(yōu)化)
做配電系統(tǒng)規(guī)劃繞不開(kāi)一個(gè)很現(xiàn)實(shí)的沖突投資預(yù)算有限但供電可靠性指標(biāo)又年年被考核。這兩件事在多數(shù)時(shí)候是矛盾的——多上一臺(tái)聯(lián)絡(luò)開(kāi)關(guān)可靠性確實(shí)上去了但賬面上多出幾十萬(wàn)投資少裝一套儲(chǔ)能經(jīng)濟(jì)性好看可夏天尖峰時(shí)段電壓和停電次數(shù)又不好看。我這兩年一直在做混合配電系統(tǒng)的規(guī)劃項(xiàng)目逐漸摸到一套比較順手的處理方式把經(jīng)濟(jì)性和可靠性拆成兩個(gè)獨(dú)立目標(biāo)用多目標(biāo)優(yōu)化算法去跑帕累托前沿再用序貫蒙特卡洛做可靠性評(píng)估驗(yàn)證方案整套流程用 Python 串起來(lái)。這篇文章就把這套技術(shù)路線的完整實(shí)現(xiàn)邏輯拆開(kāi)講從數(shù)學(xué)模型怎么建、目標(biāo)函數(shù)怎么量化到 NSGA-II 算法怎么和配電網(wǎng)潮流計(jì)算銜接再到最后可靠性評(píng)估的代碼怎么寫(xiě)適合正在做配電網(wǎng)規(guī)劃方向課題的研究生以及想從單一目標(biāo)優(yōu)化轉(zhuǎn)向雙目標(biāo)優(yōu)化的工程師參考。1. 雙目標(biāo)規(guī)劃的源起為什么單一目標(biāo)在配電系統(tǒng)里不夠用配電系統(tǒng)規(guī)劃的經(jīng)典做法通常是先算負(fù)荷預(yù)測(cè)然后按容量滿足、電壓合格、短路電流不越限這幾個(gè)約束條件去做網(wǎng)架方案比選。這個(gè)思路本質(zhì)上是在給定可靠性水平下找費(fèi)用最低的方案也就是把可靠性當(dāng)成一個(gè)固定約束。問(wèn)題是可靠性到底定在什么水平才算合理這本身就是一個(gè)決策問(wèn)題。你把它當(dāng)成約束等于預(yù)先替決策者把答案藏起來(lái)了。我在實(shí)際項(xiàng)目里遇到的情況是供電公司通常有一個(gè)明確的可靠性考核指標(biāo)比如年戶均停電時(shí)間不能超過(guò)多少小時(shí)但規(guī)劃方案一旦涉及新增分布式電源、儲(chǔ)能這類投資較大的設(shè)備領(lǐng)導(dǎo)層就會(huì)追問(wèn)這些錢花下去可靠性到底提升了多少停電損失減少了多少這時(shí)候你拿單一目標(biāo)優(yōu)化的結(jié)果去匯報(bào)很難講清楚為什么是這套方案而不是另外一套更便宜或更可靠的方案。雙目標(biāo)規(guī)劃的價(jià)值就在這里。它把方案篩選從找唯一最優(yōu)解變成生成一組候選方案集讓決策者直觀看到經(jīng)濟(jì)性和可靠性之間的此消彼長(zhǎng)。在帕累托前沿上每個(gè)點(diǎn)都對(duì)應(yīng)一套規(guī)劃方案任何一個(gè)目標(biāo)變好都會(huì)讓另一個(gè)目標(biāo)變差。決策者可以根據(jù)財(cái)政預(yù)算或者可靠性考核壓力在前沿上挑一個(gè)偏好的落點(diǎn)。這個(gè)視角對(duì)實(shí)際工程的意義非常大因?yàn)橐?guī)劃本身就不是一次算出一個(gè)答案交差的事而是反復(fù)權(quán)衡、多方博弈的過(guò)程。1.1 經(jīng)濟(jì)性與可靠性的矛盾具體來(lái)自哪里單純從設(shè)備投資看想讓配電網(wǎng)更可靠最直接的辦法是增加冗余。多敷設(shè)一條聯(lián)絡(luò)線、多裝一臺(tái)分段開(kāi)關(guān)、多配置一套儲(chǔ)能這些都能在故障時(shí)快速轉(zhuǎn)供或支撐重要負(fù)荷但每一樣都要花錢。而分布式電源的接入更復(fù)雜一些光伏和風(fēng)機(jī)裝多了發(fā)電量能沖抵網(wǎng)損和購(gòu)電費(fèi)用經(jīng)濟(jì)性看起來(lái)不錯(cuò)但出力的間歇性可能導(dǎo)致電壓越限或保護(hù)配合問(wèn)題反而降低可靠性指標(biāo)。儲(chǔ)能則正好反過(guò)來(lái)初始投資很大但削峰填谷和應(yīng)急供電的價(jià)值在可靠性評(píng)估里能明顯體現(xiàn)出來(lái)。這個(gè)矛盾不是線性的。投資少的階段每投入一筆錢對(duì)可靠性的邊際提升很可觀但投資超過(guò)某個(gè)閾值之后再往上加錢的提升幅度會(huì)迅速衰減。這種邊際遞減特性決定了雙目標(biāo)問(wèn)題的帕累托前沿通常是一個(gè)向下凸的曲線而不是一條直線。理解了這一點(diǎn)后面看優(yōu)化結(jié)果時(shí)就不會(huì)覺(jué)得奇怪為什么帕累托前沿右半段的點(diǎn)那么密集因?yàn)樵谀且欢位ㄙM(fèi)大量投資只能換來(lái)零點(diǎn)幾個(gè)小時(shí)的停電時(shí)間改善性價(jià)比已經(jīng)很低了。1.2 混合配電系統(tǒng)的混合到底指什么這里說(shuō)的混合不是指電壓等級(jí)混合或者交流直流混合那種拓?fù)湟饬x上的混合而是指配電系統(tǒng)內(nèi)同時(shí)存在傳統(tǒng)設(shè)備與新設(shè)備、可控電源與不可控電源、交流網(wǎng)架與電力電子接口。典型構(gòu)成包括原有輻射狀配電網(wǎng)、分布式光伏、風(fēng)電機(jī)組、儲(chǔ)能系統(tǒng)可能還有少量分布式柴油發(fā)電機(jī)或燃?xì)廨啓C(jī)作為可控備用。這些設(shè)備的運(yùn)行特性差異很大光伏和風(fēng)電幾乎零邊際成本但有間歇性儲(chǔ)能響應(yīng)快但能量有限柴油機(jī)可靠可控但運(yùn)維成本和燃料成本高。規(guī)劃這類系統(tǒng)時(shí)決策變量既包含離散的設(shè)備選型與安裝位置又包含連續(xù)性的容量配置約束條件也涉及潮流、電壓、線路載流量等多個(gè)維度。數(shù)學(xué)上這是一個(gè)混合整數(shù)非線性多目標(biāo)優(yōu)化問(wèn)題如果用傳統(tǒng)的加權(quán)求和法把經(jīng)濟(jì)性目標(biāo)和可靠性目標(biāo)合并成一個(gè)單目標(biāo)會(huì)面臨權(quán)重系數(shù)怎么定、兩次求解結(jié)果如何比較等一連串麻煩。我自己的經(jīng)驗(yàn)是少吃把多目標(biāo)壓成單目標(biāo)的虧直接上多目標(biāo)進(jìn)化算法讓算法自己去探索帕累托前沿后續(xù)分析時(shí)靈活得多。2. 經(jīng)濟(jì)與可靠性雙目標(biāo)模型的數(shù)學(xué)化過(guò)程把規(guī)劃問(wèn)題寫(xiě)清楚核心是三個(gè)步驟確定決策變量、構(gòu)造目標(biāo)函數(shù)、明確約束條件。這一步看起來(lái)是純數(shù)學(xué)工作但里面很多細(xì)節(jié)直接決定后面 Python 代碼好不好寫(xiě)、優(yōu)化算法跑起來(lái)快不快。2.1 年綜合費(fèi)用如何拆分經(jīng)濟(jì)性目標(biāo)我通常用年綜合費(fèi)用來(lái)表示單位是萬(wàn)元/年。它的物理含義是把規(guī)劃期內(nèi)所有與方案相關(guān)的支出一律折算成等年值這樣不同使用年限的設(shè)備之間可以公平比較。年綜合費(fèi)用的構(gòu)成主要有這么幾塊投資等年值設(shè)備初始投資乘以等年值系數(shù)折算到每一年。等年值系數(shù)由折現(xiàn)率和設(shè)備使用壽命決定公式是 CRF r(1r)^n / [(1r)^n - 1]其中 r 是折現(xiàn)率n 是設(shè)備壽命。光伏板壽命通常取 20 年儲(chǔ)能電池有些項(xiàng)目只按 8 到 10 年算柴油機(jī)則按 15 年。算出來(lái)的結(jié)果差別挺大規(guī)劃時(shí)最好分開(kāi)細(xì)分設(shè)備算不要圖省事統(tǒng)一用一個(gè)系數(shù)。運(yùn)行維護(hù)費(fèi)用包括設(shè)備的檢修、保養(yǎng)、人工、消耗品等一般按初始投資的百分比估算。光伏取 1% 到 2%儲(chǔ)能取 2% 到 3%柴油機(jī)取 3% 以上。儲(chǔ)能這塊還要考慮電池替換成本我習(xí)慣把它單獨(dú)列成一項(xiàng)折算成每千瓦時(shí)的更換費(fèi)用避免混在運(yùn)維費(fèi)率里失真。網(wǎng)損費(fèi)用由潮流計(jì)算結(jié)果得到系統(tǒng)總網(wǎng)損電量乘以平均購(gòu)電價(jià)。分布式電源接入后系統(tǒng)網(wǎng)損可能變大也可能變小取決于安裝位置和出力曲線這屬于規(guī)劃方案評(píng)估中容易忽略的隱藏成本。停電損失費(fèi)用這是經(jīng)濟(jì)性目標(biāo)和可靠性目標(biāo)之間的橋梁。把可靠性評(píng)估算出的缺供電量乘以單位停電損失費(fèi)用就變成經(jīng)濟(jì)損失并入年綜合費(fèi)用。不過(guò)要注意如果經(jīng)濟(jì)性目標(biāo)里已經(jīng)包含停電損失費(fèi)用那可靠性目標(biāo)可以換成純技術(shù)性指標(biāo)比如系統(tǒng)平均停電持續(xù)時(shí)間或者缺供電量期望值避免兩個(gè)目標(biāo)之間的耦合過(guò)強(qiáng)導(dǎo)致帕累托前沿形態(tài)退化。這一點(diǎn)在第三章建模時(shí)需要整體想清楚。我用一個(gè)具體的模型示例來(lái)說(shuō)明。設(shè)決策變量有分布式電源的安裝位置和容量、儲(chǔ)能的功率和容量、聯(lián)絡(luò)線選擇。那么年綜合費(fèi)用可以寫(xiě)成C_total C_inv C_om C_loss C_interruption其中 C_inv Σ設(shè)備投資額 × CRFC_om 是年運(yùn)維費(fèi)C_loss 年網(wǎng)損電量 × 單位購(gòu)電價(jià)C_interruption 年缺供電量 × 單位停電損失費(fèi)用。2.2 可靠性目標(biāo)的量化從故障率到缺供電量可靠性評(píng)估的輸出指標(biāo)有很多規(guī)劃階段最常用的是期望缺供電量Expected Energy Not SuppliedEENS和系統(tǒng)平均停電持續(xù)時(shí)間SAIDI。前者單位是 MWh/年后者是 小時(shí)/戶·年。兩個(gè)指標(biāo)對(duì)規(guī)劃方案的經(jīng)濟(jì)性評(píng)估都有價(jià)值EENS 可以直接乘單位停電損失費(fèi)用折算成錢SAIDI 則更容易與供電公司的考核指標(biāo)對(duì)應(yīng)。計(jì)算 EENS 需要輸入元件級(jí)的可靠性參數(shù)主要包括饋線段的故障率和平均修復(fù)時(shí)間、開(kāi)關(guān)的操作時(shí)間、故障隔離時(shí)間和聯(lián)絡(luò)開(kāi)關(guān)的轉(zhuǎn)供時(shí)間。這些都是規(guī)劃人員從歷史統(tǒng)計(jì)中獲得的基礎(chǔ)數(shù)據(jù)不同類型線路差別很大。架空裸導(dǎo)線的故障率明顯高于電纜絕緣導(dǎo)線介于兩者之間。沿公路敷設(shè)的電纜故障率低于穿農(nóng)田的電纜因?yàn)橥饬ζ茐牡母怕什煌?。我做?xiàng)目時(shí)一般按線路類型、敷設(shè)環(huán)境分類設(shè)定參數(shù)而不是整個(gè)網(wǎng)絡(luò)用同一套故障率否則評(píng)估結(jié)果和實(shí)際差距會(huì)很大??煽啃灾笜?biāo)對(duì)負(fù)荷點(diǎn)的計(jì)算本質(zhì)上是在枚舉所有可能的故障事件及其后果。輻射狀配電網(wǎng)中某一元件故障后部分負(fù)荷可能通過(guò)聯(lián)絡(luò)線轉(zhuǎn)供部分負(fù)荷必須等待故障修復(fù)部分負(fù)荷甚至可能被隔離后無(wú)法恢復(fù)。每一類負(fù)荷對(duì)應(yīng)各自的停電時(shí)間乘以負(fù)荷功率后得到該故障事件下的缺供電量。所有故障事件遍歷完成后求和取期望就是 EENS。2.3 決策變量與約束條件的取舍規(guī)劃問(wèn)題的決策變量常用一個(gè)編碼向量來(lái)表示。針對(duì)一個(gè)候選節(jié)點(diǎn)集合每個(gè)節(jié)點(diǎn)可能安裝的光伏、風(fēng)機(jī)、儲(chǔ)能容量都從離散檔位里選比如 0 kW、100 kW、200 kW、300 kW 這樣。線路改造或新增聯(lián)絡(luò)線則用 0/1 變量表示。把這些變量拼接起來(lái)就是粒子群或遺傳算法里一個(gè)個(gè)體的完整基因。編碼設(shè)計(jì)上要注意變量數(shù)量不能太多否則搜索空間爆炸收斂變慢。約束條件除了潮流方程本身還包含節(jié)點(diǎn)電壓上下限約束通常取 0.93 到 1.07 倍標(biāo)幺值支路電流不超過(guò)載流量極限分布式電源總滲透率不超過(guò)設(shè)定閾值這個(gè)閾值根據(jù)不同網(wǎng)絡(luò)情況而定儲(chǔ)能荷電狀態(tài)在調(diào)度周期內(nèi)保持在一定范圍防止過(guò)度充放影響壽命輻射狀網(wǎng)絡(luò)結(jié)構(gòu)約束特別是涉及網(wǎng)架改造時(shí)不能讓網(wǎng)絡(luò)出現(xiàn)環(huán)網(wǎng)或者孤島。約束處理方式我常用罰函數(shù)法。把越限量加權(quán)加到目標(biāo)函數(shù)中讓優(yōu)化算法自動(dòng)淘汰不可行解。這種方法實(shí)現(xiàn)簡(jiǎn)單但罰函數(shù)權(quán)重需要調(diào)試。權(quán)重太小不可行解會(huì)混進(jìn)帕累托前沿權(quán)重太大算法探索能力下降。我一般先跑一版看輸出的方案里不可行解的比例再調(diào)整權(quán)重重新跑通常迭代兩三輪就能找到合適的量級(jí)。3. 求解方法選型為什么最終選擇 NSGA-II多目標(biāo)優(yōu)化問(wèn)題的主流解法包括加權(quán)求和法、約束法、多目標(biāo)進(jìn)化算法MOEA。這個(gè)選擇直接關(guān)系建模和代碼實(shí)現(xiàn)的難度也影響最終結(jié)果的可用性。加權(quán)求和法最容易實(shí)現(xiàn)把兩個(gè)目標(biāo)分別乘上權(quán)重 w1、w2 再相加然后跑單目標(biāo)優(yōu)化。缺點(diǎn)也很明顯權(quán)重怎么取沒(méi)有客觀標(biāo)準(zhǔn)而且如果帕累托前沿是非凸的加權(quán)法無(wú)法找到前沿中段的一些解。我見(jiàn)過(guò)不少論文用加權(quán)法算雙目標(biāo)給出的結(jié)果只有少數(shù)幾個(gè)點(diǎn)說(shuō)服力有限。約束法是把一個(gè)目標(biāo)保留為目標(biāo)函數(shù)另一個(gè)目標(biāo)轉(zhuǎn)成約束比如可靠性指標(biāo) SAIDI 小于給定值的前提下最小化年綜合費(fèi)用。這個(gè)方法技術(shù)上可行通過(guò)改變閾值可以掃出一組解但每次掃描都要重新求解一次單目標(biāo)問(wèn)題計(jì)算開(kāi)銷很大尤其在可靠性評(píng)估還嵌套蒙特卡洛仿真的情況下耗時(shí)讓人難以接受。NSGA-II 是處理這類問(wèn)題的成熟選擇。它基于遺傳算法框架一次運(yùn)行能生成整個(gè)帕累托前沿不需要預(yù)先指定權(quán)重。它的核心機(jī)制有兩點(diǎn)非支配排序和擁擠度距離。非支配排序把種群中所有個(gè)體按照支配關(guān)系分成若干層第一層是當(dāng)前的帕累托前沿第二層是被第一層中某些個(gè)體支配的剩余個(gè)體依次類推。這樣算法的選擇壓力始終朝向更接近真實(shí)前沿的方向。擁擠度距離則保證同一層內(nèi)個(gè)體的分布盡量均勻防止算法收斂到前沿的某一小段區(qū)域。NSGA-II 還有一個(gè)精英保留策略下一代種群由父代和子代合并后的最優(yōu)個(gè)體組成這意味著算法不容易丟失已經(jīng)找到的優(yōu)秀解。對(duì)于配電網(wǎng)規(guī)劃這種單次評(píng)價(jià)成本較高的場(chǎng)景精英保留能顯著提高樣本利用效率。在具體編碼上NSGA-II 的遺傳操作包括選擇、交叉、變異。選擇階段采用錦標(biāo)賽選擇法從種群中隨機(jī)挑幾個(gè)個(gè)體比較支配關(guān)系和擁擠度性能好的留下交叉階段對(duì)兩個(gè)個(gè)體對(duì)應(yīng)的變量進(jìn)行交換或算術(shù)組合變異階段則隨機(jī)擾動(dòng)某個(gè)變量值保持種群多樣性。配電網(wǎng)規(guī)劃問(wèn)題中變量離散性強(qiáng)交叉可以用單點(diǎn)或多點(diǎn)交叉算子變異則結(jié)合位翻轉(zhuǎn)變異和重新采樣的方式。這些操作在 Python 里手寫(xiě)起來(lái)并不復(fù)雜而且可控性強(qiáng)我最終在項(xiàng)目里就是全部自己實(shí)現(xiàn)的。3.1 用現(xiàn)成庫(kù)還是手寫(xiě)算法Python 生態(tài)里有多目標(biāo)進(jìn)化算法庫(kù)比如 pymoo、Platypus、DEAP。這些庫(kù)封裝得比較完善直接調(diào)用 NSGA-II 很方便。但我實(shí)際用下來(lái)發(fā)現(xiàn)一個(gè)問(wèn)題規(guī)劃問(wèn)題的評(píng)價(jià)函數(shù)耦合了潮流計(jì)算和可靠性評(píng)估而這些計(jì)算又依賴自定義的數(shù)據(jù)結(jié)構(gòu)和前推回代求解器庫(kù)自帶的接口適配需要額外寫(xiě)不少膠水代碼。與其繞一圈去適配不如把 NSGA-II 的核心邏輯自己實(shí)現(xiàn)評(píng)價(jià)函數(shù)直接調(diào)用自己的潮流函數(shù)。這樣代碼結(jié)構(gòu)更清晰調(diào)試定位問(wèn)題也更快。當(dāng)然手寫(xiě) NSGA-II 也有代價(jià)。非支配排序的經(jīng)典實(shí)現(xiàn)是 O(MN2) 復(fù)雜度M 是目標(biāo)數(shù)量N 是種群規(guī)模。規(guī)劃問(wèn)題里種群規(guī)模通常 100 到 200目標(biāo)數(shù)只有 2這個(gè)復(fù)雜度完全可以接受。如果以后要擴(kuò)展到三目標(biāo)或大規(guī)模問(wèn)題可以再引入快速非支配排序的優(yōu)化版本或者觀察是否需要上 MOEA/D。做項(xiàng)目時(shí)先跑通為主后續(xù)優(yōu)化留到有真實(shí)需要時(shí)再說(shuō)。3.2 NSGA-II 與配電系統(tǒng)評(píng)價(jià)函數(shù)的耦合方式優(yōu)化算法和評(píng)估函數(shù)之間的關(guān)系是整條技術(shù)路線的關(guān)鍵橋梁。一個(gè)個(gè)體解碼后是一套完整的規(guī)劃方案評(píng)估它需要兩步走。第一步是潮流計(jì)算。給定這個(gè)方案下的網(wǎng)絡(luò)結(jié)構(gòu)、分布式電源出力和負(fù)荷數(shù)據(jù)用前推回代法計(jì)算各支路電流、各節(jié)點(diǎn)電壓和系統(tǒng)網(wǎng)損得到經(jīng)濟(jì)性評(píng)價(jià)所需的網(wǎng)損費(fèi)用。如果潮流不收斂說(shuō)明該方案極不可行直接給一個(gè)很大的罰值。第二步是可靠性評(píng)估。用序貫蒙特卡洛模擬法輸入該方案對(duì)應(yīng)的網(wǎng)絡(luò)拓?fù)浜驮煽啃詤?shù)隨機(jī)模擬若干年的元件故障、修復(fù)和轉(zhuǎn)供過(guò)程統(tǒng)計(jì)系統(tǒng)的缺供電量和停電時(shí)間指標(biāo)。這一步是整個(gè)流程中計(jì)算量最大的部分。兩者的順序也很講究。如果潮流算法已經(jīng)判斷方案不可行比如電壓越限很嚴(yán)重就沒(méi)必要再跑可靠性仿真了直接淘汰掉省下不少計(jì)算時(shí)間。這類先粗篩后精算的流程在工程優(yōu)化里非常常見(jiàn)也是方案可行性和計(jì)算效率之間的一種平衡。4. Python 實(shí)現(xiàn)細(xì)節(jié)從數(shù)學(xué)模型到可運(yùn)行代碼這一節(jié)講代碼怎么落地。配電網(wǎng)規(guī)劃仿真代碼框架其實(shí)不復(fù)雜但細(xì)節(jié)決定成敗。我會(huì)把幾個(gè)關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)和核心函數(shù)展開(kāi)來(lái)講照著這個(gè)思路基本能復(fù)現(xiàn)出完整的代碼框架。4.1 配電網(wǎng)數(shù)據(jù)結(jié)構(gòu)的構(gòu)建配電網(wǎng)本質(zhì)上是一張有根的樹(shù)狀圖。根節(jié)點(diǎn)是變電站出口母線其余節(jié)點(diǎn)是負(fù)荷節(jié)點(diǎn)或開(kāi)關(guān)節(jié)點(diǎn)邊是饋線或聯(lián)絡(luò)線。我用兩個(gè) Python 類來(lái)表示Node 類和 Branch 類。Node 記錄節(jié)點(diǎn)編號(hào)、父節(jié)點(diǎn)、負(fù)荷有功與無(wú)功、電壓幅值、電壓相角以及接入的分布式電源類型和容量Branch 記錄支路首末節(jié)點(diǎn)、支路電阻電抗、允許載流量以及是否屬于聯(lián)絡(luò)線。class Node: def __init__(self, index, load_p0.0, load_q0.0): self.index index self.load_p load_p # 有功負(fù)荷單位 kW self.load_q load_q # 無(wú)功負(fù)荷單位 kVar self.voltage 1.0 # 電壓標(biāo)幺值 self.dg_p 0.0 # 接入分布式電源有功出力 self.dg_q 0.0 # 接入分布式電源無(wú)功出力 self.parent -1 # 父節(jié)點(diǎn)編號(hào) class Branch: def __init__(self, start, end, resistance, reactance, capacity): self.start start self.end end self.r resistance self.x reactance self.i_max capacity self.is_tie False # 是否聯(lián)絡(luò)線網(wǎng)絡(luò)拓?fù)湓谝?guī)劃中不是固定的因?yàn)闆Q策變量中包含線路改造或新增連接。所以每次評(píng)估一個(gè)個(gè)體時(shí)要先根據(jù)解碼后的安裝方案修改相應(yīng)的 Branch 對(duì)象和 Node 對(duì)象再重新構(gòu)建鄰接表。構(gòu)建鄰接表用的是最直接的字典映射節(jié)點(diǎn)編號(hào)做鍵值是一個(gè)列表存放該節(jié)點(diǎn)相連的所有支路和鄰居節(jié)點(diǎn)信息。這個(gè)結(jié)構(gòu)雖然樸素但勝在清晰、不易出錯(cuò)。4.2 前推回代潮流計(jì)算在輻射狀配電網(wǎng)里前推回代法是配合度最高的潮流算法。思路分兩步回代時(shí)從末端節(jié)點(diǎn)往根節(jié)點(diǎn)方向逐段累加支路電流和功率損耗前推時(shí)從根節(jié)點(diǎn)往末端節(jié)點(diǎn)方向逐段更新節(jié)點(diǎn)電壓。往復(fù)迭代幾輪直到電壓變化小于閾值潮流就算收斂了。def back_forward_sweep(nodes, branches, max_iter50, tol1e-6): for _ in range(max_iter): # 回代計(jì)算每條支路的電流和功率損耗 for branch in reversed(branches): end_node nodes[branch.end] start_node nodes[branch.start] # 節(jié)點(diǎn)功率 負(fù)荷功率 - 分布式電源出力 - 父支路流入功率 power complex(end_node.load_p - end_node.dg_p, end_node.load_q - end_node.dg_q) current (power / complex(end_node.voltage, 0)).conjugate() # 累加到父支路 start_node.load_p end_node.load_p start_node.load_q end_node.load_q # 前推更新節(jié)點(diǎn)電壓 for branch in branches: end_node nodes[branch.end] start_node nodes[branch.start] delta_v (complex(end_node.load_p, end_node.load_q) / complex(start_node.voltage, 0)).conjugate() * \ complex(branch.r, branch.x) end_node.voltage abs(complex(start_node.voltage, 0) - delta_v) return nodes這段代碼是原理演示性質(zhì)實(shí)際工程中還要考慮支路電流限制、變壓器抽頭、無(wú)功補(bǔ)償設(shè)備的影響。但核心思想就是這樣每一輪更新都基于上一輪的電壓和功率假設(shè)收斂速度在配電網(wǎng)這種淺網(wǎng)絡(luò)上通常是夠用的。要注意的是如果網(wǎng)絡(luò)結(jié)構(gòu)改變比如新增了聯(lián)絡(luò)線前推回代前需要先做拓?fù)渑判虼_保支路順序是分層明確的否則迭代容易不收斂。4.3 序貫蒙特卡洛可靠性評(píng)估的代碼落地可靠性評(píng)估這塊我把序貫蒙特卡洛的核心邏輯拆成三個(gè)部分元件狀態(tài)采樣、故障事件遍歷、指標(biāo)統(tǒng)計(jì)。元件狀態(tài)采樣采用狀態(tài)持續(xù)時(shí)間抽樣法。對(duì)每個(gè)元件根據(jù)其故障率參數(shù) λ 抽樣一個(gè)正常運(yùn)行持續(xù)時(shí)間再根據(jù)修復(fù)率 μ 抽樣一個(gè)修復(fù)時(shí)間。這兩個(gè)時(shí)間都是指數(shù)分布的隨機(jī)變量可以用random.expovariate直接生成。這樣一年 8760 小時(shí)內(nèi)每個(gè)元件會(huì)經(jīng)歷若干次故障-修復(fù)循環(huán)。故障事件遍歷是指某一元件處于故障狀態(tài)時(shí)分析它對(duì)各個(gè)負(fù)荷點(diǎn)的影響。這需要知道網(wǎng)絡(luò)拓?fù)渲心男┴?fù)荷可以通過(guò)聯(lián)絡(luò)線轉(zhuǎn)供、哪些被隔離、哪些必須等待修復(fù)。實(shí)際代碼實(shí)現(xiàn)時(shí)我對(duì)每個(gè)故障元件執(zhí)行一次網(wǎng)絡(luò)分割操作以故障支路為缺口用寬度優(yōu)先搜索識(shí)別哪些節(jié)點(diǎn)在主網(wǎng)側(cè)、哪些節(jié)點(diǎn)在故障下游。下游節(jié)點(diǎn)中如果存在聯(lián)絡(luò)線且聯(lián)絡(luò)線容量足夠則這部分負(fù)荷停電時(shí)間僅為切換操作時(shí)間否則停電時(shí)間等于元件修復(fù)時(shí)間。由此累計(jì)缺供電量。def reliability_assessment(nodes, branches, fault_rate, repair_time, n_years2000): ens_total 0.0 # 總?cè)惫╇娏繂挝?MWh saidi_total 0.0 # 總停電時(shí)間單位 小時(shí)/戶 for _ in range(n_years): for year in range(1): # 每年 for branch in branches: # 模擬該支路的故障次數(shù) n_fault np.random.poisson(fault_rate * 8760) for _ in range(n_fault): repair_h np.random.exponential(repair_time) # 計(jì)算受影響負(fù)荷 affected_load, affected_customers find_affected_load( branch.start, branch.end, nodes) ens_total affected_load * repair_h saidi_total affected_customers * repair_h return ens_total / n_years, saidi_total / n_years這里find_affected_load需要結(jié)合電網(wǎng)拓?fù)鋪?lái)判斷故障后哪些負(fù)荷真正停電。如果網(wǎng)絡(luò)中有聯(lián)絡(luò)轉(zhuǎn)供路徑停電時(shí)間就不是修復(fù)時(shí)間而是切換時(shí)間統(tǒng)計(jì)邏輯要更精細(xì)。這個(gè)函數(shù)我強(qiáng)烈建議單獨(dú)寫(xiě)成一個(gè)模塊因?yàn)樗钦麄€(gè)可靠性評(píng)估里最容易出 bug 的部分。測(cè)試時(shí)用經(jīng)典的兩饋線手拉手算例驗(yàn)證一下確保邏輯沒(méi)有問(wèn)題。4.4 雙目標(biāo)優(yōu)化主循環(huán)的組裝有了評(píng)價(jià)函數(shù)NSGA-II 的主循環(huán)就順理成章了。初始化種群時(shí)隨機(jī)生成一批個(gè)體每個(gè)個(gè)體解碼后對(duì)應(yīng)一套規(guī)劃方案。評(píng)價(jià)完所有個(gè)體后進(jìn)入迭代錦標(biāo)賽選擇父代、交叉和變異生成子代、父子代合并做非支配排序、按擁擠度截?cái)嗌上乱淮?。重?fù)若干代后輸出第一層非支配個(gè)體作為帕累托前沿。def nsga2(pop_size, num_generations, nodes_data, branch_data, limits): population init_population(pop_size, limits) for generation in range(num_generations): # 評(píng)價(jià) for ind in population: if not ind.evaluated: ind.fitness evaluate(ind, nodes_data, branch_data) # 生成子代 offspring create_offspring(population) for ind in offspring: ind.fitness evaluate(ind, nodes_data, branch_data) # 合并與選擇 combined population offspring fronts fast_non_dominated_sort(combined) new_pop [] for front in fronts: if len(new_pop) len(front) pop_size: new_pop.extend(front) else: crowding crowding_distance(front) front_sorted sorted(front, keylambda x: x.crowding, reverseTrue) new_pop.extend(front_sorted[:pop_size - len(new_pop)]) break population new_pop return get_pareto_front(population)這個(gè)循環(huán)看起來(lái)簡(jiǎn)單但實(shí)際跑起來(lái)有幾個(gè)性能瓶頸??煽啃栽u(píng)估函數(shù)最耗時(shí)如果每個(gè)個(gè)體都要模擬幾千年種群一百個(gè)體迭代一百代總計(jì)算量是千萬(wàn)級(jí)的抽樣次數(shù)。我的處理方式先跑一個(gè)較小的仿真年數(shù)比如 500 年做快速評(píng)估把明顯差的方案淘汰掉最后保留的結(jié)果再用較長(zhǎng)的仿真年數(shù)重新精確評(píng)估。這種兩階段精化策略能節(jié)省大量時(shí)間。5. 仿真實(shí)例與結(jié)果解讀光講理論不夠我拿一個(gè)典型的配電系統(tǒng)作為示例把整個(gè)流程串起來(lái)演示一遍。這里采用常見(jiàn)的 IEEE 33 節(jié)點(diǎn)測(cè)試系統(tǒng)在部分節(jié)點(diǎn)上增加分布式電源候選位置并在兩組饋線之間設(shè)置可選的聯(lián)絡(luò)線。5.1 測(cè)試系統(tǒng)設(shè)定與場(chǎng)景設(shè)計(jì)IEEE 33 節(jié)點(diǎn)系統(tǒng)是配電網(wǎng)研究中用得最廣泛的標(biāo)準(zhǔn)算例原始數(shù)據(jù)網(wǎng)上到處都能找到包括線路參數(shù)和負(fù)荷分布。我在這個(gè)基礎(chǔ)上做了兩類擴(kuò)展一是設(shè)定五個(gè)候選節(jié)點(diǎn)可以安裝光伏和儲(chǔ)能容量檔位按 100 kW 的步長(zhǎng)遞增二是設(shè)定兩條可選的聯(lián)絡(luò)線用于故障時(shí)轉(zhuǎn)供負(fù)荷。這樣決策變量的數(shù)量保持在合理范圍便于觀察優(yōu)化算法的行為。方案對(duì)比設(shè)置了三個(gè)場(chǎng)景場(chǎng)景 A基礎(chǔ)網(wǎng)架不新增分布式電源僅作可靠性評(píng)估基準(zhǔn)場(chǎng)景 B允許接入分布式光伏但不裝儲(chǔ)能場(chǎng)景 C允許同時(shí)接入光伏和儲(chǔ)能并且可選聯(lián)絡(luò)線。三個(gè)場(chǎng)景分別用 NSGA-II 跑帕累托前沿對(duì)比不同選項(xiàng)組合對(duì)經(jīng)濟(jì)性目標(biāo)和可靠性目標(biāo)的影響。這樣設(shè)置能清楚看出儲(chǔ)能在雙目標(biāo)規(guī)劃里的真實(shí)價(jià)值。5.2 帕累托前沿的形態(tài)分析與方案選取跑完優(yōu)化之后把種群中第一層非支配個(gè)體對(duì)應(yīng)的兩個(gè)目標(biāo)值畫(huà)成散點(diǎn)圖橫軸是年綜合費(fèi)用縱軸是期望缺供電量 EENS就能清楚看到帕累托前沿的形狀。場(chǎng)景 A 的結(jié)果只有一個(gè)點(diǎn)因?yàn)闆](méi)有任何決策變量可選經(jīng)濟(jì)性和可靠性都是固定值。場(chǎng)景 B 的前沿是一條下降的曲線費(fèi)用越低EENS 越高反過(guò)來(lái)想要更可靠就得裝更多光伏投資隨之上升。場(chǎng)景 C 的前沿整體在場(chǎng)景 B 前沿的左下方這說(shuō)明同時(shí)配置儲(chǔ)能和聯(lián)絡(luò)線確實(shí)能實(shí)現(xiàn)用更少的錢達(dá)到同等可靠性或同等費(fèi)用下可靠性更好這也是混合系統(tǒng)相對(duì)傳統(tǒng)系統(tǒng)的主要優(yōu)勢(shì)所在。前沿上的拐點(diǎn)很有意思。左端靠近橫軸的點(diǎn)年綜合費(fèi)用最低但 EENS 很高原因是不裝任何設(shè)備故障只能被動(dòng)等待修復(fù)右端則相反光伏、儲(chǔ)能、聯(lián)絡(luò)線全裝上費(fèi)用高企EENS 很低但曲線走勢(shì)已經(jīng)趨于平緩說(shuō)明繼續(xù)增加投資的邊際收益已經(jīng)很小。實(shí)際決策時(shí)通常選擇曲線上斜率發(fā)生明顯變化的拐點(diǎn)附近再留一點(diǎn)可靠性的裕度。這樣既不會(huì)浪費(fèi)投資又能保證絕大多數(shù)考核場(chǎng)景下滿足指標(biāo)要求。5.3 結(jié)果穩(wěn)定性與參數(shù)敏感性的驗(yàn)證優(yōu)化的結(jié)果不能看一遍就信。我額外做了兩組驗(yàn)證第一組是隨機(jī)數(shù)種子穩(wěn)定性測(cè)試用不同的隨機(jī)種子重復(fù)跑幾次 NSGA-II對(duì)比最終前沿的差異范圍第二組是參數(shù)敏感性分析針對(duì)單位停電損失費(fèi)用、分布式電源投資單價(jià)、故障率這三個(gè)關(guān)鍵參數(shù)各取高、中、低三檔觀察帕累托前沿整體位置和形態(tài)的變化幅度。從結(jié)果看單位停電損失費(fèi)用對(duì)前沿形態(tài)的影響最明顯。這個(gè)參數(shù)本質(zhì)上衡量了用戶停電產(chǎn)生的社會(huì)成本如果定得高優(yōu)化會(huì)傾向于犧牲一點(diǎn)經(jīng)濟(jì)性換取更高的可靠性定得低前沿會(huì)整體向低成本方向移動(dòng)。投資單價(jià)和故障率的變化也有影響但主要表現(xiàn)在部分區(qū)域的方案排序上不會(huì)改變整體趨勢(shì)。這種敏感性分析對(duì)寫(xiě)報(bào)告特別有用因?yàn)樗驔Q策者展示了方案推薦結(jié)論對(duì)參數(shù)假設(shè)的依賴程度而不是給一個(gè)貌似精確實(shí)則脆弱的唯一答案。5.4 復(fù)現(xiàn)過(guò)程中的幾個(gè)大坑代碼層面的坑主要集中在三個(gè)方面。第一是潮流程序在新增 DG 后的收斂性問(wèn)題。光伏出力大的時(shí)候線路末端電壓可能抬升當(dāng)前推回代算法迭代次數(shù)不足時(shí)很容易誤判為不收斂。我的對(duì)策是把最大迭代次數(shù)放寬到 100并且把收斂判據(jù)從節(jié)點(diǎn)電壓變化改為節(jié)點(diǎn)注入功率殘差改進(jìn)后基本不再出現(xiàn)誤判。第二是蒙特卡洛評(píng)估的隨機(jī)波動(dòng)。仿真年數(shù)不夠時(shí)EENS 的估計(jì)值方差很大導(dǎo)致同一套方案前后兩次評(píng)估結(jié)果差很多進(jìn)而干擾優(yōu)化算法對(duì)個(gè)體優(yōu)劣的判斷。前面提到的兩階段評(píng)估策略就是專門解決這個(gè)問(wèn)題的先粗后精、先選后驗(yàn)。第三是 NSGA-II 種群規(guī)模與迭代代數(shù)的搭配。配電網(wǎng)規(guī)劃的評(píng)價(jià)函數(shù)單次耗時(shí)在秒級(jí)種群和代數(shù)設(shè)得太大整體計(jì)算可能要數(shù)小時(shí)甚至更久。我的經(jīng)驗(yàn)是問(wèn)題規(guī)模不算特別大時(shí)種群 80 到 120、迭代 60 到 100 代已經(jīng)能得到形態(tài)完整的前沿再往上加收益遞減反而明顯。6. 從仿真到落地幾個(gè)值得關(guān)注的擴(kuò)展方向前幾章講的是一套完整可運(yùn)行的技術(shù)骨架。實(shí)際做工程時(shí)這套骨架還需要往幾個(gè)方向做擴(kuò)展我把自己踩過(guò)的坑和下一步思路也一并說(shuō)一下。6.1 時(shí)序負(fù)荷與出力數(shù)據(jù)的重要性多數(shù)配電網(wǎng)規(guī)劃的簡(jiǎn)化做法是用年最大負(fù)荷進(jìn)行潮流計(jì)算評(píng)估結(jié)果偏保守。但分布式光伏的出力天然隨時(shí)間變化儲(chǔ)能更是靠時(shí)間差套利不用時(shí)序數(shù)據(jù)儲(chǔ)能的規(guī)劃結(jié)果會(huì)有系統(tǒng)性偏差。我現(xiàn)在做項(xiàng)目時(shí)至少會(huì)用典型日的方式選取夏季、冬季、過(guò)渡季各一個(gè)典型日每 24 小時(shí)一個(gè)時(shí)點(diǎn)負(fù)荷和光伏出力都按曲線輸入。這樣年綜合費(fèi)用里的網(wǎng)損計(jì)算和停電損失計(jì)算都比單點(diǎn)計(jì)算準(zhǔn)確得多代碼實(shí)現(xiàn)上只是把潮流計(jì)算多包一層時(shí)間循環(huán)而已計(jì)算量翻幾倍但完全可接受。6.2 不確定性場(chǎng)景的分析光伏出力和負(fù)荷本身就存在很強(qiáng)的隨機(jī)性用確定性的典型日代替全時(shí)序是一種近似。要想更嚴(yán)謹(jǐn)可以引入場(chǎng)景生成與削減技術(shù)用歷史數(shù)據(jù)聚類出幾十個(gè)典型場(chǎng)景每個(gè)場(chǎng)景帶有概率權(quán)重分別評(píng)估目標(biāo)函數(shù)后按概率加權(quán)求和。這樣做的好處是優(yōu)化結(jié)果對(duì)不確定性的刻畫(huà)更真實(shí)壞處是計(jì)算量成倍增加。折中的做法是在優(yōu)化迭代中使用少量代表性場(chǎng)景快速評(píng)估最終確定方案后再用全部場(chǎng)景做一次精算驗(yàn)證這個(gè)思路和前面兩階段蒙特卡洛評(píng)估是同一個(gè)套路。6.3 可靠性參數(shù)的分區(qū)差異化不同用戶對(duì)停電的敏感度差很多醫(yī)院、數(shù)據(jù)中心、通信基站這些重要負(fù)荷的停電損失費(fèi)用可能是普通居民的幾十倍。規(guī)劃時(shí)如果把所有負(fù)荷都用同一個(gè)單位停電損失費(fèi)用得到的最優(yōu)方案可能過(guò)度重視末端居民負(fù)荷而忽略了關(guān)鍵用戶的需求。我在可靠性評(píng)估里會(huì)為每個(gè)負(fù)荷節(jié)點(diǎn)或區(qū)域設(shè)置一個(gè)權(quán)重系數(shù)把 EENS 拆成普通負(fù)荷 EENS和重要負(fù)荷 EENS兩部分分別計(jì)算指標(biāo)。這樣優(yōu)化出來(lái)的方案往往會(huì)在重要負(fù)荷附近多配置一些儲(chǔ)能或聯(lián)絡(luò)線這個(gè)細(xì)節(jié)在實(shí)際匯報(bào)中非常加分。6.4 儲(chǔ)能配置問(wèn)題的專項(xiàng)建模儲(chǔ)能是混合配電系統(tǒng)里最特殊的設(shè)備因?yàn)樗饶芴嵘煽啃杂帜芡ㄟ^(guò)峰谷套利降低運(yùn)行費(fèi)用。但儲(chǔ)能電池的壽命受充放電次數(shù)和深度影響規(guī)劃時(shí)如果不建模壽命衰減優(yōu)化算法會(huì)把儲(chǔ)能容量往大里推因?yàn)樗愠鰜?lái)的收益很漂亮實(shí)際上電池提前衰減后收益遠(yuǎn)沒(méi)那么多。我習(xí)慣在目標(biāo)函數(shù)里加一個(gè)電池循環(huán)老化成本項(xiàng)按實(shí)際模擬出的年充放電次數(shù)折算損耗費(fèi)用。這個(gè)成本項(xiàng)對(duì)最終儲(chǔ)能容量的推薦值影響很大特別是前沿右半段加了這項(xiàng)之后儲(chǔ)能配置的尺寸會(huì)明顯更克制、更貼近工程實(shí)際?;氐阶畛醯膯?wèn)題經(jīng)濟(jì)性和可靠性到底誰(shuí)優(yōu)先我的答案從來(lái)不直接給而是讓帕累托前沿替我說(shuō)。作為規(guī)劃者我的任務(wù)是把前沿盡可能完整、可信地呈現(xiàn)出來(lái)把每個(gè)決策對(duì)投資和停電的影響算清楚這才是這套 Python 實(shí)現(xiàn)的核心價(jià)值所在。項(xiàng)目代碼里我一直把參數(shù)做成外部配置文件讓每次運(yùn)行都能調(diào)整故障率、電價(jià)、停電損失費(fèi)用這些關(guān)鍵參數(shù)跑出的結(jié)果也始終保留原始記錄方便后續(xù)追溯。這套流程跑順之后支撐我做其他配電網(wǎng)規(guī)劃項(xiàng)目時(shí)省了非常多重復(fù)造輪子的時(shí)間。