# Problem by designing and filtering a Bessel-Thomson filter in Python

I have an issue when I want to filter a signal with a 4th order Bessel-Thomson filter with a cutoff frequency at 18 GHz.

1. Generate data at 50 Gbps (T-spaced)

def prbs_generation(number_symbol=-1, size=15, oversampling_factor=100, bitrate=50, plot=False, save=False):
"""
Generate a PRBS
:param number_symbol: number of symbol, -1 means full PRBS
:param size: size of the PRBS (7, 15, ...)
:param oversampling_factor: oversampling factor (100 to be close to a continuous signal)
:param bitrate: bitrate in Gbps
:param plot: Authorized plotting
:param save: Authorized saving
:return: bit_oversampled & t in ps
"""

print("Generation of the PRBS ...")
bit = list()
start = 1
lfsr = start
i = 1

while True:
fb = ((lfsr >> (size-1)) ^ (lfsr >> (size-2)) & 1)
lfsr = ((lfsr << 1) + fb) & (2 ** size - 1)
bit.append(fb)
if lfsr == start or i == number_symbol:

break
i = i + 1

bit = [float(i) for i in bit]

if number_symbol != -1:
length = number_symbol
else:
length = 2**size-1

for i in range(length):
bit[i] = 2 * (bit[i] - 0.5)

# "Continuous" signal
g = np.ones(oversampling_factor)
bit_oversampled = np.zeros(len(bit) * oversampling_factor)
bit_oversampled[::oversampling_factor] = bit
bit_oversampled = signal.lfilter(g,1, bit_oversampled)
t_oversampled = np.arange(0, len(bit_oversampled)) * (1000 / (bitrate * oversampling_factor))

return bit_oversampled, t_oversampled


2. Design a filter the signal

def Bessel_Thomson_filtering(data, t, Fc=18.75, order=4, btype='low', analog='True', plot=True, save=False):

Wn = Fc                     # Cutoff frequency

# Design a Bessel-Thomson filter
b, a = signal.bessel(order, Wn * 2 * np.pi, btype=btype, analog=analog, norm='mag')

# Filter the signal
data_filtered_1 = signal.lfilter(b, a, data)

if plot:
w, h = signal.freqs(b, a)
plt.figure()
plt.semilogx(w/(2*np.pi), 20*np.log10(np.abs(h)))
plt.scatter(Wn, -3, color='red')
plt.title('Bessel filter magnitude response', fontweight='bold')
plt.xlabel('Frequency, GHz')
plt.ylabel('Amplitude, dB')
plt.grid(which='both', axis='both')
plt.tight_layout()

if save:
plt.savefig("bessel_frequency_response.png")

plt.figure()
plt.semilogx(w, np.unwrap(np.angle(h)))
plt.title('Bessel filter phase response', fontweight='bold')
plt.xlabel('Frequency, GHz')
plt.grid(which='both', axis='both')
plt.tight_layout()

if save:
plt.savefig("bessel_phase_response.png")

plt.figure()
plt.scatter(t, data, s=3, label='Original data')
plt.scatter(t, data_filtered_1, s=1, label='Filtered data moi')
plt.title("PRBS filtered at " + str(Fc) + " GHz", fontweight='bold')
plt.grid(which='both', axis='both')
#plt.ylim([-2, 2])
plt.xlim([-10, 1200])
plt.legend()
plt.tight_layout()

if save:
plt.savefig("data_filtered.png")


3. Example

import matplotlib.pyplot as plt
from scipy import signal
import numpy as np
from telecom import filterTheSignalWithBessel

if __name__ == "__main__":
# Generate data
data, t = prbs_generation()

# Bessel-Thomson filtering
Bessel_Thomson_filtering(data, t, plot=True)


When I plot the original data and the filtered on the same figure, I got this:

Do you have any idea where could be my issue?

Thanks !

• Can you fix your code? You're not returning the t from prbs_generation(). Please make sure someone can copy and paste your code and run it. As is, it gives errors.
– Jdip
Nov 14, 2023 at 17:09
• As for your question, it seems you'd want the cut-off to be in $\tt{GHz}$: Bessel_Thomson_filtering(data, t, Fc=18.75e9, ...)
– Jdip
Nov 14, 2023 at 17:14
• Thanks @Jdip ! Done ! ;) Nov 14, 2023 at 17:19
• lfilter needs a digital filter. You're using an analog filter as input. signal.bessel can be designed to be digital.
– Jdip
Nov 14, 2023 at 17:35

You can approximate or simulate an analog signal, but it lives inside your computer, so by definition is digital.

You can only filter a digital signal using a digital filter. If you’re only interested in looking at the behavior of the analog filter, then you can leave the analog design that you had (careful with the cutoff frequency though, should be $$18.75 \tt{GHz}$$, not $$18.75 \tt{Hz}$$) but you cannot use this to actually filter your signal.

If you want to filter your signal:
1. You need a digital filter.
2. You need to set the normalized cut-off frequency accordingly.
3. You should always use cascaded second order sections when designing filters with higher orders.

With that in mind:

def Bessel_Thomson_filtering(data, t, Fc=18.75e9, order=4, btype='low', analog=False, plot=True, save=False):

Wn = Fc/(50e9/2) # normalized Cutoff frequency

# Design a Bessel-Thomson filter with cascaded second order sections
sosbessel = signal.bessel(order, Wn, btype=btype, analog=analog, norm='mag', output='sos')

# Filter the signal
data_filtered_1 = signal.sosfilt(sosbessel, data)


There are other problems with this (ringing artifacts, etc) but at least the implementation is now corrected:

• Thanks a lot for your answer. I don't understand the difference between the analogic & the digital filter. The idea behind that is that I want to simulate a "continuous" signal that I will sample later. Nov 14, 2023 at 22:23
• I’ve edited my answer with precisions ;)
– Jdip
Nov 14, 2023 at 22:57