Osh
Osh

Reputation: 11

Cepstral Analysis on NMF Component

I am using Non-negative Matrix Factorization (NMF) on an audio file of a working motor to decompose it into five NMF components. I need to explore the quefrency/cepstral domain of each component, but I am unsure how to proceed.

Since the NMF components are computed after applying the Short-Time Fourier Transform (STFT) to the original signal and are represented as a 2D matrix, I am uncertain about how to transform them into the quefrency domain.

I attempted to generate a cepstrogram for one of my NMF components using the following code:

# STFT Parameters
n_fft = 2048
hop_length = 256
win_length = n_fft
window = 'hann'

# Compute STFT
S = librosa.stft(y, n_fft=n_fft, hop_length=hop_length, win_length=win_length, window=window)
X, X_phase = librosa.magphase(S)  


# Normalization
X_norm = librosa.util.normalize(X)


# NMF Calculation
n_components = 5
model = NMF(n_components=n_components, init='random', beta_loss='kullback-leibler', solver='mu', max_iter=3000, tol=1e-5, l1_ratio=0.8)
W = model.fit_transform(X_norm)
H = model.components_


# Compute the cepstrogram from log magnitude spectrum

c = np.outer(W[:, 4], H[4]) #c is already a absolute value
# Compute log magnitude
log_magnitude = np.log(c + 1e-10)  # Add small value to avoid log(0)

# Compute cepstrum using IFFT
cepstrum = np.fft.ifft(log_magnitude, axis=0).real  # Compute real cepstrum across time frames

# Number of unique cepstral coefficients
NUP = cepstrum.shape[0] // 2  # Keep only the first half

# Extract the meaningful part of the cepstrum
C = cepstrum[:NUP, :]

# Compute quefrency and time vectors
q = np.arange(NUP) / sr  # Quefrency (s)
t = np.arange(C.shape[1]) * (hop_length / sr)  # Time (s)


# ===== APPLY CONDITIONING =====
q_mask = q > 0.0005 # Ignore quefrencies below 0.5 ms
C = C[q_mask, :]  # Filter cepstrum coefficients
q = q[q_mask] * 1000  # Convert quefrency from seconds to milliseconds


plt.figure(figsize=(10, 6))
plt.imshow(C, aspect='auto', origin='lower', extent=[t[0], t[-1], q[0], q[-1]])
plt.xlabel('Time (s)')
plt.ylabel('Quefrency (ms)')
plt.title('Cepstrogram from STFT (Magnitude Spectrum)')
plt.colorbar(label='Amplitude')
plt.show()

enter image description here

I need to determine whether this approach is correct. If it is, how can I extract quefrency domain features such as Linear Frequency Cepstral Coefficients (LFCC), Constant Q Cepstral Coefficients (CQCC), Teager Energy Cepstral Coefficients (TECC), and Gabor Filterbank Cepstral Coefficients (GTFB)?

Upvotes: 0

Views: 29

Answers (0)

Related Questions