dsp/lib/util.py
2019-01-02 06:45:12 -08:00

119 lines
2.4 KiB
Python

import sys
import numpy as np
import scipy.signal as sig
isqrt2 = 1/np.sqrt(2)
tau = 2*np.pi
def dummy(*args, **kwargs):
return None
def lament(*args, **kwargs):
return print(*args, file=sys.stderr, **kwargs)
def toLK(x):
return -0.691 + 10*np.log10(x)
def toQ(bw):
return isqrt2/bw
def toA(db):
return 10**(db/40)
def unwarp(w):
return np.tan(w/2)
def warp(w):
return np.arctan(w)*2
def ceil2(x):
x = int(x)
assert x > 0
return 2**(x - 1).bit_length()
def pad2(x):
return np.r_[x, np.zeros(ceil2(len(x)) - len(x), x.dtype)]
def magnitude(src, size, broken=True):
if broken:
lament("magnitude(broken=True): DEPRECATED")
return 10*np.log10(np.abs(np.fft.rfft(src, 2 * size))**2)[:size]
else:
return 10*np.log10(np.abs(np.fft.rfft(src, size))**2)[1:]
# x axis for plotting above magnitude
def magnitude_x(srate, size, broken=True):
if broken:
lament("magnitude_x(broken=True): DEPRECATED")
return np.arange(0, srate/2, srate/2/size)
else:
return np.arange(1, size // 2 + 1) / (size // 2) * (srate / 2)
def degrees_clamped(x):
return ((x*180/np.pi + 180) % 360) - 180
def xsp(precision=4096):
"""
create #precision log-spaced points from
20 Hz (inclusive) to 20480 Hz (exclusive)
"""
xs = np.arange(0, precision)/precision
return 20*1024**xs
def blocks(a, step, size=None):
"""break an array into chunks"""
if size is None:
size = step
for start in range(0, len(a), step):
end = start + size
if end > len(a):
break
yield a[start:end]
def convolve_each(s, fir, mode='same', axis=0):
return np.apply_along_axis(
lambda s: sig.fftconvolve(s, fir, mode), axis, s)
def count_channels(s):
if s.ndim < 2:
return 1
return s.shape[1]
def monoize(s):
"""mixes an n-channel signal down to one channel.
technically, it averages a 2D array to be 1D.
existing mono signals are passed through unmodified."""
channels = count_channels(s)
if channels != 1:
s = np.average(s, axis=1)
return s
def div0(a, b):
"""division, whereby division by zero equals zero"""
# http://stackoverflow.com/a/35696047
a = np.asanyarray(a)
b = np.asanyarray(b)
with np.errstate(divide='ignore', invalid='ignore'):
c = np.true_divide(a, b)
c[~np.isfinite(c)] = 0 # -inf inf NaN
return c