PR

Arduinoで疑似正弦波を作る

記事内に広告が含まれています。
スポンサーリンク

概要

 Arduinoで正弦波を作ります。UNOでは本当のアナログ出力(DAC)はできないのでPWM出力とSIN関数を使用して疑似正弦波を出力してみます。

PWM出力で疑似正弦波

 PWM出力(青)のデューティ比を変化させて正弦波/SIN(赤)となるように疑似的に出力電圧を制御します。縦波か横波かの違い、PWM出力で縦波(疎密波)を作り出すイメージ??

 順にプログラムしながら確認していこうと思います。

SIN関数のグラフ化

 まずは単純にArduinoのSIN関数で正弦グラフを作ってみます。

//sin関数
//2025/04/21 imo Lab.
//https://garchiving.com

int16_t deg;

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(sin(deg * PI / 180.0));
  deg == 360 ? deg = 0 : deg += 1;
  delay(10);
}

 SIN関数をグラフ化しているだけのプログラムです。1度ごと0度~360度までのSIN計算の繰り返しをシリアル送信してます。delayで少し遅くしています。

正弦波グラフ シリアルプロット

 IDEのシリアルプロッタで確認。問題無く正弦波が計算されてます。ただこのままでは値が -1~1 で少し扱いづらいので、0~1の範囲になるように全振幅を半分にしてオフセットします。

  0.5 + 0.5 * sin(deg * PI / 180.0)
正弦波シリアルプロッタ

 0~1の範囲の正弦グラフです。次にこの値をそのままPWM出力のデューティ比に入れてみます。

スポンサーリンク

疑似正弦波

 先ほどの0~1のSIN関数値からPWM出力を使って疑似正弦波を出力してみます。

void loop() {
 val = 0.5 + 0.5 * sin(deg * PI / 180.0);
 deg == 360 ? deg = 0 : deg += 1;

 analogWrite(3, (int16_t)255.0 * val);
 delay(20);
}

 まずは単純にPWM出力のデューティ比にSIN関数を入れてみます。3ピンから疑似正弦波が出力されます。実際にこのスケッチを書き込んで実測してみます。20msインターバルの360分割なので正弦波の周期はおよそ7.2sです。

 3ピンの実測結果。上が出力そのままを計測。下がCRフィルターを通したものです。およそ7.2s周期で出力されてます。割と簡単に疑似正弦波の出力ができました。PWM周波数が490Hzなのとフィルター定数が合ってないのか平滑化しきれてません。

PWM周波数を変更

 PWM周波数を高くしてみます。analogWriteでは周波数変更できないのでPwmOutクラスを使用。

//疑似正弦波 Arduino UNO R4
//2025/04/21 imo Lab.
//https://garchiving.com

#include "pwm.h"
PwmOut pwm3(3);

int16_t deg;
float val;

void setup() {
 Serial.begin(115200);
 pwm3.begin();
 pwm3.period_us(100);  //10kHz
}

void loop() {
 val = 0.5 + 0.5 * sin(deg * PI / 180.0);
 deg == 360 ? deg = 0 : deg += 1;

 pwm3.pulse_perc(val * 100);
 delay(20);
}

 analogWrite()をPwmOut()に変更しているだけです。PWM周波数は10kHz。

 PWM周波数変更した効果?なのかわかりませんが正弦波はだいぶ平滑化して測定できてます。次に正弦波の周期も変更してみます。

スポンサーリンク

正弦波の周期を変更

 もう少し周期を早くしてみます

void loop() {
 currentTime = micros();

 if (currentTime - loopTimer > 100) {  //0.1ms
   loopTimer = micros();
   val = 0.5 + 0.5 * sin(deg * PI / 180.0);
   deg == 360 ? deg = 0 : deg += 12;
   pwm3.pulse_perc(val * 100);
 }
}

 delayでそのままループ周期を早くしてもよかったのですが、割り込みもどきで周期を調整。SIN関数の分解能も30まで下げて、0.1ms×30で周期3ms(333Hz)程の正弦波にしてます。

疑似正弦波

 先ほどのソースで実測してみました。あまり正確ではないですがおおむね狙った周波数は出ています。

 ブラシレスモーターを制御する目的で今回はArduinoで疑似正弦波を作成してみました。そのうちきちんとしたオシロが欲しいです。

参考
・Arduinoで正弦波を出力する | jh4vaj

コメント

タイトルとURLをコピーしました