数値計算の結果をプロットする(2)

のこぎり波は次のような形状をしています。

Saw-tooth wave

この周期波形のフーリエ級数を求めると,

f(t) = (2A/pi) * ( sin(w0t) - (1/2)*sin(2w0t) + (1/3)*sin(3w0t) - ... )

となります。なお,

w0 = 2 * pi f0 = 2 * pi * (1/T0)

であり,f0を基本周波数と呼びます。 ここで,tが変数で,A, f0が定数になります。 また,計算を有限時間で終了させるために,第n次高調波(第n項のsinの値)まで求めることにし, nを定数として宣言しておくことにします。

ここでは A = 1, f0 = 1[kHz], -2[ms] <= t <= 2[ms], dt = 0.01[ms] としてプログラムを書いてみましょう。

以下がそのプログラムです。

nc2.c

/* Numeral Computing with gnuplot: 2 */

#include <stdio.h>
#include <math.h>

#define N        10     /* 第N高調波までを計算 */
#define A        1.0    /* 振幅 */
#define F        1e3    /* 基本周波数 f0 [Hz] */
#define T_DIV    100e3  /* サンプリング周波数(1秒間当たりのtの分割数) [Hz] */
#define T_START  -2e-3  /* tの最小値 [s] */
#define T_END    2e-3   /* tの最大値 [s] */

int main(void);

int main(void) {
  int i;            /* ステップ数 */
  int j;            /* 高調波を求めるループの制御変数 */
  double t;         /* ステップiにおける時刻t */
  double y;         /* f(t) */
  int sign;         /* 各項の符号 */
  double k, omega;  /* 計算量を減らすために,定数項をあらかじめ計算しておく */
  double pi;        /* π (= 3.14...) */

  pi = 4 * atan(1.0);
  k = 2 * A / pi;
  omega = 2 * pi * F;
  for (i=T_START*T_DIV; i<=T_END*T_DIV; i++) {
    t = (double)i / T_DIV;

    y = 0;
    sign = 1;
    for (j=1; j<=N; j++) {
      y += sign * sin(j * omega * t) / j;
      sign *= -1;  /* 符号を反転 */
    }
    y = k * y;

    printf("%f %f\n", t, y);
  }

  return 0;
}

このCソースコードをコンパイルして,実行結果をnc2.pltに出力します。 なお,math.hをインクルードしているのでコンパイル時には-lmオプションをつける必要があります。

% gcc -o nc2 nc2.c -lm
% ./nc2 > nc2.plt

そしてgnuplotでプロットします。

# 結果

gnuplot> plot 'nc2.plt' w l

Nの値を変更して,実行結果のグラフがどう変化するかを調べてみてください。

$Id: numeric_computing2.shtml 1289 2007-02-04 13:22:39Z SYSTEM $