2010. 6.24.
石立 喬
Visual C++ 2010 Express の易しい使い方(13)
――― 三次元グラフィックの例題としてのFET静特性の表示 ―――
三次元グラフィックは、いろいろな関数を分かりやすく見せてくれる。ここでは、電子回路でおなじみのFET(電界効果トランジスタ)の静特性を表示することを例題にして、三次元グラフ(物体でも良い)を画面上に二次元で表示し、見る方向をスクロールバーで可変にする方法を述べる。三次元表示方法としては最も簡単な方法で、遠近効果を出したり、隠線処理をしたりするのは省略している。
FETの静特性は、Vd(ドレイン電圧)、Vg(ゲート電圧)を変数としてId(ドレイン電流)が求まるので、これをグラフで表すと三次元になる。
FET(電界効果トランジスタ)の静特性
FETの静特性は、比較的簡単なモデルでは、下記の通りである。ただし、ソース電圧を基準として、Vgはゲート電圧、Vdはドレイン電圧、Vthは閾(しきい)値電圧でトランジスタごとにほぼ一定の値、βは相互コンダクタンスで、大きいと多くの電流が流れる。



上記のように、FETの静特性はId=F(Vg,Vd)の関係があり、Vgをx軸に、Vdをy軸に、Idをz軸にとると、三次元のグラフで表示できる。教科書などに示されているのは、VdをパラメータにしたVg-Id曲線、VgをパラメータにしたVd-Id曲線などであり、全体像の把握が困難である。
三次元グラフをパソコン画面上に二次元座標で表す方法
図1に示すように、z軸からφの角度を持ち、x軸からθの角度を持つ無限遠の視点(無限遠とすると式が簡単になる)から三次元絶対座標(x,y,z)で示された座標上の一点を見た(投影した)とする。

図1 座標系と天頂角θと視角φの関係
そのときの二次元表示画面における座標をdisplay.xとdisplay.yとすると、下式の関係で表すことができる。一般に、θはマイナスの値をとる。

ただし、本文でで紹介するプログラムでは、パソコン画面上の二次元座標をPoint構造体のpoint1などで表し、そのx軸成分はpoint1.Xで、y成分はpoint1.Yなどで表している。
スクロールバーの使い方
「Form1.h[デザイン]」の画面で「ツールボックス」ウインドウを開き、「すべてのWindowsフォーム」欄から「HScrollBar」と「VScrollBar」をクリックしてForm1上に貼り付ける。
各スクロールバーの設定は、それぞれの「プロパティ」ウインドウで、下表の通りにする。「Size」は「配置」欄に、「RightToLeft」は「表示」欄に、その他は「動作」欄にある。「Maximum」から9(「LargeChange」が10のとき)を引いたものが採りうる実際の最大値となり、これは90°を意味する。
機能 |
名称 |
Size |
RightToLeft |
Maximum |
Minimum |
Large-
Change |
Small-
Change |
水平スクロールバー |
hScrollBar1 |
120,20 |
Yes |
99 |
0 |
10 |
1 |
垂直スクロールバー |
vScrollBar1 |
20,120 |
(項目なし) |
99 |
0 |
10 |
1 |
それぞれのスクロールバーは、まず目見当で配置とサイズを決め、後に細かく調整する。LargeChangeはスクロールバーの内部をクリックしたときの変化分、SmallChandeは両端の三角矢印をクリックしたときの変化分で、変更しないでデフォルトのまま使用する。
スクロールバーからの数値の読み取りは、
theta=-hScrollBar->Value;
phi=vScrollBar->Value;
スクロールバーの設定は、
hScrollBar->Value=theta;
vSCrollBar->Value=phi;
で行なう。
ラベルの設定方法
各スクロールバー周辺の文字は、ラベルを使用する。文字が上下二段になっているものは、各ラベルの「プロパティ」ウインドウで、「表示」欄の「Text」をクリックし、右に現れる下向きの矢印をクリックして、四角い入力領域に入力すれば良い。
プログラムの概要
1) FETの静特性の計算は視角に関係なく、直接画面に表示する必要がないので、あらかじめ計算し、data[i,j]としてメモリに格納しておく。これにより、視角のパラメータを変換して画面を書き換えるたびに、静特性の計算をする必要がなく、高速化できる。
具体的には、プログラムの起動時に一度だけ呼び出されるForm1_Load()メソッドで、data[i,j]の計算を行なう。data[i,j]は、Form1.hのグローバル変数として、あらかじめ宣言しておく。 メモリ内の配列をアクセスするので、VgやVdの値を直接使用できない。forループをiとjで回し、Vg=0.1*i;
Vd=0.1*j; などとしても良いが、ここでは、VgやVdを意識するためにforループをVgとVdで直接回し、その都度iとjをインクリメントした。Vgは0.0Vから5.0Vまでの0.2Vおきにしたので、iは0から50までの26個、Vdは0.0Vから12.0Vまでの0.4Vおきにしたので、jは0から30までの31個の値をとる。
2) Form1_Paint()では、
・theta、phiから、何回も使われるsinθ、cosθ、sinφ、cosφを計算して準備しておく
・三次元の座標軸と軸の名称を描く
・display3D()メソッドを呼び出し、data[i,j]により、FETの三次元グラフを描く
・使用したtheta、phiの値を表示する
を順次行なう。
3)三次元データをパソコン画面上の二次元座標に変換するdisplay3D()メソッドを記述する。
4)水平スクロールバーを動かしたときのハンドラ-(hScrollBar1_Scroll)でthetaを読み取る。
5)垂直スクロールバーのハンドラ-(vScrollBar_Scroll)でphiを読み取る。
プログラム
array<float,2>^ data;
int theta,phi;
float sint,sinp,cost,cosp;
static const float PI180=(float)Math::PI/180.0f;
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
{
float BETA=4.0f,VTH=1.5f;
theta=-45;
phi=60;
hScrollBar1->Value=45;
vScrollBar1->Value=60;
data=gcnew array<float,2>(26,31);
int i,j;
float vd,vg,id;
i=0;
for(vg=0.0f;vg<=5.0f;vg+=0.2f){
j=0;
for(vd=0.0f;vd<=12.0f;vd+=0.4f){
if(vg-VTH<=0) id=0.0f;
else if(vd>vg-VTH) id=BETA/2.0f*(vg-VTH)*(vg-VTH);
else id=BETA*((vg-VTH)*vd-0.5f*vd*vd);
data[i,j]=id;
j++;
}
i++;
}
}
private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^
e) {
int i,j;
int X0=40,Y0=320; //グラフの原点
int X1=30,Y1=20; //条件の表示位置
Point point1=Point();
Point point2=Point();
Point old_point=Point();
//三角関数の計算
sint=Math::Sin(theta*PI180);
sinp=Math::Sin(phi*PI180);
cost=Math::Cos(theta*PI180);
cosp=Math::Cos(phi*PI180);
Graphics^ g=e->Graphics;
//座標軸を描く
point1=display3D(0,0,0); //原点
point2=display3D(200,0,0); //X軸上のX=200
g->DrawLine(Pens::Black,X0+point1.X,Y0-point1.Y,X0+point2.X,Y0-point2.Y);
point2=display3D(0,240,0); //Y軸上のY=240
g->DrawLine(Pens::Black,X0+point1.X,Y0-point1.Y,X0+point2.X,Y0-point2.Y);
point2=display3D(0,0,250); //Z軸上のZ=250
g->DrawLine(Pens::Black,X0+point1.X,Y0-point1.Y,X0+point2.X,Y0-point2.Y);
//軸の名称を描く
point1=display3D(220,0,0);
g->DrawString("Vg",Font,Brushes::Black,X0+point1.X,Y0-point1.Y);
point1=display3D(0,260,0);
g->DrawString("Vd",Font,Brushes::Black,X0+point1.X,Y0-point1.Y);
point1=display3D(0,0,270);
g->DrawString("Id",Font,Brushes::Black,X0+point1.X,Y0-point1.Y);
//赤色でグラフを描く
for(i=0;i<=25;i++)
for(j=0;j<=30;j++){
point1=display3D(8*i,8*j,10*data[i,j]);
if(j==0) old_point=point1;
else{
g->DrawLine(Pens::Red,X0+old_point.X,Y0-old_point.Y,X0+point1.X,Y0-point1.Y);
old_point=point1;
}
}
//緑色でグラフを描く
for(j=0;j<=30;j++)
for(i=0;i=<25;i++){
point1=display3D(8*i,8*j,10*data[i,j]);
if(i==0) old_point=point1;
else{
g->DrawLine(Pens::Green,X0+old_point.X,Y0-old_point.Y,X0+point1.X,Y0-point1.Y);
old_point=point1;
}
}
//設定条件を表示する
String^ string1=String::Format("theta={0}, phi={1}",theta,phi);
g->DrawString(string1,Font,Brushes::Black,X1,Y1);
}
private:Point display3D(float x,float y,float z){
int xx=(int)(-sint*x+cost*y+0.5f);
int yy=(int)(-cost*cosp*x-sint*cosp*y+sinp*z+0.5f);
return Point(xx,yy);
}
private: System::Void hScrollBar1_Scroll(System::Object^ sender, System::Windows::Forms::ScrollEventArgs^
e) {
theta=-hScrollBar1->Value;
Invalidate();
}
private: System::Void vScrollBar1_Scroll(System::Object^ sender, System::Windows::Forms::ScrollEventArgs^
e) {
phi=90-vScrollBar1->Value;
Invalidate();
}
実行結果
プログラムを起動した直後の画面を図2に示す。目盛りが無いので、少しさびしいが、関心のある人は、追加して欲しい。θ(theta)やφ(phi)のデフォルト値は、三次元画面として比較的見やすい値に設定されている。陰線処理をすると、もっと見やすい画面になると思われる。
図2 プログラム実行直後の画面
スクロールバーを動かしてθ(theta)=-90°(y軸を原点側から見る)、φ(phi)=90°(水平に真横から見る)にすると、図3のように見慣れたVg―Id曲線が得られる。
図3 Vg―Id曲線
同様に、θ=0°(x軸と同じ方向から見る)、φ=90°(水平に真横から見る)に設定した場合を図4に示す。これも、よく見慣れたVd―Id曲線である。
図4 Vd―Id曲線
付録
ここでは、三次元の座標をパソコン画面上の二次元座標に変換する方法を、図を用いて解説する。
1)パソコン画面のx座標が display.x=-sinθ・x+cosθ・y
となることの説明 (図A参照)
この場合は、天頂角φを考える必要はない。また、zを考える必要もない。三次元座標(以後、原座標と呼ぶ)上のP点(x、y、z)を原座標のx、y平面に原座標のまま投影したパソコン画面上の位置をD点とする。D点の
x 軸方向成分を display.x とする。 -x・sinθは、視線が垂直に交わる投影平面への原座標の
x 成分の投影であり、視線より左側にあるので、マイナス符号を付けてある。一方、
y・cosθは、投影平面への原座標のy成分の投影である。D点の投影
display.x を求めるには、x 成分と y 成分の投影を線形的に加算した、display.x=-x・sinθ+y・cosθ
を用いれば良い。

2)パソコン画面のy座標が display.y=-cosθ・cosφ・x-sinθ・cosφ・y+sinφ・zとなることの説明 (図B、C参照)
display.yは、display.y=-cosφ(x・cosθ+y・sinθ)+z・sinφ
と書き換えることができる。この式で、括弧の中は、天頂角φやzを考えない、先ほどのD点の縦方向の距離(これをdとする)である。x・cosθは、その時の原座標のx成分の投影であり、y・sinθは
y成分の投影である。D点の距離 d は、それらを合計して求まるので、d=x・cosθ+y・sinθ
となる。(図B参照)
実際には、天頂角φを考え、かつzを考慮して投影平面への投影を考えると、原座標の
xy 平面に対しては -cosφ を乗じ、z軸に対しては
sinφを乗じて加算すればよいので、display.y=-cosθ・d+z・sinφの関係が得られる。(図C参照) d
はすでに求めてあるので、それを代入すればよい。

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