IR2110の独り言

ゲートドライバーICが独り言をつぶやくだけです

ArduinoMegaくんでVVVFの同期モード・非同期モードの実装② -非同期PWMの生成-

前置き(いらない)

前のブログからメチャクチャに期間空いちゃいましたね…。
怒らないでください、やる気が出なかっただけです…。

あとこれ結構前にやったことなので色々適当だったりして正直恥ずかしいです。

需要があれば。

非同期PWMを出すために必要なこと

非同期PWMの線間電圧波形例

正弦波のルックアップテーブルを作成

非同期PWMを出すためには、基本波の正弦波を正確に計算できるようにしなくてはなりません。しかしArduinoなどの比較的低速なマイコンでは、毎回sinの値を計算していては速度が足りません。そこで、sinの値を格納したルックアップテーブルを作成すれば、メモリから直接取り出すだけでsinの値を得ることができ、計算の必要がありません。

手計算 vs. ルックアップテーブル

タイマー割り込みで正確な周波数を出力

正確な周波数を得るためには、θを正確な周期で加算していかなくてはなりません。loop文の中でdelay関数を用いてθを加算する方法だと、他の処理の時間による誤差があり、正確な周波数を得ることは不可能に近いです。そこで、タイマー割り込みを用いて正確な時間で割り込みすることにより正確な周波数を得ることとします。

結局…

つまり非同期PWMを出すためには

  • 正弦波のルックアップテーブルの作成
  • タイマー割り込み

が必要になりそうです。

タイマー割り込みで周波数を正確に出力

タイマー割り込み

タイマー割り込みの周期ですが、経験則から10kHzくらいが最適だと勝手に思い込んでるので10kHzで実装します。PWMを出すタイマーとは別のタイマーで動作させます。

θは整数型で宣言

θの変数での表現方法は、符号なし32bit整数とし、1周期(360°)分を2^31=2147483648として考えます。(最大の2^32-1=4294967295にしないのは理由があります…。これは後ほど。)これは、ArduinoにFPUなどの高速に浮動小数点演算を行う装置がないことと、処理時間と周波数解像度のトレードオフを考慮し32bitとしました。

剰余の処理を工夫

さらなる高速動作を実現するため、θを循環的に変化させるための剰余の処理も工夫をし、高速化を実現しました。除数aが2の累乗の場合、AND演算をすることで以下のように簡単に剰余を得ることができます。

  • x mod a == x & a-1 (ただしa=2^n)

このような理由で、1周期を最大値の2^32-1ではなく、2^31で表現しました。2^32-1は2の累乗ではありませんからね。

正弦波のルックアップテーブルを作成

2の累乗の長さで作成

正弦波のルックアップテーブルですが、長さ2^11=2048、float型で±1の間で変化するものをU, V, Wの3相分作成しました。2048というのはこれまた経験則で決めたものです。これくらいあればまあいけるでしょう(適当)。長さを2の累乗にしたのにも理由があって、θをビットシフトするだけでルックアップテーブル参照用に換算することができるからです。また、ついでに3次高調波重畳の基本波や、空間ベクトル変調用の基本波も作成しておきました(二次元配列にしました。)。ただし、RAMの容量は小さいので、ルックアップテーブルはフラッシュメモリ側で記憶するようにしました。

電圧補償器用の配列の作成

言い忘れていましたが、キャリアベースPWMの場合、そのままのPWMでは含有されている基本波成分の振幅と設定されている電圧値が一致しません。例えば電圧を1に設定したら基本波を最大量含有している1パルスの波形になるのが理想ですが、実際は過変調になる手前の波形になってしまい理想電圧値と実際の電圧値に誤差が生じていることがわかります。これを補正するために、電圧補償用の配列を作成しました。長さはとりあえず1000とし、float型で作成しました。

理想と現実

過変調の処理

過変調(変調率が1を超えている場合)、最終的なPWMデューティー比を設定するOCRnxに値を入れるとオーバーフローを起こしてしまいます。そのため、65535までのリミッタをかけ、オーバーフローが起きないようにします。

Arduinoで非同期PWMを出力!

はい、ということで皆さんできたでしょうか。あ、ソースコードは載せません。
まあ参考にでもなれば幸いでございます。

次回は同期PWMを出力してみようと思います。僕のやる気が出るまでお待ちください。

 

おわり

 

第三回