ブラシレスモータを FOC で回す ―― 回る座標に乗ると、交流が直流に見える
- 制御
- モータ
- python
- シミュレーション
- foc
前回までは、ブラシ付きの DC モータを三段のカスケードで回し、そのゲインの決め方まで見てきました。ブラシ付きは「電流を流せば、その向きにトルクが出る」が素直で、内側の電流ループがトルクをそのまま担えました。
今回は予告どおり、ブラシレス(三相交流)モータに進みます。ブラシレスは、名前のとおりブラシ(整流子)がありません。ブラシは、ローターの角度に合わせて電流の向きを機械的に切り替えてくれる部品でした。それが無いということは、電流の向きを、こちらが電子的に作らないといけない。しかも、ローターが回ると、トルクを出したい向きも一緒に回ってしまう。止まった的ではなく、回っている的を狙う感じです。
ここで効くのが、「的が回るなら、こちらも同じ速さで回る台に乗ってしまえばいい」という発想です。回る台に乗れば、的は止まって見える ―― 交流だった電流が、直流に見える。これが dq 変換 / FOC(ベクトル制御) の心臓部です。今回も式は薄めに、時間領域の差分で回して波形で確かめます。
三相のモータを Python で作る
まず制御される側、三相 PMSM(永久磁石同期モータ)のモデルです。三相ぶんの電流をそのまま追ってもいいのですが、ここでは最初から「回る座標(dq)」で書いた式を使います(なぜそう書けるのかは次の節で)。
# d 軸・q 軸それぞれ、骨格はただの RL 回路 + 回転による「押し合い」
Ld·did/dt = vd - R·id + ωe·L·iq
Lq·diq/dt = vq - R·iq - ωe·L·id - ωe·λ # ωe·λ が逆起電力
トルク Te = 1.5·P·λ·iq # q 軸電流がトルクを作る
一行ずつ見ると、骨格は前回の DC モータと同じ「コイル=RL 回路」です。抵抗 R と電流の変化ぶん(L·di/dt)に、かけた電圧 v を分けている。そこに、回っているからこそ出てくる項が足されます。ひとつは ωe·λ ―― 回る磁石が発電する 逆起電力(ωe は電気的な回転の速さ)。もうひとつが ±ωe·L·i の項で、これは d 軸と q 軸が、回転を通じてお互いに滲み出す 軸間の押し合い です。この二つは、本来なら磁界から導くところですが、ここでは「回る相手が押し返してくる分」として受け取り、あとで波形で確かめます。
大事なのは トルク Te = 1.5·P·λ·iq。トルクを作るのは q 軸電流 iq だけで、d 軸電流 id はトルクに効きません(表面磁石の場合)。だから、やることははっきりしています ―― iq でトルクを出し、id は 0 に保つ。この iq が、前回の DC モータの「電流」に当たります。
(この記事のパラメータは R=0.5Ω、L=2mH、λ=0.03Wb、極対数 P=3、電圧の上限 24V、電流の上限 10A。トルク係数 Kt=1.5·P·λ=0.135 N·m/A です。)
回る座標に乗る ―― 交流が直流に見える
では、なぜ dq で書けるのか。三相の電流 abc は、モータが回っているあいだ、たがいに 120 度ずれた三本の正弦波です(下図の一段目)。この三本は、合計するとゼロになる(a+b+c=0)ので、じつは二相ぶんの情報しかありません。そこで、まず二相 αβ にまとめます(Clarke 変換)。まだ交流の正弦波です(二段目)。
つぎに、その αβ を、ローターの電気角 θe と同じ速さで回る座標に乗せ替えます(Park 変換)。回るぶんを差し引くので、回っている成分が止まって見える ―― 三段目のように、id と iq が一定値(直流)になります。

変換といっても、やっているのは sin と cos の掛け算、つまり座標を回すだけです。
# αβ → dq:電気角 θe だけ座標を回す(回るぶんを引くと止まって見える)
id = iα·cos(θe) + iβ·sin(θe)
iq = -iα·sin(θe) + iβ·cos(θe)
同じ電流でも、静止した座標から見れば交流、ローターと一緒に回る座標から見れば直流。上の図は、まったく同じ電流を、ただ見る座標を変えて描いただけ です。振幅もつじつまが合っていて、abc の正弦波の山(6A)は、dq の大きさ √(id²+iq²) とちょうど同じでした。
直流に見える、ということは ―― 前回まで DC モータでやっていた「一定の目標に PI で電流を合わせる」が、そのまま使える、ということです。
FOC の電流ループ ―― DC サーボと同じ感覚
回る座標に乗れたので、あとは前回と同じです。iq と id に、それぞれ PI をかけます。id の目標は 0、iq の目標がトルク指令。iq を 0→6A にステップで指令すると、こうなります。

上の段。iq は、前回の DC モータの電流ループとそっくりの立ち上がりで、4 ミリ秒ほどで 6A に届きます(電圧の上限に当たるぶん、少し粘ります)。その間、id は 0 に張り付いたまま。回る座標のおかげで、交流のモータを、直流の電流ループ二本 で押せています。
ひとつだけ、DC のときには無かった相手がいます。さきほどの ±ωe·L·i の 押し合い です。iq を急に動かすと、その影響が d 軸に滲み出して、本来 0 のはずの id を揺らします。下の段の赤い線がそれで、iq のステップにつられて id が 0.5A ほど膨らんでしまいました(速く回っているほど、この滲み出しは強くなります)。
対策は、前回のフィードフォワードと同じ考え方です。押し合いの分(ωe·L·i)と逆起電力(ωe·λ)は、式で分かっているのだから、先に足して打ち消しておく。青い線がそれで、id の膨らみは 0.02A まで抑えられました。この「先に打ち消す」を デカップリング(非干渉化) と呼びます。
回してみる ―― またカスケード
電流(トルク)を担えたので、あとは前回と同じ入れ子です。いちばん外に速度ループを置いて、その出力を iq の目標にします。目標 200 rad/s で回してみます。

上が速度、下がトルク電流です。加速中は iq が上限の 10A に張り付いて(=トルクの上限で加速)、20 ミリ秒ほどで 200 rad/s に乗りました。途中の 150 ミリ秒で負荷トルク 0.2 N·m を乗せると、速度が少し落ちてから戻り、iq は保持の 1.6A あたりに落ち着きます(負荷と摩擦を合わせたぶん ÷ Kt)。そして下の段、iq がどう動いても id は 0 のまま。トルクに要らない電流は流さない、という FOC の狙いが保たれています。
回していて改めて効いてくるのが、この方式(id=0)には 最高速の天井 がある、という点です。速く回るほど逆起電力(ωe·λ)が育ち、それが電圧の上限に届くと、もう電流を押し込む余地が無くなります ―― そこが最高速です。今回はその天井に収まる範囲で回しました。電源を上げずにもっと速く回したいときは、id をあえて負に流して実効的な磁石を弱める 弱め界磁 という別の道がありますが、それはまた別の話です。
やっていることは、前回の DC サーボのカスケードと骨格はまったく同じです。違うのは、いちばん内側の電流ループが、三相を dq に畳んでから押している、という一点だけです。
おわりに ―― 次は「電圧をどう作るか」
ブラシレスでも、回る座標に乗ってしまえば、DC サーボと同じ感覚で電流を押せる ―― これが FOC の気持ちよさです。三相の交流を Clarke / Park で dq に畳み、直流になった電流を PI で受け持ち、押し合いと逆起電力はデカップリングで先に消す。あとは前回と同じカスケードです。
ただ、今回は制御が出した「電圧指令(vd, vq)」を、そのままモータにかけられるものとして話を進めました。実際には、この電圧指令を、直流電源から三相の本物の電圧に作り直す部品 ―― インバータ が要ります。FET を高速でオン・オフして、狙いの電圧を平均として作り出す(PWM)。制御の出口から、実際の電流までの、最後のひと区間です。ここは、また回を改めて確かめてみます。
コード一式(PMSM のモデル、Clarke/Park 変換、FOC の電流ループとデカップリング、速度カスケード、三枚の図の生成)は、そのまま動く形で置いてあります。python foc_pmsm.py で本文の数値が、python plot_foc.py で三枚の図が出ます。
- リポジトリ: logicia32/foc-lab
この記事は Zenn に初出したものを加筆・補足したものです ── Zenn の元記事を見る