Roan Yeh
Goal: Remove interfering sound from audio file
To accomplish this goal, I created an algorithm that:
- Reads in an audio file.
- Detects prominent interfering frequencies.
- Designs a set of biquad notch filters to suppress the detected fundamental frequencies and their harmonics, with varying Q factors, along with another wider notch to reduce fuzz around the fundamental frequencies.
- Applies those filters online to the audio signal.
- Outputs a cleaned .wav file with interfering frequencies supressed.
- Visualizes the results by plotting a spectrogram for the outputted signal and frequency response curves for the filters applied to the original audio file.
See the appendix (last section) for all formulas used in this project.
- Apply filter to remove sound online one sample at a time
- Design filter on your own
- Do not use existing routine for applying filters on sounds
- Write output to "output.wav"
audio_processing.py: Main file that runs the algorithm to remove interfering frequencies.
filters.py: Contains functions that create filters
notch_biquad_coefficients- Computes the coefficients for a notch filter using the biquad filter design method.
notch_filter_coefficients_with_harmonics- Computes the coefficients for a notch filter that removes multiple harmonics of a given fundamental frequency.
filter_proccessing.py: Contains functions that apply filters to an input signal
process_single_sample- Processes a single sample of the input signal through a biquad filter.
apply_notch_filters- Applies a series of notch filters to the input signal online, sample by sample.
frequency_detection.py: Contains functions that detect peak frequencies in a given frequency range.
detect_interfering_frequencies- Detects the fundamental frequencies of the interfering sound in the input signal.
visualization.py: Contains functions that plot spectrograms and filters
compute_spectrogram- Computes a spectrogram of an audio signal.
plot_spectrogram- Plots a spectrogram of an audio signal.
plot_filters- Plots the frequency response of multiple filters.
-
Design filter
- Implement a notch filter from scratch
-
Visualization - testing aid (allows for concrete feedback from each test)
- Display a spectrogram of the filtered audio.
- Display filter response curve to see effect of filter
-
Apply filter online
- For each interfering frequency:
- Loop through each audio sample.
- Apply the filter recursively.
- For each interfering frequency:
-
Improve filter design (more notches, adjusted/scaled Q factors)
-
Analyze audio for interfering frequencies
- Take a short segment of the audio and compute its frequency spectrum.
- Identify peaks corresponding to unwanted sounds.
1. My first step was the visualize the audio file by creating a spectrogram from the signal information. Upon opening the spectrogram, I noticed two prominent frequencies centered around 2k and 2.5k Hz.
2. Filter approach: Center a notch biquad filter on the fundamental interfering frequencies with a small bandwidth to also remove fuzz. Use a moderate Q factor. The noise is not a perfect sine wave so also cut harmonics (to a lesser degree than the fundamental of course). Choosing IIR over FIR as tonal interference is stationary and efficiency (FIR is overkill).
3. Created notch biquad filter and visualized it to make sure the output is correct. Below is the notch filter at a frequency of 2,000 and Q factor of 30.
4. Now lets use my filter function to generate filter coefficients for a fundamental frequency AND its harmonics. New function made to produce multiple coefficients for fundamental and its harmonics. Updated the filter response plot function. Below is the notch filter at a frequency of 2,000 with a Q factor of 10 and a Q factor of 30 for the harmonics.
Return here to improve harmonic handling later (possibly modify the Q factor per harmonic)
6. Now I need to apply a filter to a single sample. This will be run in the main for loop and will apply the notch biquad filter to the audio wav online.
5. Now I need to focus on how to apply this filter online sample by sample. To do this, I need to look at the samples around any given sample. I will make a class for this.
7. Now I need to loop thru all samples and apply this function.
Return to this function later to add dynamic processing since the interfering noise is NOT CONSTANT
8. First test! Manually chose fundamental frequencies of 2075 and 2575 Hz (rough esimation). I probably don't need to cut the harmonics that much and need to focus on fuzz around the fundamental frequencies, but yay! It works! Now let's make it better!
9. I want to improve my filter so the harmonic cuts scale better and the fundamental frequency is cut wider. Scaled Q_factor for harmonics by n^2.
I might want to change the filter for the fundamental frequency. My method is sort of janky right now.
Here's the output spectrogram given the conditions and fundamental frequencies of the first test:
10. Now I want to detect the interfering frequencies. Created a new function and tested it in a full test going thru all steps (reference full_test_1).
Conclusion: Cutting way too much around 2.5k Hz. Need to modify the filters.
11. Reorganized my code into separate files. Tweaked some function inputs in audio_processing.py. See results in test/full_test_2
12. Need to fix frequency_detection.py. I am currently taking the top 2 of all frequencies EVEN IF they are right next to each other. I need to do clustering.
I've implemented clustering by adding a new arg to detect_interfering_frequencies. Also added a new arg bandwidth_harmonic to notch_filter_coefficients_with_harmonics to differ the Q factor between the fundamental frequencies and harmonics. See test results in tests/full_test_3
13. Let's focus on the fuzz around the fundamental interfering frequencies. I'm going to add a wider cut on the fundamental frequencies ontop of the deeper notch so I sharply remove the fundamental and reduce the fuzz around it.
14. Yay! While the algorithm is not perfect, I have removed a significant part of the interfering frequencies without overcutting and removing too much of the upper mid range. In the future, I would like to make this algorithm dynamic so the filter is adjusted based on the presence/magnitude of the interfering frequencies. This was a really fun project! Here are visuals for the final results.
Run:
pip install -r requirements.txt
Coefficient Formulas
Source: Audio EQ Cookbook by Robert Bristow-Johnson
Numerator coefficients
Denominator coefficients
Biquad Filter Formula
Direct Form 1 Filter Equation
Q_factor formula
Source: Wikipedia
Frequency Response Formulas
Source: UC Berkeley EECS











