2016年11月27日

DSPによるFFT処理

今回はSTM32でのDSPによるFFTについて紹介します。

環境はこれまで同様、
・STM32F303K8
 +SW4STM32(System Workbench for STM32)
 +STM32CubeMX(F3_1.6.0)
です。

プロジェクトのDSPライブラリ設定等はこちらを参照してください。



ちょっとしたFFT処理であれば、精度よりも速さ重視なことが多いため、
今回はあえてFloatでなくQ15でのFFTを紹介します。
q_15をf32に置き換えればFloatと同じように使えます。


FFT処理は使用するライブラリの関数によって
配列の渡し方や複素数の扱いが異なるため、
間違えて配列オーバーなどしてしまいがちです。
長さに注意しながらコーディングが必要です。


ARMのFFTコード例は下記の通りです。
一部抜粋です。


#define LENGTH_SAMPLES     256 //Num of Real & Img
#define ifftFlag         0
#define doBitReverse    1
#define fftSize            LENGTH_SAMPLES/2

#define FFTLen arm_cfft_sR_q15_len128


q15_t FFT_Input[LENGTH_SAMPLES];
q15_t FFT_Output[LENGTH_SAMPLES/2];

enum{ WAIT,RUN};
//実部と虚部で256個でAD変換値は実部のため、サイズは128
enum{ ADC_BUFFER_LENGTH = LENGTH_SAMPLES/2 };
//DMA転送でHalfWordにつき16bit長で定義
static uint16_t g_ADCBuffer[ADC_BUFFER_LENGTH];

//AD変換後に呼び出される
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
 
    HAL_TIM_Base_Stop_IT(&htim2);
    HAL_ADC_Stop_DMA(&hadc1);

    for(int i=0;i<LENGTH_SAMPLES/2;i++){
        int tmp;
        tmp= g_ADCBuffer[i];
        //dsPICのFFTは構造体で実部と虚部を格納するが、
        //ARMでは配列に実部と虚部を交互に格納する

        FFT_Input[2*i]=tmp;   //Real part
        FFT_Input[2*i+1]=0.0;   //Img part
    }
    fft_status=RUN;
}

int main(void)
{
 //~~初期化処理~~//

  while (1)
  {

     if(fft_status==RUN){

             arm_cfft_q15(&FFTLen, FFT_Input, ifftFlag, doBitReverse);
             arm_cmplx_mag_q15(FFT_Input, FFT_Output, fftSize);
             arm_max_q15(FFT_Output, fftSize, &maxValue, &testIndex);
        
        //サンプル数は実部と虚部で256個
        //fftsizeは128個
        //FFT_Outputには0~127でFFT結果が格納されるが、
        //64~127は対称の値が入っているだけ
        //実際に使うのはFFT_Outputの中で0~63のデータ
        for(int j=0;j<fftSize/2;j++){
                 printf("%d, ",FFT_Output[j]);
             }
                fft_status=WAIT;
             HAL_ADC_Start_DMA(&hadc1, g_ADCBuffer, ADC_BUFFER_LENGTH);
             HAL_TIM_Base_Start_IT(&htim2);
     }
     else{
             //なぜか何かしらの処理を入れないとwhileに入らないのでnopを入れる
             __asm volatile("nop");
     }
 }
}


N555で35kHz前後で発振させた信号を読み込むと
下記のように35kHz前後の結果となりました。

fftres.png



DMA転送で設定をHalf Wordにしているにも関わらず、
g_ADCBufferバッファ変数長さを32bitにしてしまい、
AD変換結果のバッファを破壊するというバグに気付かず、
意図したFFT結果を得るのに時間が掛かってしまいました...
HalfWordではuint16_t g_ADCBufferが正解です。


FFT処理をしているとSTM32F303K8では
RAMサイズが16kB(実質12kB)のため、
STM32F303CCなどの32kBや40kBの大容量なRAMが欲しくなります。
一方でRAMサイズが大きくなるとピン数が48ピンになるため、
扱いやピン配列が面倒になります...
32ピンでRAMサイズが大きなものが出てほしいなあと思う限りです。

posted by Crescent at 00:00| Comment(0) | TrackBack(0) | ナレッジ | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/444303025
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック