2006.11.17.
石立 喬

Visual C++ 2005 Express Edition の易しい使い方(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クラスのpointで表し、そのx軸成分はpoint->Xで、y成分はpoint->Yで表している。

スクロールバーの使い方
 フォームデザイナーの画面でツールバーを開き、HScrollBarとVScrollBarをクリックしてForm1上に貼り付ける。
 各スクロールバーの設定は、下表の通りにする。

機能 名称 Size Maximum Minimum Large-
Change
Small-
Change
RightToLeft
水平スクロールバー hScrollBar1 120,20 99 0 10   1 Yes
垂直スクロールバー vScrollBar1 20,120 99 0 10   1 (項目なし)

 それぞれのスクロールバーは、まず目見当で配置とサイズを決め、後に、ツールバーに座標を直接入力して細かく調整する。LargeChangeはスクロールバーの内部をクリックしたときの変化分、SmallChandeは両端の三角矢印をクリックしたときの変化分で、変更しないでデフォルトのまま使用する。
 MaximumとMinimumは、本来自由に決められるはずであるが、不具合が見られた。例えば、角度を-90°から0°まで変更するためにMinimumを-90、Maximumを9(実際は0であるが、つまみの幅を含めて9とする)とすると、ビルドとデバッグおよび実行は可能であったが、Form1.h[デザイン]がエラーで開けなくなった。負の数を設定するのはまずいのかもしれない。
 したがって、Minimumを0、Maximumを99(実際は90であるが、つまみの幅を含めて99とする)と設定し、デフォルトでNoになっているRightToLeftをYesに変更し、
   theta=-hScrollBar->Value;
のように、頭にマイナス符号をつけたら、正常に動作した。
 スクロールバーからの読み取りは、前述のように、
   phi=vScrollBar->Value;
で、スクロールバーの設定は、
   vSCrollBar->Value=phi;
などで行なう。

プログラムの概要
1) FETの静特性の計算は視角に関係なく、直接画面に表示する必要がないので、あらかじめ計算し、data[i,j]としてメモリに格納しておく。このようにしておくと、視角のパラメータを変換して画面を書き換えるたびに、静特性の計算をする必要がない。
  具体的には、プログラムの起動時に一度だけ呼び出されるForm1_Load()メソッドに、theta、phiの初期設定と共に、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.2Vおきにしたので、jは0から120までの61個の値をとる。
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を読み取る。


プログラム

private:
   array<double,2>^ data;
   double theta,phi;
   double sint,sinp,cost,cosp;

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

   double BETA=4.0,VTH=1.5;
   theta=-45.0;
   phi=60.0;
   hScrollBar1->Value=45;
   vScrollBar1->Value=60;

   data=gcnew array<double,2>(26,61);

   int i,j;
   double vd,vg,id;
   i=0;

   //FETの式を計算してdata[i,j]を作成する
   for(vg=0.0;vg<=5.0;vg+=0.2){
      j=0;
      for(vd=0.0;vd<=12.0;vd+=0.2){
         if(vg-VTH<=0) id=0;
         else if(vd>vg-VTH) id=BETA/2.0*(vg-VTH)*(vg-VTH);
         else id=BETA*((vg-VTH)*vd-0.5*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=350;
   int X1=30,Y1=40;
   Point^ point1=gcnew Point();
   Point^ point2=gcnew Point();
   Point^ point_old=gcnew Point();

   //三角関数の計算
   sint=Math::Sin(theta*Math::PI/180.0);
   sinp=Math::Sin(phi*Math::PI/180.0);
   cost=Math::Cos(theta*Math::PI/180.0);
   cosp=Math::Cos(phi*Math::PI/180.0);

   Graphics^ gr=e->Graphics;

   //座標軸を描く
   Pen^ pen1=gcnew Pen(Color::Black,2);
   point1=display3D(0,0,0);     //原点
   point2=display3D(200,0,0);    //x軸上のx=200
   gr->DrawLine(pen1,X0+point1->X,Y0-point1->Y,X0+point2->X,Y0-point2->Y);
   point2=display3D(0,240,0);    //y軸上のy=240
   gr->DrawLine(pen1,X0+point1->X,Y0-point1->Y,X0+point2->X,Y0-point2->Y);
   point2=display3D(0,0,240);    //z軸上のz=240
   gr->DrawLine(pen1,X0+point1->X,Y0-point1->Y,X0+point2->X,Y0-point2->Y);

   //オレンジ色で線を引く ---- Vg をパラメータにして Vd −Id 曲線を描く
   for(i=0;i<25;i++)
      for(j=0;j<60;j++){
         point1=display3D(8*i,4*j,10*data[i,j]);
         if(j==0) point_old=point1;
         else{
            gr->DrawLine(Pens::OrangeRed,X0+point_old->X,Y0-point_old->Y,X0+point1->X,Y0-point1->Y);
            point_old=point1;
         }
      }


   //緑色で線を引く ---- Vd をパラメータにして Vd − Id 曲線を描く
   for(j=0;j<60;j++)
      for(i=0;i<25;i++){
         point1=display3D(8*i,4*j,10*data[i,j]);
         if(i==0) point_old=point1;
         else{
            gr->DrawLine(Pens::LightGreen,X0+point_old->X,Y0-point_old->Y,X0+point1->X,Y0-point1->Y);
            point_old=point1;
         }
      }

   //データを表示する
   String^ string1=String::Format("theta={0}°, phi={1}°",theta,phi);
   System::Drawing::Font^ font1=gcnew System::Drawing::Font("MS ゴシック",12);
   gr->DrawString(string1,font1,Brushes::Black,X1,Y1);

}

//三次元グラフをパソコン画面上の二次元座標に変換するメソッド
private:Point^ display3D(double x,double y,double z){

   Point^ point=gcnew Point();
   point->X=(int)(-sint*x+cost*y);
   point->Y=(int)(-cost*cosp*x-sint*cosp*y+sinp*z);
   return point;

}

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=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 はすでに求めてあるので、それを代入すればよい。