对于待处理的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
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))]
plt.xlabel('Time')
plt.ylabel('Amp')
plt.stem(X, demolist)
plt.title('Time-Sequence')
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
欢迎互相关注、互相学习