2010. 6. 7.
石立  喬

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

――― C++標準のcomplexクラスを用いて水晶振動子の等価回路特性を描く ―――

  ここでは、水晶振動子の電気的等価回路にcomplexクラスを応用して、周波数とリアクタンス成分の関係を示すグラフを描く。
 具体的には、複素数で表された二つのインピーダンスの並列計算を行い、複素数インピーダンスの虚数部(リアクタンス成分)を求める。 プログラム自体は比較的簡単なので、電気回路的解説を少し詳しくする。

水晶発振器の原理
 現在、水晶発振器はいたるところで使われていて、安価で発振周波数が安定していることが知られている。水晶発振器は水晶振動子と帰還増幅回路を組み合わせて構成し、発振周波数は水晶振動子の機械的固有共振周波数で決まる。
 水晶振動子は、水晶片に電極をつけたもので、共振周波数付近では等価な電気回路で表現できる。電気回路で言うと、水晶振動子は、極めて狭い周波数範囲でのみL性(インピーダンスのリアクタンス部が正)を示し、その他ではC性を示す。
 L性素子がないと発振しない発振回路を作り、そこに水晶振動子を取り付けると、前記の固有周波数でのみ発振する。

水晶振動子の等価回路と計算式
 図1のように等価回路を想定する。上側のLCR直列回路(Z1で表す)は水晶の機械的特性を置き換えたもので、下側の並列容量C(Z2)は電極や端子などの浮遊容量である。


図1 水晶振動子の等価回路


 したがって、Z1およびZ2は、下式で表される。

   

 水晶振動子全体のインピーダンスは、プログラムではz_xtal=z1*z2/(z1+z2) で求める。発振周波数を決めるのはz_xtalのリアクタンス成分であるので、グラフにはリアクタンス成分のみを表示する。
 ある会社のカタログによれば、200kHz用の水晶振動子の等価回路の定数が R=2kΩ、L=27H、Cs=0.024pF、Cp=9pF と示されていたので、これを使用した。ただし、周波数を正確に合わせるために、Csを細かく調整した。

プログラムの概要
 1)画面最上部に、等価回路の各定数を表示する。
 2)z1とz2の実数部は、周波数に依存しないのでforループ外で設定する。z1とz2の並列インピーダンスz_xtal の虚数部は、z_xtal.imag()によって求める。
 3)プロット(計算点)は500個とし、それらを周波数の199kHzから201kHzの間に割り当てる。プロットがグラフの枠の外に出ることを想定した処置はしていない。

プログラム
 すべての本体プログラムを記述した Form1.h の内容

    #pragma once
    #include <complex>

    using namespace std;

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

        Graphics^ gr=e->Graphics;

        int X0=180,Y0=20;    //各回路定数の表示位置
        int X1=90,Y1=60;    //グラフの位置
        int X2=10,Y2=53;    //インピーダンス目盛の位置
        int X3=73,Y3=475;    //周波数目盛の位置
        double INDUCTANCE=27;           //L=27H
        double CAPACITANCE_S=2.3515E-14;       //Cs=0.023515pF
        double CAPACITANCE_P=9E-12;         //Cp=9pF
        double RESISTANCE=2E+3;           //R=2kΩ

        int i,x,y,old_x,old_y;
        complex<double> z1,z2,z_xtal;
        double frequency,omega;
        String ^ string1;

        //等価回路の各定数を表示
        string1=String::Format("L={0}H, Cs={1}pF, Cp={2}pF, R={3}Ω",
            INDUCTANCE,CAPACITANCE_S*1E+12,CAPACITANCE_P*1E+12,RESISTANCE);
        g->DrawString(string1,Font,Brushes::Black,X0,Y0);
        //枠を描く
        g->DrawRectangle(Pens::Black,X1,Y1,500,400);
        //枠内に縦線を引く
        for(i=1;i<10;i++)
            g->DrawLine(Pens::Gray,X1+i*50,Y1,X1+i*50,Y1+400);
        //枠内に横線を引く
        for(i=1;i<10;i++)
            g->DrawLine(Pens::Gray,X1,Y1+i*40,X1+500,Y1+i*40);
       //インピーダンス目盛を表示
        for(i=0;i<=10;i++){
            string1=String::Format("{0,5}kΩ",2000-i*400);
            g->DrawString(string1,Font,Brushes::Black,X2,Y2+i*40);
        }
        //周波数目盛を表示
        g->DrawString("199kHz",Font,Brushes::Black,X3,Y3);
        g->DrawString("200kHz",Font,Brushes::Black,X3+250,Y3);
        g->DrawString("201kHz",Font,Brushes::Black,X3+500,Y3);
 
        //グラフを描く
        z1.real(RESISTANCE);  //z1の実数部(R)
        z2.real(0.0);         //z2の実数部()
        for(i=0;i<500;i++){
            frequency=(1.99+i*0.00004)*1E+5;    //199kHz から201kHz まで4Hz 刻み
            omega=2*Math::PI*frequency;      //ω=2πf  
            z1.imag(omega*INDUCTANCE-1.0/(omega*CAPACITANCE_S));  //z1の虚数部(ωL-1/ωCs)
            z2.imag(-1.0/(omega*CAPACITANCE_P));          //z2の虚数部(-1/ωCp)
            z_xtal=z1*z2/(z1+z2);                  //z1とz2の並列
            if(i==0){
                old_x=X1;
                old_y=Y1+200-(int)(0.0001*z_xtal.imag()); 
            }
            else{
                x=X1+i;
                y=Y1+200-(int)(0.0001*z_xtal.imag());
                g->DrawLine(Pens::Red,old_x,old_y,x,y);
                old_x=x;
                old_y=y;
            }
        }

    }

得られた画面
 図2で、中央に垂直に伸びる線が、ちょうど200kHzとなっており、これが反共振周波数fa(並列共振周波数)である。また、その左で、曲線が0kΩをクロスするのが直列共振周波数fsである。これらは、下式によって求められ、結果が良く一致している。
      


図2 得られた画面


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