快速傅里葉變換

多項式乘法

理解傅里葉變換首先要從多項式乘法開始。

多項式的係數表示和點值表示

多項式的係數表示

存在多項式

則稱式(2)爲多項式(1)的係數表示法,係數表示法下多項式乘法的算法複雜度爲O(n2)。

 

多項式的點值表示

任意一個n階多項式函數可由n+1個點來確定。

點值表示法下多項式乘法的算法複雜度爲O(n)

係數表示轉化爲離散的點”稱爲離散傅里葉變換

離散的點”還原爲”係數”表示法稱爲離散傅里葉反變換。

如何求一個多項式的點值表示?

帶入n+1個x,分別求的f(x),求一次f(x)的時間複雜度爲O(n),所以總的時間複雜度爲O(n2).

利用複數的性質,可以簡化計算。

複數

複數w滿足wn=1,則稱w是n次單位根。W的n次單位根有n個。

W的8次單位根和4次單位根。

複數的單位根存在如下性質:

複數使用結構體表示

typedef struct {
	double real;
	double img;
}complex;

FFT離散傅里葉變換

將係數表示法轉化爲點值表示法稱爲離散傅里葉變換,核心是需要找到n+1個點來表示n階多項式函數。

多項式分解爲奇偶次數項

至此,已經可以通過第一輪蝴蝶變換求得所有的f(x),且要帶入的值減少了一半。

void initW(complex *W, int n)
{
	int i; 
	for (i = 0; i<n; i++)
	{
		W[i].real = cos(2 * PI / n*i);  
		W[i].img = -1 * sin(2 * PI / n*i);
	}
}

 

也就是說,每一層對於一個確定的m,用對應的兩個值可以更新出當前的值。這個操作稱爲蝴蝶變換

遞歸調用樹

如果自底向上觀察這顆樹,將初始向量按照葉子的位置預先重排好的話,就可以實現自底向上一步步合併結果。

觀察重排的規律,發現重排之後序列的下標爲序列下標二進制數的翻轉

void bit_reverse(int n, complex *x)
{
	complex t;
	for (int i = 0, j = 0; i != n; ++i)
	{
		if (i > j) {
			t = x[i];
			x[i] = x[j];
			x[j] = t;
		}
		for (int l = n >> 1; (j ^= l) < l; l >>= 1);
	}
}

在用代碼實現的過程中,輸入和輸出都可以理解爲長度爲n的數組,n爲2的p次方,不夠的使用0補,所以需要將數據轉化到複數域,FFT變換結束後再轉換到實數域。

在用代碼實現的過程中,輸入和輸出都可以理解爲長度爲n的數組,n爲2的p次方,不夠的使用0補,所以需要將數據轉化到複數域,FFT變換結束後再轉換到實數域。

void fft(float *input, unsigned int n)
{
	int i = 0, j = 0, k = 0, l = 0;
	complex up, down, product;
	complex *data = malloc(sizeof(complex) * n);

	for (j = 0; j < n; j++)
	{
		data[j].real = input[j];
		data[j].img = 0;
	}

	bit_reverse(n, data);

	for (i = 0; i< log(n) / log(2); i++)
	{
		l = 1 << i;
		for (j = 0; j<n; j += 2 * l)
		{
			for (k = 0; k<l; k++)
			{
				product.real = data[j + k + l].real * W[n*k / 2 / l].real
					- data[j + k + l].img * W[n*k / 2 / l].img;
				product.img = data[j + k + l].real * W[n*k / 2 / l].img
					+ data[j + k + l].img * W[n*k / 2 / l].real;

				up.real = data[j + k].real + product.real;
				up.img = data[j + k].img + product.img;
				down.real = data[j + k].real - product.real;
				down.img = data[j + k].img - product.img;

				data[j + k] = up;
				data[j + k + l] = down;
			}
		}
	}

	for (j = 0; j < n; j++)
	{
		input[j] = sqrt(data[j].real * data[j].real + data[j].img * data[j].img);
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章