# Bandpass filter equivalent for amplitude

I have a signal where I am using a bandpass filter to limit the frequency range. I am also interested in filtering the remaining frequencies (after bandpass filtering) within the signal by their amplitudes. So for example if I set the bandpass filter to exclude frequencies outside of the range of 20-100 Hz, I also want an "amplitude filter" to exclude remaining components if their amplitude range is outside of, for example, 0.2-0.8.

See the rough drawing below. The area within the black rectangle should be kept. • an algorithm like this exists
• if so, are there any implementations in python, Julia, R, Octave, Matlab, etc.?

Thank you.

• Do you need the results back in the time domain ? Jun 15, 2021 at 14:38
• Yes eventually. Jun 15, 2021 at 14:50
• that's not a linear filter what you propose, so you have a nonlinear operation there. This will have unexpected effects on the time domain signal. So, I'm taking an educated guess here, this isn't really what you need. What is the purpose, why do you want to do this? Jun 15, 2021 at 16:24

This can be accomplished with an analytic time-frequency representation, like CWT or STFT. Goal must be known precisely to attain desired result, however, as time and frequency are coupled and targeting amplitude alone may yield distortion. The steps are:

1. Transform to time-frequency
2. Zero undesired amplitudes
3. Invert

Below I generate linearly amplitude-modulated cosine, exclude amplitudes outside 0.2-0.8 with synchrosqueezed CWT for two wavelet settings, and compare result with same cosine that was generated with already-excluded amplitudes.   It won't always work out this nicely.

Advantage over un-synchrosqueezed CWT/STFT is merger of frequential uncertainty envelopes that would leave residual components, like so:

Clarifying "residual components": x-axis = time, y-axis = freq; zooming: These are per uncertainty principle: frequencies a bit higher and lower than the "true frequency" correlate to non-zero values, but the farther they are from "true frequency" the weaker the correlation, so thresholding out by amplitude will keep these "residual" frequencies whereas with SSQ they're merged and dropped together.

### Code

Uses ssqueezepy.

import numpy as np
from ssqueezepy import cwt, icwt, Wavelet, ssq_cwt, issq_cwt
from ssqueezepy.visuals import imshow, plot

def filter_amplitude(x, xtarget, amin, amax, transform=ssq_cwt):
wavelet = Wavelet(('gmw', {'beta': 60}))
S = transform(x, wavelet)

name = transform.__name__.upper()
imshow(S, abs=1, title="abs(%s)" % name)

Sa = np.abs(S)
S[Sa < amin * Sa.max()] = 0
S[Sa > amax * Sa.max()] = 0
imshow(S, abs=1, title="abs(%s) | amplitude-filtered" % name)

transform_inverse = issq_cwt if name == 'SSQ_CWT' else icwt
xrec = transform_inverse(S, wavelet)

##########################################################################
mae = np.mean(np.abs(xtarget - xrec))
plot(xrec, ylims=(-1, 1), title="result", show=1)
plot(xrec, ylims=(-1, 1), title="overlapped with target | MAE=%.3f" % mae)
plot(xtarget, show=1)

#%%###########################################################################
N = 2049
amin, amax = .2, .8

t = np.linspace(0, 1, N, 1)
A = np.linspace(0, 1, N, 1)
c = np.cos(2*np.pi * 64 * t)

x = c * A
xtarget = c * A * ((A > amin) * (A < amax))

plot(x,       title="input",  ylims=(-1, 1), show=1)
plot(xtarget, title="target", ylims=(-1, 1), show=1)

#%%
filter_amplitude(x, xtarget, amin, amax, transform=ssq_cwt)
filter_amplitude(x, xtarget, amin, amax, transform=cwt)

• Thanks, this is really cool! Can you explain a bit more this line: "Advantage over un-synchrosqueezed CWT/STFT is merger of frequential uncertainty envelopes that would leave residual components" What are the residual components? Jun 16, 2021 at 12:25
• @connor449 Updated. Jun 16, 2021 at 17:28