[Python] Cepstral Analysis on NMF Component

Discussão em 'Python' iniciado por Stack, Fevereiro 13, 2025.

  1. Stack

    Stack Membro Participativo

    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()


    [​IMG]

    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)?

    Continue reading...

Compartilhe esta Página