美文网首页
FFT变换(快速傅里叶变换)

FFT变换(快速傅里叶变换)

作者: 客昂康 | 来源:发表于2021-03-06 09:59 被阅读0次

    FFT.h:

    //==============================================================================
    //  Copyright (C) 2020 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: 一维二维快速傅里叶变换(FFT)
    //  日期: 2020-07-13
    //
    //==============================================================================
    
    #ifndef _FFT_H_
    #define _FFT_H_
    
    typedef struct {
        float real;
        float imag;
    } FFT_COMPLEX;
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void* FFT_init  (int bit);
    void  FFT_uninit(void *fftCtx);
    
    int FFT_1D_fft (void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in);
    int FFT_1D_ifft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in);
    int FFT_2D_fft (void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in);
    int FFT_2D_ifft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in);
    
    int FFT_1D_getSpectrum(void *fftCtx, float *out, FFT_COMPLEX *in);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    

    FFT.c:

    //==============================================================================
    //  Copyright (C) 2020 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: 一维二维快速傅里叶变换(FFT)
    //  日期: 2020-07-13
    //
    //==============================================================================
    
    #include <stdlib.h>
    #include <stdint.h>
    #include <math.h>
    #include "FFT.h"
    
    typedef struct {
        uint32_t  bit;
        uint32_t  len;
        float    *sin;
        float    *cos;
        uint16_t *index;
        uint8_t   buffer[0];
    } FFT_CTX;
    
    //左右翻转二进制位
    static uint16_t reverseBit(uint16_t bit, uint16_t value){
        uint16_t i, ret = 0;
        for(i=0; i<bit; i++){
            ret = (ret<<1) | ((value>>i)&1);
        }
        return ret;
    }
    
    //对一行进行 FFT
    static void horizontal_FFT(FFT_CTX *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint16_t a, b, c, d, e, f, g;
        FFT_COMPLEX tmp;
        for(a=0; a<fftCtx->len; a++){
            out[a].real = in[fftCtx->index[a]].real;
            out[a].imag = in[fftCtx->index[a]].imag;
        }
        for(a=0; a<fftCtx->bit; a++){
            b = 1 << a;
            c = 2 << a;
            d = 1 << (fftCtx->bit-1-a);
            for(e=0,f=0; e<b; e+=1,f+=d){
                for(g=e; g<fftCtx->len; g+=c){
                    tmp.real = out[g+b].real * fftCtx->cos[f] + out[g+b].imag * fftCtx->sin[f];
                    tmp.imag = out[g+b].imag * fftCtx->cos[f] - out[g+b].real * fftCtx->sin[f];
                    out[g+b].real = out[g].real - tmp.real;
                    out[g+b].imag = out[g].imag - tmp.imag;
                    out[ g ].real = out[g].real + tmp.real;
                    out[ g ].imag = out[g].imag + tmp.imag;
                }
            }
        }
    }
    
    //对一列进行 FFT
    static void vertical_FFT(FFT_CTX *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint16_t a, b, c, d, e, f, g;
        FFT_COMPLEX tmp;
        for(a=0; a<fftCtx->len; a++){
            out[fftCtx->len*a].real = in[fftCtx->len*fftCtx->index[a]].real;
            out[fftCtx->len*a].imag = in[fftCtx->len*fftCtx->index[a]].imag;
        }
        for(a=0; a<fftCtx->bit; a++){
            b = 1 << a;
            c = 2 << a;
            d = 1 << (fftCtx->bit-1-a);
            for(e=0,f=0; e<b; e+=1,f+=d){
                for(g=e; g<fftCtx->len; g+=c){
                    tmp.real = out[fftCtx->len*(g+b)].real * fftCtx->cos[f] + out[fftCtx->len*(g+b)].imag * fftCtx->sin[f];
                    tmp.imag = out[fftCtx->len*(g+b)].imag * fftCtx->cos[f] - out[fftCtx->len*(g+b)].real * fftCtx->sin[f];
                    out[fftCtx->len*(g+b)].real = out[fftCtx->len*g].real - tmp.real;
                    out[fftCtx->len*(g+b)].imag = out[fftCtx->len*g].imag - tmp.imag;
                    out[  fftCtx->len*g  ].real = out[fftCtx->len*g].real + tmp.real;
                    out[  fftCtx->len*g  ].imag = out[fftCtx->len*g].imag + tmp.imag;
                }
            }
        }
    }
    
    //对一行进行 IFFT
    static void horizontal_IFFT(FFT_CTX *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint16_t a, b, c, d, e, f, g;
        FFT_COMPLEX tmp;
        for(a=0; a<fftCtx->len; a++){
            out[a].real = in[fftCtx->index[a]].real;
            out[a].imag = in[fftCtx->index[a]].imag;
        }
        for(a=0; a<fftCtx->bit; a++){
            b = 1 << a;
            c = 2 << a;
            d = 1 << (fftCtx->bit-1-a);
            for(e=0,f=0; e<b; e+=1,f+=d){
                for(g=e; g<fftCtx->len; g+=c){
                    tmp.real = out[g+b].real * fftCtx->cos[f] - out[g+b].imag * fftCtx->sin[f];
                    tmp.imag = out[g+b].imag * fftCtx->cos[f] + out[g+b].real * fftCtx->sin[f];
                    out[g+b].real = out[g].real - tmp.real;
                    out[g+b].imag = out[g].imag - tmp.imag;
                    out[ g ].real = out[g].real + tmp.real;
                    out[ g ].imag = out[g].imag + tmp.imag;
                }
            }
        }
        for(a=0; a<fftCtx->len; a++){
            out[a].real /= fftCtx->len;
            out[a].imag /= fftCtx->len;
        }
    }
    
    //对一列进行 IFFT
    static void vertical_IFFT(FFT_CTX *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint16_t a, b, c, d, e, f, g;
        FFT_COMPLEX tmp;
        for(a=0; a<fftCtx->len; a++){
            out[fftCtx->len*a].real = in[fftCtx->len*fftCtx->index[a]].real;
            out[fftCtx->len*a].imag = in[fftCtx->len*fftCtx->index[a]].imag;
        }
        for(a=0; a<fftCtx->bit; a++){
            b = 1 << a;
            c = 2 << a;
            d = 1 << (fftCtx->bit-1-a);
            for(e=0,f=0; e<b; e+=1,f+=d){
                for(g=e; g<fftCtx->len; g+=c){
                    tmp.real = out[fftCtx->len*(g+b)].real * fftCtx->cos[f] - out[fftCtx->len*(g+b)].imag * fftCtx->sin[f];
                    tmp.imag = out[fftCtx->len*(g+b)].imag * fftCtx->cos[f] + out[fftCtx->len*(g+b)].real * fftCtx->sin[f];
                    out[fftCtx->len*(g+b)].real = out[fftCtx->len*g].real - tmp.real;
                    out[fftCtx->len*(g+b)].imag = out[fftCtx->len*g].imag - tmp.imag;
                    out[  fftCtx->len*g  ].real = out[fftCtx->len*g].real + tmp.real;
                    out[  fftCtx->len*g  ].imag = out[fftCtx->len*g].imag + tmp.imag;
                }
            }
        }
        for(a=0; a<fftCtx->len; a++){
            out[fftCtx->len*a].real /= fftCtx->len;
            out[fftCtx->len*a].imag /= fftCtx->len;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    
    //初始化,生成变址表、sin表和cos表。
    void* FFT_init(int bit){
        if((bit < 3) || (bit > 15)) return NULL;
        uint32_t len = 1 << bit;
        FFT_CTX *ctx = malloc(sizeof(FFT_CTX) + (sizeof(float)+sizeof(uint16_t))*len);
        if(ctx == NULL) return NULL;
        ctx->bit   = bit;
        ctx->len   = len;
        ctx->sin   = (float*)(ctx->buffer) + 0;
        ctx->cos   = (float*)(ctx->buffer) + len/2;
        ctx->index = (uint16_t*)((float*)(ctx->buffer) + len);
        uint32_t i;
        for(i=0; i<len; i++){
            ctx->index[i] = reverseBit(bit&0x00ff, i);
        }
        for(i=0; i<len/2; i++){
            ctx->sin[i] = sin((3.14159265359*2/len)*i);
            ctx->cos[i] = cos((3.14159265359*2/len)*i);
        }
        return ctx;
    }
    
    //去初始化
    void FFT_uninit(void *fftCtx){
        free(fftCtx);
    }
    
    //一维 FFT
    int FFT_1D_fft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        horizontal_FFT(fftCtx, out, in);
        return 0;
    }
    
    //一维 IFFT
    int FFT_1D_ifft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        horizontal_IFFT(fftCtx, out, in);
        return 0;
    }
    
    //二维 FFT。先一行行做 FFT,再一列列做 FFT。
    int FFT_2D_fft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint32_t i;
        FFT_CTX *ctx = fftCtx;
        FFT_COMPLEX *tmp = malloc(ctx->len*ctx->len*sizeof(FFT_COMPLEX));
        if(tmp == NULL) return -1;
        for(i=0; i<ctx->len; i++){
            horizontal_FFT(ctx, tmp+(i*ctx->len), in+(i*ctx->len));
        }
        for(i=0; i<ctx->len; i++){
            vertical_FFT(ctx, out+i, tmp+i);
        }
        free(tmp);
        return 0;
    }
    
    //二维 IFFT。先一列列做 IFFT,再一行行做 IFFT。
    int FFT_2D_ifft(void *fftCtx, FFT_COMPLEX *out, FFT_COMPLEX *in){
        uint32_t i;
        FFT_CTX *ctx = fftCtx;
        FFT_COMPLEX *tmp = malloc(ctx->len*ctx->len*sizeof(FFT_COMPLEX));
        if(tmp == NULL) return -1;
        for(i=0; i<ctx->len; i++){
            vertical_IFFT(ctx, tmp+i, in+i);
        }
        for(i=0; i<ctx->len; i++){
            horizontal_IFFT(ctx, out+(i*ctx->len), tmp+(i*ctx->len));
        }
        free(tmp);
        return 0;
    }
    
    //获取一维FFT后的频谱图
    int FFT_1D_getSpectrum(void *fftCtx, float *out, FFT_COMPLEX *in){
        uint32_t i;
        FFT_CTX *ctx = fftCtx;
        out[0] = sqrt(in[0].real*in[0].real+in[0].imag*in[0].imag) / ctx->len;
        for(i=1; i<=ctx->len/2; i++){
            out[i] = 2 * sqrt(in[i].real*in[i].real + in[i].imag*in[i].imag) / ctx->len;
        }
        return 0;
    }
    

    测试程序test.c:

    //==============================================================================
    //  Copyright (C) 2020 王小康. All rights reserved.
    //
    //  作者: 王小康
    //  描述: 一维二维快速傅里叶变换(FFT)测试程序
    //  日期: 2020-07-13
    //
    //==============================================================================
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    #include "FFT.h"
    
    #define FFT_2PI     (3.14159265359*2)
    #define FFT_1D_BIT  (8)
    #define FFT_1D_LEN  (1<<FFT_1D_BIT)
    #define FFT_2D_BIT  (4)
    #define FFT_2D_LEN  (1<<FFT_2D_BIT)
    
    static void showWave(FFT_COMPLEX *wave, int num, float ratio){
        int i, j, A;
        for(i=0; i<num; i++){
            printf("%13f %13f ", wave[i].real, wave[i].imag);
            A = (int)(wave[i].real*ratio+(wave[i].real>=0.0?0.5:-0.5)) + 80;
            for(j=0; j<=160; j++){
                if     (j == A ) putchar('0');
                else if(j == 80) putchar('|');
                else             putchar('-');
            }
            putchar('\n');
        }
    }
    
    static void showSpectrum(float *wave, int num){
        int i, j, A;
        for(i=0; i<num; i++){
            printf("%11dHz %13f ", i, wave[i]);
            A = (int)(wave[i]+0.5);
            for(j=0; j<=160; j++){
                if(j < A ) putchar('|');
                else       putchar('-');
            }
            putchar('\n');
        }
    }
    
    static void test1D(void){
        float buffer0[1+FFT_1D_LEN/2];
        FFT_COMPLEX buffer1[FFT_1D_LEN];
        FFT_COMPLEX buffer2[FFT_1D_LEN];
        FFT_COMPLEX buffer3[FFT_1D_LEN];
        void *fftCtx = FFT_init(FFT_1D_BIT);
        
        //通过多个正弦波构造复合波,FFT_1D_LEN 个采样点视为一个周期。
        int i;
        for(i=0; i<FFT_1D_LEN; i++){
            buffer1[i].real = 10;                                           //直流分量 10
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) *  1 + 10) * 30;  //频率1Hz, 振幅30,初相位10。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) *  2 + 30) * 40;  //频率2Hz, 振幅40,初相位30。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) *  3 + 20) * 20;  //频率3Hz, 振幅20,初相位20。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) *  6 + 30) * 40;  //频率6Hz, 振幅40,初相位30。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) *  9 + 15) * 16;  //频率9Hz, 振幅16,初相位15。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 10 + 13) * 15;  //频率10Hz,振幅15,初相位13。
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 12 + 11) * 11;  //以此类推
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 15 + 25) * 13;  //以此类推
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 16 + 15) * 20;  //以此类推
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 19 + 19) * 10;  //以此类推
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 20 + 14) * 16;  //以此类推
            buffer1[i].real += sin(i*(FFT_2PI/FFT_1D_LEN) * 25 + 21) * 10;  //以此类推
            buffer1[i].imag = 0;
        }
        printf("原始波:\n");
        showWave(buffer1, FFT_1D_LEN, 0.35);
        putchar('\n');
        
        //快速傅里叶变换 获取频谱
        FFT_1D_fft(fftCtx, buffer2, buffer1);
        FFT_1D_getSpectrum(fftCtx, buffer0, buffer2);
        printf("进行FFT后获取的频谱:\n");
        showSpectrum(buffer0, 1+FFT_1D_LEN/2);
        putchar('\n');
        
        //快速傅里叶逆变换
        FFT_1D_ifft(fftCtx, buffer3, buffer2);
        printf("进行IFFT之后:\n");
        showWave(buffer3, FFT_1D_LEN, 0.35);
        putchar('\n');
        
        FFT_uninit(fftCtx);
    }
    
    void show2D(FFT_COMPLEX data[][FFT_2D_LEN]){
        int i, j;
        for(i=0; i<FFT_2D_LEN; i++){
            for(j=0; j<FFT_2D_LEN; j++) printf("%13f", data[i][j].real); putchar('\n');
            for(j=0; j<FFT_2D_LEN; j++) printf("%13f", data[i][j].imag); putchar('\n');
            putchar('\n');
        }
        putchar('\n');
    }
    
    static void test2D(void){
        FFT_COMPLEX buffer1[FFT_2D_LEN][FFT_2D_LEN];
        FFT_COMPLEX buffer2[FFT_2D_LEN][FFT_2D_LEN];
        FFT_COMPLEX buffer3[FFT_2D_LEN][FFT_2D_LEN];
        void *fftCtx = FFT_init(FFT_2D_BIT);
        
        //构造数据
        int i, j;
        for(i=0; i<FFT_2D_LEN; i++){
            for(j=0; j<FFT_2D_LEN; j++){
                buffer1[i][j].real = i;
                buffer1[i][j].real += sin(j*(FFT_2PI/FFT_2D_LEN) *  1 + 10 + i) * 30;
                buffer1[i][j].real += sin(j*(FFT_2PI/FFT_2D_LEN) *  2 + 15 + i) * 40;
                buffer1[i][j].real += sin(j*(FFT_2PI/FFT_2D_LEN) *  3 + 20 + i) * 20;
                buffer1[i][j].real += sin(j*(FFT_2PI/FFT_2D_LEN) *  6 + 30 + i) * 40;
                buffer1[i][j].imag = 0;
            }
        }
        printf("原始矩阵:\n");
        show2D(buffer1);
        
        //2维 FFT
        FFT_2D_fft(fftCtx, (void*)buffer2, (void*)buffer1);
        printf("进行二维FFT之后的矩阵:\n");
        show2D(buffer2);
        
        //2维 IFFT
        FFT_2D_ifft(fftCtx, (void*)buffer3, (void*)buffer2);
        printf("进行二维IFFT之后的矩阵:\n");
        show2D(buffer3);
        
        FFT_uninit(fftCtx);
    }
    
    static void help(char *name){
        printf("Usage: %s 1|2\n", name);
        printf("       1: 1D FFT test.\n");
        printf("       2: 2D FFT test.\n");
    }
    
    int main(int argc, char* argv[]){
        if(argc < 2){
            help(argv[0]);
            return 0;
        }
        if(strcmp(argv[1], "1") == 0){
            test1D();
        }
        else if(strcmp(argv[1], "2") == 0){
            test2D();
        }
        else {
            help(argv[0]);
            return 0;
        }
        return 0;
    }
    

    测试结果


    原始波形(局部)
    FFT变换后获取的频谱(局部)
    FFT逆变换后的波形(局部)

    相关文章

      网友评论

          本文标题:FFT变换(快速傅里叶变换)

          本文链接:https://www.haomeiwen.com/subject/puujqltx.html