先能量回收策略實現(xiàn))
做純電動車仿真和標定的同行應(yīng)該都碰過同一個矛盾整車模型用CRUISE搭電機、電池、制動器、輪胎一個個模塊往里拖就行十分鐘就能拉出一臺整車的仿真骨架但控制策略尤其是能量回收這種帶狀態(tài)判斷、帶扭矩分配、帶一堆邊界條件的邏輯塞進CRUISE內(nèi)置的Function模塊里寫起來難受調(diào)起來更難受。這次做“CRUISE純電動車仿真模型基于Simulink DLL聯(lián)合仿真實現(xiàn)電制動優(yōu)先能量回收策略”這個項目我的處理思路就是把策略層整體放到Simulink里整車動力學(xué)交給CRUISE能量回收策略在Simulink里搭好編譯成DLL交給CRUISE調(diào)用。兩個工具各干各擅長的活聯(lián)合仿真的關(guān)鍵就是中間那層DLL接口。這篇內(nèi)容把項目從思路、策略設(shè)計、DLL實現(xiàn)到參數(shù)標定和踩坑記錄完整拆一遍適合正在做CRUISE和Simulink聯(lián)合仿真的工程師參考也適合剛接觸能量回收策略、想搞明白“電制動優(yōu)先”怎么落地的新人。全文技術(shù)性偏強但我會把每個關(guān)鍵選擇的理由都寫清楚照著做能少繞很多彎。1. 項目整體設(shè)計與技術(shù)選型1.1 為什么是“CRUISE跑整車、Simulink跑策略”的分工CRUISE做整車動力學(xué)模型確實強部件模塊覆蓋電機、電池、制動器、車輪、車身、差速器應(yīng)有盡有建?;究客献Ш吞顓?shù)比從零搭一套整車動力學(xué)方程要快得多。但它的短板也很明顯內(nèi)置邏輯模塊寫復(fù)雜策略不友好。制動能量回收不是一條公式就完事它涉及制動踏板解析、SOC區(qū)間判斷、電機外特性查表、電池充電功率限制、回收扭矩斜率限制、急剎退出條件……這一串邏輯用CRUISE自帶的Function模塊堆層級不清晰后續(xù)調(diào)參也費勁。反過來Simulink在邏輯編寫和調(diào)試上有天然優(yōu)勢Stateflow畫狀態(tài)機、查表模塊做特性曲線、Rate Limiter做斜率限制信號線往Scope上一拖就是實時曲線調(diào)參效率高一個量級。而且策略模型放在Simulink里還有一個隱性好處——后續(xù)如果要把策略往實車控制器遷移很多函數(shù)級邏輯可以直接復(fù)用不用推倒重寫。所以這個項目從一開始就定了分工CRUISE提供受模型驗證過的整車部件模型負責車輛縱向動力學(xué)響應(yīng)Simulink里的DLL負責控制策略包括駕駛員意圖解析、扭矩分配、回收邊界判斷。這樣兩邊都是自己最擅長的工作方式聯(lián)合仿真才能把精力花在策略本身而不是花在跟工具較勁上。1.2 為什么選DLL而不是MATLAB API或FMUCRUISE和Simulink聯(lián)合仿真的路不止一條項目初期我把常見的三種方式都對比過一遍。接口方式基本原理優(yōu)點缺點MATLAB API仿真時CRUISE實時調(diào)用MATLAB引擎執(zhí)行模型部署簡單模型改動即時生效不用編譯每步都要和MATLAB進程交互批量跑路譜速度慢機器上必須裝完整MATLAB環(huán)境DLL動態(tài)鏈接庫Simulink模型生成C代碼編譯成獨立DLL供CRUISE加載調(diào)用獨立運行不依賴MATLAB執(zhí)行效率高模型打包后便于交付改模型要重新編譯接口規(guī)范必須嚴格定義編譯環(huán)境和運行環(huán)境要對齊FMU/FMI將Simulink模型導(dǎo)出為標準功能樣機單元由CRUISE導(dǎo)入跨工具鏈通用性好模型可以多次復(fù)用FMI版本兼容問題偶發(fā)配置信息多出問題排查鏈路長DLL版本實際用下來最有工程價值。同一套模型編譯好后組里其他人拿到DLL就能跑聯(lián)合仿真根本不需要裝MATLAB和Simulink這對團隊協(xié)作和后續(xù)批量標定太重要了。而且DLL是加載進CRUISE進程內(nèi)部調(diào)用數(shù)據(jù)交換走內(nèi)存仿真心跳比MATLAB API那套方式快很多。我跑過一輪城市工況對比DLL方式整體仿真耗時大概只有MATLAB API方式的一半多一些。當然選DLL是有代價的。最明顯的代價是每改一次策略就要重新生成DLL、重新加載迭代周期比MATLAB API多一個編譯步驟。中間如果編譯器版本、CRUISE位寬、運行時庫哪一環(huán)沒對齊報錯能卡你半天。所以這個項目從第一天起就把編譯工具鏈固定死后來少踩了很多坑。2. 電制動優(yōu)先能量回收策略設(shè)計2.1 先弄清楚“電制動優(yōu)先”優(yōu)先的是什么制動能量回收的原理不用多說電機在制動時切換到發(fā)電工況把車的動能轉(zhuǎn)化成電能回充到電池省下這部分能量就等于省了電、延長了續(xù)航。而“電制動優(yōu)先”指的是當駕駛員踩下制動踏板產(chǎn)生制動請求時控制策略首先讓電機承擔制動的責任電機制動力不足的部分才由機械制動系統(tǒng)補上。換句話說機械制動永遠只在“電機忙不過來”的時候出手。這種策略也常被叫作“串聯(lián)制動”或“首選再生制動”。為什么不是簡單地把電制動和機械制動按固定比例疊加完事因為固定比例并聯(lián)回收是省事但犧牲了回收深度比例調(diào)高了低速或大制動請求時電機扛不住回收扭矩會超限比例調(diào)低了大量本可回收的動能被摩擦片白白磨掉。電制動優(yōu)先的思路則永遠追求“先問電機要要不到再問剎車要”同等工況下回收能量最多。除了回收能量這個策略還有一層現(xiàn)實意義機械制動用得少摩擦片磨損和制動盤熱衰退問題都減輕對整車維修成本和制動安全都有好處。當然這些都是建立在策略不出錯的前提下所以邊界條件的設(shè)計比那幾條核心公式更重要。2.2 核心分配邏輯與關(guān)鍵計算整個分配邏輯可以拆成四步每一步對應(yīng)的模塊在Simulink里都是獨立的一塊方便單獨調(diào)試。第一步把制動踏板行程換算成制動需求扭矩。制動踏板開度經(jīng)過死區(qū)處理和濾波后查一張“減速度請求-踏板開度-車速”的關(guān)系表得到整車目標減速度再用近似公式換算到電機端[ T_{req} \frac{m \cdot a_{req} \cdot r}{i_0 \cdot \eta} ]其中 (m) 是整車質(zhì)量(a_{req}) 是目標減速度(r) 是輪胎滾動半徑(i_0) 是主減速比(\eta) 是傳動效率。換算統(tǒng)一到電機端做的好處是后面和電機外特性、電池功率限值比較時單位都是電機軸扭矩不用來回折算。第二步計算電制動可用上限。電機不是任何時候都能輸出全部回收扭矩的它同時受轉(zhuǎn)速特性和電池充電能力雙重約束[ T_{elec_max} \min(T_{motor_cap}(n),\ T_{bat_cap}(SOC, T_{bat})) ](T_{motor_cap}(n)) 是電機發(fā)電外特性低速區(qū)受電流限制扭矩近似恒定高速區(qū)受功率限制扭矩隨轉(zhuǎn)速升高而下降。(T_{bat_cap}) 由電池允許的充電功率換算而來[ T_{bat_cap} \frac{9550 \cdot P_{chg_max}(SOC, T_{bat})}{n} ]電池SOC越高、溫度越低允許充電功率越小這是一條查表曲線Simulink里直接用二維查表模塊實現(xiàn)。第三步做分配。這是整個策略最簡明的一段[ T_{elec} \min(T_{req},\ T_{elec_max}) ][ T_{mech} T_{req} - T_{elec} ]電制動先扛扛不住的機械制動補比例關(guān)系不用查表天然就是最徹底的優(yōu)先策略。第四步也是實際標定時最花時間的一步——邊界與平順性處理。我在這套模型里加了這么幾條硬規(guī)則車速低于5 km/h時電制動完全退出避免低速回收效率低且容易造成車輛蠕動感。SOC高于95%時電制動退出防止過充損傷電池同時加滯回區(qū)間SOC降到93%以下才恢復(fù)回收防止臨界點反復(fù)橫跳。電池大倍率充電持續(xù)時間超過設(shè)定值后逐步限制回收功率?;厥张ぞ刈兓首鲂甭氏拗颇J先給一個300~600 Nm/s的區(qū)間具體值靠仿真主觀評價和整車頓挫感測試來標定。急剎工況減速度請求超過設(shè)定閾值時電制動快速退出機械制動全權(quán)接管保證安全。這幾條看著簡單但少了任何一條仿真里都會出現(xiàn)可復(fù)現(xiàn)的異常要么SOC沖到100%后過充報警要么踏板微動就引起回收扭矩劇烈波動要么急剎過程中回收扭矩退出慢導(dǎo)致減速度出現(xiàn)臺階。2.3 和整車制動穩(wěn)定性的耦合關(guān)系這是策略里容易被忽略、但極其重要的一點電制動扭矩作用在驅(qū)動軸上。如果電機在前軸回收扭矩就等于給前軸額外加了一份制動力。機械制動系統(tǒng)如果還按原方案分配前后軸力后軸制動力相對不足車輛制動時后軸容易失去穩(wěn)定性。所以在策略輸出不能只給一個“總機械制動請求”了事。我的做法是Simulink輸出前軸機械制動請求和后軸機械制動請求兩個信號電制動扭矩作為前軸附加制動力分配時先把回收扭矩從總需求里扣掉再按原始前后軸比例分配剩余制動力同時還要檢查前軸總制動力不要超出路面附著極限防止前輪抱死。這一塊在CRUISE里驗證優(yōu)勢特別明顯。整車實測極限制動工況成本高、風險大仿真里改個附著系數(shù)、改個路面坡度就能反復(fù)試先把策略邏輯跑穩(wěn)實車標定時就能集中精力去標定真正的車輛差異參數(shù)而不是去排查邏輯漏洞。3. Simulink模型搭建與DLL生成3.1 接口定義必須先畫表再動手DLL聯(lián)合仿真最忌諱的是模型還沒搭接口就隨手拉。信號順序一旦定下來編譯進DLL后修改成本很高。我每次做這種項目第一步永遠是先畫一張接口表跟做軟件設(shè)計文檔一樣雙方對齊了再動Simulink。信號名單位方向說明brake_pedal%輸入制動踏板行程0~100acc_pedal%輸入加速踏板行程用于回收退出判斷veh_speedkm/h輸入當前車速motor_speedrpm輸入電機轉(zhuǎn)速battery_soc%輸入電池荷電狀態(tài)battery_temp℃輸入電池溫度battery_pack_vV輸入電池總電壓t_elecNm輸出電機回收扭矩請求t_mech_frontNm輸出前軸機械制動請求t_mech_rearNm輸出后軸機械制動請求接口設(shè)計有三個原則值得寫出來第一輸入盡量給原始量。SOC、電壓、踏板行程直接作為輸入歸一化和濾波在Simulink內(nèi)部做。這樣CRUISE側(cè)信號連接最簡單也便于模型復(fù)用。第二輸出必須明確單位。CRUISE里對應(yīng)接口是什么單位DLL輸出就是什么單位不要在模型出口再做一次單位換算。換算散落在模型里是聯(lián)合仿真相位不一致的頭號來源。第三信號順序定下后不要輕易改。生成C代碼后輸入輸出是靠數(shù)組索引對應(yīng)的一旦改順序整個數(shù)據(jù)集全部要重對純屬自找麻煩。3.2 模型內(nèi)部結(jié)構(gòu)Simulink模型內(nèi)部整體分三段信號預(yù)處理、策略計算、輸出整形。預(yù)處理段做踏板信號一階低通濾波、車速單位規(guī)整、SOC限幅。這個階段不需要花哨的邏輯目的只有一個保證進策略核心的數(shù)據(jù)干凈穩(wěn)定不讓仿真數(shù)值的小噪聲引發(fā)策略層面的大動作。策略計算段用Stateflow搭了一個狀態(tài)機狀態(tài)包括正?;厥諔B(tài)、低車速不回收態(tài)、高SOC保護態(tài)、急剎退出回收態(tài)。每個狀態(tài)內(nèi)部單獨算自己的允許回收扭矩上限再統(tǒng)一走分配公式。用狀態(tài)機的好處是邏輯表達直觀幾個狀態(tài)之間切換條件一目了然比層層if嵌套可讀性好很多。輸出整形段做最后的限幅和斜率限制。所有扭矩請求輸出前都過一次Rate Limiter回收扭矩的變化率被限制在標定值以內(nèi)。這一段的參數(shù)直接決定駕駛員感受是主觀評價里反饋最集中的環(huán)節(jié)。3.3 DLL編譯環(huán)境與導(dǎo)出函數(shù)封裝編譯這步第一次做的人問題最多這里按順序?qū)懸槐?。先確保Simulink Coder配置正確系統(tǒng)目標文件選grtGeneric Real-Time模型代碼生成接口設(shè)為可被外部調(diào)用的形式。然后準備好Windows下的C/C編譯器在Simulink Coder配置里選中對應(yīng)編譯器Simulink會調(diào)用編譯器自動完成模型C代碼生成和編譯。需要注意編譯出來的目標格式要是DLL而不是可執(zhí)行文件。再按照CRUISE的DLL接口規(guī)范封裝一個導(dǎo)出函數(shù)。核心思路是這樣每個仿真步長CRUISE調(diào)用一次該函數(shù)把采集到的輸入信號放進去策略算完把輸出信號寫回來。一個最小模板大概是這個意思#include stdlib.h #include math.h /* 輸入輸出結(jié)構(gòu)體 */ typedef struct { double brake_pedal; /* 0~100 */ double acc_pedal; /* 0~100 */ double veh_speed; /* km/h */ double motor_speed; /* rpm */ double battery_soc; /* % */ double battery_temp; /* ℃ */ double battery_voltage; /* V */ } StrategyInput; typedef struct { double t_elec; /* Nm */ double t_mech_front; /* Nm */ double t_mech_rear; /* Nm */ } StrategyOutput; /* DLL導(dǎo)出函數(shù)CRUISE每個仿真步調(diào)用 */ __declspec(dllexport) void EnergyRecStrategy(StrategyInput* in, StrategyOutput* out) { double t_req, t_elec_max, t_elec, t_mech; /* 1. 踏板行程 車速 - 需求扭矩 */ t_req CalcBrakeTorque(in-brake_pedal, in-veh_speed); /* 2. 電機轉(zhuǎn)速 SOC 溫度 電壓 - 電制動上限 */ t_elec_max CalcElecMax(in-motor_speed, in-battery_soc, in-battery_temp, in-battery_voltage); /* 3. 電制動優(yōu)先分配 */ t_elec fmin(t_req, t_elec_max); t_mech t_req - t_elec; /* 4. 前后軸分配回收扭矩作用在前軸 */ out-t_elec t_elec; out-t_mech_front t_mech * FrontRatio - t_elec; out-t_mech_rear t_mech * RearRatio; }上面的代碼是示意性的實際CRUISE的接口字段名稱和結(jié)構(gòu)體定義按你自己的版本調(diào)整。重要的是理解這個數(shù)據(jù)流輸入來自CRUISE總線輸出回到電機和制動器模塊中間是策略算法。封裝好后編譯成DLL用開發(fā)工具鏈自帶的導(dǎo)出函數(shù)查看器確認導(dǎo)出函數(shù)名和調(diào)用約定都正確再放到CRUISE能訪問的路徑里。編譯時有三個坑我每次都要提醒人位寬必須一致。CRUISE是64位就編譯64位DLL32位對32位混著來幾乎必掛。路徑別帶中文和空格。CRUISE加載DLL時有時候?qū)β窂浇馕鲇兄v究純英文路徑最省心。目標機器上缺運行庫是常見問題。DLL依賴的C/C運行庫沒裝齊加載時會直接失敗報錯信息還特別隱晦。3.4 在CRUISE側(cè)接入DLL模塊CRUISE側(cè)操作不復(fù)雜在模型里拖入一個Function/Control類的DLL接口模塊指定DLL文件路徑然后做信號連接。輸入側(cè)將車輛總線上的車速信號、電機轉(zhuǎn)速、電池SOC、電池溫度、制動踏板行程、加速踏板行程六個信號按接口表接好。輸出側(cè)電機回收扭矩接到電機的扭矩請求輸入前軸機械制動請求接到前軸制動器后軸機械制動請求接到后軸制動器。連接完成后先別急著跑完整工況做一個冒煙測試最穩(wěn)妥固定一個中等車速和中等SOC給一個恒定制動踏板開度檢查電機回收扭矩是否為負值、機械制動是否按預(yù)期減少。鏈路通了再上循環(huán)工況出問題時排查范圍會小很多。4. 參數(shù)標定與仿真驗證4.1 整車與關(guān)鍵部件參數(shù)仿真模型的參數(shù)我直接列一張表實際項目按你自己車型參數(shù)替換就行。我用的是一套典型純電家用車的配置參數(shù)數(shù)值單位整車整備質(zhì)量1600kg迎風面積2.2m2風阻系數(shù)0.28-滾動阻力系數(shù)0.012-輪胎滾動半徑0.31m主減速比8.1-電機峰值功率150kW電機峰值扭矩310Nm電池容量52kWh電池SOC運行范圍10~100%常溫最大充電功率80kW這套參數(shù)下電機功率較大回收能力很強電制動幾乎能覆蓋大多數(shù)日常制動的需求區(qū)間。如果電機只有六七十千瓦功率策略邏輯完全一樣但電制動覆蓋范圍會小很多機械制動的分擔比例會明顯上升標定時要重新平衡。標定步驟我習(xí)慣按這樣走先標定踏板到減速度的映射曲線再標定回收退出邊界低車速、高SOC接著調(diào)回收扭矩斜率限制最后做整車主觀平順性相關(guān)參數(shù)微調(diào)。順序不能亂映射沒標好之前去調(diào)斜率限制等于地基沒打好先刷墻。4.2 典型循環(huán)工況驗證模型和DLL都跑通后進入正式驗證階段。我主要用城市工況卡因為城市工況制動頻繁、平均車速低最能體現(xiàn)能量回收策略的價值。重點看四個指標SOC下降曲線對比同一工況下分別跑無回收、固定比例回收、電制動優(yōu)先回收三個版本看SOC終值差多少。這個差值直接反映回收了多少能量。電制動承擔比例統(tǒng)計整個工況里電制動承擔的制動能量占總制動能量的比例城市工況下這個比例通常能做到相當可觀?;厥张ぞ夭▌忧闆r觀察回收扭矩曲線是否頻繁大幅振蕩振蕩意味著斜率限制沒標好會引起整車頓挫。電池充電倍率看整個仿真過程中最大充電倍率有沒有超出電池限值這在低溫段尤其要盯緊。多數(shù)城市工況里電制動優(yōu)先相比無回收的SOC終值提升都是肉眼可見的而相比固定比例回收優(yōu)勢在中低速跟車、緩踩減速這類輕度制動片段里特別明顯——固定比例策略在這類片段往往因為比例偏低而白白漏掉能量。4.3 邊界工況與魯棒性驗證跑過的標準工況如果只跑一遍就收工那后面實車一定會被邊界工況打臉。我做這套模型時至少補了這三組工況第一組高SOC起步連續(xù)下坡。把電池SOC初始值直接設(shè)為98%跑一段帶坡度的循環(huán)確認回收功率能及時退出、SOC不會沖破上限。這種工況實車找路很難仿真里改SOC初值就能復(fù)現(xiàn)是聯(lián)合仿真的典型優(yōu)勢場景。第二組制動踏板抖動。在制動踏板信號上人為疊加一個高頻小幅抖動看回收扭矩會不會跟著亂跳。正常情況下策略里的濾波和滯回應(yīng)該把抖動吸收掉如果回收扭矩還是出現(xiàn)快速通斷說明濾波時間常數(shù)或滯回窗口太小。第三組高速急剎。從120 km/h左右急踩制動確認回收扭矩快速退出時機械制動力能無延遲補上整車減速度曲線不能出現(xiàn)斷崖或后退。這一組驗證的是策略的快速響應(yīng)能力也是底盤安全性最核心的一個場景。這三組邊界用例跑完策略才有底氣進入實車階段。5. 常見問題與排查技巧實錄5.1 DLL加載失敗類問題這類問題在聯(lián)合仿真里出現(xiàn)頻率最高典型報錯就是CRUISE加載DLL不成功。按下面順序排查多數(shù)情況下幾分鐘能定位先確認位寬看CRUISE版本和DLL位數(shù)是否一致再檢查路徑把DLL放到純英文且無空格的目錄下然后驗證導(dǎo)出函數(shù)用工具查看導(dǎo)出函數(shù)名和大小寫是否匹配最后查運行庫確認運行環(huán)境中依賴的C/C運行庫版本齊全。有一個技巧很管用單獨寫一個小測試程序不經(jīng)過CRUISE直接加載DLL并調(diào)用導(dǎo)出函數(shù)。如果這一步能過問題基本鎖定在CRUISE配置側(cè)如果這一步就掛那是DLL自身或環(huán)境問題。這個隔離方法幫我節(jié)省了大量推導(dǎo)時間。5.2 仿真數(shù)據(jù)對不上、扭矩方向反了DLL能加載但仿真結(jié)果詭異大概率是信號鏈路問題。最常見的三種情況輸入輸出順序定義不一致數(shù)組里第0個信號實際是另一個量;CRUISE里信號單位沒對齊km/h和m/s、百分比和0~1之間混用;Simulink模型出口漏了系數(shù)換算比如輸出扭矩實際是半軸端值CRUISE電機端接口要的是電機端值。我常用一個“直通模式”來快速定位問題在模型里臨時把制動踏板輸入原樣映射到輸出即輸入什么輸出什么加一個固定偏移。先驗證鏈路對不對再把真正的策略計算恢復(fù)回來。鏈路和算法分開排查能省下大量對數(shù)據(jù)的時間。5.3 回收扭矩抖動與電池過充回收扭矩抖動有三個高概率嫌疑。第一個嫌疑是SOC信號噪聲大導(dǎo)致策略在回收和不回收之間來回切換解決辦法是給SOC判斷加滯回區(qū)間。第二個嫌疑是斜率限制參數(shù)設(shè)置不當限制太嚴反而引起系統(tǒng)振蕩需要重新標定。第三個嫌疑是CRUISE仿真步長偏大DLL內(nèi)部濾波對這個步長不匹配可以嘗試減小仿真步長驗證。過充問題則基本是策略邊界沒覆蓋要么SOC上限判斷用了瞬時值而沒有滯回要么電池充電功率限值在低溫段沒查表。這兩個都是典型策略細節(jié)疏漏仿真里通過刻意把初始SOC拉高、把電池溫度調(diào)低就能復(fù)現(xiàn)出來。5.4 聯(lián)合仿真速度太慢DLL方式本身比MATLAB API快很多但如果太慢就要檢查是不是開了過多日志記錄。每步寫盤是非常拖速度的操作批量跑工況時尤其明顯。我的建議是仿真時只保存必要的標量結(jié)果比如終點SOC、回收能量、電制動參與時長不要全程記錄所有信號波形。需要觀測詳細波形的工況單獨跑一遍再開全量記錄。再分享一個批量仿真提速習(xí)慣需要掃描的參數(shù)做成腳本批量修改跑完只落一個匯總表不保留中間數(shù)據(jù)文件。這樣一輪幾十個參數(shù)的掃描能在合理時間內(nèi)完成數(shù)據(jù)也不至于堆成山。這套項目做下來我個人最大的體會是DLL聯(lián)合仿真的技術(shù)門檻真不高真正花時間的是把接口約定和邊界條件想清楚。CRUISE和Simulink都是工具中間那層DLL就像一個“翻譯官”翻譯得好不好取決于你對兩個工具各自的信號和單位有多了解。最后再分享一個小習(xí)慣每次重新編譯DLL之前先保存一份基準仿真結(jié)果。能量回收這種閉環(huán)控制改一處可能牽動全局沒有baseline做對照出問題根本說不清是這次改動引起的還是之前就存在。這個習(xí)慣幫我省掉了大量排查時間你也值得試試。