2006.10.28.
石立 喬
Visual C++ 2005 Express Editionの易しい使い方(11)
--- C++標準のcomplexクラスを用いて水晶振動子の等価回路特性を描く---
「Visual C++ 2005 Express Editionの易しい使い方(10)」でComplexクラスを自作したが、本来C++に標準で付属しているcomplexクラスも、Visual C++ 2005で使用できる。ここでは、水晶振動子の電気的等価回路にcomplexクラスを応用して、周波数とリアクタンス成分の関係を示すグラフを描く。
具体的には、複素数で表された二つのインピーダンスの並列計算を行い、複素数インピーダンスの虚数部(リアクタンス成分)を求める。
水晶振動子の等価回路と計算式
水晶振動子が正確な発振周波数を決めることができるのは、水晶振動子が、特定の極めて狭い周波数範囲のみで大きなL性(インピーダンスの虚数部、すなわちリアクタンスが正)になるからである。水晶振動子がL性になると、それと組み合わせたコンデンサとの間で発振が可能になるので、その特定周波数のみで発振する。
下図のように等価回路を想定する。左側のLCR直列回路(z1で表す)は水晶の機械的特性を置き換えたもので、右側の並列容量(z2)は浮遊容量である。

したがって、z1およびz2は、下記の式で表される。

水晶振動子全体のインピーダンスは、z_xtal=z1*z2/(z1+z2) で求める。Rが非常に小さいので、z_xtalはほとんどリアクタンス成分のみであり、グラフにはリアクタンス成分のみを表示する。
C++標準のcomplexクラスの使い方
◎ヘッダ
#include <complex> を #pragma once
の下に記述する。
◎名前空間
C++ の標準ライブラリに含まれているので、using
namespace std; が必要である。
◎コンストラクタ
complex<double> z;
complex<double> z(real,imag);
などを使用する。
◎複素数の実数部、虚数部を設定する
zを複素数とすると、z.real(x) で実数部を、z.imag(y) で虚数部を設定することができる。
◎複素数間の演算
z1、z2、z3を複素数とすると、
z3=z1+z2;
z3=z1*z2;
z1/=z2; (z1=z1/z2 と同じ)
などが使える。
インピーダンスz1とインピーダンスz2を並列接続した時のインピーダンスは、
z3=1.0/(1.0/z1+1.0/z2);
を変形した、
z3=z1*z2/(z1+z2);
で求めることができる。
◎実数部、虚数部などのフィールドを取得する
zを複素数とすると、z.real() で実数部を、z.imag() で虚数部を取得することができる。
プログラムの概要
1)最上部に、等価回路の各定数を表示する。
2)座標(X1,Y1)はグラフ描画の基点を示すもので、これを基にしてグラフの升目の線を引き、データの表示を行なう。
3)z1とz2の実数部は、周波数に依存しないのでforループ外で設定する。z1とz2の並列インピーダンスz_xtal
の虚数部は、z_xtal.imag()によって求める。
4)プロット(計算点)は500個とし、それらを周波数の7.1MHzから7.2MHzの間に割り当てる。プロットがグラフの枠の外に出たときの処置はしていない。
プログラム
すべての本体プログラムを記述した Form1.h
の内容
#pragma once
#include <complex>
using namespace std; //complexクラスの使用に必要
private: System::Void Form1_Paint(System::Object^
sender,
System::Windows::Forms::PaintEventArgs^
e) {
Graphics^ gr=e->Graphics;
int X0=170,Y0=10; //各定数の表示位置
int X1=90,Y1=50; //グラフの位置
int X2=75,Y2=25; //周波数目盛の位置
int X3=10,Y3=45; //インピーダンス目盛の位置
double INDUCTANCE=1.0E-3;
double CAPACITANCE_S=0.5E-12;
double CAPACITANCE_P=50.0E-12;
double RESISTANCE=0.01;
int i;
int x,y,old_x,old_y;
complex<double> z1,z2,z_xtal;
double frequency,omega;
char buf[80];
String ^ string1;
System::Drawing::Font^ font1=gcnew System::Drawing::Font("MSゴシック",12);
//等価回路の各定数を表示
string1=String::Format("L={0}mH, Cs={1}pF, Cp={2}pF, R={3}Ω",
INDUCTANCE*1E+3,CAPACITANCE_S*1E+12,CAPACITANCE_P*1E+12,RESISTANCE);
gr->DrawString(string1,font1,Brushes::Black,X0,Y0);
//枠を描く
gr->DrawRectangle(Pens::Black,X1,Y1,500,400);
//枠内に縦線を引く
for(i=1;i<10;i++)
gr->DrawLine(Pens::Gray,X1+i*50,Y1,X1+i*50,Y1+400);
//枠内に横線を引く
for(i=1;i<10;i++)
gr->DrawLine(Pens::Gray,X1,Y1+i*40,X1+500,Y1+i*40);
//周波数目盛を表示
string1=String::Format("7.1MHz");
gr->DrawString(string1,font1,Brushes::Black,X2,Y2);
string1=String::Format("7.2MHz");
gr->DrawString(string1,font1,Brushes::Black,X2+500,Y2);
//インピーダンス目盛を表示
for(i=0;i<=10;i++){
sprintf_s(buf,80," %4dkΩ",200-i*40);
string1=gcnew String(buf);
gr->DrawString(string1,font1,Brushes::Black,X3,Y3+i*40);
}
//グラフを描く
z1.real(RESISTANCE); //z1の実数部(R)
z2.real(0.0); //z2の実数部()
for(i=0;i<500;i++){
frequency=(7.1+i*0.0002)*1E+6;
//7.1MHz から7.2MHz まで200Hz 刻み
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.001*z_xtal.imag());
}
else{
x=X1+i;
y=Y1+200-(int)(0.001*z_xtal.imag());
gr->DrawLine(Pens::Red,old_x,old_y,x,y);
old_x=x;
old_y=y;
}
}
}
得られた画面