2010. 6. 2.
2014. 2.10.  System.Numerics への参照方法を追加
石立  喬

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

―――標準C++ライブラリのcomplexクラスを使用し、複素数計算の結果をグラフに表す―――

  Visual C++ 2010 Express を使って、電気技術者向きのプログラムを作ってみた。電気回路では、インピーダンスの計算などで面倒な複素数計算が必要になるので、複素数計算を簡単にするために、標準C++ライブラリのcomplexクラスを使用した。一例として、適当な値を持った抵抗、コイル、コンデンサの直列回路に交流信号を流したとき、コンデンサの両端の電圧を計算し、横軸を対数目盛の周波数に、縦軸をデシベルで表し、グラフ化する場合を紹介する。
 Visual C++ 2010は .NET Framework 4.0を使用していて、これにはComplex構造体が新たに導入されている。ただし、これを利用するには、System.Numerics.dllへの参照を追加する必要がある。方法については、末尾を参照されたい。

使用する電気回路と式
 図1のような、抵抗R、コイルL、コンデンサCの直列回路で、交流の入力電圧をこの直列回路に加えたとき、コンデンサの両端の電圧を出力電圧として求める。


図1 LCR直列回路


 出力電圧/入力電圧を伝達係数と考えて、それを求める式を下記に示す。結局、実数部が(1-ωLC)で虚数部がωCRの複素数で1を割れば良いことになる。このプログラムでは、分子と分母をそれぞれ複素数と考え、二つの複素数の割り算を行う。


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) で虚数部を設定することができる。
◎実数部、虚数部などのフィールドを取得する
   
zを複素数とすると、z.real() で実数部を、z.imag() で虚数部を取得することができる。
◎複素数間の演算
 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);
で求めることができる。

プログラムの概要

 グラフの座標の作成は、横軸に対数目盛を使用しているので、decade (10倍ごとの大きな目盛、インデックスはd)と、各 decade 内のlog101からlog1010まで(インデックスはf)とに分けて描画した。
 グラフの描画は、単に数式に忠実に従っただけであって、特別の解説は要らないと思う。複素数z_oneは定数として使用し、複素数zは、フィールドz_realとz_imagから設定した。比率 ratio は、complexクラスの除算で求めた。
 デシベル計算は、電圧比の場合、20*Math::Log10(ratio) で求めるが、描画の都合上、さらに5倍してある。

プログラム
◎Form1.hの頭に下記のように記述する
   #pragma once
   #include <complex>
   
using namespace std;

 標準C++関係には、図2のようにIntelliSenseが効くので、それを使用した。


図2 ヘッダー・リストから「complex」を選ぶ


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

      Graphics^ g=e->Graphics;

      int X0=50,Y0=30,Y1=180,Y2=380;
      int DECADE=6;
      int d,f,i;
      int x,y,old_x,old_y;

      array<String^>^ horiscale={" 1","10","100","1k","10k","100k","1M"};
      array<String^>^ vertscale={" 60dB"," 40dB"," 20dB"," 0dB","-20dB","-40dB","-60dB","-80dB"};

      double ratio_abs;
      double frequency,omega,resistance,inductance,capacitance;

      complex<double> z_one(1.0,0.0);   //定数1
      complex<double> z;
      complex<double> ratio;

      resistance=1.0;       //R=1Ω
      inductance=1.0E-3;     //L=1mH
      capacitance=1.0E-8;    //C=0.01uF

      //縦線を引く
      for(d=0;d<DECADE;d++)
         for(f=1;f<=10;f++)
            g->DrawLine(Pens::Black,X0+(int)((d+Math::Log10(f))*100),
                                 Y2,X0+(int)((d+Math::Log10(f))*100),Y0);
      //横線を引く
      for(i=0;i<8;i++)
         g->DrawLine(Pens::Black,X0,Y2-i*50,X0+DECADE*100,Y2-i*50);
      //横軸の目盛を入れる
      for(i=0;i<=DECADE;i++){
         if(i==DECADE)
            g->DrawString(horiscale[i]+" Hz",Font,Brushes::Black,40+i*100,Y2+10);
         else
            g->DrawString(horiscale[i],Font,Brushes::Black,40+i*100,Y2+10);
      }
      //縦軸の目盛を入れる
      for(i=0;i<8;i++)
         g->DrawString(vertscale[i],Font,Brushes::Black,5,Y0-8+i*50);

      //比率のグラフを描く
      for(d=0;d<DECADE;d++)
         for(f=10;f<100;f++){
            frequency=f/10.0*Math::Pow(10,d);
            omega=2.0*Math::PI*frequency;             //ω=2πf
            z_real=1.0-omega*omega*inductance*capacitance; //1-ω2LC
            z_imag=omega*capacitance*resistance;         //ωCR
            z.real(z_real);
            z.imag(z_imag);
            ratio=z_one/z;                        //1/((1-ω2LC)+jωCR)
            ratio_abs=abs(ratio);
            if(d==0 && f==10){
               old_x=X0;
               old_y=Y1-(int)(Math::Log10(ratio_abs)*50);
            }
            else{
               x=X0+(int)((d+Math::Log10(f/10.0))*100);
               y=Y1-(int)(Math::Log10(ratio_abs)*50);
               g->DrawLine(Pens::Red,old_x,old_y,x,y);
               old_x=x;
               old_y=y;
            }
      }

   }

得られた画面
 結果を図3に示す。共振周波数fは、
    
で計算でき、これは50.33kHzになるので、良く一致している。


図3 得られた周波数特性

System.Numerics.dll への参照を追加する方法
 1)ソリューションエクスプローラで、<プロジェクト名>を右クリックする。
 2)「追加」→「参照」を選択する。
 3)「参照マネージャ」ダイアログボックスが開くので、
 4)「System.Numerics」を選択し、左側のチェックボックスにチェックを入れる。
 5)「OK」をクリックする。

 プログラムに、using System.Numerics; を記述する。


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