赞
踩
过年整理资料的时候,发现了之前导师介绍的,一个号称专门针对离散实序列的变换,经分析总运算量为普通FFT的几乎一半(O(nLog(n)),而且完全没有复数。这么强的吗?之前也是一知半解,于是花了一个上午,重新验证了以下,顺便在这里把这个东西稍微普及一下,不知大家是否能用得上...
预备知识
1. DFT的意义
2. FFT实现
3. C语言编程
原理部分可以参考西电的《数字信号处理》,或者参考https://www.cnblogs.com/RRRR-wys/p/10090007.html
- Adc=2; %直流分量幅度
- A1=5; %频率F1信号的幅度
- A2=1.5; %频率F2信号的幅度
- F1=50; %信号1频率(Hz)
- F2=75; %信号2频率(Hz)
- Fs=256; %采样频率(Hz)
- P1=-30; %信号1相位(度)
- P2=90; %信号相位(度)
- N=256; %采样点数
- t=[0:1/Fs:N/Fs]; %采样时刻
- %信号
- S=Adc+A1*cos(2*pi*F1*t+pi*P1/180)+A2*cos(2*pi*F2*t+pi*P2/180) + 0.2 * rand();
根据采样定理,假设采样频率Fs,则要求原采样信号的最高频率小于Fs/2,否则傅里叶变换后的信号会出现频谱叠加的现象,实际操作时,由于采样精度和噪声的因素,采样得到的离散信号还会包含了高频信号(大于Fs/2),所以需要用加窗滤波的方式去除,否则计算后的数据不准确,这里略过。
原理参考《数字信号处理》,主要是体现为以下规律
N点数据处理后,结果还是N点(N=2^n),需要进行一下处理可得到原信号的频率和幅度信息
x(i) = x(i) / N; i∈(0 ~N-1)
y(i) = x(i) ^2 + x(N - i)^2; i∈(0 ~N/2)
y(i) = y(i) * 2; i∈(1 ~N/2)
y(i) = sqrt(y(i)); i∈(0 ~N/2)
即得到 0Hz - Fs / 2 对应的幅度
每个点对应频率 f(i) = i * Fs / N ; (i ∈ 0 - N/2)
对应的幅度 y(i) = y(i); (i ∈ 0 - N/2)
- /*
- HFT验证
- Auther:Terry
- Date: 2020.1.30
- */
- #include "stdio.h"
- #include "math.h"
-
- #define pi 3.1416
- #define N 256
-
- void daoxu(float * datas, int n);
- void fht(float *Data,int Log2N);
- void fftchange(float *f,float*p);
-
- /*matlab生成的模拟采样数据 Fs = 256 N = 256*/
- float mm[256] = {
- 6.4659,4.5027,1.1457,-1.8293,-0.7943,5.7235,7.8800,0.6097,-4.0687,0.9870,
- 6.1950,5.2453,1.9558,-1.2726,-1.6702,4.0584,8.3512,2.7280,-3.9023,-0.7336,
- 5.5067,5.8766,2.7658,-0.5706,-2.1237,2.3254,8.1404,4.7758,-3.0589,-2.2715,
- 4.4053,6.3156,3.5751,0.2061,-2.1793,0.7180,7.3058,6.5113,-1.6160,-3.4260,
- 2.9543,6.4730,4.3728,1.0107,-1.9020,-0.6085,5.9799,7.7358,0.2676,-4.0300,
- 1.2770,6.2685,5.1273,1.8208,-1.3777,-1.5535,4.3462,8.3204,2.3729,-3.9779,
- -0.4539,5.6509,5.7824,2.6308,-0.6944,-2.0770,2.6104,8.2214,4.4500,-3.2442,
- -2.0367,4.6156,6.2596,3.4405,0.0738,-2.1953,0.9700,7.4834,6.2529,-1.8923,
- -3.2679,3.2159,6.4700,4.2416,0.8759,-1.9678,-0.4120,6.2276,7.5737,-0.0682,
- -3.9730,1.5654,6.3304,5.0067,1.6857,-1.4784,-1.4249,4.6312,8.2703,2.0171,
- -4.0343,-0.1701,5.7834,5.6832,2.4957,-0.8159,-2.0189,2.8981,8.2846,4.1166,
- -3.4123,-1.7920,4.8157,6.1962,3.3057,-0.0577,-2.2016,1.2293,7.6465,5.9810,
- -2.1553,-3.0951,3.4703,6.4572,4.1096,0.7412,-2.0263,-0.2050,6.4659,7.3940,
- -0.3967,-3.8979,1.8514,6.3808,4.8836,1.5507,-1.5743,-1.2846,4.9124,8.2011,
- 1.6617,-4.0716,0.1169,5.9041,5.5796,2.3607,-0.9348,-1.9493,3.1877,8.3294,
- 3.7765,-3.5624,-1.5384,5.0051,6.1257,3.1708,-0.1880,-2.1979,1.4952,7.7943,
- 5.6964,-2.4042,-2.9083,3.7171,6.4350,3.9768,0.6068,-2.0771,0.0119,6.6937,
- 7.1974,-0.7167,-3.8051,2.1341,6.4201,4.7584,1.4157,-1.6650,-1.1326,5.1888,
- 8.1129,1.3079,-4.0896,0.4060,6.0129,5.4718,2.2257,-1.0508,-1.8681,3.4782,
- 8.3556,3.4309,-3.6944,-1.2768,5.1836,6.0487,3.0358,-0.3171,-2.1839,1.7670,
- 7.9263,5.4000,-2.6382,-2.7082,3.9555,6.4037,3.8433,0.4728,-2.1199,0.2384,
- 6.9102,6.9843,-1.0273,-3.6952,2.4127,6.4483,4.6313,1.2806,-1.7501,-0.9691,
- 5.4595,8.0057,0.9568,-4.0886,0.6964,6.1099,5.3602,2.0908,-1.1635,-1.7751,
- 3.7687,8.3629,3.0810,-3.8078,-1.0082,5.3509,5.9655,2.9008,-0.4447,-2.1592,
- 2.0440,8.0419,5.0928,-2.8567,-2.4956,4.1851,6.3638,3.7094,0.3391,-2.1540,
- 0.4740,7.1145,6.7554,-1.3274,-3.5686,2.6863
- };
-
- float fdata[N/2 + 1];
- int main(void)
- {
- int i;
-
- daoxu(mm,256);
- fht(mm,8);
- fftchange(fdata,mm);
-
- for(i = 0; i < N/2;i++)
- {
- if(i % 10 == 0)
- printf("\n");
- printf("%.3f ",fdata[i]);
- }
-
- getchar();
- return 0;
- }
-
-
- /*=====================================================================
- 倒序计算 datas 为数据 n 为 长度
- ================================================================*/
- void daoxu(float * datas, int n)
- {
- int nv2 = n / 2;
- int nm1 = n-1;
- int j = 0, i = 0, k;
- float t;
- do
- {
- if(i < j)
- {
- t = datas[i];
- datas[i] = datas[j];
- datas[j] = t;
- }
- k = nv2;
- while(k <= j)
- {
- j = j - k;
- k = k / 2;
- }
-
- j = j + k;
- i = i + 1;
- }while(i < nm1);
- }
- /*哈特莱变换后数据处理,用来计算每个频率的幅度曲线*/
- void fftchange(float *f,float*p)
- {
- int i;
- for( i = 0;i < N; i++)
- p[i] = p[i] / N ;
- for( i = 0 ; i < (N/2) ; i++)
- {
- printf("\t%.3f,\t%.3f\n",p[i],p[N-i]);
- f[i] = p[i] * p[i] + p[N-i] *p[N-i];
- if(i > 0)
- f[i] = f[i] * 2 ;
-
- f[i] = sqrt(f[i]); /*数据开方,可得到每个频率点对应的幅度*/
- }
- }
-
- /*===========================================================
- 哈特莱变换 data 为滤波后的数据 Log2N为阶数
- =============================================================*/
- void fht(float *Data,int Log2N)
- {
- int length,i,j,k,step,i0,i1,i2,i3;
- float ck,sk,temp,temp0,temp1,temp2,temp3;
-
- length = 1<<Log2N;
- for(i = 0; i < length; i += 2)
- {
- temp = Data[i];
- Data[i] = temp + Data[i+1];
- Data[i+1] = temp - Data[i+1];
- }
-
- for(i = 2; i <= Log2N; i++)
- {
- step = 1 << i;
-
- for(k = 0; k < length/step; k++)
- {
- i0=k * step;
- i1 = k * step + step/2;
- i2 = k * step + step/4;
- i3=k*step+step*3/4;
-
- temp0 = Data[i0] + Data[i1];
- temp1 = Data[i0] - Data[i1];
- temp2 = Data[i2] + Data[i3];
- temp3 = Data[i2] - Data[i3];
- Data[i0] = temp0;
- Data[i1] = temp1;
- Data[i2] = temp2;
- Data[i3] = temp3;
- }
- for(j = 1; j < step/4; j++)
- {
- ck = cos(2.0 * pi * j/step);
- sk = sin(2.0 * pi * j/step);
- for(k = 0;k < length/step;k++)
- {
- i0=k*step+j;i1=k*step+step/2+j;i2=k*step+step/2-j;i3=k*step+step-j;
- temp0 = Data[i0]+ck*Data[i1]+sk*Data[i3];
- temp1 = Data[i0]-ck*Data[i1]-sk*Data[i3];
- temp2 = Data[i2]+sk*Data[i1]-ck*Data[i3];
- temp3 = Data[i2]-sk*Data[i1]+ck*Data[i3];
- Data[i0] = temp0;
- Data[i1] = temp1;
- Data[i2] = temp2;
- Data[i3] = temp3;
- }
- }
- }
- }
-
计算后的数据
Matlab FFT计算结果来检查HFT的计算数据
- Ayy =
-
- 1 至 10 列
-
- 2.1357 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 11 至 20 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 21 至 30 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 31 至 40 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 41 至 50 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 51 至 60 列
-
- 5.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 61 至 70 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 71 至 80 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 1.5000 0.0000 0.0000 0.0000 0.0000
-
- 81 至 90 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 91 至 100 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 101 至 110 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 111 至 120 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 121 至 130 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 131 至 140 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 141 至 150 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
-
- 151 至 156 列
-
- 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000
C语言计算数据
绘制曲线
原信号:
Adc=2; %直流分量幅度 加 rand(0,0.2)的随机噪声
A1=5; %频率F1信号的幅度
A2=1.5; %频率F2信号的幅度
HFT变换得到的数据
直流分量 2.136,且近似等于Matlab的计算值2.1357
F1 的幅度 为 5,等于 A1 和 FFT计算数据
F2 的幅度 为 1.5,等于 A2 和 FFT计算数据
由此可见,HTF计算结果和FFT计算结果一致,且准确反映了原信号的特征,计算正确。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。