)
在無刷直流電機仿真這條路上折騰了小半年我發(fā)現自己最上頭的畫面不是板子第一次轉起來的瞬間而是仿真模型里那條轉速曲線穩(wěn)穩(wěn)咬住設定值的那一刻。沒錯就是仿真。不少朋友不理解放著現成的電機庫不用偏要自己手搓一套無刷直流電機仿真模型又是坐標變換又是SVPWM又是PI整定這不是跟自己過不去嗎但我的體會恰恰是這段“手搓”的經歷比直接拖現成模型學到的東西多了一個量級。這篇就把我從電機方程一路搭到轉速閉環(huán)的完整過程記錄下來電機的參數、每個環(huán)節(jié)的原理、整定過程和踩過的坑都盡量交代清楚給那些也想自己搭一套無刷直流電機仿真、又不想用黑盒模型的朋友一條可以直接上手的路。文章里所有代碼和參數都是我實測跑過的最小可用版本不追求花哨只求你能跟著搭出來。1. 為什么放著現成工具不用非要自己搭電機模型1.1 現成模型像罐頭省事但出事不好查很多初學者起步都會選現成方案在Simulink環(huán)境里找現成的電機模塊配一個封裝好的FOC庫把母線電壓、極對數、相電阻填進去雙擊一跑三相電流、轉速、電磁轉矩曲線就出來了。風平浪靜什么都好看??梢坏┠阋稣骓椖烤蜁l(fā)現“能跑”和“能用”之間隔著好幾條街?,F成模型里的參數往往是理想化的你手上那顆實際電機的磁鏈、電感、反電動勢系數具體是多少庫里根本沒有地方告訴你。更麻煩的是如果轉速響應和電流波形跟預期對不上你沒法判斷問題出在模型本身、控制器參數還是坐標變換里面。黑盒模型擋在中間定位問題跟隔著一層霧似的。自己手搓就不一樣了。每個狀態(tài)量怎么算出來的、每個環(huán)節(jié)的帶寬多少、哪個濾波引入的相位延遲有多大你心里一清二楚。轉速閉環(huán)一振蕩我基本能在十分鐘內定位到是哪一環(huán)帶寬沒拉開哪一級濾波器滯后太多。這種判斷力靠拖現成模型是練不出來的。1.2 拆開看一套手搓模型就是六塊積木搭模型的時候我把整個系統(tǒng)拆成六塊電機本體模型、逆變器橋、PWM調制SVPWM、電流采樣/濾波、電流環(huán)、轉速環(huán)。電機本體是“被控對象”逆變器和PWM是“執(zhí)行器”電流環(huán)和轉速環(huán)是“大腦”。這個分層特別重要——每一塊都能單獨驗證拼起來之后一旦出問題能快速隔離到具體模塊。我的開發(fā)順序是這樣的先用Python腳本做快速驗證把電機方程和PI控制器寫成函數跑通再接上SVPWM和逆變器邏輯最后才把整套東西搬進Simulink環(huán)境搭最終版。為什么這么做腳本調參方便改一個參數重跑一遍只要幾秒鐘而且報錯信息比圖形界面里拖線直觀太多。2. 電機本體建模沒搞清楚反電動勢之前別動手2.1 BLDC的反電動勢不能隨手當正弦波處理無刷直流電機從結構上說是永磁同步電機的一種但它的驅動方式有講究。BLDC的反電動勢波形是梯形波普通PMSM是正弦波。如果你不管三七二十一按正弦波建模反電動勢的諧波部分會直接體現成轉矩脈動電流環(huán)設計也會偏樂觀。不過實際項目里在梯形波反電動勢條件下用FOC算法也大有人在。原因在于你控制的是電流的基波平均值諧波部分會被電流環(huán)帶寬壓制一部分剩下的變成轉矩脈動。我在模型里仍然按正弦反電動勢近似但對轉速環(huán)這種慢動態(tài)來說完全夠用這也是大多數仿真教程的通用做法。2.2 三相方程和坐標變換三個變量變兩個最直接的三相靜止坐標系方程長這樣每一相都包括電阻壓降、電感壓降和反電動勢三項u_a Rs * i_a Ls * di_a/dt e_a u_b Rs * i_b Ls * di_b/dt e_b u_c Rs * i_c Ls * di_c/dt e_c三相量之間有120度相位差三個PI控制器如果直接控制交流量靜態(tài)誤差很難消除。所以要干兩件事Clarke變換把三相靜止的ia、ib、ic投影到兩相靜止坐標αβPark變換再把αβ投影到跟轉子同步旋轉的dq軸這兩步合在一起本質上是把三個糾纏在一起的交流量變成兩個在穩(wěn)態(tài)下恒定的直流量。在dq坐標系里電流是直流用PI就能做到無靜差跟蹤。這就是整個FOC的精髓。坐標變換之后的dq軸電壓方程簡潔很多u_d Rs * i_d Ld * di_d/dt - ωe * Lq * i_q u_q Rs * i_q Lq * di_q/dt ωe * Ld * i_d ωe * λpm方程里ωe是電角速度等于極對數乘以機械角速度λpm是轉子磁鏈。反電動勢項出現在u_q方程的ωe * λpm上這就是為什么轉速越高你需要的端電壓越高。電磁轉矩公式也順手列出來。對于表貼式電機Ld等于Lq所以Te 1.5 * Pp * λpm * i_q Kt * i_qKt是扭矩常數對表貼式BLDC來說就是1.5乘以極對數再乘以磁鏈。這是個特別重要的換算關系后面調轉速環(huán)、算負載轉矩全靠它。2.3 我用的電機參數和一個能跑的核心代碼為了后面所有計算都能對上我先給出一組我仿真時用的電機參數之后所有PI整定、帶寬計算都基于這組數參數符號數值單位母線電壓Udc48V極對數Pp4定子電阻Rs0.20Ωd/q軸電感LdLq0.15mH轉子磁鏈λpm0.02V·s/rad轉動慣量J8e-5kg·m2阻尼系數B5e-5N·m·s/rad額定轉速n_N3000rpm扭矩常數Kt算出來是0.12 N·m/A。額定轉速3000rpm對應機械角速度約314 rad/s電角速度就是約1256 rad/s。所以額定點附近的反電動勢壓降大約在25V左右加上電阻壓降48V母線還是撐得住的。電機模型的核心更新代碼我用Python寫了一個最簡版本import numpy as np # 電機參數 Rs 0.20 Ld 0.15e-3 Lq 0.15e-3 flux 0.02 Pp 4 J 8e-5 B 5e-5 def motor_step(x, udq, TL, dt): # x [id, iq, omega_m] # udq [ud, uq] id_, iq_, omega_m x omega_e Pp * omega_m # dq軸電流微分 did_dt (udq[0] - Rs * id_ omega_e * Lq * iq_) / Ld diq_dt (udq[1] - Rs * iq_ - omega_e * Ld * id_ - omega_e * flux) / Lq # 電磁轉矩和機械微分 Te 1.5 * Pp * flux * iq_ dome_dt (Te - TL - B * omega_m) / J # 顯式歐拉積分 new_id id_ dt * did_dt new_iq iq_ dt * diq_dt new_omega omega_m dt * dome_dt return np.array([new_id, new_iq, new_omega])這段代碼里電機是機械和電氣方程聯(lián)立的。為了讓讀者能直接復現我用的是最簡單的顯式歐拉積分。歐拉法在步長足夠小的情況下可以穩(wěn)定跑但對步長很敏感后面我會專門講步長選擇的問題。實際做長時間仿真時我換成的是四階龍格庫塔ode4同樣的參數波形平滑度和穩(wěn)定性都好很多。3. 執(zhí)行器也得搭得像樣逆變器、SVPWM和時序3.1 逆變器模型理想開關加死區(qū)就夠用做系統(tǒng)級仿真時完全沒必要把MOSFET的開通關斷過程、米勒平臺、體二極管反向恢復這些細節(jié)全建模。那些屬于器件級仿真留給專門做功率半導體的人去糾結。我的逆變器模型就是三個半橋的理想開關外加一個死區(qū)時間參數。寫代碼的時候邏輯就是根據PWM比較值判斷每相上管還是下管導通然后把對應的相電壓賦給電機模型。要模擬死區(qū)就在換相瞬間插入一個兩個管子都關斷的小時間段。系統(tǒng)級模型的重點是控制環(huán)把開關瞬態(tài)省掉之后仿真速度能快一個數量級。如果后面要做損耗分析、EMI評估再單獨把開關模型加進去不遲。3.2 SVPWM的扇區(qū)判斷和作用時間SVPWM的全稱是空間矢量脈寬調制。它的核心思想不是分別調制三相而是把三相合成一個旋轉電壓矢量然后用六個非零基本電壓矢量和兩個零矢量去逼近它。實現時最常用的就是七段式發(fā)波每個PWM周期內插入兩段零矢量開關次數均勻諧波畸變最小。關鍵步驟只有兩步第一步判斷當前目標電壓矢量落在哪個扇區(qū)。已知目標矢量在αβ軸的分量Uα和Uβ可以通過三個中間量的正負組合判斷扇區(qū)A Uβ B (sqrt(3)/2) * Uα - (1/2) * Uβ C -(sqrt(3)/2) * Uα - (1/2) * Uβ三個量的正負組合對應六個扇區(qū)。常見的判斷邏輯是條件組合扇區(qū)號A0, B0, C≤0IA0, B≤0, C≤0IIA≤0, B≤0, C≤0IIIA≤0, B≤0, C0IVA≤0, B0, C0VA0, B0, C0VI第二步計算相鄰兩個基本矢量的作用時間。設Uref是目標電壓矢量幅值Ts是PWM周期θ是矢量在扇區(qū)內的角度Udc是母線電壓相鄰兩個矢量的作用時間分別用下面兩個表達式計算T1 sqrt(3) * Uref * Ts * sin(π/3 - θ) / Udc T2 sqrt(3) * Uref * Ts * sin(θ) / Udc剩下的時間分給兩個零矢量而且零矢量要對稱分配在周期頭和周期尾這樣輸出電壓波形是對稱的PWM。這就是七段式SVPWM的標準套路。3.3 仿真步長、PWM周期和控制周期三者千萬別混為一談這是很多新手容易繞暈的地方。我用的配置是項目數值仿真步長1 μsPWM周期50 μs20 kHz電流環(huán)更新周期50 μs轉速環(huán)更新周期500 μs這樣選的邏輯很直接。仿真步長是數值積分的采樣間隔必須比PWM周期小一個數量級否則開關切換時刻落在積分間隔之外電流波形會出現鋸齒狀誤差。PWM周期由硬件決定20kHz是電機驅動器的主流頻率兼顧開關損耗和電流紋波。電流環(huán)跟著PWM周期走在一個周期內更新一次PI輸出這是單片機能輕松承受的頻率。轉速環(huán)比電流環(huán)慢10倍因為機械時間常數遠大于電氣時間常數沒必要跑那么快。有些人在仿真里把仿真步長設成跟PWM周期一樣結果電流波形全是高頻毛刺然后懷疑是算法問題。其實不是是時間尺度的分辨率不夠。我一開始也踩過后面詳細說。4. 調PI像調火鍋底料光給結論不給過程是耍流氓4.1 電流環(huán)參數用零極點對消做一次計算電流環(huán)的被控對象是電機繞組它的傳遞函數近似是一個一階慣性環(huán)節(jié)G(s) 1 / (Ls Rs)PI控制器的傳遞函數是Kp加Ki/s。整定的經典思路是讓PI的零點去對消電機的極點這樣閉環(huán)就變成一個純一階系統(tǒng)帶寬由PI比例系數決定。推導下來得到兩條工程公式Kp L * ωc Ki Rs * ωc其中ωc是期望的電流環(huán)截止角頻率。截止頻率通常取開關頻率的10分之1到20分之1。我的開關頻率是20kHz取截止頻率1.5kHz對應ωc約9425 rad/s。代入我的電機參數L 0.15e-3Rs 0.20 Kp 0.15e-3 * 9425 ≈ 1.41 V/A Ki 0.20 * 9425 ≈ 1885 V/(A·s)這兩個數就是電流環(huán)PI的起點。跑仿真之后電流波形如果抖動先把Kp往下調而不是急著調Ki。電流環(huán)是內環(huán)它穩(wěn)不住轉速環(huán)做得再漂亮也沒用。4.2 轉速環(huán)參數先Kp后Ki單位換算是重災區(qū)轉速環(huán)的被控對象比電流環(huán)簡單可以近似成一個純積分環(huán)節(jié)加上扭矩常數KtG(s) Kt / (Js)期望的轉速環(huán)帶寬通常取電流環(huán)帶寬的10分之1到10分之1我取150Hz對應角頻率約942 rad/s。忽略阻尼項Kp的估算公式是Kp J * ωc_ω / Kt Kp 8e-5 * 942 / 0.12 ≈ 0.63 A/(rad/s)注意這個單位。速度環(huán)的輸出是q軸電流指令轉速誤差單位是rad/s所以Kp單位是“安培/每弧度每秒”。如果你把轉速看成rpm數值上就要換算差了60/2π還不自知的話調出來的參數會讓人崩潰。我后來把轉速環(huán)里所有量統(tǒng)一用SI單位轉速一律用rad/s力矩一律用N·m電流一律用A避免反復換算出錯。Ki先不急著給我的習慣是只加Kp空載啟動看階躍響應。如果轉速收斂不到設定值說明積分作用不夠再慢慢加Ki。加Ki時注意設置積分限幅我最終用的速度環(huán)參數是Kp0.65Ki55輸出限幅±12A積分限幅±6A。這兩個限幅值看著不起眼作用卻很大后面講積分飽和時會專門說。4.3 空載啟動加負載突變觀察曲線咬住設定值我最常用的調試場景是這樣0時刻給階躍目標轉速3000rpm空載啟動0.3秒的時候突然加上1.0 N·m負載轉矩看轉速跌落后能不能拉回來0.5秒時再撤掉負載看會不會過沖。整定好之后的仿真行為大致是這樣的啟動階段電流先頂到限幅值12A電磁轉矩約1.44N·m加速度穩(wěn)定轉速線性上升。到接近3000rpm時電流回落轉速無超調地貼在目標值上。0.3秒突加負載后轉速跌落到約2940rpm然后轉速環(huán)積分作用把它拉回3000rpm恢復時間約40毫秒穩(wěn)態(tài)誤差在0.5rpm以內。那種曲線穩(wěn)穩(wěn)咬住設定值的感覺確實像標題說的跟吃火鍋配冰闊落一樣暢快。但為了這個結果我整整調了兩天而且大部分時間浪費在錯誤方向上了。5. 轉速咬上去之前我踩過的幾個大坑5.1 極對數問題電角度和機械角度互相背叛第一個讓我懷疑人生的坑來自極對數。電機機械轉一圈電角度實際轉了P圈。我在坐標變換里用Park變換需要電角度但在機械方程里積分出來的是機械角度。如果忘了乘極對數轉速反饋信號全亂PI控制器會輸出一個高頻振蕩的電流指令。這個錯誤非常隱蔽因為模型還是能跑出轉速曲線只是波形帶明顯抖動。我當時的排查方式是打印udq和idq波形發(fā)現id和iq在穩(wěn)態(tài)下根本不恒定而是疊加了一個高次波動這才意識到角度信號頻率不對。排查過程花了整整一晚上最后不過是把Pp乘了進去。5.2 反電動勢系數單位換算搜到的公式和模型參數對不上第二個坑是反電動勢系數的單位。網上資料里有人給V/(krpm)有人給V/(rad/s)還有人給V·s/rad。這三個單位之間差著系數直接套用會差好幾個數量級。我在模型里用的磁鏈λpm單位是V·s/rad反電動勢項就是電角速度乘以磁鏈。但如果你拿電機的實測反電動勢系數比如標稱多少V每千轉每分鐘去反推磁鏈一定要先統(tǒng)一單位。3000rpm對應的機械角速度是314rad/s電角速度是1256rad/s漏掉任何一個換算系數都會讓模型里的反電動勢跟實機差36倍。我的建議是模型內部所有物理量統(tǒng)一使用SI標準單位外部標定數據進入模型前先做一次單位轉換并且把轉換過程寫在注釋里。這樣哪怕后面忘了回頭看代碼也能想起來。5.3 仿真步長太大電流波形全是毛刺第三個坑最為迷惑。最初我把仿真步長設成10μsPWM周期50μs心想這不比PWM快五倍了嗎應該夠了吧。結果跑出來的電流波形上疊加了一層明顯的鋸齒狀毛刺轉速環(huán)在穩(wěn)定點附近小幅振蕩。排查了很久最后把步長砍到1μs毛刺消失波形變得非常干凈。原因是電感電流的動態(tài)速度太快了理想化處理下電流的上升速率接近電壓除以電感量級能到幾十萬安培每秒顯式歐拉法在10μs步長下數值誤差積累得太嚴重。所以保守建議是仿真步長至少要比PWM周期小一個數量級。如果模型里開關時刻是離散的還要保證步長跟PWM周期是整數倍關系否則不同步的周期性誤差會變成低頻干擾。5.4 積分飽和帶來的啟動沖擊和轉速超調最后一個坑也是最“經典”的積分飽和。啟動時電流長時間頂在12A限幅值轉速環(huán)誤差一直很大積分項瘋狂累積等轉速真正到達3000rpm時積分項已經把輸出推到極其夸張的數值。轉速是到了積分器卻還在持續(xù)輸出等于讓電機繼續(xù)加速最終轉速沖到3150rpm才被反向拉回來形成一次明顯的過沖。解決方案是給速度環(huán)PI加積分限幅并且當輸出達到限幅時停止積分累加這就叫抗積分飽和。我用的積分限幅是±6A跟輸出限幅±12A錯開一半。加了之后啟動過沖消失轉速曲線像用尺子畫的一樣服帖地貼上設定值。6. 模型跑順之后離實機上電還有哪些功課6.1 仿真模型里故意“忽略”的那些東西仿真通過很容易讓人過度自信但我要提醒你模型里忽略了不少東西。我列一下我仿真時根本不關心、但實機繞不開的量MOS管導通壓降和死區(qū)效應導致的電壓偏差母線電壓波動和電容紋波鐵損、永磁體溫度變化帶來的磁鏈漂移摩擦轉矩的非線性靜摩擦和粘滯摩擦不是常數編碼器零位誤差和霍爾換相誤差這些在仿真模型里都被我當成理想條件但實機上它們一個都不會缺席。所以仿真結果的絕對數值不要直接當實機性能預測它更多是用來驗證控制方案、參數量級和邏輯正確性的。6.2 上板子前參數至少要重新估一遍我自己的流程是在用仿真參數上硬件之前先按實機重新測一遍關鍵參數。相電阻用LCR表或者直流壓降法測量相電感在鎖住轉子的情況下測反電動勢系數用對拖法轉速和開路電壓做一個比值轉動慣量靠加減速實驗或自由停車曲線辨識。還有一個特別容易被忽略的環(huán)節(jié)電角度零點標定。仿真模型里Park變換的角度是理想對齊的但實機編碼器零點跟電機磁極位置存在一個固定偏移。如果這個偏移不標定id會混入非零值電流環(huán)會產生嚴重的直軸電流浪費降低效率。6.3 最小可行驗證路線別一上來就閉環(huán)最后分享一個我嘔心瀝血總結出來的上電順序。不要一上來就切轉速閉環(huán)跑階躍那樣一出問題就是大煙花。先做一個開環(huán)電壓斜坡測試讓電機緩慢轉動確認驅動和旋變/編碼器邏輯正常然后單獨跑電流環(huán)給定一個小電流指令驗證id和iq的解耦再切轉速環(huán)給定低速目標逐步往上加。每次切換只改一個環(huán)節(jié)確認穩(wěn)定后再進行下一步。這個順序幫我排除了不少低級問題比如相位接反、編碼器方向反了、PWM極性錯誤等等。仿真里沒人接反線實機可能犯的錯仿真根本發(fā)現不了。這也是為什么我始終建議先把仿真做到“每個模塊都能自己解釋清楚”再上實機。仿真幫不了你排除接線錯誤但它能幫你排除算法錯誤。等算法層面的坑都被仿真消化掉實機上電時剩下來的問題就只有物理世界自己的胡鬧了。