dsp/lib/smoothfft.py
2015-10-18 23:06:39 -07:00

60 lines
2.2 KiB
Python

from . import xsp
import numpy as np
def smoothfft(xs, ys, bw=1, precision=512):
"""performs log-lin smoothing on magnitude data,
generally from the output of averfft."""
# TODO: option to extrapolate (pad) fft data
xs2 = xsp(precision)
ys2 = np.zeros(precision)
log_xs = np.log(xs)
for i, x in enumerate(xs2):
dist = np.exp(np.abs(log_xs - np.log(x + 1e-35)))
window = np.maximum(0, 1 - (dist - bw))
# at this point you could probably
# normalize our *triangular* window to 0-1
# and transform it into *another* windowing function
wsum = np.sum(window)
ys2[i] = np.sum(ys*window/wsum)
return xs2, ys2
def smoothfft2(xs, ys, bw=1, precision=512, compensate=True):
"""performs log-lin smoothing on magnitude data,
generally from the output of averfft."""
xs2 = xsp(precision)
ys2 = np.zeros(precision)
log2_xs2 = np.log2(xs2)
for i, x in enumerate(xs):
#dist = np.abs(np.log2(xs2/(x + 1e-35)))/bw
dist = np.abs(log2_xs2 - np.log2(x + 1e-35))/bw
#window = np.maximum(0, 1 - dist) # triangle window
window = np.exp(-dist**2/(0.5/2)) # gaussian function (non-truncated)
ys2 += ys[i]*window
if compensate:
_, temp = smoothfft2(xs, np.ones(len(xs)), bw=bw, precision=precision, compensate=False)
ys2 /= temp
return xs2, ys2
def smoothfft3(xs, ys, bw=1, precision=1024):
# actually this will never work...
# you need to go back to smoothfft2,
# which technically works as-designed,
# and fix the compensation to work with widely-spaced data.
raise Exception("smoothfft3 is broken.")
xs2 = xsp(precision)
ys2 = np.zeros(precision)
step = (xs[1] - xs[0])
if True:
for i, x in enumerate(xs):
dist = np.abs(xs2 - x)
bw2 = x*bw/2
window = np.maximum(0, 1 - dist/bw2)
#window = np.minimum(1, np.maximum(0, 1 - (dist - bw)))
ys2 += ys[i]*window
else:
for i, x2 in enumerate(xs2):
dist = np.abs(xs - x2)
window = np.maximum(0, 1 - (dist/step/bw))
wsum = np.sum(window)
ys2[i] = np.sum(ys*window/wsum)
return xs2, ys2