VVVFを作ってみよう(2)

お久しぶりです

最近寒くなってきましたね、わかばです。また、ぼちぼち書いていきたいと思います。寒くてタイプミスが増えてきてますが多めに見てください。


本講座では、VVVFの簡単なプログラムの作り方を紹介しています。(1)をまだご覧になっていない方は、下記のリンクよりご確認下さい。

  1. VVVFの説明と、DDSの説明 (1) 
  2. DDSの説明 (2) この記事
  3. Arduinoのコード用いたDDSの実践 (予定)
  4. VVVFのプログラムを用いて実践 (予定)

 

前回は何があったの?

はい、前回はVVVFの説明と,DDSと固定小数点演算の説明をしましたね。

では前回の続きから行きたいと思います。


波形テーブルをでっかく

前回、固定小数点を用いてオペレータの加算値を表現しました。

が、それでも加算値が1よりも小さい値になってしまいました。

#inculde(“🔰”)

int sin_table[256] = [/*SINの値が入っている*/];

unsigned int  operator_sin = 0;

unsigned int  operator_sin_adder = 0;

void main(){

interrupt_set(dds_output,10000);

while(1){

operator_sin_adder = (256*1<<3)/10000;

}

}

interrupt dds_output(){

operator_sin += operator_sin_adder;

operator_sin &= 2047;//ここの説明は後述します。ヒントはビットシフト

OutPut(sin_table[operator_sin>>3]);

}

こちらが前回の最後に出てきたプログラムになります。

まず前回の未説明部分から

operator_sin &= 2047;

operator_sin = operator_sin & 2047;

であり

operator_sin = operator_sin % 2047;

と同意味です。

なぜでしょうか?簡単に3bitで考えてみましょう。

22 % 8 =

22を8で割ったときのあまりはいくつでしょうか?

22 % 8  = 1

22 – 8×2  = 22 -16 =  6 

どうやら、答えは6のようです

ではこの計算を次のようにします

22 & 7 =

さて、この答えはいくつになるでしょうか  ※(N)はN進数

22 (10)= 10110(2)

7 (10) =  00111(2)

10110(2) & 00111(2) = 110 (2) = 6(10)

となります。実は剰余算は特別な場合論理演算(ビット演算)に置き換えることができます。

詳しくは、Wikiセンセに聞いてください。今回は高速化のため随所にビット演算を入れてあります。

ビット演算による効率化

2047という数字が出てきた理由は剰余算のためというのもありますが、一番は本来0~255のあたいの範囲を3左シフトしているためです

本来

operator_sin &= 255;

今回 [<<3]を考慮すると

operator_sin &= 255<<3;

になるべきであるが

255<<3 = 2040 =  111 1111 1000(2)

となり、3bit増やした分が失われてしまう

これでは本末転倒なので

operator_sin &= 111 1111 1111(2) ;

つまり

operator_sin &= 2047;

となります

本題まだ?

ということで、本題に入ります。

#inculde(“🔰”)

int sin_table[256] = [/*SINの値が入っている*/];

unsigned int  operator_sin = 0;

unsigned int  operator_sin_adder = 0;

void main(){

interrupt_set(dds_output,10000);

while(1){

operator_sin_adder = (256*1<<3)/10000;

}

}

interrupt dds_output(){

operator_sin += operator_sin_adder;

operator_sin &= 2047;

OutPut(sin_table[operator_sin>>3]);

}

もう一度プログラムを載せておきます。

さて、前回こんな式を出しました。

タイマ割り込み処理内で、オペレータに加算する値の計算式ですね。

この計算が少数になってしまうと困るので、前回固定小数点なんてものを説明したんでしたね。

前回、書いたかわからないのですがここまでしてadd値を大きくさせようとしているのは、出力周波数の分解能を向上させるためでもあります。

分解能1Hzあればよくねって思うかもしれないですが。インバータにとって1Hz刻みは大きすぎです。市販のインバータも大体0.1Hz刻みがざらです。

そんなこんなで、固定小数点でだけではadd値を大きくできないということでサンプル長を長くしようという魂胆でございます。

#inculde(“🔰”)

int sin_table[8192] = [/*SINの値が入っている*/];

unsigned int  operator_sin = 0;

unsigned int  operator_sin_adder = 0;

void main(){

interrupt_set(dds_output,10000);

while(1){

operator_sin_adder = (8192*1<<3)/10000;

}

}

interrupt dds_output(){

operator_sin += operator_sin_adder;

operator_sin &=  0xFFFF;// = 65536

OutPut(sin_table[operator_sin>>3]);

}

はい、配列幅は8192 固定小数点は3bitとド~ンと大きくしました。0xFFFFは上記の通り、固定小数点分を消さないよう剰余算しています。

operator_sin_adder = (8192*1<<3)/10000;// 1<<3 =  8

operator_sin_adder =  6;

ようやく、6です。

ちなみに、分解能は0.15Hzくらいです。まぁまぁですね。

ちなみに前回書いたかもしれませんが、add値が1になるときの出力周波数が周波数分解能です。

今回はこのくらいで

いかがでしょうか、なんとなくDDSの処理についてなんとなく分かっていただけたでしょうか

次回は、実際にArduinoのコードを用いながら説明をしていければと思っております。

と、いいますことで

ここまでお読みいただきありがとうございます。

不明点等ございましたら、コメントの方にお願いします

あ、ちなみにWindowsの方

標準装備の電卓アプリには、プログラマーモードがあり、2進数、10進数、16進数などの変換に非常に便利なのでオススメです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください