【概要]
sin() 関数は、与えられた角度(ラジアン)に対して正弦(sine)の値を計算する標準数学関数です。Arduinoの環境では、C言語の標準ライブラリである <math.h>(Arduino環境では Arduino.h を通じて利用可能)に含まれています。主に、周期的な波形の生成、信号処理、物理シミュレーション、およびモーターの滑らかな加速・減速制御などの動的挙動の実装に使用されます。
【仕様]
- 引数:
floatまたはdouble型の数値。単位はラジアン(radians)です。 - 戻り値:
-1.0から1.0の範囲のfloatまたはdouble型。 - データ型: 実行環境のアーキテクチャに依存します。
- AVR(Uno, Nanoなど):
doubleはfloat(32ビット)として扱われるため、実質的にfloat精度の計算が行われます。 - ESP32 / ARM Cortex-M系: 32ビットまたは64ビットの浮動小数点演算ユニット(FPU)の有無により、
double型の精度が保持される場合があります。
- AVR(Uno, Nanoなど):
【技術的特徴]
1. 計算アルゴリズム
sin() の内部実装はコンパイラおよびハードウェアに依存しますが、一般的には以下のいずれかの手法で近似または計算されます:
– テイラー展開 (Taylor Series): 多項式を用いて値を算出。計算負荷と精度のトレードオフが存在します。
– CORDICアルゴリズム: 角度を回転と加算の繰り返しで計算するアルゴリズム。演算リソースの乏しいマイクロコントローラでよく採用されます。
– ルックアップテーブル (LUT): あらかじめ計算された値をメモリから参照する手法。関数自体ではなく、最適化の過程で使用されることがあります。
2. ハードウェアによる実行特性
- 8bit AVRプロセッサ: 浮動小数点演算ユニット(FPU)を搭載していないため、すべての演算はソフトウェアエミュレーションによって行われます。このため、計算コストは非常に高く、サイクル数(Clock Cycles)を大幅に消費します。
- 32bit / 64bitプロセッサ: FPUを搭載している場合、ハードウェアレベルでの高速な演算が可能となり、実行速度は劇的に向上します。
3. sin() と sinf() の比較
sin():double型を対象とする標準関数。高い精度を求める場合に適していますが、8bit機ではsinf()と同等のコストがかかることが多いです。sinf():float型を対象とする関数。32bit以上のプロセッサにおいて、double型を扱うsin()よりも高速に動作します。
【注意点]
- ラジアン変換の必須性: Arduinoの
sin()関数は「度(Degrees)」ではなく「ラジアン」を受け取ります。度からラジアンへの変換式:rad = deg * (PI / 180.0)を適用する必要があります。 - 計算コストとジッタ: タイマー割り込み内や、極めて高いサンプリングレートが必要な制御ループ内で
sin()を呼び出すと、CPUリソースを枯渇させ、実行時間のバラツキ(ジッタ)の原因となります。高頻度の計算が必要な場合は、事前計算したルックアップテーブル(LUT)の使用を検討してください。 - 累積誤差: 時間の経過とともに加算される変数(例:
time += 0.01)を引数に直接使用する場合、浮動小数点の精度限界により、長時間の稼働で位相がずれる可能性があります。これを防ぐには、角度を 0 から 2π の範囲にモジュロ演算でリセットする手法が有効です。
【サンプルコード]
#include <math.h>
#include <Arduino.h>
const float PI = 3.141592653589793;
const float frequency = 1.0; // 周波数 (1Hz)
const float amplitude = 100.0; // 最大振幅
void setup() {
Serial.begin(9600);
}
void loop() {
static unsigned long lastMillis = 0;
unsigned long currentMillis = millis();
// 10msごとに計算を実行
if (currentMillis - lastMillis >= 10) {
lastMillis = currentMillis;
// 現在の時間を秒に変換し、ラジアンに変換
float time_sec = (currentMillis / 1000.0) * frequency;
float angle = time_sec * 2.0 * PI;
// sin() 関数を使用してサイン波を計算
float value = amplitude * sin(angle);
Serial.print("Value: ");
Serial.println(value);
}
}
【活用例]
- オーディオ信号生成: 正弦波を生成し、PWM出力を通じて電子音やトーンを生成する。
- モーターの滑らかな動作: 物理的な加速・減速をシミュレートするためのS字カーブに近い制御信号の生成。
- センサーデータの信号処理: 交流信号の波形解析や、特定の周波数成分の抽出における位相計算。
- LEDフェード演出: 周期的な輝度の変化を、線形補間よりも滑らかに表現する際の係数計算。


コメント