基2时域采样快速傅里叶变换、反变换算法在python上的实现(自制轮子)

首先,我们收到一个不定长度的时域离散信号,我们暂且称它为series

对于待处理的series,为满足基2fft算法的需求,我们需要先把它补零至2的整数幂次长度,为此,我们定义一个函数用于补零、二进制按位反序操作,这是一切算法前的预处理,所以我们不妨叫她initlist

import math
from math import ceil, log2


def initlist(series):
    if log2(len(series)) % 1:                              
        newdit = ceil(log2(len(series)))
        newlen = 2 ** newdit
        aplen = newlen - len(series)
        for i in range(aplen):
            series.append(0)
    else:
        newdit = log2(len(series))
        newdit = int(newdit)
        newlen = 2 ** newdit
    indexlist = []  #补零完成
 
    for i in range(newlen):                                
        ind = bin(i)[2:]
        if len(ind) < newdit:
            for j in range(newdit - len(ind)):
                ind = '0' + ind
        ind = ind[::-1]
        newind = trim(ind)                                
        newind = '0b' + newind                             
        ind = int(newind, 2)
        indexlist.append(ind)
    obj = series.copy()
    series = []
    for i in indexlist:
        series.append(obj[i])
    return series, newdit  #按位倒序完成

整个函数返回倒序后序列、补零后序列长度的幂次

用到的二进制修剪函数如下,作用是将0(二进制中为0b0)转换为指定位数的纯数,例:若16点fft则为0000,我们不妨叫她trim

def trim(string):
    for i in range(len(string)):                           
        if string[i:].startswith('0'):
            if i == len(string) - 1:
                return '0'
            else:
                continue
        else:
            break
    return string[i:]

蝶形运算函数如下:

def butterfly(x1, x2, wn):                                 
    y1 = x1 + x2 * wn
    y2 = x1 - x2 * wn
    return y1, y2

旋转因子的定义如下,涉及到正旋转因子W和反旋转因子W_(用于IFFT):

def W(n, N):
    result = math.e ** complex(0, -2 * math.pi * n / N)  
    return result

def W_(n, N):
    result = math.e ** complex(0, 2 * math.pi * n / N)  
    return result

下面是对DIT-FFT和反变换主函数的定义

def dit_fft(series):
    obj, digt = initlist(series)
    length = 2 ** digt
    for i in range(digt):
        leap = 2 ** i
        group = 2 ** (i + 1)
        medium = obj.copy()
        for k in range(length // group):
            for j in range(leap):  
                medium[j + k * group], medium[j + leap + k * group] = butterfly(obj[j + k * group],
                                                                                obj[j + leap + k * group],
                                                                                W(j, 2 ** group))
        obj = medium
    Rseries = []
    Iseries = []
    raw = []
    for i in range(len(obj)):
        Rseries.append(abs(obj[i].real))
        Iseries.append(obj[i].imag)
        raw.append(obj[i])

    return Rseries, Iseries, raw

def idft(Fseries):
    obj, digt = initlist(Fseries)
    length = 2 ** digt
    for i in range(digt):
        leap = 2 ** i
        group = 2 ** (i + 1)
        medium = obj.copy()
        for k in range(length // group):
            for j in range(leap): 
                medium[j + k * group], medium[j + leap + k * group] = butterfly(obj[j + k * group],
                                                                                obj[j + leap + k * group],
                                                                                W_(j, 2 ** group))
        obj = medium
    Rseries = []
    Iseries = []
    raw = []
    for i in range(len(obj)):
        Rseries.append(abs(obj[i].real/length))
        Iseries.append(obj[i].imag/length)
        raw.append(obj[i]/length)

    return Rseries, Iseries, raw

核心算法按照基2标准信号流建模,为满足不同需求,将输出分为实部Rseries,虚部Iseries,原复数序列raw

以下是效果展示:

import matplotlib.pyplot as plt
demolist = [math.sin(i * math.pi / 8) for i in range(128)]
YR, YI, raw = dit_fft(demolist)
yr, yi, y_ = idft(raw)
X = [i for i in range(len(YR))]

我们以周期为16的128点正弦序列作为实验对象

plt.xlabel('Time')
plt.ylabel('Amp')
plt.stem(X, demolist)
plt.title('Time-Sequence')

原序列如下:
在这里插入图片描述

经DIT-FFT变换后,得到128位FFT频谱:

plt.xlabel('Freq')
plt.ylabel('Amp')
plt.title('Freq-Sequence')
plt.stem(X, YR)

在这里插入图片描述

采用反旋转因子,反变换后得到还原序列,画出序列实部()

plt.xlabel('Time')
plt.ylabel('Amp')
plt.stem(X, yr)
plt.title('Time-SequenceA')
plt.show()

在这里插入图片描述
至此,DIT-FFT和IFFT在python上的实现就告一段落了,后续会有复杂性分析、鲁棒性测试(也许吧),敬请关注。
本人github源码:https://github.com/A-nnonymous/DSPy
欢迎互相关注、互相学习

发布了6 篇原创文章 · 获赞 2 · 访问量 532

猜你喜欢

转载自blog.csdn.net/u010870244/article/details/102995376
今日推荐