境下數(shù)據(jù)驅(qū)動(dòng)MPC實(shí)戰(zhàn):從DeePC求解到參數(shù)整定與避坑)
簡(jiǎn)介面向嘈雜環(huán)境下的數(shù)據(jù)驅(qū)動(dòng)模型預(yù)測(cè)控制MPC研究這份Matlab程序包提供了完整的可運(yùn)行實(shí)驗(yàn)環(huán)境。程序包以Matlab 2014、2019a、2024a為運(yùn)行平臺(tái)內(nèi)置附贈(zèng)案例數(shù)據(jù)采用參數(shù)化編程方式用戶可快速修改參數(shù)以適配不同控制場(chǎng)景適合控制工程領(lǐng)域的學(xué)生、工程師及研究人員用來(lái)驗(yàn)證算法或開(kāi)展二次開(kāi)發(fā)。整個(gè)壓縮包共包含2002個(gè)文件總大小約13.85MB其中以1697個(gè)Matlab腳本.m為主體另有269個(gè)HTML輔助文檔、C語(yǔ)言源文件、PDF說(shuō)明等覆蓋模型構(gòu)建、控制器求解與結(jié)果分析等環(huán)節(jié)代碼注釋詳細(xì)、結(jié)構(gòu)清晰降低了學(xué)習(xí)門(mén)檻。目前該資源已有57人學(xué)習(xí)感興趣者可借此直觀感受數(shù)據(jù)驅(qū)動(dòng)MPC在噪聲干擾下的魯棒性與自適應(yīng)能力為復(fù)雜系統(tǒng)控制方案的設(shè)計(jì)與優(yōu)化提供參考。1. 嘈雜環(huán)境中的數(shù)據(jù)驅(qū)動(dòng) MPC數(shù)據(jù)越“臟”越不能上來(lái)就調(diào)包現(xiàn)場(chǎng)工程師拿到一個(gè)標(biāo)著“嘈雜環(huán)境中的數(shù)據(jù)驅(qū)動(dòng) MPC.rar”的壓縮包時(shí)心情通常是矛盾的傳統(tǒng)模型預(yù)測(cè)控制最折磨人的環(huán)節(jié)就是機(jī)理建模而數(shù)據(jù)驅(qū)動(dòng) MPC 號(hào)稱能從歷史數(shù)據(jù)里直接把預(yù)測(cè)模型學(xué)出來(lái)省掉一次次階躍測(cè)試和辨識(shí)實(shí)驗(yàn)但“嘈雜環(huán)境”四個(gè)字又提醒你這批代碼要面對(duì)的是傳感器噪聲、工藝擾動(dòng)和執(zhí)行器死區(qū)疊加在一起的真實(shí)工業(yè)數(shù)據(jù)。結(jié)論先說(shuō)數(shù)據(jù)驅(qū)動(dòng) MPC 在嘈雜環(huán)境下完全能用但直接拿開(kāi)環(huán)數(shù)據(jù)訓(xùn)練再閉環(huán)保真大概率前幾步就翻車。這篇筆記把從數(shù)據(jù)生成、Hankel 矩陣構(gòu)造、DeePC 求解到參數(shù)整定和閉環(huán)驗(yàn)證的完整路徑拆開(kāi)講適合鍋爐燃燒優(yōu)化、壓縮機(jī)控制、機(jī)器人軌跡跟蹤這些被機(jī)理模型逼瘋、又怕噪聲毀掉閉環(huán)的從業(yè)者。2. 數(shù)據(jù)驅(qū)動(dòng) MPC 的三條技術(shù)路線子空間、DeePC 與偽數(shù)據(jù)驅(qū)動(dòng)陷阱先講原理。數(shù)據(jù)驅(qū)動(dòng) MPC 并不是丟掉優(yōu)化框架而是把“預(yù)測(cè)模型”這個(gè)環(huán)節(jié)從機(jī)理白盒換成數(shù)據(jù)黑匣子。標(biāo)準(zhǔn) MPC 在每個(gè)控制周期要做的事是“基于當(dāng)前狀態(tài)預(yù)測(cè)未來(lái) N 步輸出在輸入輸出約束下求使代價(jià)函數(shù)最小的控制序列”傳統(tǒng)做法需要被控對(duì)象的傳遞函數(shù)或狀態(tài)空間模型數(shù)據(jù)驅(qū)動(dòng) MPC 的差異只在于預(yù)測(cè)這一動(dòng)作不再依賴物理方程而是由歷史輸入輸出數(shù)據(jù)決定的線性映射或參數(shù)化表示。2.1 路線一子空間辨識(shí) 標(biāo)準(zhǔn) MPC控制器內(nèi)核不動(dòng)只換模型來(lái)源最保守、也最適合工程師上手的數(shù)據(jù)驅(qū)動(dòng) MPC 路線是子空間辨識(shí)。它的思想是直接從一批足夠激勵(lì)的輸入輸出數(shù)據(jù)里估計(jì)出一個(gè)低階狀態(tài)空間模型A, B, C, D然后用這個(gè)模型繼續(xù)跑你已經(jīng)寫(xiě)好的標(biāo)準(zhǔn) MPC 求解器。常見(jiàn)做法是先構(gòu)造由過(guò)去和未來(lái)的輸入輸出構(gòu)成的塊 Hankel 矩陣做一次 LQ 分解或 SVD把可觀測(cè)矩陣分離出來(lái)進(jìn)而得到狀態(tài)序列估計(jì)最后用最小二乘解出系統(tǒng)矩陣。這條路的優(yōu)點(diǎn)在于你已有的 MPC 代碼、約束和權(quán)重全都不用改等于只把“模型來(lái)源”換掉了。在噪聲環(huán)境下子空間辨識(shí)最容易踩的坑是將來(lái)噪聲當(dāng)作狀態(tài)通道導(dǎo)致控制量頻繁抖動(dòng)。常規(guī)解決辦法是使用工具變量法用過(guò)去的輸入作為工具變量來(lái)消除噪聲項(xiàng)與狀態(tài)的關(guān)聯(lián)本質(zhì)是在 SVD 之前先做一個(gè)投影去偏。做完這步后續(xù) MPC 的魯棒性基本等同你原有控制器比較可控。2.2 路線二DeePC用數(shù)據(jù)本身當(dāng)預(yù)測(cè)模型不是先學(xué)模型再用模型近五年學(xué)術(shù)界和工程界討論“數(shù)據(jù)驅(qū)動(dòng) MPC”時(shí)很大一部分指的是 DeePCData-enabled Predictive Control數(shù)據(jù)驅(qū)動(dòng)預(yù)測(cè)控制。它依據(jù) Willems 基本引理對(duì)一個(gè)可控的線性系統(tǒng)只要輸入序列持續(xù)激勵(lì)那么任意一條足夠長(zhǎng)的歷史輸入輸出軌跡都可以表示為同一個(gè) Hankel 矩陣行空間的線性組合。也就是說(shuō)數(shù)據(jù)塊本身就可以當(dāng)預(yù)測(cè)模型用不需要先提煉出 A, B, C, D。DeePC 每一拍求解的是一個(gè)帶約束的二次規(guī)劃設(shè) T_ini 步歷史窗口、N 步預(yù)測(cè)窗口把輸入和輸出拼成一個(gè)塊 Hankel 矩陣再引入一個(gè)系數(shù)向量 g讓“Hankel 矩陣乘 g”同時(shí)復(fù)現(xiàn)過(guò)去 T_ini 步和預(yù)測(cè)未來(lái) N 步然后對(duì)預(yù)測(cè)輸出施加入力約束和代價(jià)函數(shù)。噪聲環(huán)境下這個(gè)等式約束不能精確滿足因此要加松弛變量并由正則化項(xiàng)懲罰。比起子空間辨識(shí)DeePC 的優(yōu)勢(shì)是省去中間模型辨識(shí)環(huán)節(jié)劣勢(shì)是矩陣規(guī)模隨數(shù)據(jù)量和窗口長(zhǎng)度膨脹實(shí)時(shí)性壓力明顯更大。2.3 路線三偽數(shù)據(jù)驅(qū)動(dòng)的端到端學(xué)習(xí)控制第三種常見(jiàn)做法是端到端策略學(xué)習(xí)即不構(gòu)造 Hankel 矩陣也不設(shè)計(jì)預(yù)測(cè)時(shí)域直接把當(dāng)前狀態(tài)送到神經(jīng)網(wǎng)絡(luò)或高斯過(guò)程回歸里輸出控制量。它在演示視頻里效果驚人但在嘈雜的工業(yè)環(huán)境里我一般不會(huì)優(yōu)先推薦原因有三個(gè)一是它沒(méi)有預(yù)測(cè)時(shí)域的概念也沒(méi)有約束的可行性保證本質(zhì)上已經(jīng)不是 MPC二是噪聲會(huì)被當(dāng)作狀態(tài)特征直接映射到控制量噪聲方向的小擾動(dòng)都可能帶來(lái)執(zhí)行機(jī)構(gòu)的大動(dòng)作三是這類方法的數(shù)據(jù)需求量和閉環(huán)驗(yàn)證成本遠(yuǎn)高于前兩者。與其說(shuō)它是數(shù)據(jù)驅(qū)動(dòng) MPC不如說(shuō)是“偽數(shù)據(jù)驅(qū)動(dòng)”的強(qiáng)化學(xué)習(xí)應(yīng)用。2.4 選型對(duì)照數(shù)據(jù)量、噪聲強(qiáng)度與實(shí)時(shí)性路線需要的數(shù)據(jù)量噪聲魯棒性約束處理實(shí)時(shí)性子空間辨識(shí) 標(biāo)準(zhǔn) MPC中等半小時(shí)開(kāi)環(huán)激勵(lì)足夠依賴辨識(shí)去偏手段中高靠原有 MPC 層保障高模型階次低DeePC大Hankel 矩陣需要足夠列依賴正則化與松弛變量中等直接在優(yōu)化中施加中等矩陣規(guī)模大端到端學(xué)習(xí)很大且需要閉環(huán)試錯(cuò)低噪聲易被放大難以嚴(yán)格保證推理雖快訓(xùn)練與驗(yàn)證成本高對(duì)絕大多數(shù)帶噪聲的過(guò)程控制場(chǎng)景我會(huì)優(yōu)先建議子空間辨識(shí)打底、DeePC 做對(duì)比驗(yàn)證如果追求論文級(jí)效果或系統(tǒng)強(qiáng)烈非線性再考慮更復(fù)雜的變體。選型時(shí)還有一個(gè)容易被忽略的現(xiàn)實(shí)因素你的團(tuán)隊(duì)后續(xù)要維護(hù)的是哪個(gè)代碼棧。子空間辨識(shí)加標(biāo)準(zhǔn) MPC 的維護(hù)成本最低DeePC 一旦需要調(diào)窗長(zhǎng)和正則化排錯(cuò)難度會(huì)陡增。3. 最小復(fù)現(xiàn)跑通一個(gè)帶測(cè)量噪聲的 mpc 模型預(yù)測(cè)控制閉環(huán)標(biāo)題里的“rar”通常意味著拿到的是一批腳本、數(shù)據(jù)和說(shuō)明文檔而不是一個(gè)可以 pip install 的庫(kù)。這類工程包常見(jiàn)的組織方式是一個(gè)生成開(kāi)環(huán)數(shù)據(jù)的腳本、一個(gè)構(gòu)造 Hankel 矩陣并求解優(yōu)化問(wèn)題的腳本、一個(gè)閉環(huán)仿真主循環(huán)以及一個(gè)集中存放參數(shù)的配置文件。建議先把這個(gè)骨架建起來(lái)再往里填你的真實(shí)數(shù)據(jù)比直接改網(wǎng)上陌生人貼的單個(gè)文件要穩(wěn)得多。3.1 先梳理包結(jié)構(gòu)把運(yùn)行入口和參數(shù)入口分開(kāi)一個(gè)我常用的結(jié)構(gòu)大致是這樣data_driven_mpc/ ├── data_gen.py # 開(kāi)環(huán)激勵(lì) 噪聲注入生成 u_history.npy / y_history.npy ├── deepc_core.py # 構(gòu)造塊 Hankel 矩陣定義并求解 DeePC 優(yōu)化問(wèn)題 ├── run_closed_loop.py # 閉環(huán)主循環(huán)調(diào)用 deepc_core 里的求解器 └── params.yaml # 所有窗口長(zhǎng)度、正則化權(quán)重、約束邊界集中管理這樣組織有兩個(gè)好處換數(shù)據(jù)時(shí)不用改求解器代碼調(diào)參數(shù)時(shí)不破壞代碼結(jié)構(gòu)。無(wú)論你拿到的壓縮包內(nèi)部怎么命名建議先按這個(gè)思路把文件和參數(shù)重新歸位否則后續(xù)更換采樣周期或數(shù)據(jù)文件時(shí)到處找超參數(shù)的體驗(yàn)會(huì)非常痛苦。這看起來(lái)像流程問(wèn)題實(shí)際是很多工程師最初的“玄學(xué)”煩惱來(lái)源參數(shù)明明改了代碼里卻被另一處硬編碼覆蓋掉了。3.2 第一步生成帶噪聲的開(kāi)環(huán)數(shù)據(jù)集假設(shè)被控對(duì)象是一個(gè)二階系統(tǒng)狀態(tài)方程為x[k1] A x[k] b u[k] w[k]測(cè)量輸出為y[k] c x[k] v[k]其中w是過(guò)程噪聲、v是測(cè)量噪聲。用隨機(jī)二進(jìn)制序列做輸入激勵(lì)模擬工廠里常見(jiàn)的 PRBS 測(cè)試代碼保留隨機(jī)種子以保證結(jié)果可復(fù)現(xiàn)import numpy as np # 被控對(duì)象二階離散狀態(tài)空間采樣周期 0.1s A np.array([[0.95, 0.10], [-0.05, 0.85]]) b np.array([[0.10], [0.20]]) c np.array([[1.0, 0.5]]) T 2000 # 開(kāi)環(huán)數(shù)據(jù)長(zhǎng)度 rng np.random.default_rng(42) u rng.choice(np.array([-1.0, 1.0]), sizeT) # PRBS 式激勵(lì) u u 0.01 * rng.standard_normal(T) # 輸入端小幅擾動(dòng) x np.zeros((2, T)) y np.zeros((T, 1)) w_std 0.05 # 過(guò)程噪聲標(biāo)準(zhǔn)差 v_std 0.10 # 測(cè)量噪聲標(biāo)準(zhǔn)差 for k in range(T - 1): x[:, [k 1]] A x[:, [k]] b * u[k] w_std * rng.standard_normal((2, 1)) y[k] c x[:, [k]] v_std * rng.standard_normal() u u.reshape(-1, 1) np.save(u_history.npy, u) np.save(y_history.npy, y) print(SNR(dB):, 20 * np.log10(np.std(y) / v_std))這段代碼的要點(diǎn)是激勵(lì)信號(hào)要足夠“有效”。隨機(jī)二進(jìn)制序列相比正弦掃頻的優(yōu)勢(shì)是能同時(shí)激發(fā)多個(gè)頻率段讓 Hankel 矩陣行滿秩的概率更高。測(cè)量噪聲標(biāo)準(zhǔn)差 v_std 決定了信噪比工程上一般先調(diào)到能看到輸出趨勢(shì)、又不至于淹沒(méi)信號(hào)的程度建議設(shè)成輸出標(biāo)準(zhǔn)差的 5% 到 15%。過(guò)程噪聲 w_std 不要設(shè)成零否則閉環(huán)仿真的“嘈雜環(huán)境”就名不副實(shí)了。3.3 第二步實(shí)現(xiàn) DeePC 核心求解器DeePC 的求解邏輯是把“歷史軌跡必須被復(fù)現(xiàn)”和“未來(lái)軌跡要盡量接近參考”同時(shí)塞進(jìn)一個(gè)帶約束的二次規(guī)劃。假設(shè) T_ini 為過(guò)去窗口長(zhǎng)度N 為預(yù)測(cè)時(shí)域塊 Hankel 矩陣由輸入軌跡和輸出軌跡上下堆疊而成總行數(shù)為 2倍的T_ini N。先構(gòu)建矩陣def build_hankel(u, y, T_ini, N, T_data): L T_ini N # 每條軌跡的長(zhǎng)度 n_cols T_data - L 1 H_u np.zeros((L * u.shape[1], n_cols)) H_y np.zeros((L * y.shape[1], n_cols)) for j in range(n_cols): H_u[:, j] u[j:j L].flatten() H_y[:, j] y[j:j L].flatten() return np.vstack([H_u, H_y]) # 上半塊是輸入軌跡下半塊是輸出軌跡接下來(lái)是每一拍的優(yōu)化求解。把 Hankel 矩陣乘上系數(shù)向量 g就得到一整條長(zhǎng)度為 T_ini N 的輸入軌跡和輸出軌跡。上半塊前 T_ini 行應(yīng)等于過(guò)去輸入下半塊前 T_ini 行應(yīng)等于過(guò)去輸出允許松弛上半塊后 N 行是未來(lái)的控制序列下半塊后 N 行是預(yù)測(cè)輸出import cvxpy as cp import numpy as np def solve_deepc(H, T_ini, N, u_past, y_past, U_ub, U_lb, lambda_g, lambda_y): L T_ini N n_g H.shape[1] g cp.Variable(n_g) sigma_y cp.Variable(N) # 輸出等式松弛變量吸收噪聲影響 y_ref np.zeros(N) # 參考軌跡實(shí)際場(chǎng)景由設(shè)定值平移后得到 u_traj H[0:L, :] g y_traj H[L:2 * L, :] g u_past_pred u_traj[0:T_ini] y_past_pred y_traj[0:T_ini] u_fut_pred u_traj[T_ini:L] y_fut_pred y_traj[T_ini:L] cost cp.sum_squares(y_fut_pred - y_ref) \ lambda_g * cp.sum_squares(g) \ lambda_y * cp.sum_squares(sigma_y) constraints [ u_past_pred u_past.flatten(), y_past_pred y_past.flatten() sigma_y, U_lb u_fut_pred, u_fut_pred U_ub, ] prob cp.Problem(cp.Minimize(cost), constraints) prob.solve(solvercp.CLARABELLE) # 也可換成 OSQP / ECOS return g.value, sigma_y.value這里 cost 的三項(xiàng)分別對(duì)應(yīng)跟蹤誤差、系數(shù)向量范數(shù)、輸出松弛變量范數(shù)。lambda_g 是抵抗噪聲過(guò)擬合的關(guān)鍵lambda_y 是允許“輸出歷史軌跡不必被嚴(yán)格復(fù)現(xiàn)”的退路。代碼中行索引的規(guī)則是H 的上半塊是輸入軌跡下半塊是輸出軌跡每一塊內(nèi)部前 T_ini 行是過(guò)去、后 N 行是未來(lái)。真實(shí)驗(yàn)證時(shí)建議先在開(kāi)環(huán)數(shù)據(jù)上做一步預(yù)測(cè)測(cè)試確認(rèn)索引對(duì)齊了再接入閉環(huán)否則會(huì)出現(xiàn)看似正常、其實(shí)完全失效的“靜默翻車”。3.4 第三步閉環(huán)主循環(huán)把求解器嵌進(jìn)被控對(duì)象閉環(huán)仿真的每一拍要做三件事取當(dāng)前窗口的輸入輸出作為初始條件、調(diào)用求解器得到系數(shù) g、把 g 對(duì)應(yīng)的第一個(gè)未來(lái)輸入施加給被控對(duì)象然后更新?tīng)顟B(tài)T_sim 800 T_ini 50 N 30 H build_hankel(u, y, T_ini, N, T) u_sim np.zeros((T_sim, 1)) y_sim np.zeros((T_sim, 1)) # 前 T_ini 步用零輸入建立初始窗口實(shí)際工程中來(lái)自上一段運(yùn)行歷史 for k in range(T_sim): if k T_ini: u_sim[k] 0.0 # 更新被控對(duì)象狀態(tài)y_sim[k] 為帶噪聲測(cè)量 continue u_past u_sim[k - T_ini:k] y_past y_sim[k - T_ini:k] g_vec, _ solve_deepc(H, T_ini, N, u_past, y_past, 2.0, -2.0, 1e-3, 1e2) u_sim[k] H[T_ini, :] g_vec # 只取未來(lái)控制序列的第一個(gè)值 # 在這里把 u_sim[k] 施加給被控對(duì)象更新?tīng)顟B(tài)并記錄 y_sim[k]關(guān)鍵不在循環(huán)本身而在三個(gè)細(xì)節(jié)。第一每次“只取第一個(gè)控制量”就是滾動(dòng)優(yōu)化的意義如果為了省事把全部序列都執(zhí)行一遍就不是 MPC 了。第二T_ini 長(zhǎng)度要大于系統(tǒng)記憶尤其對(duì)含積分過(guò)程的系統(tǒng)太短會(huì)導(dǎo)致初始條件信息不足。第三如果輸入端有執(zhí)行器飽和約束不能只加在優(yōu)化變量上仿真環(huán)境里的被控對(duì)象也要加同樣的限幅否則控制器會(huì)以為它給了一個(gè) 2.0 的輸入實(shí)際執(zhí)行機(jī)構(gòu)只動(dòng)到 1.5閉環(huán)表現(xiàn)自然對(duì)不上。4. 嘈雜環(huán)境的建模鏈路數(shù)據(jù)清洗、正則化與參數(shù)整定這一篇集中回答“數(shù)據(jù)臟了怎么辦”。數(shù)據(jù)驅(qū)動(dòng) MPC 的上限由數(shù)據(jù)決定不是由求解器決定的。哪怕優(yōu)化器寫(xiě)得再漂亮喂進(jìn)去的是一段帶趨勢(shì)漂移、異常脈沖和時(shí)變?cè)鲆娴臄?shù)據(jù)學(xué)出來(lái)的預(yù)測(cè)也一樣飄。所以進(jìn)入?yún)?shù)整定之前先把數(shù)據(jù)處理做扎實(shí)。4.1 數(shù)據(jù)清洗異常值剔除、趨勢(shì)項(xiàng)消除與均值去偏工業(yè)數(shù)據(jù)的第一次清洗是異常值檢測(cè)。傳感器卡死、通信抖動(dòng)會(huì)產(chǎn)生單點(diǎn)跳變這種脈沖在 Hankel 矩陣?yán)飼?huì)污染一整列。常見(jiàn)做法是先做中位數(shù)濾波再做閾值判別如果某一時(shí)刻的測(cè)量偏離局部中位數(shù)超過(guò) k 倍標(biāo)準(zhǔn)差就把該點(diǎn)標(biāo)記為異常并按線性插值替換。第二步是去趨勢(shì)因?yàn)殚_(kāi)環(huán)激勵(lì)期間工藝基線可能緩慢漂移這會(huì)讓數(shù)據(jù)不滿足時(shí)不變假設(shè)。工程上我會(huì)先做一階差分并檢查差分序列是否平穩(wěn)再?zèng)Q定是減趨勢(shì)項(xiàng)還是高通濾波。最后一定要減均值因?yàn)?DeePC 的初始條件里包含直流分量如果不把均值單獨(dú)建??刂破鲿?huì)為一個(gè)實(shí)際上不存在的直流工作點(diǎn)浪費(fèi)執(zhí)行機(jī)構(gòu)行程。import numpy as np from scipy.ndimage import median_filter def clean_data(y_raw, k_thresh8.0): y_med median_filter(y_raw, size7) resid y_raw - y_med std_r np.std(resid) mask np.abs(resid) k_thresh * std_r y_clean y_raw.copy() y_clean[mask] y_med[mask] y_clean y_clean - np.mean(y_clean) # 去均值直流工作點(diǎn)另行建模 return y_clean, mask參數(shù) k_thresh 一般取 6 到 10。取 6 會(huì)更激進(jìn)適合傳感器經(jīng)常毛刺的現(xiàn)場(chǎng)取 10 更保守適合本身較干凈但偶爾有周期擾動(dòng)的數(shù)據(jù)。中位數(shù)濾波器窗口 size 取 5 到 9窗口太小去不掉成串的尖峰窗口太大會(huì)把真實(shí)階躍變化也抹平。清洗完成后建議打印被標(biāo)記的樣本占總樣本的比例如果超過(guò) 2%就要懷疑是傳感器硬件問(wèn)題而不是單純的偶發(fā)噪聲。4.2 正則化與秩約束對(duì)抗噪聲的后悔藥噪聲環(huán)境下DeePC 的 Hankel 矩陣幾乎必然滿秩因?yàn)樵肼暯o矩陣注入了無(wú)關(guān)的奇異值。此時(shí)不加正則優(yōu)化器會(huì)利用這些虛假自由度把歷史軌跡“完美復(fù)現(xiàn)”但預(yù)測(cè)出的未來(lái)軌跡對(duì)噪聲極度敏感。兩個(gè)后悔藥一個(gè)是給系數(shù) g 加 2 范數(shù)正則逼著解不要依賴過(guò)大的系數(shù)組合另一個(gè)更本質(zhì)是直接對(duì) Hankel 矩陣做截?cái)?SVD預(yù)估系統(tǒng)階次 n只保留前 n 個(gè)奇異值把剩下的當(dāng)作噪聲子空間丟掉。實(shí)際操作中我一般兩個(gè)都用先截?cái)喟延行е冉迪聛?lái)再保留一個(gè)小量 lambda_g 防止截?cái)噙吔缣帞?shù)值抖動(dòng)。截?cái)?SVD 的 Python 寫(xiě)法很簡(jiǎn)短def truncate_hankel(H, rank): U, S, Vt np.linalg.svd(H, full_matricesFalse) S[rank:] 0.0 return (U * S) Vtrank 怎么選一個(gè)實(shí)用辦法是畫(huà)出奇異值曲線找到明顯“膝蓋”的位置。以第 3 章的二階系統(tǒng)為例前兩個(gè)奇異值通常比后面的高一個(gè)數(shù)量級(jí)取 rank2 是合理的如果系統(tǒng)有積分環(huán)節(jié)或明顯延遲rank 適當(dāng)增加到 4 到 6。注意截?cái)嘀?H 不再嚴(yán)格等于原始數(shù)據(jù)矩陣但求解器并不關(guān)心這一點(diǎn)它只關(guān)心行空間是否被合理壓縮。4.3 參數(shù)整定第一輪可直接抄的準(zhǔn)則初學(xué)者拿到窗長(zhǎng) T_ini、預(yù)測(cè)時(shí)域 N、數(shù)據(jù)長(zhǎng)度 T_data、lambda_g 和 lambda_y通常無(wú)從下手。下面是一組在多個(gè)仿真工程上驗(yàn)證得比較順的初始值參數(shù)第一輪取值調(diào)整方向T_data2000 點(diǎn)以上噪聲大就加到 5000保證 Hankel 列數(shù)遠(yuǎn)大于有效秩T_ini對(duì)象階次估值的 3 到 5 倍系統(tǒng)記憶長(zhǎng)就加大過(guò)大會(huì)讓可用列數(shù)變少N覆蓋上升時(shí)間的 1.5 倍太短會(huì)短視激進(jìn)太長(zhǎng)松弛變量權(quán)力過(guò)大lambda_g1e-3 到 1e-2噪聲大則調(diào)大先抑制振蕩再回調(diào)lambda_y1e1 到 1e3噪聲大應(yīng)允許更大松弛但過(guò)大會(huì)放棄歷史信息一個(gè)實(shí)用的整定順序是先用截?cái)?SVD 確定有效階次接著固定 T_ini 和 N然后單獨(dú)觀察給定值階躍下的閉環(huán)響應(yīng)。如果輸出在設(shè)定值附近高頻抖動(dòng)優(yōu)先加大 lambda_g如果輸出遲緩甚至不跟蹤再檢查 lambda_y 是否太大。噪聲大的系統(tǒng)里lambda_y 偏大比偏小的后果更具隱蔽性——每一步求解都合理但長(zhǎng)時(shí)間看就是“躺平不干活”控制器把一切偏差都?xì)w咎于松弛變量而 g 幾乎沒(méi)有作用。5. 避坑記錄數(shù)據(jù)驅(qū)動(dòng) MPC 最容易翻車的 5 個(gè)場(chǎng)景下面這些坑不是理論里的假想是實(shí)際操作中最常被反復(fù)問(wèn)到的五類典型故障。每條按現(xiàn)象、原因、解決的順序?qū)憣?duì)應(yīng)到代碼和參數(shù)上可以直接排查。5.1 現(xiàn)象訓(xùn)練誤差很小閉環(huán)仿真前幾步就發(fā)散這是最讓人沮喪的一種場(chǎng)景離線重構(gòu)歷史軌跡時(shí)誤差只有 0.01一接閉環(huán)第一個(gè)時(shí)刻輸出就飛了。原因通常是 Hankel 矩陣的行空間包含了噪聲對(duì)應(yīng)的高頻方向離線預(yù)測(cè)用的是同一批數(shù)據(jù)的內(nèi)插所以“預(yù)測(cè)”天然容易過(guò)擬合閉環(huán)時(shí)初始條件是從在線測(cè)量取的噪聲方向與訓(xùn)練數(shù)據(jù)不一致問(wèn)題立刻暴露。解決對(duì) H 做截?cái)?SVD、降低有效秩并把 lambda_g 從 1e-3 往上調(diào)到 1e-1 左右觀察同時(shí)確認(rèn)初始條件里沒(méi)有把噪聲放大測(cè)量濾波如果已經(jīng)顯著滯后也不要用過(guò)大的 T_ini。5.2 現(xiàn)象開(kāi)環(huán)激勵(lì)數(shù)據(jù)明明很豐富求解時(shí)卻報(bào)“不可行”DeePC 里最容易被忽略的約束是輸入輸出的初始軌跡等式約束。如果 T_ini 步的過(guò)去數(shù)據(jù)在 Hankel 矩陣?yán)餂](méi)有對(duì)應(yīng)的列能匹配等式約束就會(huì)沖突。原因通常是激勵(lì)不充分激勵(lì)信號(hào)在某些幅值區(qū)間停留時(shí)間太短導(dǎo)致 Hankel 矩陣中某些行的線性組合覆蓋不到當(dāng)前工作點(diǎn)。解決檢查持續(xù)激勵(lì)條件把輸入改為幅值在 [-2, 2] 之間隨機(jī)切換、每段保持 3 到 5 個(gè)采樣周期的 PRBS如果仍然不可行可以先把初始軌跡等式約束加松弛變量但這種方式只能用來(lái)排查不能作為長(zhǎng)期方案留在控制器里。5.3 現(xiàn)象輸出跟蹤看著不錯(cuò)控制量卻像鋸齒一樣瘋狂切換控制量高頻抖動(dòng)的直接原因是代價(jià)函數(shù)里缺少對(duì)控制量變化量的懲罰或者有效秩沒(méi)有被截?cái)唷:芏喙こ處煹谝环磻?yīng)是調(diào)權(quán)重但真正的問(wèn)題是模型把噪聲當(dāng)成了可控動(dòng)態(tài)被控對(duì)象本質(zhì)上對(duì)高頻控制不那么敏感而噪聲讓預(yù)測(cè)輸出對(duì)高頻輸入非常敏感。解決順序是先做截?cái)?SVD 降低有效秩再在代價(jià)函數(shù)里增加對(duì)u_fut_pred[1:] - u_fut_pred[:-1]的懲罰項(xiàng)。如果你現(xiàn)在的代碼沒(méi)有構(gòu)造對(duì)控制增量的懲罰即便把 lambda_g 調(diào)大也只能緩解系數(shù)爆炸不能直接抑制控制量切換頻率。5.4 現(xiàn)象把訓(xùn)練數(shù)據(jù)換到另一個(gè)工況閉環(huán)性能明顯下降數(shù)據(jù)驅(qū)動(dòng) MPC 的前提是工作點(diǎn)附近的線性化。嘈雜環(huán)境還疊加了另一個(gè)問(wèn)題同一個(gè)過(guò)程在不同負(fù)荷下增益和動(dòng)態(tài)特性變化很大一組數(shù)據(jù)訓(xùn)練出來(lái)的 Hankel 矩陣不可能覆蓋所有工況。解決用分段建模每個(gè)工況段單獨(dú)構(gòu)造 Hankel 矩陣與訓(xùn)練數(shù)據(jù)在控制器里根據(jù)當(dāng)前工作點(diǎn)切換數(shù)據(jù)塊或者在數(shù)據(jù)生成階段加入雙脈沖測(cè)試以覆蓋不同幅值區(qū)間的增益再用離線閉環(huán)仿真驗(yàn)證。如果你的現(xiàn)場(chǎng)工況切換很頻繁那么純線性的數(shù)據(jù)驅(qū)動(dòng) MPC 也許不該是首選子空間辨識(shí)加增益調(diào)度會(huì)更務(wù)實(shí)。5.5 現(xiàn)象按論文默認(rèn)參數(shù)跑通實(shí)測(cè)性能比不過(guò) PID很多初次嘗試者忽略了一個(gè)事實(shí)論文里的 lambda_g 和 lambda_y 是針對(duì)某個(gè)特定系統(tǒng)調(diào)出來(lái)的換系統(tǒng)就必須重新整定PID 的整定經(jīng)驗(yàn)也不能直接照搬。這里面有個(gè)深層原因DeePC 的代價(jià)函數(shù)各項(xiàng)量綱不一致輸出誤差的平方和與 g 的平方和可能相差好幾個(gè)數(shù)量級(jí)論文里設(shè)成 1e-3 的 lambda_g 放到實(shí)際系統(tǒng)里相當(dāng)于沒(méi)有約束。解決先把所有信號(hào)做歸一化再整定然后從一次開(kāi)環(huán)預(yù)測(cè)實(shí)驗(yàn)的誤差尺度出發(fā)讓 lambda_g 與跟蹤誤差項(xiàng)的數(shù)值量級(jí)處于同一范圍。不要盲從壓縮包里的默認(rèn)配置那些配置通常只對(duì)生成它的那一臺(tái)設(shè)備有效。6. 驗(yàn)證閉環(huán)性能蒙特卡羅擾動(dòng)測(cè)試與三個(gè)可復(fù)現(xiàn)指標(biāo)數(shù)據(jù)驅(qū)動(dòng)控制的匯報(bào)容易讓人“看體驗(yàn)”但工程決策需要數(shù)字。單次仿真具有偶然性噪聲環(huán)境下我一般至少跑 30 種不同的隨機(jī)種子每次使用不同的噪聲序列然后統(tǒng)計(jì)三個(gè)指標(biāo)RMS 跟蹤誤差、控制量變化總量、約束違反率。計(jì)算代碼很簡(jiǎn)短err_rms np.sqrt(np.mean(err_seq ** 2)) act_var np.mean(np.abs(np.diff(u_seq, axis0)), axis0) viol_rate np.sum(viol_count) / len(viol_count)判斷這一技術(shù)方向值不值得投入我的經(jīng)驗(yàn)是先花兩天把開(kāi)環(huán)數(shù)據(jù)生成與清洗跑通再用現(xiàn)有 PID 或常規(guī) MPC 做基線與數(shù)據(jù)驅(qū)動(dòng) MPC 在同樣的擾動(dòng)序列下對(duì)比。如果數(shù)據(jù)驅(qū)動(dòng)版本在約束條件相同的情況下RMS 跟蹤誤差能下降 20% 以上并且控制量動(dòng)作量沒(méi)有翻倍就值得繼續(xù)投入精力和預(yù)算否則再天花亂墜的“無(wú)模型”故事也不值得為它付出額外的維護(hù)成本。黑匣子輕便但必須建立在可驗(yàn)證的性能增益上否則就會(huì)變成后期排錯(cuò)的地獄入口。我自己的教訓(xùn)是曾經(jīng)花了兩周做一版端到端學(xué)習(xí)控制最后還是在閉環(huán)里加了 PID 墊底才敢交給現(xiàn)場(chǎng)白白多付出一倍時(shí)間。希望這篇筆記里的整定順序和參數(shù)準(zhǔn)則能幫你省掉那一周多的返工也希望你下次從壓縮包里解出來(lái)的數(shù)據(jù)驅(qū)動(dòng) MPC不再是玄學(xué)而是你手里握得住的一套測(cè)量、整定與驗(yàn)證流程。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取