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