(二):基二FFT

FFT:

(二):基二FFT_第1张图片

这里使用基二FFT算法,非基二FFT难度有点大,等以后补充。

对于非2的幂次方长度的序列,我们采用的是补零法:即:我们的FFT只能用于分析或者产生频谱,而不能求得某一特定点的DFT。

首先定义复数操作,实际上,复数操作的定义非常繁琐,这里我只定义了在本次应用中能用到的操作:

const double PI=3.1415926;
const double prec=0.00001;//控制精度
const char MARK='j';//复数的标志符,工程上喜欢使用j,数学上喜欢使用i
//下面是复数结构,主要定义了加减乘除操作符
template
class complex
{
public:

	T real;
	T imag;
public:
	complex(T a=T(),T b=T()):real(a),imag(b){ }
	//copy和copy assigment,析构函数可以使用编译器合成的
public:
	 inline complex conjugate()const;
	 inline T  module() const;
public:
	inline complex&  operator/=(int rhs);
};
template
complex operator+(const complex& lhs,const complex& rhs)
{
	return complex(lhs.real+rhs.real,lhs.imag+rhs.imag);
}
template
complex operator+(const int& lhs,const complex& rhs)
{
	return complex(lhs+rhs.real,rhs.imag);
}
template
complex operator+(const complex& lhs,const int& rhs)
{
	return complex(lhs.real+rhs,lhs.imag);
}
template
complex operator+(const double& lhs,const complex& rhs)
{
	return complex(lhs+rhs.real,rhs.imag);
}
template
complex operator+(const complex& lhs,const double& rhs)
{
	return complex(lhs.real+rhs,lhs.imag);
}
template
complex operator+(const T& lhs,const complex& rhs)
{
	return complex(lhs+rhs.real,rhs.imag);
}
template
complex operator+(const complex& lhs,const T& rhs)
{
	return complex(lhs.real+rhs,lhs.imag);
}
//---------------------------------------------------------------------------
template
complex operator-(const complex& lhs,const complex& rhs)
{
	return complex(lhs.real-rhs.real,lhs.imag-rhs.imag);
}
template
complex operator-(const int& lhs,const complex& rhs)
{
	return complex(lhs-rhs.real,-rhs.imag);
}
template
complex operator-(const complex& lhs,const int& rhs)
{
	return complex(lhs.real-rhs,lhs.imag);
}
template
complex operator-(const double& lhs,const complex& rhs)
{
	return complex(lhs-rhs.real,-rhs.imag);
}
template
complex operator-(const complex& lhs,const double& rhs)
{
	return complex(lhs.real-rhs,lhs.imag);
}
template
complex operator-(const T& lhs,const complex& rhs)
{
	return complex(lhs-rhs.real,-rhs.imag);
}
template
complex operator-(const complex& lhs,const T& rhs)
{
	return complex(lhs.real-rhs,lhs.imag);
}
//---------------------------------------------------------------------------
template
complex operator*(const complex& lhs,const complex& rhs)
{
	return 
		complex(lhs.real*rhs.real-lhs.imag*rhs.imag,lhs.real*rhs.imag+lhs.imag*rhs.real);
}
template
complex operator*(const int& lhs,const complex& rhs)
{
	return complex(lhs*rhs.real,lhs*rhs.imag);
}
template
complex operator*(const complex& lhs,const int& rhs)
{
	return complex(lhs.real*rhs,lhs.imag*rhs);
}
template
complex operator*(const double& lhs,const complex& rhs)
{
	return complex(lhs*rhs.real,lhs*rhs.imag);
}
template
complex operator*(const complex& lhs,const double& rhs)
{
	return complex(lhs.real*rhs,lhs.imag*rhs);
}
template
complex operator*(const T& lhs,const complex& rhs)
{
	return complex(lhs*rhs.real,lhs*rhs.imag);
}
template
complex operator*(const complex& lhs,const T& rhs)
{
	return complex(lhs.real*rhs,lhs.imag*rhs);
}
//--------------------------------------------------------------------------------
template
complex operator/(const complex& lhs,const complex& rhs)
{
	complex tmp=lhs*rhs.conjugate();
	double tmp2=rhs.module();
	return complex(tmp.real/tmp2,tmp.imag/tmp2);
}
template
complex operator/(const int& lhs,const complex& rhs)
{
	complex tmp=lhs*rhs.conjugate();
	double tmp2=rhs.module();
	return complex(tmp.real/tmp2,tmp.imag/tmp2);
}
template
complex operator/(const complex& lhs,const int& rhs)
{
	return complex(lhs.real/rhs,lhs.imag/rhs);
}
template
complex operator/(const double& lhs,const complex& rhs)
{
	complex tmp=lhs*rhs.conjugate();
	double tmp2=rhs.module();
	return complex(tmp.real/tmp2,tmp.imag/tmp2);
}
template
complex operator/(const complex& lhs,const double& rhs)
{
	return complex(lhs.real/rhs,lhs.imag/rhs);
}
template
complex operator/(const T& lhs,const complex& rhs)
{
	complex tmp=lhs*rhs.conjugate();
	double tmp2=rhs.module();
	return complex(tmp.real/tmp2,tmp.imag/tmp2);
}
template
complex operator/(const complex& lhs,const T& rhs)
{
	return complex(lhs.real/rhs,lhs.imag/rhs);
}
//---------------------------------------------------------------------------
template
inline bool operator==(const complex& lhs,const complex& rhs)
{
	return (lhs.real==rhs.real)&&(lhs.imag==rhs.imag);
}
template
inline bool operator!=(const complex& lhs,const complex& rhs)
{
	return !(lhs==rhs);
}
//------------------------------------------------------------------------------
template
std::ostream& operator<<(std::ostream& os,const complex& rhs)
{
	if(rhs.imag<0){
		os< inline complex complex::conjugate()const  {return complex(real,-imag);}
template inline T  complex::module() const{return ((*this)*(this->conjugate())).real;}
template inline complex&  complex::operator/=(int rhs){*this=(*this)/rhs;return(*this);}

然后是FFT程序用到的辅助程序:

//检查n是否是2的幂次方
bool is_2_pow(int n)
{
	if(n<=1){
		return false;
	}else{
		//若n为2^k,则二进制中,只有n的最高位为1,其余为0
		for(;(n&1)==0;n>>=1);
		if(n==1)return true;
		else return false;
	}
}
//采用补零法转化至2的幂次方
int padding(int n)
{
	if(n<=1){
		return 2;
	}else{
		int digits=(int)(log(n)/log(2))+1;
		return (1<<(digits));
	}
}


//对于长度为2^digitts的数组,求k的位逆序
int rev(int k,int digits)
{
	int result=0;
	for(int i=0;i

FFT的一般版,一般使用数组装序列:

//如果按位逆序输入数组,那么得到的是正确顺序的DFT
template
void bit_inverse_copy(T1* a,T2* A,int length)
{
	int digits=(int)(log(length)/log(2));
	for(int i=0;i
bool FFT(T1* a,T2* A,int length,bool inverse=false)//inverse为true表示傅里叶逆变换
{
	if(!is_2_pow(length)) return false;//长度不是2的幂次方
	int inver=-1;
	if(inverse)  inver=1;
	bit_inverse_copy(a,A,length);
	int digit=int(log(length)/log(2));//递归树的层数
	for(int s=1;s<=digit;++s){//外层循环,
		int m=(int)pow(2,s);//当s确定时,此时进行两个大小为m/2个数组进行蝶形操作
		//w=e^-2PIj/m时进行离散傅里叶变换,w=e^2PIj/m进行逆变换
		T2 w_m=T2(cos(2*PI*inver/m),sin(2*PI*inver/m));
		for(int k=0;k
bool RFFT(T1* a,complex* A,int length,bool inverse=false)
{
	int  inver=-1;
	if(inverse) inver=1;
	int half_length=length/2;
	complex* z=new complex[half_length];

	//x1(n)=a(2n),x2=a(2n+1),z(n)=x1(n)+jx2(n)
	for(int i=0,j=0;i* Z=new complex[half_length];
	FFT(z,Z,half_length);
	//此时有 X1(k)=1/2[Z(k)+Z*(N-k)],X2(k)=1/2j[Z(k)-Z*(N-k)];
	//其中Z*代表Z的共轭,N代表Z的长度,当k=0时,N-k=N=0
	complex w_2m=complex(cos(2*PI*inver/length),sin(2*PI*inver/length));
	complex w(1);
	complex X1_k,X2_k;//辅助变量
	complex unit_imag=complex(0,1);//大小为j
	//此时A[k]=X1[k]+W{k,2N}X2[k],A[k+N]=X1[k]-W{k,2N}X2[k]
	for(int k=0;k

这里有专门针对实数序列做FFT的函数:对于长度为2N的序列g,我们令:x1(n)=g(2n),x2(n)=g(2n+1),然后令 x(n)=x1(n)+jx2(n)

有X1(k)=1/2[X(k)+X*(N-k)],   X2(k)=1/(2j)[X(k)-X*(N-k)] (其中X*代表X的共轭),于是我们有:

G(k)=X1(k)+W{k,2N}X2(k), G(k+N)=X1(k)-W{k,2N}X2(k)


下面是迭代器版的FFT,可以使用容器装序列:

//如果按位逆序输入数组,那么得到的是正确顺序的DFT
template
void bit_inverse_copy(RandomIter1 _s_beg,RandomIter1 _s_end,RandomIter2 _d_beg,RandomIter2 _d_end)
{
	size_t length=_s_end-_s_beg;
	int digits=(int)(log(length)/log(2));
	for(int i=0;i
bool FFT(RandomIter1 _s_beg,RandomIter1 _s_end,RandomIter2 _d_beg,RandomIter2 _d_end,bool inverse=false)//inverse为true表示傅里叶逆变换
{
	typedef typename iterator_traits::value_type T2;

	int length=_s_end-_s_beg;
	if(!is_2_pow(length)) return false;//长度不是2的幂次方
	int inver=-1;
	if(inverse)  inver=1;
	bit_inverse_copy(_s_beg,_s_end,_d_beg,_d_end);
	int digit=int(log(length)/log(2));//递归树的层数
	for(int s=1;s<=digit;++s){//外层循环,
		int m=(int)pow(2,s);//当s确定时,此时进行两个大小为m/2个数组进行蝶形操作
		//w=e^-2PIj/m时进行离散傅里叶变换,w=e^2PIj/m进行逆变换
		T2 w_m=T2(cos(2*PI*inver/m),sin(2*PI*inver/m));
		for(int k=0;k
bool RFFT(RandomIter1 _s_beg,RandomIter1 _s_end,RandomIter2 _d_beg,RandomIter2 _d_end,bool inverse=false)
{
	typedef typename iterator_traits::value_type T2;
	int length=_s_end-_s_beg;

	int  inver=-1;
	if(inverse) inver=1;
	int half_length=length/2;
	T2* z=new T2[half_length];

	//x1(n)=a(2n),x2=a(2n+1),z(n)=x1(n)+jx2(n)
	for(int i=0,j=0;i

最后的使用测试程序如下:

int main()	
{
	ifstream in("E:\\file.txt");
	vector vc;
	float tmp;
	while(in>>tmp){
		vc.push_back(tmp);
	}
	in.close();

	int oldsize=vc.size();
	int newsize=0;
	if(!is_2_pow(vc.size())){
	 newsize=padding(oldsize);
	}else
		newsize=oldsize;

	for(int i=oldsize;i* h=new complex[newsize];
	RFFT(vc.begin(),vc.end(),h,h+newsize);
	ofstream out("E:\\file_fft.txt");
	out.precision(4);
	out<

当然,我们如果直接使用数组的话,完全可以使用非迭代器版本,看个人喜好。

你可能感兴趣的:(信号)