<FFTのひとつの例>
AD変換して求めた入力信号の周波数特性を求めるため、2のn乗のポイント数を計算する高速フーリエ変換をC++で記述したサンプルプログラムを参考に下
記に示す。
FFTを計算するにあたり、ハ二ングの窓を掛けて、滑らかに両端の値をゼロにして、入力信号を見かけ上有限の長さに押し込めている。
このサンプルを実際に動作させるためには、おそらく、
ご使用されるプログラミング環境に合わせて修正・変更・追加などが必要です。
万一、このサンプルを動作させる場合は、あなたの責任においておこなってください。
#include <math.h>
//--------------------------------------------------------
TCFFT::TCFFT(int nzyou)
// データのポイント数が2のnzyou乗である
// FFTを計算するたの準備を行う。
//
// nzyou=8の時は 計算するポイント数は 256
// nzyou=9 512
// nzyou=10 1024
// nzyou=11 2048
{
value_nzyou= nzyou;
// データのポイント数をvalue_pointsに格納する。
value_points=f_zyou(value_nzyou);
// 準備1
// 繰り返して使用するものを、
// あらかじめ、計算して値を求めておく。
f_mkdat();
f_bitrev();
// 準備2 窓の準備。窓はFFTで必修ではないが、実用上、使用する。
f_set_hanig();
// 作業領域を確保
works=(double *)malloc(sizeof(double) * value_points
* 2);
datas=(double *)malloc(sizeof(double) * value_points
* 2);
}
//--------------------------------------------------------
void TCFFT::f_fft()
{
// 入出力は共通で下記のような複素数とする。
// data[2*i ] 実数部
// data[2*i+1] 虚数部 *実数の場合はゼロを設定する。
// iは、0,1,...,value_points-1 の整数である。
int n,nh,i,i1,i2;
double *ws;
// ポイント数
nh=value_points;
// sin,cos のテーブルをセット
ws=mk;
// 計算
for(i1=0;i1<value_nzyou;++i1)
{
nh= nh/2;
n= f_zyou(i1);
for(i2=0;i2<n;++i2)
{
f_fftsub(nh,2*nh*i2,n,datas,ws);
}
}
// 入れ替え
for(i=0;i<value_points;++i)
{
i1= table[i];
works[2*i1] = datas[2*i];
works[2*i1+1]= datas[2*i+1];
}
for(i=0;i<value_points;++i)
{
datas[2*i]=works[2*i];
datas[2*i+1]=works[2*i+1];
}
}
//--------------------------------------------------------
int TCFFT::f_zyou( int nzyou)
// 2のn乗を出力する
{
return( 1 << nzyou);
}
//---------------------------------------------------------
void TCFFT::f_mkdat( )
// sin,cosの値 を事前に計算しておく
{
int i;
double x;
double *p;
mk = (double *)malloc( sizeof(double) * value_points *2 );
p=mk;
for(i=0;i<value_points;++i)
{
x= M_PI * 2.0 *(double)i /
(double)value_points;
*p= cos(x);
++p;
*p= -sin(x);
++p;
}
}
//---------------------------------------------------------
void TCFFT::f_bitrev()
// bit-reversed ビット リバースド 入れ替え順番の設定
{
int i,j,x1,x;
int out;
int *p;
table=(int *)malloc( sizeof(int) * value_points);
p=table;
for(i=0;i<value_points;++i)
{
out=0;
x1=i;
for(j=value_nzyou;j>0;--j)
{
x = x1 & 0x0001;
out = out + x*f_zyou(j-1);
x1>>=1;
}
*p=out;
++p;
}
}
//---------------------------------------------------------
void TCFFT::f_multc( double *x, double *ws, double *z)
// 複素数の掛け算
{
z[0] = x[0] * ws[0] - x[1] * ws[1];
z[1] = x[0] * ws[1] + x[1] * ws[0];
}
//---------------------------------------------------------
void TCFFT::f_fftsub(int nh, int offset,int nstep, double datas[],
double ws[])
// 小さい分割部分の計算
{
double a[4];
int i;
int x1,y1;
int x2,y2;
for(i=0;i<nh;++i)
{
x1=2*(i+offset);
y1=x1+1;
x2=2*(i+nh+offset);
y2=x2+1;
a[0]= datas[x1];
a[1]= datas[y1];
datas[x1] = a[0] + datas[x2];
datas[y1]= a[1] + datas[y2];
a[0]= a[0] - datas[x2];
a[1]= a[1] - datas[y2];
f_multc( a, (ws+2*i*nstep), (datas +
x2));
}
}
//--------------------------------------------------------
//
// 以下は、AD変換して求めた入力信号のデータに窓を掛けて
// 値を複素数に拡張する。FFTを求める前の準備用。
//
//--------------------------------------------------------
void TCFFT::f_dohan(short *wave, int mode)
// 入力信号の16ビット整数データ(wave)にハニングの窓を掛けて、
// 複素数(datas)に変換する。
//
// mode が HANNING 時はハニングの窓を掛ける。
// mode が HANNING 以外ならば、窓を掛けない。
{
int i;
for(i=0;i<value_points;++i)
{
if( mode == HANNING)
{
datas[2*i] = (double)wave[i]
* hng_data[i]; // 実数部
}
else
{
datas[2*i] = (double)wave[i];
}
datas[2*i+1] =
0.0;
// 虚数部
}
}
//--------------------------------------------------------
void TCFFT::f_set_hanig()
// ハニングの窓を計算する
{
int i,z;
double y,y2;
double *p;
hng_data=(double *)malloc( sizeof(double) *
value_points);
p=hng_data;
y2=(double)value_points;
for(i=0;i<value_points;++i)
{
y = (double)i/y2 ;
y = y * 2.0 * M_PI;
*p= 0.5 - 0.5 * cos(y);
++p;
}
}
//--------------------------------------------------------
double *TCFFT::return_datas_pointer()
{
return( datas);
}
//--------------------------------------------------------
int TCFFT::return_value_points()
{
return(value_points);
}
//--------------------------------------------------------
TCFFT::~TCFFT()
{
free(mk);
free(table);
free(hng_data);
free(works);
free(datas);
}
//--------------------------------------------------------
//
//
//--------------------------------------------------------
#define HANNING 1
class TCFFT
{
public:
void f_dohan(short *wave,
int mode);
void f_fft();
// クラスTCFFTの内部の値を返す関数
//
FFTの計算結果が格納されるdatasを返す。
double
*return_datas_pointer();
//
FFT計算のためのデータポイント数を返す。
int return_value_points();
double *datas;
TCFFT(int nzyou);
virtual ~TCFFT();
private:
int f_zyou(int nzyou);
void f_multc( double *x,
double *ws, double *z);
void f_fftsub(int nh, int
offset,int nstep, double datas[], double ws[]);
void f_mkdat();
void f_bitrev();
void f_set_hanig();
double *mk;
int *table;
double *hng_data;
double *works;
int
value_nzyou;
int
value_points;
};
No.2c 2006年1月12日