點(diǎn)配電網(wǎng)潮流計(jì)算中的實(shí)現(xiàn)與避坑指南)
簡(jiǎn)介這份資源面向電力系統(tǒng)分析與MATLAB編程的學(xué)習(xí)者聚焦IEEE33節(jié)點(diǎn)輻射網(wǎng)的潮流計(jì)算問題采用前推回代法實(shí)現(xiàn)求解。輻射狀網(wǎng)絡(luò)結(jié)構(gòu)簡(jiǎn)單卻典型適合教學(xué)演示與算法驗(yàn)證讀者可借此理解節(jié)點(diǎn)電壓、功率分布等電氣參數(shù)的求解流程。壓縮包共3個(gè)文件包含1個(gè)m腳本與2個(gè)txt數(shù)據(jù)文件分別承擔(dān)算法實(shí)現(xiàn)、支路參數(shù)與節(jié)點(diǎn)信息存儲(chǔ)的職責(zé)整體約2KB體量輕便易于上手。目前已有738人學(xué)習(xí)下載說明該案例在相關(guān)課程與自學(xué)場(chǎng)景中具有一定參考價(jià)值。通過解析支路與節(jié)點(diǎn)數(shù)據(jù)、運(yùn)行前推回代程序并分析計(jì)算結(jié)果讀者能夠掌握稀疏矩陣求解思路、節(jié)點(diǎn)導(dǎo)納矩陣構(gòu)建方法以及潮流收斂性驗(yàn)證技巧為后續(xù)處理更大規(guī)模配電網(wǎng)絡(luò)打下基礎(chǔ)。1. 前推回代法在 IEEE33 節(jié)點(diǎn)算例上的真實(shí)定位配電網(wǎng)潮流計(jì)算里IEEE33 節(jié)點(diǎn)算例幾乎是繞不開的基準(zhǔn)。它結(jié)構(gòu)簡(jiǎn)單、參數(shù)公開、輻射狀拓?fù)淝逦嬲屢痪€工程師頭疼的不是算例本身而是選什么方法能穩(wěn)定收斂。前推回代法就是在這個(gè)場(chǎng)景下被反復(fù)驗(yàn)證過的方案——它不依賴雅可比矩陣不需要求解大規(guī)模線性方程組迭代邏輯直觀對(duì)輻射狀配電網(wǎng)的收斂性極好。如果你正在做分布式電源接入分析、配網(wǎng)重構(gòu)、無功優(yōu)化或者線損計(jì)算前推回代法配合 IEEE33 節(jié)點(diǎn)算例基本是入門和驗(yàn)證算法的第一站。這篇文章不講空泛概念直接從前推回代的數(shù)學(xué)邏輯拆到代碼實(shí)現(xiàn)把參數(shù)設(shè)置、收斂判據(jù)、常見翻車點(diǎn)全部攤開讓你能照著跑通并理解每一步在干什么。2. 前推回代法的數(shù)學(xué)邏輯與 IEEE33 節(jié)點(diǎn)數(shù)據(jù)準(zhǔn)備2.1 為什么輻射狀配電網(wǎng)適合前推回代而不是牛頓拉夫遜配電網(wǎng)和輸電網(wǎng)最大的區(qū)別在于拓?fù)漭旊娋W(wǎng)是環(huán)網(wǎng)配電網(wǎng)是輻射狀樹形結(jié)構(gòu)。牛頓拉夫遜法在輸電網(wǎng)里收斂快、精度高但它的雅可比矩陣在配電網(wǎng)里容易因?yàn)橹纷杩贡萊/X偏大而條件數(shù)變差導(dǎo)致迭代震蕩甚至不收斂。前推回代法恰恰利用了輻射狀拓?fù)涞膶哟侮P(guān)系把潮流計(jì)算拆成兩個(gè)交替進(jìn)行的步驟回代過程從末端節(jié)點(diǎn)向根節(jié)點(diǎn)推算支路電流前推過程從根節(jié)點(diǎn)向末端節(jié)點(diǎn)更新節(jié)點(diǎn)電壓。這個(gè)交替過程不需要矩陣求逆每次迭代的計(jì)算量是 O(n) 級(jí)別對(duì) IEEE33 節(jié)點(diǎn)這種規(guī)模幾乎瞬間完成。IEEE33 節(jié)點(diǎn)算例的基準(zhǔn)參數(shù)需要先明確基準(zhǔn)電壓 12.66 kV基準(zhǔn)功率 10 MVA總負(fù)荷 3715 kW 2300 kvar。系統(tǒng)有 33 個(gè)節(jié)點(diǎn)、32 條支路根節(jié)點(diǎn)是節(jié)點(diǎn) 1也就是變電站出口母線。支路參數(shù)和負(fù)荷數(shù)據(jù)通常以表格形式給出包含首節(jié)點(diǎn)、末節(jié)點(diǎn)、電阻、電抗、有功負(fù)荷、無功負(fù)荷。這些數(shù)據(jù)在代碼里一般用數(shù)組或矩陣存儲(chǔ)索引從 1 開始更符合工程習(xí)慣但 Python 里從 0 開始需要做一次映射。2.2 IEEE33 節(jié)點(diǎn)支路與負(fù)荷數(shù)據(jù)的結(jié)構(gòu)化存儲(chǔ)先把原始數(shù)據(jù)整理成代碼可用的格式。常見做法是用三個(gè)矩陣分別存儲(chǔ)支路參數(shù)、負(fù)荷參數(shù)和拓?fù)潢P(guān)系。支路參數(shù)矩陣每行包含首節(jié)點(diǎn)、末節(jié)點(diǎn)、電阻、電抗負(fù)荷矩陣每行包含節(jié)點(diǎn)編號(hào)、有功、無功。拓?fù)潢P(guān)系可以用一個(gè)父節(jié)點(diǎn)數(shù)組表示每個(gè)節(jié)點(diǎn)記錄它的上游節(jié)點(diǎn)是誰這樣回代時(shí)可以直接從末端往上遍歷。import numpy as np # IEEE33節(jié)點(diǎn)支路參數(shù)首節(jié)點(diǎn)、末節(jié)點(diǎn)、電阻(Ω)、電抗(Ω) branch_data np.array([ [1, 2, 0.0922, 0.0470], [2, 3, 0.4930, 0.2511], [3, 4, 0.3660, 0.1864], [4, 5, 0.3811, 0.1941], [5, 6, 0.8190, 0.7070], [6, 7, 0.1872, 0.6188], [7, 8, 0.7114, 0.2351], [8, 9, 1.0300, 0.7400], [9, 10, 1.0440, 0.7400], [10, 11, 0.1966, 0.0650], [11, 12, 0.3744, 0.1238], [12, 13, 1.4680, 1.1550], [13, 14, 0.5416, 0.7129], [14, 15, 0.5910, 0.5260], [15, 16, 0.7463, 0.5450], [16, 17, 1.2890, 1.7210], [17, 18, 0.7320, 0.5740], [2, 19, 0.1640, 0.1565], [19, 20, 1.5042, 1.3554], [20, 21, 0.4095, 0.4784], [21, 22, 0.7089, 0.9373], [3, 23, 0.4512, 0.3083], [23, 24, 0.8980, 0.7091], [24, 25, 0.8960, 0.7011], [6, 26, 0.2030, 0.1034], [26, 27, 0.2842, 0.1447], [27, 28, 1.0590, 0.9337], [28, 29, 0.8042, 0.7006], [29, 30, 0.5075, 0.2585], [30, 31, 0.9744, 0.9630], [31, 32, 0.3105, 0.3619], [32, 33, 0.3410, 0.5302] ]) # 負(fù)荷數(shù)據(jù)節(jié)點(diǎn)編號(hào)、有功(kW)、無功(kvar) load_data np.array([ [2, 100, 60], [3, 90, 40], [4, 120, 80], [5, 60, 30], [6, 60, 20], [7, 200, 100], [8, 200, 100], [9, 60, 20], [10, 60, 20], [11, 45, 30], [12, 60, 35], [13, 60, 35], [14, 120, 80], [15, 60, 10], [16, 60, 20], [17, 60, 20], [18, 90, 40], [19, 90, 40], [20, 90, 40], [21, 90, 40], [22, 90, 40], [23, 90, 50], [24, 420, 200], [25, 420, 200], [26, 60, 25], [27, 60, 25], [28, 60, 20], [29, 120, 70], [30, 200, 600], [31, 150, 70], [32, 210, 100], [33, 60, 40] ])這段代碼把支路和負(fù)荷數(shù)據(jù)硬編碼成 NumPy 數(shù)組方便后續(xù)索引。注意負(fù)荷數(shù)據(jù)里節(jié)點(diǎn) 30 的無功是 600 kvar這是 IEEE33 算例里比較特殊的一個(gè)點(diǎn)很多簡(jiǎn)化版本會(huì)把它改小但標(biāo)準(zhǔn)算例就是 600改了之后線損和電壓分布會(huì)對(duì)不上。支路數(shù)據(jù)里節(jié)點(diǎn) 2 分出了兩條支路一條去節(jié)點(diǎn) 3一條去節(jié)點(diǎn) 19這種分支結(jié)構(gòu)在回代時(shí)需要特別處理不能簡(jiǎn)單按節(jié)點(diǎn)編號(hào)順序遍歷。2.3 拓?fù)渑判虬演椛錉罹W(wǎng)絡(luò)變成可遍歷的父子關(guān)系前推回代的核心是遍歷順序?;卮仨殢淖钅┒斯?jié)點(diǎn)開始前推必須從根節(jié)點(diǎn)開始。輻射狀網(wǎng)絡(luò)天然是一棵樹只要確定每個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)和子節(jié)點(diǎn)列表就能用深度優(yōu)先或廣度優(yōu)先生成遍歷序列。常見做法是構(gòu)建一個(gè)父節(jié)點(diǎn)數(shù)組parent其中parent[i]表示節(jié)點(diǎn) i 的上游節(jié)點(diǎn)編號(hào)根節(jié)點(diǎn)的父節(jié)點(diǎn)設(shè)為 0 或 -1。def build_topology(branch_data, num_nodes33): 構(gòu)建父節(jié)點(diǎn)數(shù)組和子節(jié)點(diǎn)列表 parent np.zeros(num_nodes 1, dtypeint) children [[] for _ in range(num_nodes 1)] for br in branch_data: f, t int(br[0]), int(br[1]) parent[t] f children[f].append(t) # 生成回代順序從末端到根節(jié)點(diǎn) back_order [] visited set() stack [1] while stack: node stack.pop() if node not in visited: visited.add(node) back_order.append(node) for ch in children[node]: stack.append(ch) back_order.reverse() # 反轉(zhuǎn)后末端在前 # 前推順序就是回代順序的反轉(zhuǎn) forward_order list(reversed(back_order)) return parent, children, back_order, forward_orderbuild_topology函數(shù)做了三件事記錄每個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)、記錄每個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)列表、生成回代和前推的遍歷順序?;卮樞蛲ㄟ^深度優(yōu)先搜索得到從根到末端的順序然后反轉(zhuǎn)這樣末端節(jié)點(diǎn)排在最前面。前推順序直接反轉(zhuǎn)回代順序即可。這里用棧實(shí)現(xiàn)深度優(yōu)先避免遞歸在節(jié)點(diǎn)數(shù)多時(shí)爆棧。參數(shù)num_nodes33是 IEEE33 的固定節(jié)點(diǎn)數(shù)如果換成其他算例只需要改這個(gè)值。3. 前推回代迭代實(shí)現(xiàn)從支路電流到節(jié)點(diǎn)電壓的完整閉環(huán)3.1 回代過程用負(fù)荷功率反推支路電流回代的目標(biāo)是計(jì)算每條支路的電流。對(duì)于末端節(jié)點(diǎn)它的注入電流只由自身負(fù)荷決定對(duì)于中間節(jié)點(diǎn)它的注入電流等于自身負(fù)荷電流加上所有下游支路電流之和。用公式表示就是節(jié)點(diǎn) i 的注入電流 I_inj(i) conj(S_load(i) / V(i))支路電流 I_branch(i) I_inj(i) sum(I_branch(下游支路))。def backward_sweep(V, parent, children, back_order, load_data, branch_data, S_base10e6, V_base12.66e3): 回代過程計(jì)算各支路電流 num_nodes len(V) - 1 I_branch np.zeros(num_nodes 1, dtypecomplex) # 支路電流索引為末節(jié)點(diǎn) I_inj np.zeros(num_nodes 1, dtypecomplex) # 節(jié)點(diǎn)注入電流 # 先把負(fù)荷功率轉(zhuǎn)成標(biāo)幺值 S_load_pu np.zeros(num_nodes 1, dtypecomplex) for row in load_data: node int(row[0]) P row[1] * 1e3 / S_base Q row[2] * 1e3 / S_base S_load_pu[node] complex(P, Q) # 按回代順序從末端向根節(jié)點(diǎn)遍歷 for node in back_order: if node 1: continue # 根節(jié)點(diǎn)不參與回代 # 節(jié)點(diǎn)注入電流 負(fù)荷電流 下游支路電流之和 if abs(V[node]) 1e-10: V[node] 1.0 # 防止除零首次迭代電壓初值設(shè)為1 I_inj[node] np.conj(S_load_pu[node] / V[node]) # 加上所有子節(jié)點(diǎn)的支路電流 for ch in children[node]: I_inj[node] I_branch[ch] # 該節(jié)點(diǎn)到父節(jié)點(diǎn)的支路電流等于注入電流 I_branch[node] I_inj[node] return I_branch這段代碼的關(guān)鍵在于遍歷順序。back_order保證末端節(jié)點(diǎn)先被處理這樣當(dāng)處理中間節(jié)點(diǎn)時(shí)它所有子節(jié)點(diǎn)的支路電流已經(jīng)算好了。I_inj[node]初始為負(fù)荷電流然后累加子節(jié)點(diǎn)支路電流。注意np.conj是共軛因?yàn)楣β适且曉诠β孰娏鞯扔诠β食噪妷旱墓曹?。電壓初值設(shè)為 1.0 標(biāo)幺值這是平啟動(dòng)的常見做法。如果電壓接近零會(huì)導(dǎo)致除零錯(cuò)誤所以加了一個(gè)保護(hù)判斷。3.2 前推過程從根節(jié)點(diǎn)電壓推算全網(wǎng)電壓分布前推的目標(biāo)是更新所有節(jié)點(diǎn)電壓。根節(jié)點(diǎn)電壓由變電站給定通常是 1.0 標(biāo)幺值。對(duì)于每條支路末節(jié)點(diǎn)電壓等于首節(jié)點(diǎn)電壓減去支路阻抗乘以支路電流。由于支路電流已經(jīng)在回代中算出前推就是簡(jiǎn)單的電壓降計(jì)算。def forward_sweep(V, I_branch, parent, forward_order, branch_data, Z_base): 前推過程更新節(jié)點(diǎn)電壓 num_nodes len(V) - 1 V_new V.copy() # 構(gòu)建支路阻抗字典鍵為末節(jié)點(diǎn) Z_branch {} for br in branch_data: f, t int(br[0]), int(br[1]) R br[2] X br[3] Z_branch[t] complex(R, X) / Z_base # 按前推順序從根節(jié)點(diǎn)向末端遍歷 for node in forward_order: if node 1: V_new[node] 1.0 # 根節(jié)點(diǎn)電壓固定 continue p parent[node] V_new[node] V_new[p] - Z_branch[node] * I_branch[node] return V_newforward_order保證父節(jié)點(diǎn)先于子節(jié)點(diǎn)被處理這樣計(jì)算子節(jié)點(diǎn)電壓時(shí)父節(jié)點(diǎn)電壓已經(jīng)更新。Z_base是基準(zhǔn)阻抗等于V_base**2 / S_baseIEEE33 算例下約為 16.03 Ω。支路阻抗除以基準(zhǔn)阻抗得到標(biāo)幺值。根節(jié)點(diǎn)電壓固定為 1.0這是平衡節(jié)點(diǎn)的約束。每次前推結(jié)束后節(jié)點(diǎn)電壓被更新下一輪回代用新電壓重新計(jì)算電流如此交替直到收斂。3.3 收斂判據(jù)與迭代控制什么時(shí)候停、怎么停收斂判據(jù)通??聪噜弮纱蔚墓?jié)點(diǎn)電壓最大差值。如果最大差值小于設(shè)定容差比如 1e-6 標(biāo)幺值就認(rèn)為收斂。也可以看功率不平衡量但電壓差值更直觀。迭代次數(shù)上限一般設(shè) 100 次防止不收斂時(shí)死循環(huán)。def power_flow_ieee33(branch_data, load_data, tol1e-6, max_iter100): 前推回代法主流程 num_nodes 33 S_base 10e6 V_base 12.66e3 Z_base V_base**2 / S_base parent, children, back_order, forward_order build_topology(branch_data, num_nodes) V np.ones(num_nodes 1, dtypecomplex) # 平啟動(dòng) V[1] 1.0 # 根節(jié)點(diǎn) for iteration in range(max_iter): I_branch backward_sweep(V, parent, children, back_order, load_data, branch_data, S_base, V_base) V_new forward_sweep(V, I_branch, parent, forward_order, branch_data, Z_base) max_diff np.max(np.abs(V_new[2:] - V[2:])) # 排除根節(jié)點(diǎn) V V_new if max_diff tol: print(f收斂于第 {iteration 1} 次迭代最大電壓差 {max_diff:.2e}) break else: print(達(dá)到最大迭代次數(shù)仍未收斂) return V, I_branch主流程把回代和前推串起來每次迭代后檢查電壓差。max_diff只比較非根節(jié)點(diǎn)因?yàn)楦?jié)點(diǎn)電壓固定不變。收斂后返回節(jié)點(diǎn)電壓和支路電流。如果達(dá)到最大迭代次數(shù)還沒收斂說明參數(shù)或拓?fù)溆袉栴}需要排查。IEEE33 算例在平啟動(dòng)下通常 5 到 8 次迭代就能收斂到 1e-6速度非常快。4. 結(jié)果驗(yàn)證與線損計(jì)算怎么確認(rèn)你的前推回代沒算錯(cuò)4.1 節(jié)點(diǎn)電壓分布與標(biāo)準(zhǔn)結(jié)果的對(duì)比方法跑完潮流后第一件事是看節(jié)點(diǎn)電壓分布。IEEE33 算例的標(biāo)準(zhǔn)結(jié)果里最低電壓通常出現(xiàn)在節(jié)點(diǎn) 18 或節(jié)點(diǎn) 33 附近標(biāo)幺值大約在 0.91 左右。如果算出來最低電壓低于 0.85 或者高于 0.95大概率是數(shù)據(jù)或拓?fù)溴e(cuò)了。常見錯(cuò)誤包括支路首末節(jié)點(diǎn)寫反、負(fù)荷單位沒換算、基準(zhǔn)功率搞錯(cuò)。V, I_branch power_flow_ieee33(branch_data, load_data) # 打印各節(jié)點(diǎn)電壓標(biāo)幺值和幅值 print(節(jié)點(diǎn)電壓分布) for i in range(1, 34): print(f節(jié)點(diǎn) {i:2d}: {abs(V[i]):.4f} pu, 相角 {np.angle(V[i])*180/np.pi:.2f}°) # 找最低電壓節(jié)點(diǎn) min_v min(abs(V[2:])) min_node np.argmin(abs(V[2:])) 2 print(f\n最低電壓節(jié)點(diǎn){min_node}電壓 {min_v:.4f} pu)這段代碼輸出所有節(jié)點(diǎn)電壓并找最低點(diǎn)。標(biāo)準(zhǔn) IEEE33 算例在額定負(fù)荷下節(jié)點(diǎn) 18 的電壓約為 0.9131 pu節(jié)點(diǎn) 33 約為 0.9167 pu。如果你的結(jié)果和這個(gè)差太多先檢查支路數(shù)據(jù)里節(jié)點(diǎn) 2 到節(jié)點(diǎn) 19 那條支路是否漏了這條支路經(jīng)常被簡(jiǎn)化掉。另外節(jié)點(diǎn) 30 的無功 600 kvar 如果改成 200最低電壓會(huì)偏高。4.2 線損計(jì)算從支路電流反推有功損耗線損是配電網(wǎng)分析的核心指標(biāo)之一。IEEE33 算例的總有功線損標(biāo)準(zhǔn)值約為 202.7 kW占總負(fù)荷的 5.46%。線損計(jì)算很簡(jiǎn)單每條支路的有功損耗等于支路電流幅值的平方乘以支路電阻。def calculate_losses(I_branch, branch_data, S_base10e6, V_base12.66e3): 計(jì)算線路有功損耗和無功損耗 Z_base V_base**2 / S_base total_P_loss 0.0 total_Q_loss 0.0 for br in branch_data: t int(br[1]) R_pu br[2] / Z_base X_pu br[3] / Z_base I_mag abs(I_branch[t]) P_loss I_mag**2 * R_pu * S_base / 1e3 # kW Q_loss I_mag**2 * X_pu * S_base / 1e3 # kvar total_P_loss P_loss total_Q_loss Q_loss return total_P_loss, total_Q_loss P_loss, Q_loss calculate_losses(I_branch, branch_data) print(f總有功線損{P_loss:.2f} kW) print(f總無功線損{Q_loss:.2f} kvar) print(f線損率{P_loss / 3715 * 100:.2f}%)calculate_losses遍歷所有支路用標(biāo)幺電流和標(biāo)幺電阻算損耗再乘回基準(zhǔn)功率。注意I_branch[t]里的索引是末節(jié)點(diǎn)因?yàn)橹冯娏鞔嬖谀┕?jié)點(diǎn)位置。算出來總有功線損應(yīng)該在 200 kW 附近如果偏差超過 10%回去檢查負(fù)荷數(shù)據(jù)是否完整。常見坑是節(jié)點(diǎn) 30 的無功負(fù)荷被忽略或者節(jié)點(diǎn) 24、25 的大負(fù)荷 420 kW 寫成了 42 kW。4.3 迭代收斂曲線判斷算法是否健康的直觀手段收斂曲線能看出算法是否健康。正常的前推回代收斂曲線是指數(shù)下降的每次迭代電壓差縮小一個(gè)數(shù)量級(jí)左右。如果曲線震蕩或者下降很慢說明網(wǎng)絡(luò)參數(shù)有問題比如存在環(huán)網(wǎng)或者阻抗比過大。def power_flow_with_history(branch_data, load_data, tol1e-6, max_iter100): 帶收斂歷史的前推回代 num_nodes 33 S_base 10e6 V_base 12.66e3 Z_base V_base**2 / S_base parent, children, back_order, forward_order build_topology(branch_data, num_nodes) V np.ones(num_nodes 1, dtypecomplex) V[1] 1.0 history [] for iteration in range(max_iter): I_branch backward_sweep(V, parent, children, back_order, load_data, branch_data, S_base, V_base) V_new forward_sweep(V, I_branch, parent, forward_order, branch_data, Z_base) max_diff np.max(np.abs(V_new[2:] - V[2:])) history.append(max_diff) V V_new if max_diff tol: break return V, I_branch, history V, I_branch, history power_flow_with_history(branch_data, load_data) print(收斂歷史) for i, h in enumerate(history): print(f第 {i1} 次迭代{h:.2e})把每次迭代的最大電壓差存進(jìn)history列表打印出來就能看到收斂過程。IEEE33 算例通常第 1 次迭代差在 0.1 左右第 2 次降到 0.01第 3 次 0.001第 5 到 6 次就到 1e-6 以下。如果第 10 次還在 0.01 以上基本可以確定數(shù)據(jù)有問題。5. 前推回代法在 IEEE33 節(jié)點(diǎn)上的避坑與排查5.1 支路首末節(jié)點(diǎn)寫反導(dǎo)致潮流方向錯(cuò)亂現(xiàn)象迭代不收斂或者收斂后節(jié)點(diǎn)電壓普遍偏高線損為負(fù)值。原因支路數(shù)據(jù)里首節(jié)點(diǎn)和末節(jié)點(diǎn)寫反了導(dǎo)致拓?fù)潢P(guān)系錯(cuò)亂回代時(shí)電流方向反了。解決檢查branch_data每一行的前兩個(gè)數(shù)字確保首節(jié)點(diǎn)是靠近根節(jié)點(diǎn)的那個(gè)。IEEE33 算例里節(jié)點(diǎn) 1 是根所有支路的方向都應(yīng)該從低編號(hào)指向高編號(hào)但節(jié)點(diǎn) 2 到 19 這條支路是例外19 比 2 大方向正確。如果發(fā)現(xiàn)某條支路首節(jié)點(diǎn)編號(hào)大于末節(jié)點(diǎn)大概率寫反了。5.2 負(fù)荷單位混淆kW 當(dāng)成 W 或者 MW現(xiàn)象線損計(jì)算出來只有幾 kW或者大到幾千 kW。原因負(fù)荷數(shù)據(jù)單位沒統(tǒng)一。IEEE33 標(biāo)準(zhǔn)算例里負(fù)荷是 kW 和 kvar但代碼里標(biāo)幺化時(shí)要除以S_baseS_base是 10 MVA 即 10000 kW。如果直接把 kW 除以 10e6結(jié)果會(huì)小 1000 倍。解決在backward_sweep里把負(fù)荷功率乘以 1e3 轉(zhuǎn)成 W再除以S_base。或者統(tǒng)一用 kW 和 kVA 做基準(zhǔn)但要注意阻抗基準(zhǔn)也要對(duì)應(yīng)改。5.3 根節(jié)點(diǎn)電壓初值設(shè)成非 1.0 導(dǎo)致收斂異?,F(xiàn)象迭代次數(shù)明顯增多或者收斂后電壓分布整體偏移。原因平衡節(jié)點(diǎn)電壓被設(shè)成了其他值比如 0.95 或 1.05。前推回代法里根節(jié)點(diǎn)是電壓源它的電壓由變電站決定標(biāo)準(zhǔn)算例就是 1.0 標(biāo)幺值。解決在forward_sweep里強(qiáng)制V_new[1] 1.0并且在收斂判據(jù)里排除根節(jié)點(diǎn)。如果確實(shí)要算變壓器分接頭調(diào)整后的情況應(yīng)該改的是根節(jié)點(diǎn)電壓設(shè)定值而不是讓它參與迭代。5.4 拓?fù)渑判蜻z漏分支導(dǎo)致部分節(jié)點(diǎn)電壓不更新現(xiàn)象某些節(jié)點(diǎn)電壓始終是初始值 1.0或者線損偏小。原因build_topology生成的遍歷順序漏掉了某些分支。IEEE33 算例里節(jié)點(diǎn) 2 有三個(gè)子節(jié)點(diǎn)3、19還有一條去節(jié)點(diǎn) 19 的支路。如果深度優(yōu)先搜索時(shí)棧操作寫錯(cuò)可能只遍歷了主鏈漏掉分支。解決在build_topology里打印back_order和forward_order的長(zhǎng)度確保等于 33。如果小于 33說明有節(jié)點(diǎn)沒被訪問到檢查children列表構(gòu)建是否正確。5.5 收斂容差設(shè)得太松導(dǎo)致結(jié)果精度不夠現(xiàn)象迭代很快結(jié)束但電壓和標(biāo)準(zhǔn)值差在小數(shù)點(diǎn)后第三位。原因tol設(shè)成了 1e-3 或 1e-4精度不夠。前推回代法收斂速度快完全可以設(shè)到 1e-6 甚至 1e-8。解決把tol改成 1e-6迭代次數(shù)只會(huì)增加一兩次但結(jié)果精度足夠用于線損分析和電壓評(píng)估。如果做靈敏度分析或者優(yōu)化建議設(shè)到 1e-8。6. 進(jìn)階技巧用前推回代法做分布式電源接入的快速評(píng)估前推回代法最大的優(yōu)勢(shì)是迭代邏輯簡(jiǎn)單改造成本低。當(dāng)你需要在 IEEE33 算例上評(píng)估分布式電源接入影響時(shí)不需要重寫整個(gè)潮流算法只需要在回代過程里修改節(jié)點(diǎn)注入電流。分布式電源通常按恒功率因數(shù)控制注入電流等于conj(S_dg / V)方向和負(fù)荷電流相反。把S_load_pu[node]改成S_load_pu[node] - S_dg_pu[node]就行負(fù)號(hào)表示注入。def backward_sweep_with_dg(V, parent, children, back_order, load_data, dg_data, branch_data, S_base10e6, V_base12.66e3): 含分布式電源的回代過程 num_nodes len(V) - 1 I_branch np.zeros(num_nodes 1, dtypecomplex) I_inj np.zeros(num_nodes 1, dtypecomplex) S_load_pu np.zeros(num_nodes 1, dtypecomplex) for row in load_data: node int(row[0]) S_load_pu[node] complex(row[1] * 1e3 / S_base, row[2] * 1e3 / S_base) # 減去分布式電源注入 for row in dg_data: node int(row[0]) P_dg row[1] * 1e3 / S_base pf row[2] # 功率因數(shù) Q_dg P_dg * np.tan(np.arccos(pf)) S_load_pu[node] - complex(P_dg, Q_dg) for node in back_order: if node 1: continue if abs(V[node]) 1e-10: V[node] 1.0 I_inj[node] np.conj(S_load_pu[node] / V[node]) for ch in children[node]: I_inj[node] I_branch[ch] I_branch[node] I_inj[node] return I_branch這段代碼在原有回代基礎(chǔ)上增加了dg_data參數(shù)每行包含節(jié)點(diǎn)編號(hào)、有功容量、功率因數(shù)。分布式電源的注入功率從負(fù)荷里減去等效于負(fù)負(fù)荷。注意功率因數(shù)轉(zhuǎn)換Q_dg P_dg * tan(arccos(pf))如果 pf 是 0.9Q 約為 0.484 倍 P。接入分布式電源后節(jié)點(diǎn)電壓會(huì)抬升線損可能降低也可能升高取決于電源位置和容量。用這個(gè)改造版跑幾組不同接入方案能快速看出電壓改善效果和線損變化趨勢(shì)。一個(gè)實(shí)用技巧是把power_flow_with_history里的backward_sweep替換成backward_sweep_with_dg其他不變就能直接算含分布式電源的潮流。我一般會(huì)先跑無 DG 的基準(zhǔn)再跑 DG 接入后的對(duì)比最低電壓節(jié)點(diǎn)和總線損。如果最低電壓從 0.91 升到 0.95 以上說明 DG 容量偏大可能需要限制接入。如果線損反而增加說明 DG 位置不合理離根節(jié)點(diǎn)太近或者容量太小電流倒送導(dǎo)致?lián)p耗增加。最后說個(gè)血淚經(jīng)驗(yàn)前推回代法雖然簡(jiǎn)單但拓?fù)涮幚硎亲钊菀追嚨牡胤健N乙娺^太多人因?yàn)橹讽樞驔]排對(duì)迭代了 100 次還不收斂最后發(fā)現(xiàn)是節(jié)點(diǎn) 2 到 19 那條支路被漏掉了。建議每次改完數(shù)據(jù)先打印back_order和forward_order確認(rèn)長(zhǎng)度等于節(jié)點(diǎn)數(shù)再跑潮流。另外收斂容差別設(shè)太松1e-6 是底線做優(yōu)化的時(shí)候直接上 1e-8多迭代兩次換來的精度絕對(duì)值得。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取