fix: fs/D in lowpass, add missing fs attr
This commit is contained in:
26
rhythm.py
26
rhythm.py
@@ -15,6 +15,7 @@ import numpy as np
|
|||||||
from numpy.fft import fft
|
from numpy.fft import fft
|
||||||
|
|
||||||
from hsh_signal.signal import lowpass_fft
|
from hsh_signal.signal import lowpass_fft
|
||||||
|
import time
|
||||||
|
|
||||||
def viterbi_highest_frequency_path_vectorized(Scp2, jump_penalty=2.0, use_log_amplitude=True):
|
def viterbi_highest_frequency_path_vectorized(Scp2, jump_penalty=2.0, use_log_amplitude=True):
|
||||||
Scp2 = np.asarray(Scp2, dtype=float)
|
Scp2 = np.asarray(Scp2, dtype=float)
|
||||||
@@ -127,21 +128,33 @@ class BassAnalyzer:
|
|||||||
self.M = (self.L-self.W) // self.D + 1 #: number of time steps
|
self.M = (self.L-self.W) // self.D + 1 #: number of time steps
|
||||||
self.fs = fs
|
self.fs = fs
|
||||||
|
|
||||||
def viterbi_wavelet_scalogram_amplitudes(self):
|
def viterbi_wavelet_scalogram_amplitudes(self, dbg_time=False):
|
||||||
"""
|
"""
|
||||||
Compute scalogram amplitudes from Viterbi path of highest-power frequencies.
|
Compute scalogram amplitudes from Viterbi path of highest-power frequencies.
|
||||||
NOTE: downsampled from the original 'fs'.
|
NOTE: downsampled from the original 'fs'.
|
||||||
:returns: (fsd, sig): sampling rate, amplitude signal
|
:returns: (fsd, sig): sampling rate, amplitude signal
|
||||||
"""
|
"""
|
||||||
|
t1 = time.time()
|
||||||
Spf = self._spectrogram()
|
Spf = self._spectrogram()
|
||||||
|
t2 = time.time()
|
||||||
pto = self._pulse_train(Spf)
|
pto = self._pulse_train(Spf)
|
||||||
|
t3 = time.time()
|
||||||
Spf2 = self._spectrogram_2()
|
Spf2 = self._spectrogram_2()
|
||||||
|
t4 = time.time()
|
||||||
pms = self._scalogram_params(pto)
|
pms = self._scalogram_params(pto)
|
||||||
|
t5 = time.time()
|
||||||
Spsi_ss = self._scalogram_wavelets(pms)
|
Spsi_ss = self._scalogram_wavelets(pms)
|
||||||
|
t6 = time.time()
|
||||||
Scp2 = self._scalogram(Spf2, Spsi_ss)
|
Scp2 = self._scalogram(Spf2, Spsi_ss)
|
||||||
|
t7 = time.time()
|
||||||
path = self._viterbi_path(Scp2)
|
path = self._viterbi_path(Scp2)
|
||||||
|
t8 = time.time()
|
||||||
ampl = self._viterbi_ampl(Scp2, path)
|
ampl = self._viterbi_ampl(Scp2, path)
|
||||||
|
t9 = time.time()
|
||||||
|
if not dbg_time:
|
||||||
return ampl
|
return ampl
|
||||||
|
else:
|
||||||
|
return ampl, np.diff([t1, t2, t3, t4, t5, t6, t7, t8, t9])
|
||||||
|
|
||||||
def _spectrogram(self):
|
def _spectrogram(self):
|
||||||
"""W-FFT (STFTs) to determine scalogram parameters"""
|
"""W-FFT (STFTs) to determine scalogram parameters"""
|
||||||
@@ -171,7 +184,7 @@ class BassAnalyzer:
|
|||||||
# TODO: check if 'A' needs to be a smooth signal slowly varying over time, not a const.
|
# TODO: check if 'A' needs to be a smooth signal slowly varying over time, not a const.
|
||||||
#A = np.mean(g_bar) # amplitude cutoff for pulse train
|
#A = np.mean(g_bar) # amplitude cutoff for pulse train
|
||||||
ip = int(fs)
|
ip = int(fs)
|
||||||
g_bar_l = lowpass_fft(np.pad(g_bar, (ip, ip), mode='edge'), fps=fs, cf=0.5, tw=0.05)[ip:-ip]
|
g_bar_l = lowpass_fft(np.pad(g_bar, (ip, ip), mode='edge'), fps=fs/self.D, cf=0.5, tw=0.05)[ip:-ip]
|
||||||
A = g_bar_l
|
A = g_bar_l
|
||||||
|
|
||||||
# compute transitions (pulse train)
|
# compute transitions (pulse train)
|
||||||
@@ -202,6 +215,8 @@ class BassAnalyzer:
|
|||||||
f2 = self.f2
|
f2 = self.f2
|
||||||
Wp, Mp, Dp = self.Wp, self.Mp, self.Dp
|
Wp, Mp, Dp = self.Wp, self.Mp, self.Dp
|
||||||
|
|
||||||
|
# TODO(perf): 5.0 sec runtime
|
||||||
|
|
||||||
#
|
#
|
||||||
# compute spectrogram: 'Spf2' (M x Wp) <- from 'f'
|
# compute spectrogram: 'Spf2' (M x Wp) <- from 'f'
|
||||||
#
|
#
|
||||||
@@ -266,12 +281,18 @@ class BassAnalyzer:
|
|||||||
# T, Lp, Wp
|
# T, Lp, Wp
|
||||||
T, Lp, Wp = self.T, self.Lp, self.Wp
|
T, Lp, Wp = self.T, self.Lp, self.Wp
|
||||||
|
|
||||||
|
# TODO(perf): reduce num of wavelets, and/or parallelize into freq slices
|
||||||
|
# TODO(perf): 3.5 sec runtime
|
||||||
|
|
||||||
# compute convolution with wavelets, by multiplication in freq-domain
|
# compute convolution with wavelets, by multiplication in freq-domain
|
||||||
# 'Scp2' (M x I*J)
|
# 'Scp2' (M x I*J)
|
||||||
Scp2 = np.matmul(Spf2, Spsi_ss.T) * (T/(Lp-Wp))
|
Scp2 = np.matmul(Spf2, Spsi_ss.T) * (T/(Lp-Wp))
|
||||||
return Scp2
|
return Scp2
|
||||||
|
|
||||||
def _viterbi_path(self, Scp2):
|
def _viterbi_path(self, Scp2):
|
||||||
|
# TODO(perf): parallelize into time slices
|
||||||
|
# TODO(perf): 4.5 sec runtime
|
||||||
|
|
||||||
# TODO: check if we should re-weight freq-jumps, because of log-scale frequencies
|
# TODO: check if we should re-weight freq-jumps, because of log-scale frequencies
|
||||||
path, dp, backptr = viterbi_highest_frequency_path_vectorized(
|
path, dp, backptr = viterbi_highest_frequency_path_vectorized(
|
||||||
(np.abs(Scp2)**2).T,
|
(np.abs(Scp2)**2).T,
|
||||||
@@ -313,6 +334,7 @@ class GuitarAnalyzer:
|
|||||||
self.D = int(self.shift_sec * fs) #: spectrogram step
|
self.D = int(self.shift_sec * fs) #: spectrogram step
|
||||||
self.L = self.f.shape[0]
|
self.L = self.f.shape[0]
|
||||||
self.M = (self.L-self.W) // self.D + 1 #: number of time steps
|
self.M = (self.L-self.W) // self.D + 1 #: number of time steps
|
||||||
|
self.fs = fs
|
||||||
|
|
||||||
def spectrogram_power_amplitudes(self):
|
def spectrogram_power_amplitudes(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user