2010. 5.30.
石立 喬

Visual C++ 2010 Express の易しい使い方(9)

――― リサージュ波形を画面に表示させる ―――

 リサージュ(Lissajous)波形は、電気技術者にとって、非常に馴染みの深い波形である。二つの周波数源の同期や位相を調整するのに便利で、オッシロスコープを学ぶ際に、必ずと言っても良いほど実験させられる。ここでは、新たにスクロールバーの使用方法を紹介する。

リサージュ(Lissajous)波形とは
 リサージュ図形、リサージュ曲線などとも呼ばれることがある。フランスの物理学者Jules Antoine Lissajousが、1857年に発表したと言われ、その名前が付けられている。これは、直交するX軸とY軸のそれぞれに異なる正弦波を加えて得られる平面図形のことで、それぞれの正弦波の周波数、位相の違いなどによって、多様な曲線が描かれる。

リサージュ波形による周波数の測定(設定)
 オッシロスコープで、基準波を横軸に、被測定波を縦軸に入力すると、リサージュ図形が得られる。上下に描かれた山の数と、左右に描かれた山の数が、基準波と被測定波の周波数比となって現れるので、周波数の測定ができる。リサージュ波形を見ながら被測定波の周波数を調整することにより、周波数を設定することもできる。

リサージュ波形による位相の測定(設定)
 同様に、基準波を横軸に、それと同じ周波数の被測定波を縦軸に入力し、縦横が同振幅に表示されるように調節すると、二つの波の位相関係により、直線、円、楕円のリサージュ図形が得られる。位相差を0またはπ(逆相)にすると直線になり、2/πまたは-2/πにすると円になる。この原理により、位相の測定または設定ができる。

パソコン上でのリサージュ波形の作成方法
 画面上の座標を(x,y)としたとき、
  横軸入力波形 x = A・sin ωt
  縦軸入力波形 y = B・sin(ωt + φ)
で描いた図形がリサージュ波形である。
 ただし、ここで紹介する例では、A = B とし、tは時間で 0秒から1秒までとする。ωは角周波数で、ω = 2πfの関係がある。fは周波数で、1 Hzから10Hzまでとする。φは縦軸入力波形に付加する位相シフトで、-πラジアンからπラジアンまで変化させる。

プログラムの使用方法
1) プログラムを起動させると、横軸周波数 = 2Hz、縦軸周波数 = 3Hz、位相 = 0の初期設定になっており、その条件でのリサージュ波形が描かれる。
2) 横軸周波数と縦軸周波数は、コンボボックスによって設定可能で、変更すると、直ちにリサージュ波形が描かれる。
3) 縦軸周波数の位相は、スクロールバーで、0.01π単位で設定でき、これも変更と同時にリサージュ波形の描画が行われる。
4) 「ゆっくり」ボタンをクリックすると、その時の設定条件で、各種波形の再描画がゆっくり行われる。

コンボボックスの設定
 すでに説明した方法に従い、二個のコンボボックスを設ける。「プロパティ」ウインドウから開いた「文字列コレクション エディター」で、二個のコンボボックス共に図1のように設定する。


図1 コンボボックスで周波数を決めるための文字列


水平スクロールバーの設定

 「ツールボックス」ウインドウの「すべてのWindowsフォーム」の中から、「HScrollBar」をクリックして、フォーム上の希望する場所で、再びクリックする。配置されたスクロールバーを右クリックし、「プロパティ」ウインドウで、図1のように設定する(変更したのは「Maximum」のみで、その他はデフォルトのまま)。
 スクロールバーで数値を設定できるのは正の整数に限られ、使用できる最大値は、Maximum + 1 - LargeChange の関係がある。「Maximum」を「209」に設定したことは、使用できる最大値が「200」であることを意味する。


図2 水平スクロールバーの「プロパティ」ウインドウで、「Maximum」を変更する。


プログラム
1) 時間待ちをさせる Thread::Sleep(10); を使用するために、System::Threading を名前空間として追加する。Sleepのカッコ内は、msecで指定する。
2)コンボボックスでは、周波数を1Hzから10Hzまで、1Hz刻みで設定できる。これを、SelectedIndexの0から11に対応させているので、周波数は、SelectedIndex+1で得られる。

    using namespace System::Threading;

    Boolean slow_flag;

    private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {

        comboBox1->SelectedIndex=1;   //横軸入力波形の周波数を2Hzに初期設定
        comboBox2->SelectedIndex=2;   //縦軸入力波形の周波数を3Hzに初期設定
        hScrollBar1->Value=100;     //縦軸位相を0に初期設定
        slow_flag=false;

    }

    private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {

        Graphics^ g=e->Graphics;

        int X0=10,Y0=50;    //横軸入力波形用
        int X1=190,Y1=50;   //縦軸入力波形用
        int X2=20,Y2=230;   //リサージュ波形用

        int t,x1,x2,y1,y2;
        double time,x,y,old_x,old_y;

        int freq_x=comboBox1->SelectedIndex+1;
        int freq_y=comboBox2->SelectedIndex+1;
        double omega_x=2.0*Math::PI*freq_x;
        double omega_y=2.0*Math::PI*freq_y;
        double phi1=(hScrollBar1->Value-100)/100.0;
        double phi=phi1*Math::PI;

        //位相シフトを表示する
        if(phi1==0.0)       label4->Text=" 0";
        else if(phi1==1.0)     label4->Text=" π";
        else if(phi1==-1.0)    label4->Text=" -π";
        else            label4->Text=String::Format("{0}π",phi1);

        //グラフの背景を黒にする
        g->FillRectangle(Brushes::Black,X0,Y0,160,160);
        g->FillRectangle(Brushes::Black,X1,Y1,160,160);
        g->FillRectangle(Brushes::Black,X2,Y2,320,320);

        //グラフに目盛を入れる
        for(int i=0;i<=10;i++){
            //横軸入力波形用
            g->DrawLine(Pens::LightGray,X0+16*i,Y0,X0+16*i,Y0+160);
            g->DrawLine(Pens::LightGray,X0,Y0+16*i,X0+160,Y0+16*i);
            //縦軸入力波形用
            g->DrawLine(Pens::LightGray,X1+16*i,Y1,X1+16*i,Y1+160);
            g->DrawLine(Pens::LightGray,X1,Y1+16*i,X1+160,Y1+16*i);
            //リサージュ波形用
            g->DrawLine(Pens::LightGray,X2+32*i,Y2,X2+32*i,Y2+320);
            g->DrawLine(Pens::LightGray,X2,Y2+32*i,X2+320,Y2+32*i);
        }

        //各種波形を描く
        for(t=0;t<=320;t++){
            time=t/(320.0);
            x=Math::Sin(omega_x*time);
            y=Math::Sin(omega_y*time+phi);
            if(t==0){
                x_old=x;
                y_old=y;
            }
            else{
                x1=0.5*(t-1);
                x2=0.5*t;
                y1=80-64*old_x;
                y2=80-64*x;
                g->DrawLine(Pens::LightGreen,X0+x1,Y0+y1,X0+x2,Y0+y2);  //横軸入力波形
                y1=80-64*old_y;
                y2=80-64*y;
                g->DrawLine(Pens::LightGreen,X1+x1,Y1+y1,X1+x2,Y1+y2);  //縦軸入力波形
                x1=160-128*old_x;
                x2=160-128*x;
                y1=160-128*old_y;
                y2=160-128*y;
                g->DrawLine(Pens::LightGreen,X2+x1,Y2+y1,X2+x2,Y2+y2);  //リサージュ波形
                x_old=x;
                y_old=y;
           }
           if(slow_flag)   Thread::Sleep(10);   //10msecだけ待つ
        }
        slow_flag=false;

    }

    //「横軸周波数」が変更になった
    private: System::Void comboBox1_SelectedIndexChanged(System::Object^ sender,System::EventArgs^ e) {

        Invalidate();

    }

    //「縦軸周波数」が変更になった
    private: System::Void comboBox2_SelectedIndexChanged(System::Object^ sender,System::EventArgs^ e) {

        Invalidate();

    }

    //「縦軸位相」が変更になった
    private: System::Void hScrollBar1_ValueChanged(System::Object^ sender,System::EventArgs^ e) {

        Invalidate();

    }

    //「ゆっくり」ボタンが押された
    private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {

        slow_flag=true;
        Invalidate();

    }

得られた画面
 図3は、コンボボックスにより、横軸周波数を3Hzに、縦軸周波数を5Hzに設定し、スクロールバーで縦軸位相を0.51πに設定した場合のリサージュ波形を示す。上の山が5個、横の山が3個ある。


図3 リサージュ波形の例


「Visual C++ の勉強部屋」(目次)へ