• FFT专题:IFFT后信号如何重建


    1. ifft(outFFTData, g_fft_temp, inFFTData, g_twiddle_ifft, twiddle_stride, F_WLEN);
    2. //思考ifft输出的复数结果怎么给到硬件输出

    之前一直关注FFT后信号奔赴到频域处理,那么频域处理完后,怎么重建信号呢?

    给出一段FFT和IFFT函数源码

    1. int nFrameRunCount = 0;
    2. #pragma section("ss_fw_code_fast")
    3. void ToneChip_TestFFT_Process(float *Din, float *Dout, int nLen)
    4. {
    5. float freqResol; //频点间隔,单位:Hz
    6. int i = 0;
    7. int j = 0;
    8. int k = 0;
    9. float *pDataIn = (float *)Din;
    10. float *pDataOut = (float *)Dout;
    11. int nDataInLen = nLen;
    12. int twiddle_stride = 1;
    13. float amp = 0.0f; //幅值
    14. float n2r = 2.0 / F_WLEN; //计算幅值时,相乘
    15. complex_float *inFFTData = (complex_float *)g_fft_input;
    16. complex_float *outFFTData = (complex_float *)g_fft_output;
    17. float *inFrameData = (float * )g_inFrameData;
    18. float fAmpMax = 0.0;
    19. freqResol = (SAMPLING_RATE_48K * 1.0) / (F_WLEN * 1.0); //得到频率分辨率
    20. memset(inFFTData, 0, sizeof(complex_float) * (F_WLEN) );
    21. memset(outFFTData, 0, sizeof(complex_float) * (F_WLEN) );
    22. // NHS处理帧旧数据的移动(最老的数据放在inFrameData[0],最新的数据放在了inFrameData[F_WLEN])
    23. fft_sp_blk_move((float *)&inFrameData[nDataInLen], (float *)inFrameData, (F_WLEN - nDataInLen));
    24. // 用新采样的数据更新NHS处理帧的sampleNumber个长度空间
    25. fft_sp_blk_move((float *)pDataIn, (float *)&inFrameData[F_WLEN - nDataInLen], nDataInLen);
    26. nFrameRunCount++;
    27. //前面4帧就不处理
    28. if(nFrameRunCount < F_WLEN / nDataInLen)
    29. {
    30. return;
    31. }
    32. //2021年10月29日在加窗前对数据进行一次overlap
    33. for(i = 0; i < F_WLEN; i++)
    34. {
    35. inFFTData[i].re = inFrameData[i] * (g_win[i]); //数据加窗hanning
    36. inFFTData[i].im = 0.0f;
    37. }
    38. //在ADSP21489中调用FFT库函数
    39. cfft(inFFTData, g_fft_temp, outFFTData, g_twiddle_fft, twiddle_stride, F_WLEN);
    40. //如果inFFTData可以数据是临时性可以被重写,那么可以把g_fft_temp省出来
    41. // cfft(inFFTData, NULL, outFFTData, g_twiddle_fft, twiddle_stride, F_WLEN);
    42. fAmpMax = -F_FLT_MAX;
    43. //计算频点的功率
    44. for(i = 1; i < F_WLEN / 2; i++)
    45. {
    46. amp = sqrtf(outFFTData[i].re * outFFTData[i].re + outFFTData[i].im * outFFTData[i].im );
    47. amp = amp * n2r * 2.0;
    48. if (fAmpMax < amp)
    49. {
    50. fAmpMax = amp; //找出频点中最大的值
    51. k = i;
    52. }
    53. }
    54. cfft_mag(outFFTData, g_fftSpectrum, F_WLEN);
    55. memset(inFFTData, 0, sizeof(complex_float) * F_WLEN);
    56. memset(g_fft_temp, 0, sizeof(complex_float) * F_WLEN);
    57. twiddle_stride = 1;
    58. ifft(outFFTData, g_fft_temp, inFFTData, g_twiddle_ifft, twiddle_stride, F_WLEN);
    59. //思考ifft输出的复数结果怎么给到硬件输出
    60. for(i = 0; i < nLen; i++)
    61. {
    62. pDataOut[i] = inFFTData[i].re; //重建信号,只取实部
    63. // pDataOut[i] = pDataIn[i]; //直通测试
    64. }
    65. }

     原始波形

    经过fft和iff处理后上述代码输出的波形

     输出不正常,原因分析:

    1.原始信号经过了hanning加窗,信号有衰减,经过加窗后,能量有所衰减。

    查阅了相关资料后了解到 

    在做FFT计算时,有时候需要用到平顶汉宁窗,如下:
    //Tukey window: for 20ms 
    /* 
    The Tukey window, also known as the cosine-tapered window, 
    can be regarded as a cosine lobe of width N*alpha/2 (spanning N*alpha/2 + 1 observations) 
    that is convolved with a rectangular window of width N(1 - alpha/2). 
    w(n) = 1/2 * (1 - cos(2*pi*n/(alpha*N))); 0 <= n <= alpha*N/2; 
    w(n) = 1; alpha*N/2 <= n <= N/2; 
    w(N-n) = w(n); 0 <= n <= N/2; 
    At α = 0 it becomes rectangular, and at α = 1 it becomes a Hann window. 
    */
    平顶汉宁窗的使用场景是:当2帧数据叠在一起时,当前帧大于上一帧,即当前帧所有数据和上一帧的部分数据一起叠帧时,此时就需要使用平顶汉宁窗函数。例如每一帧长320点,当前帧的320点和上一帧的后192点的数据一起叠帧,做512点的FFT,此时就需要使用平顶汉宁窗,其中平顶的数据长度为320-192+1(汉宁窗本身就有1个值为1).

     添加的窗函数还必须满足另外一个条件,即重叠缓冲区的部分的窗口的平方和必须为1, 
    即:w(N)^2 + w(M+N)^2 = 1;

    虽然加窗能减少频谱泄露,但是加窗也存在一个问题:加窗衰减了每帧信号的能量,特别是边界处。为了解决这一个问题,就引入了合成窗的概念。

    在iSTFT中,合成窗是在iFFT之后,对时域信号做的。此次加窗,并不是为了减少频谱泄露,因为之后不再做FFT,不需要满足周期性序列条件。而是为解决分析窗导致能量衰减问题的。

    总结就是要对IFFT后的数据进行重建,需要注意

    根据完美重建公式,合成窗的选择,不仅跟分析窗有关,还和overlap有关。不同的overlap要采用不同的合成窗。

    重点总结

    对ifft后的数据要加一个合成窗函数,该函数满足重叠缓冲区的部分的窗口的平方和必须为1,即分析窗和合成窗平方和等于1,(另外测试如果对原始信号不加窗,那么ifft后可以得到正常信号)

    参考文档:使用多特征建模分析语音噪声可能性的噪声抑制方法和装置.caj (专利文档:0059,0060)

  • 相关阅读:
    暑假加餐|有钱人和你想的不一样+多目标蝙蝠优化算法(Matlab代码实现)
    基于Redis网络模型的简易网络库
    国家互联网信息办公室修订《互联网跟帖评论服务管理规定》发布施行
    泰安双软申请指南
    高德地图与CAD图叠加显示方法汇总及优缺点分析
    传输层协议 --TCP报文格式详细介绍
    代码随想录算法训练营第三十一天 | LeetCode 455. 分发饼干、376. 摆动序列、53. 最大子数组和
    [附源码]Python计算机毕业设计Django现代诗歌交流平台
    R语言使用rpart包拟合随机森林回归模型:使用predict函数和训练好的模型进行预测推理、使用plot函数可视化线图对比预测值和实际值曲线
    Llama2 论文中译版——开放式基础和微调聊天模型
  • 原文地址:https://blog.csdn.net/zz603976046/article/details/126366645