離散哈特萊變換(DHT)
摘 要
離散哈特萊變換(DHT)是一種與傅里葉變換相關的轉換。類似於離散傅里葉變換。與傅里葉變換在信號處理及其他相關領域有相似的應用。
本設計介紹了DHT的定義以及使用C語言實現其算法。
關鍵字:傅里葉變換 哈特萊變換
二、設計平臺
Linux平臺、GCC編譯器、VIM、windows、Visual Studio 2017
三、設計原理
DHT的定義
設x(n),n=0,1,…,N−1x(n),n=0,1,…,N−1,爲一實序列,其DHT定義爲:
式中cas(a)=cos(a)+sin(a)cas(a)=cos(a)+sin(a)逆變換(IDHT)爲:
DHT的正交證明:
DHT和DFT關係
用X(k)表示實序列x(n)的,用XH(k)表示x(n)的DHT,分別用XHe(k), XHo(k)表示XH(k)的偶對稱分量與奇對稱分量,即:
其中:
DHT的優點
DHT爲實值,避免了複數運算
DHT正反變換形式基本一致
DHT與DFT的轉換容易實現
DHT的性質
DHT的性質與DFT的性質類似,但由於DHT是實序列間的變換,有些性質有具體的表達形式。這裏只給出結論。
設x(n)、y(n)的DHT分別爲Xh(k)、Yh(k)。用符號x(n)↔Xh(k)表示Xh(k)=DHT(x(n))。
1.線性性
2.逆序列x(N-n)的DHT
且
當k=0時,可得Xh(N)=Xh(0)。
3.循環位移的性質
四、實現代碼
【C語言】
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
const int N = 1024;
const float PI = 3.1416;
inline void swap(float &a, float &b)
{
float t;
t = a;
a = b;
b = t;
}
void bitrp(float xreal[], float ximag[], int n)
{
// 位反轉置換 Bit-reversal Permutation
int i, j, a, b, p;
for (i = 1, p = 0; i < n; i *= 2)
{
p++;
}
for (i = 0; i < n; i++)
{
a = i;
b = 0;
for (j = 0; j < p; j++)
{
b = (b << 1) + (a & 1); // b = b * 2 + a % 2;
a >>= 1; // a = a / 2;
}
if (b > i)
{
swap(xreal[i], xreal[b]);
swap(ximag[i], ximag[b]);
}
}
}
void FFT(float xreal[], float ximag[], int n)
{
// 快速傅立葉變換,將複數 x 變換後仍保存在 x 中,xreal, ximag 分 // 別是 x 的實部和虛部
float wreal[N / 2], wimag[N / 2], treal, timag, ureal, uimag, arg;
int m, k, j, t, index1, index2;
bitrp(xreal, ximag, n);
// 計算 1 的前 n / 2 個 n 次方根的共軛複數 W'j = wreal [j] + i * wimag [j] , j = 0, 1, ... , n / 2 - 1
arg = -2 * PI / n;
treal = cos(arg);
timag = sin(arg);
wreal[0] = 1.0;
wimag[0] = 0.0;
for (j = 1; j < n / 2; j++)
{
wreal[j] = wreal[j - 1] * treal - wimag[j - 1] * timag;
wimag[j] = wreal[j - 1] * timag + wimag[j - 1] * treal;
}
for (m = 2; m <= n; m *= 2)
{
for (k = 0; k < n; k += m)
{
for (j = 0; j < m / 2; j++)
{
index1 = k + j;
index2 = index1 + m / 2;
t = n * j / m; // 旋轉因子 w 的實部在 wreal [] 中 //的下標爲 t
treal = wreal[t] * xreal[index2] - wimag[t] * ximag[index2];
timag = wreal[t] * ximag[index2] + wimag[t] * xreal[index2];
ureal = xreal[index1];
uimag = ximag[index1];
xreal[index1] = ureal + treal;
ximag[index1] = uimag + timag;
xreal[index2] = ureal - treal;
ximag[index2] = uimag - timag;
}
}
}
}
void FFT_test()
{
float xreal[N] = {}, ximag[N] = {};
int n = 8;
int i = 0;
printf("請輸入數據,格式(實部 虛部) : \n");
for (i = 0; i < 8; i++)
{
scanf("%f%f",xreal+i,ximag+i);
}
n = i; // 要求 n 爲 2 的整數冪
while (i > 1)
{
if (i % 2)
{
printf("%d is not a power of 2! ", n);
}
i /= 2;
}
FFT(xreal, ximag, n);
printf("=====================================\n");
printf("FFT: i 實部 虛部 \n");
for (i = 0; i < n; i++)
{
printf(" %4d %8.4f %8.4f ", i+1, xreal[i], ximag[i]);
printf("\n");
}
printf("===================================== \n");
printf("DHT: i 結果 \n");
for (i = 0; i < n; i++)
{
printf(" %4d %8.4f ", i+1, xreal[i]-ximag[i]);
printf("\n");
}
printf("=====================================\n ");
}
int main()
{
FFT_test();
system("pause");
return 0;
}