Source code for tftb.generators.utils
import numpy as np
from scipy.signal import hilbert
from scipy.integrate import trapz
# from tftb.utils import nextpow2
[docs]def sigmerge(x1, x2, ratio=0.0):
"""
Add two signals with a specific energy ratio in decibels.
:param x1: 1D numpy.ndarray
:param x2: 1D numpy.ndarray
:param ratio: Energy ratio in decibels.
:type x1: numpy.ndarray
:type x2: numpy.ndarray
:type ratio: float
:return: The merged signal
:rtype: numpy.ndarray
"""
assert x1.ndim == 1
assert x2.ndim == 1
assert type(ratio) in (float, int)
ex1 = np.mean(np.abs(x1) ** 2)
ex2 = np.mean(np.abs(x2) ** 2)
h = np.sqrt(ex1 / (ex2 * 10 ** (ratio / 10.0)))
sig = x1 + h * x2
return sig
[docs]def scale(X, a, fmin, fmax, N):
"""Scale a signal with the Mellin transform.
:param X: signal to be scaled.
:param a: scale factor
:param fmin: lower frequency bound
:param fmax: higher frequency bound
:param N: number of analyzed voices
:type X: array-like
:type a: float
:type fmin: float
:type fmax: float
:type N: int
:return: A-scaled version of X.
:rtype: array-like
"""
Z = hilbert(np.real(X))
T = X.shape[0]
M = (T + np.remainder(T, 2)) / 2
# B = fmax - fmin
# R = B / ((fmin + fmax) / 2)
# Nq = np.ceil((B * T * (1 + 2.0 / R)) * np.log())
# Nmin = Nq - np.remainder(Nq, 2)
# Ndflt = 2 ** nextpow2(Nmin)
# Geometric sampling of the analyzed spectrum
k = np.arange(N)
q = (fmax / float(fmin)) ** (1.0 / (N - 1.0))
geo_f = fmin * np.exp((k - 1) * np.log(q))
t = np.arange(X.shape[0]) - M - 1
tfmatx = np.exp(-2 * 1j * np.dot(t.reshape(128, 1), geo_f.reshape(1, 128)) * np.pi)
ZS = np.dot(Z, tfmatx)
ZS = np.hstack((ZS, np.zeros((N,))))
# Mellin transform computation of the analyzed signal
p = np.arange(2 * N)
MS = np.fft.fftshift(np.fft.ifft(ZS, axis=0))
beta = (p / float(N) - 1.0) / (2 * np.log(q))
# Inverse mellin and fourier transform.
Mmax = np.amax(np.ceil(X.shape[0] / 2.0 * a))
if isinstance(a, np.ndarray):
S = np.zeros((2 * Mmax, a.shape[0]), dtype=complex)
else:
S = np.zeros((2 * Mmax,), dtype=complex)
ptr = 0
DMS = np.exp(-2 * np.pi * 1j * beta * np.log(a)) * MS
DS = np.fft.fft(np.fft.fftshift(DMS), axis=0)
Mcurrent = np.ceil(a * X.shape[0] / 2)
t = np.arange(-Mcurrent, Mcurrent) - 1
itfmatx = np.exp(2 * 1j * np.pi * np.dot(t.reshape((256, 1)),
geo_f.reshape((1, 128))))
dilate_sig = np.zeros((2 * Mcurrent,), dtype=complex)
for kk in range(2 * int(Mcurrent)):
dilate_sig[kk] = trapz(itfmatx[kk, :] * DS[:N], geo_f)
S[(Mmax - Mcurrent):(Mmax + Mcurrent)] = dilate_sig
ptr += 1
S = S * np.linalg.norm(X) / np.linalg.norm(S)
return S
if __name__ == '__main__':
from tftb.generators import altes
sig = altes(256, 0.1, 0.45, 10000)