Download features/padding.py from JsonDONSON/Machine-Sound-Anomaly-Detector: direct link, hf CLI and curl.
- Browser
- Download file 3.03 kB
-
https://huggingface.co/spaces/JsonDONSON/Machine-Sound-Anomaly-Detector/resolve/main/features/padding.py
- Command line
-
hf download hf://spaces/JsonDONSON/Machine-Sound-Anomaly-Detector/features/padding.py
-
curl -L -o padding.py https://huggingface.co/spaces/JsonDONSON/Machine-Sound-Anomaly-Detector/resolve/main/features/padding.py
3.03 kB
| """ | |
| =============================================================================== | |
| features/padding.py — Fixed-Size Spectrogram Padding / Trimming | |
| =============================================================================== | |
| """ | |
| import numpy as np | |
| # we will use (top_db=40), trimmed clips average ~8.5 to 9.0 seconds. | |
| # Calculation: 9.0 seconds * 16000 Hz / 512 hop_length = ~281 frames. | |
| DEFAULT_FIXED_FRAMES = 281 | |
| # Padding strategy. Options: "constant" (fill with a number) or "edge" (repeat last frame) | |
| PAD_MODE = "constant" | |
| # Log-mel spectrograms use negative numbers for silence (e.g., -80.0). | |
| # Padding with absolute 0.0 might accidentally represent maximum volume. | |
| # Setting this to True forces the pad to use the quietest part of the current file. | |
| USE_MIN_VALUE = True | |
| CONSTANT_PAD_VALUE = 0.0 | |
| def pad_or_trim_spectrogram(mel_spec, target_length=None): | |
| """ | |
| Pad or trim a mel spectrogram to a fixed number of time frames. | |
| Notes | |
| ----- | |
| - Zero-padding doesn't add energy — padded regions are "silence" in the | |
| spectrogram and the CNN will learn to ignore them. | |
| - Trimming from the right assumes the important machine sound is at the | |
| beginning. After silence removal, this is guaranteed. | |
| """ | |
| if target_length is None: | |
| target_length = DEFAULT_FIXED_FRAMES | |
| n_mels, current_length = mel_spec.shape | |
| if current_length < target_length: | |
| # --- PAD: Add values on the right --- | |
| pad_width = target_length - current_length | |
| if PAD_MODE == "constant": | |
| # Decide what "silence" means mathematically | |
| # so here I try to use the lowest possible sound in the current spectrogram as the padding value, which is more realistic than using a fixed constant like 0.0 that might not represent silence in log-mel space. | |
| pad_val = mel_spec.min() if USE_MIN_VALUE else CONSTANT_PAD_VALUE | |
| mel_spec = np.pad( | |
| mel_spec, | |
| pad_width=((0, 0), (0, pad_width)), # Only pad the time axis, not the mel axis | |
| mode="constant", | |
| constant_values=pad_val | |
| ) | |
| else: | |
| # Fallback for other numpy pad modes "edge" | |
| # so in this method we just repeat the last frame of the spectrogram, which is a common padding strategy that doesn't introduce new values but extends the existing pattern. | |
| # This can be useful if the end of the spectrogram contains relevant information that we want to preserve. | |
| # also depending on the CNN we need to try and error for this as in the CNN it might see the sudden | |
| # silience as a FEATURE | |
| mel_spec = np.pad( | |
| mel_spec, | |
| pad_width=((0, 0), (0, pad_width)), | |
| mode=PAD_MODE | |
| ) | |
| elif current_length > target_length: | |
| # --- TRIM: Cut from the right --- | |
| mel_spec = mel_spec[:, :target_length] | |
| return mel_spec | |