Implementation of impedance tube code
This commit is contained in:
parent
a1e4a63043
commit
96edc90c55
148
lasp/lasp_imptube.py
Normal file
148
lasp/lasp_imptube.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""!
|
||||||
|
Author: J.A. de Jong - ASCEE
|
||||||
|
|
||||||
|
Description: Two-microphone impedance tube methods
|
||||||
|
"""
|
||||||
|
__all__ = ['TwoMicImpedanceTube']
|
||||||
|
from lrftubes import Air
|
||||||
|
from .lasp_measurement import Measurement
|
||||||
|
from numpy import pi, sqrt, exp
|
||||||
|
import numpy as np
|
||||||
|
from scipy.interpolate import UnivariateSpline
|
||||||
|
|
||||||
|
class TwoMicImpedanceTube:
|
||||||
|
def __init__(self, mnormal: Measurement,
|
||||||
|
mswitched: Measurement,
|
||||||
|
s: float,
|
||||||
|
d1: float,
|
||||||
|
d2: float,
|
||||||
|
fl: float = None,
|
||||||
|
fu: float = None,
|
||||||
|
periodic_method=False,
|
||||||
|
mat= Air(),
|
||||||
|
**kwargs):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Initialize two-microphone impedance tube methods
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mnormal: Measurement in normal configuration
|
||||||
|
mswitched: Measurement in normal configuration
|
||||||
|
s: Microphone distance
|
||||||
|
fl: Lower evaluation frequency
|
||||||
|
fu: Lower evaluation frequency
|
||||||
|
|
||||||
|
kwargs: tuple with extra arguments, of which:
|
||||||
|
N: Period length of periodic excitation *obligatory*
|
||||||
|
chan0: Measurement channel index of mic 0
|
||||||
|
chan1: Measurement channel index of mic 1
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.mnormal = mnormal
|
||||||
|
self.mswitched = mswitched
|
||||||
|
|
||||||
|
self.mat = mat
|
||||||
|
self.s = s
|
||||||
|
self.d1 = d1
|
||||||
|
self.d2 = d2
|
||||||
|
|
||||||
|
self.fl = fl
|
||||||
|
if fl is None:
|
||||||
|
ksmin = 0.1*pi
|
||||||
|
kmin = ksmin/s
|
||||||
|
self.fl = kmin*mat.c0/2/pi
|
||||||
|
|
||||||
|
self.fu = fu
|
||||||
|
if fu is None:
|
||||||
|
ksmax = 0.8*pi
|
||||||
|
kmax = ksmax/s
|
||||||
|
self.fu = kmax*mat.c0/2/pi
|
||||||
|
|
||||||
|
self.periodic_method = periodic_method
|
||||||
|
self.channels = [kwargs.pop('chan0', 0), kwargs.pop('chan1', 1)]
|
||||||
|
# Compute calibration correction
|
||||||
|
if periodic_method:
|
||||||
|
self.N = kwargs.pop('N')
|
||||||
|
freq, C1 = mnormal.periodicCPS(self.N, channels=self.channels)
|
||||||
|
freq, C2 = mswitched.periodicCPS(self.N, channels=self.channels)
|
||||||
|
else:
|
||||||
|
self.nfft = kwargs.pop('nfft', 16000)
|
||||||
|
freq, C1 = mnormal.CPS(nfft=self.nfft, channels=self.channels)
|
||||||
|
freq, C2 = mswitched.CPS(nfft=self.nfft, channels=self.channels)
|
||||||
|
|
||||||
|
# Store this, as it is often used for just a single sample.
|
||||||
|
self.C1 = C1
|
||||||
|
self.freq = freq
|
||||||
|
|
||||||
|
self.il = np.where(self.freq<= self.fl)[0][-1]
|
||||||
|
self.ul = np.where(self.freq > self.fu)[0][0]
|
||||||
|
|
||||||
|
# Calibration correction factor
|
||||||
|
# self.K = 0*self.freq + 1.0
|
||||||
|
K = sqrt(C2[:,0,1]*C1[:,0,0]/(C2[:,1,1]*C1[:,1,0]))
|
||||||
|
self.K = UnivariateSpline(self.freq, K.real)(self.freq) +\
|
||||||
|
1j*UnivariateSpline(self.freq, K.imag)(self.freq)
|
||||||
|
|
||||||
|
def cut_to_limits(self, ar):
|
||||||
|
return ar[self.il:self.ul]
|
||||||
|
|
||||||
|
def getFreq(self):
|
||||||
|
"""
|
||||||
|
Array of frequencies, cut to limits of validity
|
||||||
|
"""
|
||||||
|
return self.cut_to_limits(self.freq)
|
||||||
|
|
||||||
|
def G_AB(self, meas):
|
||||||
|
if meas is self.mnormal:
|
||||||
|
C = self.C1
|
||||||
|
freq = self.freq
|
||||||
|
else:
|
||||||
|
if self.periodic_method:
|
||||||
|
freq, C = meas.periodicCPS(self.N, self.channels)
|
||||||
|
else:
|
||||||
|
freq, C = meas.CPS(nfft=self.nfft, channels=self.channels)
|
||||||
|
|
||||||
|
# Microphone transfer function
|
||||||
|
G_AB = self.K*C[:,1,0]/C[:,0,0]
|
||||||
|
return self.getFreq(), self.cut_to_limits(G_AB)
|
||||||
|
|
||||||
|
def R(self, meas):
|
||||||
|
freq, G_AB = self.G_AB(meas)
|
||||||
|
s = self.s
|
||||||
|
k = 2*pi*freq/self.mat.c0
|
||||||
|
d1 = self.d1
|
||||||
|
RpA = (G_AB - exp(-1j*k*s))/(exp(1j*k*s)-G_AB)
|
||||||
|
|
||||||
|
R = RpA*exp(2*1j*k*(s+d1))
|
||||||
|
|
||||||
|
return freq, R
|
||||||
|
|
||||||
|
def alpha(self, meas):
|
||||||
|
"""
|
||||||
|
Acoustic absorption coefficient
|
||||||
|
"""
|
||||||
|
freq, R = self.R(meas)
|
||||||
|
return freq, 1 - np.abs(R)**2
|
||||||
|
|
||||||
|
def z(self, meas):
|
||||||
|
"""
|
||||||
|
Acoustic impedance at the position of the sample, in front of the sample
|
||||||
|
"""
|
||||||
|
freq, R = self.R(meas)
|
||||||
|
return freq, self.mat.z0*(1+R)/(1-R)
|
||||||
|
|
||||||
|
def zs(self, meas):
|
||||||
|
"""
|
||||||
|
Sample impedance jump, assuming a cavity behind the sample with
|
||||||
|
thickness d2
|
||||||
|
"""
|
||||||
|
freq, R = self.R(meas)
|
||||||
|
z0 = self.mat.z0
|
||||||
|
k = 2*pi*freq/self.mat.c0
|
||||||
|
d2 = self.d2
|
||||||
|
|
||||||
|
zs = 2*z0*(1-R*exp(2*1j*k*d2))/((R-1)*(exp(2*d2*k*1j)-1))
|
||||||
|
return freq, zs
|
||||||
|
|
Loading…
Reference in New Issue
Block a user