I have trouble understanding how the sample rate of a DSP system is taken into account when creating FIR coefficients from a complex frequency response.

I work with Jupyter and Python 3.7. The complex frequency data for the code and the plots can be found here

Starting point

A complex frequency response for a loudspeaker that is part of a beamforming array. The frequency range of interest is from 100Hz to 10kHz. I want to create a FIR filter that reproduces this specific frequency response. The sample rate of the DSP is 48kHz.

Bode plot of an exemplary frequency response for one loudspeaker: Here

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

# Sample rate
fs = 48e3
# Number of array loudspeakers
L = 16
# Exemplary loudspeaker
ls_no = 3

f_total = np.floor(np.linspace(0, int(np.round(fs)), int(fs)))
# Used for calculations
f_start_idx = 100
f_stop_idx = 10886
f = f_total[f_start_idx:f_stop_idx]
q_fd_g_05 = np.load("q_fd_g_05.npy")

First step: Mirroring complex frequency response

Mirror and conjugate the complex frequency response at fs/2 (Source). Since I am only interested in the frequency range from 100Hz to 10kHz I decided to zero pad the rest of the spectrum. Exemplary mirrored spectrum with fs/2 as dashed red line here.

Question: When I use zero padding I get calculation errors as soon as I try to convert the values to the dB scale with $20\cdot \log_{10}(|\text{complex_value}|)$. Which makes sense because $log_{10}$ is not defined for 0. The correct result after converting to the dB scale is reached when I use ones instead of zeros. Which one is the correct approach?

# Zero padding or one padding?
q_fd_g_05_mir = np.ones((len(f_total),L), dtype=complex)
# Copy calculated values into array
q_fd_g_05_mir[f_start_idx:f_stop_idx,:] = q_fd_g_05[:, :, 0]
# Mirror array from idx 1 (ignore DC part) to idx(fs/2)-1
q_fd_g_05_mir[int(len(f_total)/2)+1:,:] = q_fd_g_05_mir[1:int(len(f_total)/2),:][::-1].conj()

Second step: IDFT, windowing, ...

IDFT of the complex mirrored frequency response. Apply windowing to the impulse response in order to minimize the Gibbs effect. The impulse response looks rather strange with the constant line between array index 12000 to 38000 plot here, but this could also be my lack of experience with such things.

N = 1024
q_fd_g_05_ifft = np.real(np.fft.ifft(q_fd_g_05_mir, n=N, axis=1))

# Window the Impulse response
w = signal.windows.hamming(int(N))
q_fd_g_05_ifft_window = q_fd_g_05_ifft*w

Question: As you can see I am getting lost here. In this step expect some sort of scaling or norming with regards to the sample rate but I don't know how to do this. Could you help me out here?

Please forgive sloppy or inefficient programming. I just get started with Python.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.