ある周期を持つ波形は、その周期の1/nの周期をもつsin/cos波の合成であらわせる、とする「フーリエ解析」という理論があります。音で言えば、ある音を基本周期の倍音に分解して解析して行くような感じでしょうか。この理論で行くと、複雑な波形でもまたデジタル的な矩形波までも三角関数の和で表現(数値的な分析)できるようです。ちょっとイメージがわきにくいですが、これはもともと数式からイメージしにくい「波形」をさらに合成するからですね。今回は、この波形の合成をイメージとしてつかむために2つのsin波を合成してその様子を描画してみる事にしましょう。 波の加算今回は、単純な2つのサイン波を合成してみます。式で書けば、 f1(x)=a1sinb1x f2(x)=a2sinb2x という2つのサイン関数を各xで加算した f(x)=f1(x)+f2(x) という関数を作って、その関数の描く波形を見てみるわけですね。この式では、a1, a2が各関数のf(x)に与える影響の大きさを、またb1, b2が各関数の周期を決めるパラメータになっています。このa1, a2, b1, b2の各数値をいじる事でさまざまな波形を作る事が出来るわけです。これらの関数の様子をx方向は0〜2π、y方向はー4〜4の範囲で描いてみる事にしましょう。 今回は、2つのサイン波と合成した結果の合わせて3つの波形を描くわけですが、描画用には2つのサイン波を合成して描くクラスを定義すれば良いでしょう。2つのサイン波については、一方を0にする事で対応できます。クラスにはパラメータとしてa1, a2, b1, b2を持たせ、2つのサイン波を描く時にはa1, b1の方にパラメータをいれa2, b2は常に0にしておきましょう。 波形表示用クラスCSinDispは、表示サイズを指定するコンストラクタで初期化します。 CSinDisp(int w,int h) { width=w; height=h; setA1(1); setB1(1); setA2(0); setB2(0); setSize(width+2,height+2); } 続いて、指定されたパラメータとxから関数の値を求める関数getVal()を定義。 private double getVal(double x) { double res; res=Math.sin(b1*x)*a1; res+=Math.sin(b2*x)*a2; return res; } パラメータa2, b2を0にしておけば、この関数はa1sinb1xの値を返すので、一つのサイン波だけの表示にも使えるわけです。さらに、現在のパラメータで波形をグラフィックオブジェクトg_img描く関数drawData()は private void draw() { // 現在の状況を描画 double dx=2*pi/(double)width,dy=(double)height/8.0; int y1,y2; g_img.setColor(Color.blue); g_img.fillRect(0,0,width,width); g_img.setColor(Color.gray); g_img.drawLine(0,height/2,width,height/2); g_img.setColor(Color.white); y1=height-((int)Math.sin(0)+height/2); for (int i=1;i<width;i++) { y2=(int)(getVal(i*dx)*dy); y2=height-(y2+height/2); g_img.drawLine(i,y1,i,y2); y1=y2; } } という感じになります。今回は、このCSinDispを3つ作りパラメータ入力用テキストフィールドや数式表示用ラベルとともにアプレットに追加してみました。 プログラムテキストフィールドにパラメータを追加してGoボタンをクリックしてみてください。各パラメータで描かれたサイン波と、そのサイン波を合成した波形を描きます。最初は、上の周期2πのサイン波はそのままにして下の方のサイン波の周期を変化させて波形を変えてみましょう。この時、下の関数の周期はb2分の1になるので、b2に2以上の整数を指定すると合成波形の周期を2πに保ったまま波形を変える事が出来ます。次に、a2を変化させて下の方の関数が合成波形に与える影響の大きさを変えてみてください。 |