Filtering

The audiotoolbox library provides access to commonly used filters as well as the option to generate and apply filterbanks.

Applying Filters to Signals

The easiest way to filter a signal is to use the methods directly available on the Signal object. This provides a unified, fluent interface for low-pass, high-pass, and band-pass filtering.

The following example demonstrates applying a low-pass filter to a white noise signal.

import audiotoolbox as audio
import matplotlib.pyplot as plt
import numpy as np

# Create a white noise signal
sig = audio.Signal(n_channels=1, duration=100e-3, fs=48000).add_noise('white')

# Create a low-passed version of the signal
# A copy is made so the original signal is not modified
lp_sig = sig.copy().lowpass(f_cut=1000, filter_type='butter', order=4)

# Plot the original and filtered signals
fig, ax = plt.subplots(2, 1, sharex=True, sharey=True, figsize=(8, 6))
ax[0].plot(sig.time, sig, label='Original')
ax[0].set_title('Original White Noise')
ax[0].grid(True)

ax[1].plot(lp_sig.time, lp_sig, label='Filtered', color='C1')
ax[1].set_title('After 1kHz Low-Pass Filter')
ax[1].set_xlabel('Time / s')
ax[1].grid(True)

for a in ax:
    a.set_ylabel('Amplitude')

plt.tight_layout()
plt.show()

(Source code, png, hires.png, pdf)

../_images/filtering-1.png

Filter Functions

For more direct control, you can also use the filter functions available in the audiotoolbox.filter submodule. These functions take a signal as their first argument.

The following filters are available:

import audiotoolbox as audio

sig = audio.Signal(n_channels=2, duration=1, fs=48000).add_noise()

# Apply a 3rd-order Butterworth low-pass filter
filt_sig = audio.filter.butterworth(sig, high_f=1000, order=3)

Filterbanks

audiotoolbox provides two commonly used standard filterbanks and allows for the creation of custom banks.

Standard Filterbanks

The following standard filterbanks are available:

  1. octave_bank(): A (fractional) octave filterbank.

  2. auditory_gamma_bank(): An auditory gammatone filterbank.

A 1/3-octave filterbank can be generated as follows:

import audiotoolbox as audio

bank = audio.filter.bank.octave_bank(
    fs=48000, flow=25, fhigh=20000, oct_fraction=3
)

# The .fc property contains the center frequencies
print(bank.fc)

Applying a Filterbank

A filterbank can be applied to a signal using its filt() method. This returns a multi-channel signal where each channel corresponds to the output of one filter in the bank.

sig = audio.Signal(n_channels=2, duration=1, fs=48000).add_noise()

# Filter the signal with the entire bank
filt_sig = bank.filt(sig)

# The output has shape (n_samples, n_original_channels, n_filters)
print(f"Shape of filtered signal: {filt_sig.shape}")

You can also index the filterbank to apply only a subset of filters:

# Apply only the 10th through 15th filters of the bank
filt_sig_partial = bank[10:15].filt(sig)
print(f"Shape of partially filtered signal: {filt_sig_partial.shape}")

Custom Filterbanks

The create_filterbank() function can be used to create custom filterbanks from any of the available filter types.

import audiotoolbox as audio
import numpy as np

# Define center frequencies and bandwidths
fc_vec = np.array([100, 200, 300])
bw_vec = np.array([10, 20, 30])

# Create a custom brickwall filterbank
custom_bank = audio.filter.bank.create_filterbank(
    fc=fc_vec, bw=bw_vec, filter_type='brickwall', fs=48000
)

Frequency Weighting Filters

audiotoolbox implements A- and C-weighting filters following the IEC 61672-1 standard. While the weighted levels can be accessed directly via the stats property (e.g., sig.stats.dba), the filters can also be applied directly.

noise = audio.Signal(n_channels=1, duration=1, fs=48000).add_noise('pink')

# Apply A-weighting filter
a_weighted_noise = audio.filter.a_weighting(noise)