元網(wǎng)絡(luò)算法與Python實(shí)踐)
簡(jiǎn)介面向多變量系統(tǒng)控制研究者與自動(dòng)化專(zhuān)業(yè)學(xué)生這份資源提供了基于比例-積分-微分PID神經(jīng)元網(wǎng)絡(luò)實(shí)現(xiàn)解耦控制的完整MATLAB程序。針對(duì)多輸入多輸出系統(tǒng)中變量相互耦合、控制難度大的問(wèn)題算法借助神經(jīng)網(wǎng)絡(luò)的自學(xué)習(xí)與非線(xiàn)性映射能力對(duì)PID參數(shù)進(jìn)行在線(xiàn)優(yōu)化并通過(guò)解耦矩陣把耦合系統(tǒng)轉(zhuǎn)換為多個(gè)獨(dú)立的單變量回路。壓縮包為rar格式包含六個(gè)文件全部為.m腳本總大小僅13KB涵蓋主程序、解耦邏輯、粒子群優(yōu)化算法、目標(biāo)函數(shù)及結(jié)果繪圖等腳本模塊各模塊分工明確便于讀者快速定位、運(yùn)行和修改。目前該資源已有三百二十九人學(xué)習(xí)下載適合用作控制理論課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)仿真或工程控制方案預(yù)研的參考樣例。通過(guò)研讀代碼可以掌握解耦矩陣計(jì)算、神經(jīng)網(wǎng)絡(luò)模型構(gòu)建、PID參數(shù)整定與系統(tǒng)仿真驗(yàn)證的完整流程為后續(xù)擴(kuò)展到更復(fù)雜工業(yè)過(guò)程提供可復(fù)用的實(shí)現(xiàn)基礎(chǔ)。1. 多變量耦合回路為什么常規(guī) PID 一投自動(dòng)就互相打架過(guò)程控制現(xiàn)場(chǎng)最常遇到的一個(gè)畫(huà)面是兩個(gè)回路單獨(dú)切手動(dòng)、單獨(dú)整定 PID 時(shí)都好好的一旦都投自動(dòng)系統(tǒng)就開(kāi)始周期性地互相拉扯輸出曲線(xiàn)像兩條在較勁的蛇。你以為是參數(shù)沒(méi)整好把比例度調(diào)來(lái)調(diào)去結(jié)果越調(diào)越糟。這往往不是 PID 參數(shù)的問(wèn)題而是回路之間存在耦合你調(diào)的是其中一個(gè)回路但擾動(dòng)順著耦合通道串到了另一個(gè)回路另一個(gè)回路的控制器又把自己的調(diào)整串回來(lái)。PID 神經(jīng)元網(wǎng)絡(luò)解耦控制算法要解決的正是這個(gè)問(wèn)題它把常規(guī) PID 的比例、積分、微分運(yùn)算直接做成網(wǎng)絡(luò)結(jié)構(gòu)里的三種神經(jīng)元再用輸出層的連接權(quán)把多變量系統(tǒng)里回路間的耦合關(guān)系在線(xiàn)學(xué)出來(lái)讓解耦和整定同時(shí)完成。適合正在做多變量過(guò)程控制、想先在仿真里驗(yàn)證控制方案再考慮現(xiàn)場(chǎng)落地的工程師。2. PID 神經(jīng)元網(wǎng)絡(luò)的結(jié)構(gòu)邏輯比例、積分、微分神經(jīng)元如何承擔(dān)解耦2.1 隱含層直接實(shí)現(xiàn) PID 律三種神經(jīng)元的輸入輸出規(guī)則PID 神經(jīng)元網(wǎng)絡(luò)和普通 BP 網(wǎng)絡(luò)最大的區(qū)別在隱含層。普通 BP 的隱含層神經(jīng)元用的是 sigmoid 或 tanh 這類(lèi)非線(xiàn)性激活函數(shù)網(wǎng)絡(luò)到底學(xué)到什么規(guī)律外部很難解釋。PID 神經(jīng)元網(wǎng)絡(luò)的做法相反隱含層每個(gè)神經(jīng)元的運(yùn)算規(guī)則是事先定死的分別對(duì)應(yīng)比例、積分、微分三種操作。以雙入雙出系統(tǒng)為例輸入層每個(gè)回路取兩個(gè)量當(dāng)前誤差 e(k) 和誤差變化量 Δe(k)。隱含層每個(gè)回路對(duì)應(yīng)三個(gè)神經(jīng)元比例元輸出就是當(dāng)前誤差本身h_P e(k)它決定控制力對(duì)偏差的即時(shí)反應(yīng)積分元輸出是誤差的累積值h_I Σe(k)它負(fù)責(zé)消除靜差把長(zhǎng)期存在的偏差一點(diǎn)點(diǎn)頂回來(lái)微分元輸出是當(dāng)前誤差與上一拍誤差之差h_D e(k) - e(k-1)它起到預(yù)測(cè)偏差走勢(shì)、抑制超調(diào)的作用。輸出層做的是線(xiàn)性加權(quán)和第 i 個(gè)控制量 u_i b_i Σ w_ij * h_j其中 h_j 遍歷所有回路的比例、積分、微分神經(jīng)元輸出。這里有一個(gè)關(guān)鍵設(shè)計(jì)輸出層沒(méi)有非線(xiàn)性激活函數(shù)。原因是控制回路的誤差信號(hào)在動(dòng)態(tài)過(guò)程中變化范圍很大如果套一個(gè) sigmoid誤差稍大就進(jìn)入飽和區(qū)梯度趨近于零在線(xiàn)學(xué)習(xí)就停擺了。線(xiàn)性加權(quán)和保證權(quán)值在任何時(shí)刻都能獲得有效的修正量。這樣做的意義在于PID 規(guī)律不是靠訓(xùn)練「學(xué)」出來(lái)的而是被結(jié)構(gòu)「保證」的。網(wǎng)絡(luò)要學(xué)的只是各條連接通路的權(quán)值也就是每個(gè)誤差成分對(duì)每個(gè)控制量該貢獻(xiàn)多大。這部分恰恰是耦合信息所在。2.2 輸出層權(quán)值就是隱式解耦矩陣?yán)斫饨怦钤淼年P(guān)鍵在于隱含層輸出的 h 向量包含了全部回路的誤差信息。回路 1 的比例元、積分元、微分元在 h 里回路 2 的也在 h 里。輸出層計(jì)算 u1 時(shí)會(huì)對(duì)所有這些分量加權(quán)求和包括來(lái)自回路 2 誤差的分量。這就帶來(lái)一個(gè)很有意思的性質(zhì)當(dāng)回路 2 因?yàn)樵O(shè)定值變化產(chǎn)生偏差時(shí)這個(gè)偏差會(huì)通過(guò)回路 2 的比例元和積分元進(jìn)入 h 向量再通過(guò)權(quán)值 w_12、w_22 等通道直接影響 u1。如果訓(xùn)練讓這些交叉權(quán)值收斂到合適的值u1 就會(huì)在回路 2 出現(xiàn)偏差的瞬間提前產(chǎn)生一個(gè)補(bǔ)償分量抵消回路 2 通過(guò)對(duì)象耦合通道對(duì)回路 1 的擾動(dòng)。這就是解耦補(bǔ)償?shù)麄€(gè)過(guò)程沒(méi)有一個(gè)顯式的解耦矩陣。傳統(tǒng)的前饋解耦或?qū)蔷仃嚱怦钚枰冉?duì)象模型算出耦合通道的傳遞函數(shù)再設(shè)計(jì)補(bǔ)償器。PID 神經(jīng)元網(wǎng)絡(luò)的思路完全不同輸出層權(quán)值本身就是解耦矩陣而且它是通過(guò)在線(xiàn)梯度下降逐步調(diào)整的不需要精確的對(duì)象模型甚至能在耦合強(qiáng)度隨工況變化時(shí)持續(xù)自適應(yīng)修正。代價(jià)是權(quán)值收斂需要充分的激勵(lì)如果兩個(gè)回路的設(shè)定值長(zhǎng)期不動(dòng)交叉權(quán)值就學(xué)不到有效的耦合信息這一點(diǎn)到第 5 章會(huì)展開(kāi)說(shuō)。2.3 學(xué)習(xí)算法符號(hào)近似梯度加動(dòng)量項(xiàng)為什么不用純 BP權(quán)值修正的目標(biāo)函數(shù)取誤差平方和 J 0.5 * Σ e_i2(k)e_i r_i - y_i。對(duì)權(quán)值 w_ij 求梯度時(shí)會(huì)碰到 ?J/?w_ij -e_i * (?y_i/?u_i) * h_j。問(wèn)題來(lái)了?y_i/?u_i 是被控對(duì)象的增益工程上拿不到解析表達(dá)式尤其現(xiàn)場(chǎng)對(duì)象還有純延遲和非線(xiàn)性。常見(jiàn)做法是用穩(wěn)態(tài)增益的方向符號(hào)來(lái)近似也就是只保留 ?y_i/?u_i 的正負(fù)號(hào)幅值讓學(xué)習(xí)率去吸收。這樣每一拍的權(quán)值修正量近似為Δw_ij η * e_i * sign(G_i) * h_j α * Δw_ij(previous)其中 η 是學(xué)習(xí)率α 是動(dòng)量因子G_i 是第 i 個(gè)回路對(duì)象增益的方向。更新時(shí)要特別注意如果 sign(G_i) 取反誤差不但不會(huì)減小反而會(huì)被放大輸出幾拍之內(nèi)就會(huì)頂?shù)较薹@個(gè)坑在第 5 章專(zhuān)門(mén)列了一條。為什么不直接用純 BP兩個(gè)原因。第一純 BP 依賴(lài)激活函數(shù)的導(dǎo)數(shù)而這里的輸出層是線(xiàn)性的梯度本身不含非線(xiàn)性壓縮信息直接用 BP 的誤差反傳公式意義不大。第二控制回路的誤差序列在動(dòng)態(tài)階段經(jīng)常是振蕩的不帶動(dòng)量項(xiàng)的梯度下降會(huì)在最優(yōu)解附近來(lái)回震蕩收斂極慢。動(dòng)量項(xiàng)相當(dāng)于給權(quán)值更新加了慣性能濾掉高頻抖動(dòng)讓權(quán)值沿誤差下降的主導(dǎo)方向平滑移動(dòng)。實(shí)際實(shí)現(xiàn)時(shí)動(dòng)量項(xiàng)取 0.8 左右學(xué)習(xí)率取 0.02 到 0.1具體調(diào)法見(jiàn)第 4 章。3. 用 Python 復(fù)現(xiàn)雙入雙出解耦控制對(duì)象模型、網(wǎng)絡(luò)類(lèi)和訓(xùn)練循環(huán)3.1 被控對(duì)象帶交叉耦合的二階差分模型仿真需要先有一個(gè)能體現(xiàn)耦合的對(duì)象。常見(jiàn)做法是用兩個(gè)二階欠阻尼通道加上交叉項(xiàng)因?yàn)檫^(guò)阻尼對(duì)象單回路 PID 就能壓住看不出解耦的價(jià)值。下面這個(gè)離散模型是我常用的一組系數(shù)模擬某工藝過(guò)程中兩個(gè)相互關(guān)聯(lián)的溫控通道主通道有欠阻尼二階動(dòng)態(tài)交叉通道增益約為主通道的一半左右。import numpy as np class CoupledPlant: 雙入雙出二階對(duì)象含交叉耦合項(xiàng)模擬某過(guò)程通道的離散化模型 def __init__(self, g11.0, g21.0): self.g1 g1 # 通道1增益攝動(dòng)系數(shù) self.g2 g2 # 通道2增益攝動(dòng)系數(shù) self.y1_1, self.y2_1 0.0, 0.0 # k-1 時(shí)刻輸出 self.y1_2, self.y2_2 0.0, 0.0 # k-2 時(shí)刻輸出 self.u1_1, self.u1_2 0.0, 0.0 # 控制量歷史 self.u2_1, self.u2_2 0.0, 0.0 def step(self, u1, u2): # 主通道本回路控制量驅(qū)動(dòng)本回路輸出二階欠阻尼動(dòng)態(tài) y1 1.63 * self.y1_1 - 0.67 * self.y1_2 0.34 * self.g1 * self.u1_2 y2 1.55 * self.y2_1 - 0.58 * self.y2_2 0.29 * self.g2 * self.u2_2 # 交叉耦合對(duì)方控制量串入本回路 y1 0.16 * self.g2 * self.u2_2 y2 0.13 * self.g1 * self.u1_2 self.y1_2, self.y2_2 self.y1_1, self.y2_1 self.y1_1, self.y2_1 y1, y2 self.u1_2, self.u2_2 self.u1_1, self.u2_1 self.u1_1, self.u2_1 u1, u2 return y1, y2這里用差分方程而不是傳遞函數(shù)是為了讓對(duì)象代碼足夠短方便直接嵌入訓(xùn)練循環(huán)。系數(shù) 1.63 和 -0.67 對(duì)應(yīng)離散域里阻尼比約 0.45、自然角頻率約 1.0 rad/s 的二階系統(tǒng)采樣周期取 0.1 秒時(shí)換算過(guò)來(lái)的近似值。耦合項(xiàng) g1、g2 是給第 6 章攝動(dòng)掃描預(yù)留的參數(shù)平時(shí)保持 1.0 即可。u 的延遲取 2 拍模擬對(duì)象固有的純滯后。3.2 PID 神經(jīng)元網(wǎng)絡(luò)控制器約 60 行可運(yùn)行實(shí)現(xiàn)控制器實(shí)現(xiàn)的核心是積分元狀態(tài)在每次 forward 時(shí)累加誤差微分元取當(dāng)前誤差與上一拍誤差之差比例元直接透?jìng)髡`差輸出層做線(xiàn)性加權(quán)和。注意輸出限幅和積分限幅是必須的否則訓(xùn)練初期權(quán)值稍大就會(huì)讓控制量飛出執(zhí)行機(jī)構(gòu)范圍。class PIDNeuralNet: PID神經(jīng)元網(wǎng)絡(luò)解耦控制器隱含層固定 P/I/D 運(yùn)算輸出層權(quán)值在線(xiàn)學(xué)習(xí) def __init__(self, n_loop2, lr0.05, momentum0.8, u_lim2.0, i_lim3.0): self.n n_loop self.lr lr self.momentum momentum self.u_lim u_lim # 控制量限幅 self.i_lim i_lim # 積分累積限幅防 windup self.h_dim n_loop * 3 # 每回路 比例/積分/微分 三個(gè)神經(jīng)元 # 輸出層權(quán)值小隨機(jī)初始化避免第一拍就打滿(mǎn)限幅 self.W np.random.uniform(-0.05, 0.05, (n_loop, self.h_dim)) self.b np.zeros(n_loop) # 輸出層偏置可學(xué)習(xí) self.vW np.zeros_like(self.W) # 動(dòng)量緩沖 self.vb np.zeros_like(self.b) self.integrators np.zeros(n_loop) # 積分元累積狀態(tài) self.last_e np.zeros(n_loop) # 上一拍誤差 def forward(self, e): # e: 長(zhǎng)度為 n 的誤差向量e r - y de e - self.last_e self.last_e e.copy() self.integrators e self.integrators np.clip(self.integrators, -self.i_lim, self.i_lim) # 組裝隱含層輸出向量 h h np.zeros(self.h_dim) for i in range(self.n): h[3 * i] e[i] # 比例元 h[3 * i 1] self.integrators[i] # 積分元 h[3 * i 2] de[i] # 微分元 u self.W h self.b return np.clip(u, -self.u_lim, self.u_lim), h def update(self, h, e, gain_sign): # 負(fù)梯度方向近似為 e * sign(G)G 為對(duì)象穩(wěn)態(tài)增益方向 delta e * gain_sign gradW np.outer(delta, h) # 對(duì) W 的負(fù)梯度 gradb delta.copy() # 對(duì) b 的負(fù)梯度 self.vW self.momentum * self.vW self.lr * gradW self.vb self.momentum * self.vb self.lr * gradb self.W self.vW self.b self.vbgain_sign 是每個(gè)回路對(duì)象增益的方向u 增大導(dǎo)致 y 增大就取 1.0反之為 -1.0。update 里的梯度方向與 2.3 節(jié)推導(dǎo)一致因?yàn)??J/?w -e * G * h梯度下降取負(fù)號(hào)后權(quán)值實(shí)際沿 e * sign(G) * h 的方向增加。邏輯上要記住這不是隨便定的方向而是「誤差為正時(shí)增強(qiáng)對(duì)應(yīng)控制通道、誤差為負(fù)時(shí)減弱對(duì)應(yīng)控制通道」的直觀(guān)體現(xiàn)。3.3 訓(xùn)練循環(huán)在線(xiàn)自整定的正確時(shí)序與收斂判斷訓(xùn)練采用在線(xiàn)自整定模式每個(gè)采樣周期做一次「對(duì)象演化 → 算誤差 → 生成控制量 → 更新權(quán)值」的循環(huán)。設(shè)定值序列要用不同周期的方波錯(cuò)開(kāi)保證兩個(gè)回路持續(xù)被激勵(lì)交叉耦合路徑才有機(jī)會(huì)被權(quán)值學(xué)習(xí)到。def run_train(steps1200): plant CoupledPlant() ctrl PIDNeuralNet(lr0.05, momentum0.8) # 兩路設(shè)定值用不同周期錯(cuò)開(kāi)保證耦合路徑被持續(xù)激勵(lì) t np.arange(steps) r1 np.where(t % 400 200, 1.0, 0.5) r2 np.where(t % 500 250, 0.8, 0.3) y1_list, y2_list [], [] u1_now u2_now 0.0 # 第一拍先用零控制量 for k in range(steps): # 先用上一拍的控制量演化對(duì)象再算本拍誤差 y1, y2 plant.step(u1_now, u2_now) e np.array([r1[k] - y1, r2[k] - y2]) u1_now, u2_now, h ctrl.forward(e) ctrl.update(h, e, gain_signnp.array([1.0, 1.0])) y1_list.append(y1) y2_list.append(y2) tail slice(steps - 400, steps) mae1 np.mean(np.abs(np.array(y1_list)[tail] - r1[tail])) mae2 np.mean(np.abs(np.array(y2_list)[tail] - r2[tail])) print(末段 MAE y1:, round(mae1, 4), y2:, round(mae2, 4)) if __name__ __main__: run_train()循環(huán)里的時(shí)序是一個(gè)容易寫(xiě)錯(cuò)的地方對(duì)象演化必須使用上一拍算出的控制量而不是本拍剛算出來(lái)的 u。如果順序反了等于把控制量提前了一拍仿真會(huì)表現(xiàn)出虛假的「超前調(diào)節(jié)」看起來(lái)跟蹤很好換到真實(shí)對(duì)象上立刻露餡。訓(xùn)練結(jié)束后觀(guān)察末段 MAE 是否明顯收斂到小值同時(shí)可以打印前 200 拍和末 200 拍的平均絕對(duì)誤差作對(duì)比。如果末段誤差不降反升優(yōu)先檢查 gain_sign 和積分限幅這兩處是發(fā)散的高發(fā)區(qū)。4. 把參數(shù)調(diào)到能上線(xiàn)學(xué)習(xí)率、動(dòng)量、初值與采樣周期的取舍4.1 一張參數(shù)表看懂異常表現(xiàn)PID 神經(jīng)元網(wǎng)絡(luò)的參數(shù)數(shù)量比普通 PID 多但沒(méi)有一個(gè)參數(shù)是「玄學(xué)」每個(gè)參數(shù)異常時(shí)都有可識(shí)別的現(xiàn)象。下表是我在仿真和半實(shí)物測(cè)試?yán)锓磸?fù)確認(rèn)過(guò)的對(duì)應(yīng)關(guān)系。參數(shù)推薦范圍異常表現(xiàn)調(diào)整策略學(xué)習(xí)率 η0.02 0.10偏大控制量高頻抖動(dòng)偏小幾百拍誤差都降不下來(lái)從 0.05 起步出現(xiàn)抖動(dòng)就減半動(dòng)量項(xiàng) α0.60 0.90過(guò)大階躍響應(yīng)超調(diào)明顯過(guò)小收斂慢且路徑曲折先用 0.8超調(diào)大就降到 0.7輸出層權(quán)值初值±0.01 ±0.05絕對(duì)值過(guò)大會(huì)導(dǎo)致第一拍控制量接近限幅用 0.05 以?xún)?nèi)的小隨機(jī)積分累積限幅標(biāo)稱(chēng)設(shè)定值的 2 5 倍過(guò)小靜差消不掉過(guò)大超調(diào)大且回落慢按誤差典型幅值乘 3 左右給控制量限幅執(zhí)行機(jī)構(gòu)飽和值的 1.2 倍左右限幅太緊會(huì)讓網(wǎng)絡(luò)長(zhǎng)期在邊界上磨比真實(shí)飽和值略寬即可學(xué)習(xí)率和動(dòng)量項(xiàng)是最常調(diào)的兩個(gè)旋鈕。學(xué)習(xí)率決定權(quán)值每一步走多遠(yuǎn)動(dòng)量項(xiàng)決定權(quán)值是否記得上一步的走向。兩者配合不好時(shí)典型表現(xiàn)是學(xué)習(xí)率大加動(dòng)量大輸出像鋸齒學(xué)習(xí)率小加動(dòng)量小訓(xùn)練像蝸牛爬。我一般先固定動(dòng)量 0.8調(diào)學(xué)習(xí)率到系統(tǒng)穩(wěn)定不抖再反過(guò)來(lái)微調(diào)動(dòng)量。4.2 權(quán)值初值與誤差歸一化別讓第一拍就打滿(mǎn)執(zhí)行機(jī)構(gòu)輸出層權(quán)值初值用 0.05 以?xún)?nèi)的小隨機(jī)數(shù)目的很明確訓(xùn)練第一拍時(shí)隱含層輸出 h 的數(shù)量級(jí)在 1 到 3 左右如果權(quán)值給到 0.5控制量第一拍就可能打到限幅之后積分元在飽和區(qū)里累積誤差權(quán)值修正方向被扭曲整個(gè)訓(xùn)練從起步就歪了。偏置 b 初始化為零即可讓網(wǎng)絡(luò)從「什么都不補(bǔ)償」的狀態(tài)開(kāi)始學(xué)。誤差歸一化是容易被新手忽略的步驟。上面仿真里設(shè)定值在 0.3 到 1.0 之間誤差量級(jí)是 1 以?xún)?nèi)直接可用。如果換到實(shí)際工藝參數(shù)比如溫度設(shè)定是 80 攝氏度流量是 50 立方米每小時(shí)誤差可能到幾十的量級(jí)這時(shí)候必須先把誤差縮放到 ±1 區(qū)間再送進(jìn)網(wǎng)絡(luò)否則積分元累積飛快限制幅形同虛設(shè)不同回路的誤差量級(jí)差異還會(huì)讓權(quán)值更新失衡。常見(jiàn)做法是每個(gè)回路單獨(dú)做縮放縮放系數(shù)取該回路設(shè)定值變化范圍的倒數(shù)。4.3 采樣周期決定微分元是幫手還是噪聲放大器的隱藏前提采樣周期在這類(lèi)神經(jīng)元網(wǎng)絡(luò)控制器里是一個(gè)容易被低估的參數(shù)。采樣周期取主導(dǎo)時(shí)間常數(shù)的 1/10 到 1/5 是仿真對(duì)象的常用經(jīng)驗(yàn)。太大會(huì)讓每一拍之間系統(tǒng)狀態(tài)變化過(guò)大微分元輸出變成大幅跳變等效增益被放大控制量會(huì)跟著毛刺太小則相鄰兩拍的誤差幾乎一樣微分元輸出接近零但測(cè)量噪聲被差分放大微分元從預(yù)測(cè)偏差變成噪聲放大器。一個(gè)額外的坑是純延遲。前面對(duì)象模型里 u 對(duì) y 有 2 拍延遲采樣周期縮短并不能減少延遲拍數(shù)反而會(huì)讓延遲對(duì)應(yīng)的相位損失相對(duì)更大。這時(shí)候不要試圖靠調(diào)學(xué)習(xí)率找回穩(wěn)定性正確做法是讓網(wǎng)絡(luò)結(jié)構(gòu)里給誤差多留一拍的記憶或者在輸出層前面加一個(gè)移位寄存器存儲(chǔ)歷史控制效果。等效地把微分元的差分間隔從 1 拍擴(kuò)大到 2 到 3 拍也能緩解短采樣周期帶來(lái)的噪聲放大問(wèn)題。5. PID 神經(jīng)元網(wǎng)絡(luò)解耦控制避坑五個(gè)常見(jiàn)排錯(cuò)場(chǎng)景5.1 換一組設(shè)定值就發(fā)散訓(xùn)練陷入過(guò)擬合現(xiàn)象在某一組設(shè)定值序列下訓(xùn)練末段跟蹤誤差很漂亮一換設(shè)定值的幅值或周期系統(tǒng)就開(kāi)始振蕩甚至發(fā)散。原因權(quán)值只在訓(xùn)練那組設(shè)定值附近被充分激勵(lì)輸出層權(quán)值記住了特定幅值下的誤差分布相當(dāng)于過(guò)擬合。積分元和比例元對(duì)不同幅值的響應(yīng)是線(xiàn)性的但耦合權(quán)值未必在別的幅值區(qū)間仍然合適。解決訓(xùn)練設(shè)定值序列里至少包含三組不同幅值、兩組不同周期的方波讓網(wǎng)絡(luò)見(jiàn)過(guò)多種誤差組合。另一個(gè)有用的習(xí)慣是訓(xùn)練結(jié)束后凍結(jié)權(quán)值換一組新設(shè)定值做驗(yàn)證如果驗(yàn)證誤差比訓(xùn)練誤差明顯大說(shuō)明激勵(lì)不充分需要回去加訓(xùn)練序列而不是加學(xué)習(xí)率。5.2 靜差消不掉積分元被限幅截?cái)嗷蛘?bias 沒(méi)學(xué)到位現(xiàn)象系統(tǒng)穩(wěn)定了但輸出與設(shè)定值始終差一個(gè)固定值比如設(shè)定 1.0輸出穩(wěn)定在 0.93。原因兩處最容易出問(wèn)題。一是積分累積限幅設(shè)得太小誤差累積到限幅值之后不再增長(zhǎng)積分元的輸出被截?cái)鄼?quán)值再大也補(bǔ)不回誤差二是輸出層偏置 b 沒(méi)有被正確更新或者初值給得太大導(dǎo)致網(wǎng)絡(luò)在零誤差附近靠偏置硬撐。解決把積分累積限幅放寬到設(shè)定值幅度的 3 倍以上同時(shí)檢查 update 里偏置的修正量是否和權(quán)值修正量同數(shù)量級(jí)。偏置的學(xué)習(xí)率可以比權(quán)值略大因?yàn)槠贸袚?dān)的是穩(wěn)態(tài)補(bǔ)償。另一個(gè)排查辦法是人為給系統(tǒng)加一個(gè)恒值擾動(dòng)看靜差是否隨著訓(xùn)練拍數(shù)增加而逐步縮小如果完全不縮小問(wèn)題幾乎都出在積分限幅。5.3 一路調(diào)整另一路跟著抖耦合通道激勵(lì)不足現(xiàn)象回路 2 的設(shè)定值階躍變化回路 1 的輸出跟著明顯波動(dòng)而且波動(dòng)幅度不隨時(shí)間減弱。原因交叉權(quán)值沒(méi)有學(xué)到有效的解耦值。最典型的原因是訓(xùn)練過(guò)程中兩個(gè)回路的設(shè)定值同步變化回路 2 的誤差和回路 1 的誤差總是同時(shí)出現(xiàn)網(wǎng)絡(luò)無(wú)法區(qū)分哪個(gè)誤差來(lái)自哪個(gè)通道交叉權(quán)值被平均掉了。解決把兩個(gè)回路的設(shè)定值在時(shí)間上錯(cuò)開(kāi)讓系統(tǒng)分別經(jīng)歷「只有回路 2 動(dòng)、回路 1 不動(dòng)」和「只有回路 1 動(dòng)、回路 2 不動(dòng)」的階段。前文訓(xùn)練代碼里 r1 用 400 拍周期、r2 用 500 拍周期錯(cuò)開(kāi)效果已經(jīng)夠用。如果現(xiàn)場(chǎng)不允許大范圍錯(cuò)開(kāi)設(shè)定值可以在訓(xùn)練指標(biāo)里加入耦合懲罰項(xiàng)把交叉通道上多余的波動(dòng)計(jì)進(jìn)損失函數(shù)但這需要能實(shí)時(shí)測(cè)量?jī)陕份敵龅牟▌?dòng)實(shí)現(xiàn)起來(lái)比重排訓(xùn)練序列要麻煩。5.4 輸出一直頂限幅增益方向符號(hào)給反了現(xiàn)象訓(xùn)練開(kāi)始后控制量直接沖上限幅輸出朝設(shè)定值相反的方向跑誤差越來(lái)越大幾拍后徹底發(fā)散。原因gain_sign 數(shù)組里有一個(gè)回路的符號(hào)給反了。前面推導(dǎo)里 Δw 的方向依賴(lài) sign(G)如果實(shí)際對(duì)象是反作用u 增大導(dǎo)致 y 減小而 sign 給了 1權(quán)值更新方向完全反轉(zhuǎn)誤差會(huì)被持續(xù)放大而不是減小。這是這門(mén)算法里最隱蔽也最致命的錯(cuò)誤因?yàn)榉?hào)錯(cuò)時(shí)網(wǎng)絡(luò)一樣在「學(xué)習(xí)」只不過(guò)學(xué)的是反方向。解決在接入網(wǎng)絡(luò)前先對(duì)每個(gè)回路單獨(dú)做一次開(kāi)環(huán)階躍測(cè)試記錄控制量增大時(shí)輸出的實(shí)際變化方向把符號(hào)寫(xiě)死進(jìn)配置。如果對(duì)象特性會(huì)隨工況翻轉(zhuǎn)增益方向比如某些換熱過(guò)程在低溫段和高溫段增益符號(hào)不同需要在每個(gè)工況區(qū)間單獨(dú)確認(rèn)必要時(shí)用在線(xiàn)辨識(shí)的差商替代固定符號(hào)但差商會(huì)引入噪聲一般只在仿真里用。5.5 仿真滿(mǎn)意現(xiàn)場(chǎng)不行模型失配被網(wǎng)絡(luò)照單全收現(xiàn)象仿真里跟蹤和耦合抑制都很好放到真實(shí)對(duì)象或半實(shí)物環(huán)境里卻出現(xiàn)持續(xù)慢振蕩或者某一回路始終達(dá)不到設(shè)定值。原因仿真對(duì)象的參數(shù)是固定的網(wǎng)絡(luò)在訓(xùn)練過(guò)程中把對(duì)象特性「記」進(jìn)了權(quán)值對(duì)象實(shí)際增益、時(shí)間常數(shù)和純延遲稍有偏差權(quán)值就失配。PID 神經(jīng)元網(wǎng)絡(luò)和普通 PID 一樣對(duì)模型失配沒(méi)有天然的免疫力不會(huì)因?yàn)閹狭恕妇W(wǎng)絡(luò)」兩個(gè)字就自動(dòng)魯棒。解決訓(xùn)練完成后做一次參數(shù)攝動(dòng)掃描把對(duì)象增益和時(shí)間常數(shù)在 ±20% 范圍內(nèi)打亂凍結(jié)權(quán)值重新跑同一組設(shè)定值看誤差和耦合度是否還在可接受范圍內(nèi)。如果掃描不過(guò)說(shuō)明方案需要加魯棒化處理比如約束權(quán)值范數(shù)、降低學(xué)習(xí)率讓權(quán)值不要走得太遠(yuǎn)或者用一個(gè)帶參數(shù)的失配對(duì)象集做多對(duì)象聯(lián)合訓(xùn)練。這個(gè)驗(yàn)證流程具體怎么做就是下一章的內(nèi)容。6. 進(jìn)階用對(duì)象攝動(dòng)掃描給解耦結(jié)果做魯棒性驗(yàn)收6.1 攝動(dòng)掃描腳本與兩個(gè)判定指標(biāo)訓(xùn)練完的權(quán)值不能直接拿去現(xiàn)場(chǎng)用我習(xí)慣先做一輪攝動(dòng)掃描。思路很簡(jiǎn)單凍結(jié)訓(xùn)練好的網(wǎng)絡(luò)讓對(duì)象參數(shù)在一個(gè)范圍內(nèi)隨機(jī)變化反復(fù)跑同一組設(shè)定值序列統(tǒng)計(jì)誤差和耦合度。對(duì)象代碼里預(yù)留的 g1、g2 參數(shù)就是為這一步準(zhǔn)備的。def robustness_sweep(ctrl, rounds40, seed7): rng np.random.default_rng(seed) worst_coupling 0.0 worst_mae 0.0 for _ in range(rounds): g1 rng.uniform(0.8, 1.2) # 通道1增益攝動(dòng) ±20% g2 rng.uniform(0.8, 1.2) # 通道2增益攝動(dòng) ±20% plant CoupledPlant(g1g1, g2g2) # 用凍結(jié)權(quán)值跑一遍不調(diào)用 update mae1, mae2, coup evaluate_frozen(ctrl, plant) worst_coupling max(worst_coupling, coup) worst_mae max(worst_mae, (mae1 mae2) / 2) return worst_mae, worst_couplingevaluate_frozen 的寫(xiě)法就是把第 3 章訓(xùn)練循環(huán)里的 ctrl.update 去掉其余時(shí)序不變。耦合度指標(biāo)我取回路 2 的設(shè)定值階躍期間回路 1 輸出的最大偏移量除以回路 2 設(shè)定值的變化幅值。這個(gè)比值在 10% 以?xún)?nèi)算合格10% 到 30% 可以接受但要注意現(xiàn)場(chǎng)風(fēng)險(xiǎn)超過(guò) 30% 說(shuō)明解耦只在名義模型附近成立權(quán)值還需要重新訓(xùn)練或者增加訓(xùn)練序列的覆蓋范圍。這個(gè)過(guò)程是我每次改完網(wǎng)絡(luò)結(jié)構(gòu)都會(huì)跑一遍的固定動(dòng)作。寧可多花半天把參數(shù)域掃完摸清方案的邊界在哪里也不愿意到現(xiàn)場(chǎng)才第一次看到系統(tǒng)在模型失配下的反應(yīng)。解耦控制算法的價(jià)值從來(lái)不只是仿真曲線(xiàn)好看而是換一組工況、換一組參數(shù)它還能不能站得住。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取