DirectX EmptyProjectを使う その17 (AGCを考えましょう)



 step 1

     まず、振幅を一定にする事を、かんがえる。

     出力の振幅を一定にするには

     入力 input が変化するときに、ゲインを変化させて、出力を一定にします。

        gain= 0.35/input     (0.35の値は、サウンドカードのline outの出力で、歪んでいない値を、採用しました)

     に、してやれば、如何なる入力があっても、出力は、一定にできます。

        output = input * gain = input * 0.35 / input  = 0.35

  //AGC
  if(DATA->AGC)
  {
   DATA->peak_output=0.0f;

   //peak detect
   for(i=0;i<span;i++)
    {
     DATA->peak_output=max(DATA->peak_output,DATA->output[i]);
    }

   DATA->gain=0.35f/DATA->peak_output;
  }
  else
   DATA->gain=4.0f;
  
  //CW時
  if(cw)
   DATA->gain *=3.0f;



        
               input = 10dBu 
     
       input = 120dBu

     これだと、ノイズまでも、一定の振幅に、してしまいますから、うるさいですね。

   
<BR>     いや、案外使えるかも....

 
   step 2

     次は gainを一定の時間間隔だけ、hold するための、仕掛けです。

     これには、新しい変数 counterを用意します。

    

     これで、一定の時間間隔の間、gainが一定に保たれます。

     今の場合、counterが初期設定値、98の時だけ、gainが計算されて

     counterがゼロ以下になったら、新たに gainを設定し直します。

     時間間隔の計算なのですが

     私の場合、samplingは、 2048個のデータを一回で、取り込んでいます。

     ですので、

     96KHz samplingだと

      2048/96 = 21.3mS
     
           だけの、データを一回で、取り込んでいます。

     この sub routineを一回通り抜けると、21.3mSぶん のデータ ですので (プログラムが、計算に要する時間では、ありませぬ)

     カウンターを 10にすると、

      21.3 * 10 = 213mS

     ぶん だけのデータを通す事になると思うのです。

     これが、hold する時間になると、思います。

     先ほどのプログラムでは、カウンターを98にしていますから

      21.3 * 98 =2090mS

     なりますから、これは、hold timeとしては、大きい値ですね。
  
 step 3

     step 1 では、 ノイズまでも、一定の振幅のしようと、していました。

     これを、解決するには、geinが大きくなりすぎるのを、阻止するのです。

   

     //set gain upper limit と、書いてある所です。

     これだと、Sにして 6位でしょうか.....

     少し、静かになりました。
   
      

  step 4

     geinが、急激に 上がったり下がったりするのは、聞きづらいです。

     で、gein の上がり下がりに、ステップを付けます。

     そして、現在の所、最終段階は、以下のようになりました。

  //AGC
  if(DATA->AGC)
  {
    DATA->peak_output=0.0f;

    //peak detect
    for(i=0;i<span;i++)
      DATA->peak_output=max(DATA->peak_output,DATA->output[i]);


      if(DATA->count==DATA->hold_time || DATA->peak_output>DATA->prev_output)
      {
        DATA->count=DATA->hold_time ;
    
        DATA->diff=(DATA->peak_output-DATA->prev_output)/(float)DATA->attack_time;

        for(i=0;i<DATA->attack_time;i++)
        {
           if(DATA->prev_output!=0.0f && DATA->diff!=0.0f)
           {
              DATA->gain[i]=0.3f/(DATA->prev_output+DATA->diff*(float)i);

              //limit upper gain
              if(DATA->gain[i]>1.65f)
                 DATA->gain[i]=1.65f;
           }
          else
             DATA->gain[i]=1.0f;
        }

    for(i;i<Capture_Data_Length;i++)
     DATA->gain[i]=DATA->gain[DATA->attack_time-1];

    DATA->prev_output=DATA->peak_output;
    }

     DATA->count--;

     if(DATA->count<=0)
     {
       DATA->count=DATA->hold_time ;

       DATA->diff=(DATA->prev_output-DATA->peak_output)/(float)DATA->attack_time;
    
       for(i=0;i<DATA->attack_time;i++)
       {
          if(DATA->prev_output!=0.0f && DATA->diff!=0.0f)
          {
            DATA->gain[i]=0.3f/(DATA->prev_output+DATA->diff*(float)i);
            if(DATA->gain[i]>1.65f)
               DATA->gain[i]=1.65f;
          }
          else
            DATA->gain[i]=1.0f;

       }
    for(i;i<Capture_Data_Length;i++)
     DATA->gain[i]=DATA->gain[DATA->attack_time-1];

   }
 else
 {

 
    まだ、改良すべき点は、沢山ありますが、一応なんとか、それらしいものが.....

    SDR QEX vol.3 を参考にさせていただきました。御礼もうしあげます。

  H.19.11.7