I'm trying to implement Farina's method in python to measure impulse response with an exponential sine sweep.
I convolved the output of the system with the inverse filter of the exponential sweep.
Here is my code for the generation of the exponential sweep and the inverse filter:
def logsweep(fmin,fmax,duration,phi0=0):
global fs
time = np.arange(0,duration,1/fs)
omegaMin = fmin * 2 * np.pi
omegaMax = fmax * 2 * np.pi
phi = (omegaMin*duration)/np.log(omegaMax/omegaMin) * (np.exp(time/duration * np.log(omegaMax/omegaMin)) - 1) + phi0 # Phase instantanée
return np.sin(phi)
def inverseFilter(fmin,fmax,duration,phi0=0):
global fs
sweep = logsweep(fmin,fmax,duration,phi0)
time = np.arange(0,duration,1/fs)
L = 1/fmin*(duration*fmin/(np.log(fmax/fmin)))
normalisation = (np.exp(-time/L))/L*fmax*duration**2
sweep_reverse = sweep[::-1] * normalisation
return sweep_reverse
When I convolved the output of my system with the inverse fitler, the resulting IR has a good shape but is wrong in amplitude.
Here is my code :
print("Génération du filtre inverse...")
invFilter = inverseFilter(fmin,fmax,duration)
print("Calcul de la IR...")
farinaTempIR = np.convolve(measure,invFilter,mode="full") / fs
farinaTempIR = farinaTempIR[sweep.size-1:]
timeFarinaTempIR = np.arange(0,farinaTempIR.size,1) / fs
plt.figure("IR")
plt.plot(timeFarinaTempIR,farinaTempIR,'--',label = "Farina Temp")
plt.legend()
print("Calcul de la TF...")
farinaTempTF = np.fft.rfft(farinaTempIR)
freqFarinaTempTF = np.fft.rfftfreq(farinaTempIR.size,1/fs)
plt.figure("Fonction de transfert")
plt.semilogx(freqFarinaTempTF,20*np.log10(np.abs(farinaTempTF)),'--',label = "Farina Temp")
plt.legend()
I suppose my inverse filter is correct because, when I did the same operation in frequency domain I got the expected result.
Here is my code in frequency domain:
print("Génération du filtre inverse...")
invFilter = inverseFilter(fmin,fmax,duration)
print("Calcul de la FFT du signal de sortie...")
measureFFT = np.fft.rfft(measure) / measure.size * 2
freqMeasure= np.fft.rfftfreq(measure.size,1/fs)
print("Calcul de la FFT du filtre inverse...")
invFFT = np.fft.rfft(invFilter) / invFilter.size * 2
freqInv = np.fft.rfftfreq(invFilter.size,1/fs)
print("Calcul de la TF...")
farinaFreqTF = measureFFT * invFFT
plt.figure("Fonction de transfert")
plt.semilogx(freqInv,20*np.log10(np.abs(farinaFreqTF)),'--',label = "Farina Freq")
plt.legend()
print("Calcul de la IR...")
farinaFreqIR = np.fft.irfft(farinaFreqTF)
timeFarinaFreqIR = np.arange(0,farinaFreqIR.size,1) / fs
plt.figure("IR")
plt.plot(timeFarinaFreqIR,farinaFreqIR,'--',label = "Farina Freq")
plt.legend()
Here is the plots of my code:
I suppose that I'm missing something about the discrete convolution operator. Should I divide by the sampling frequency? By the sum of the inverse filter? I'm not really confortable with this operator.