1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """ Radiation.py - Multimodal radiation matrix implementations.
23
24 """
25
26 import os
27 import numpy
28 from numpy import sin, cosh, sqrt, real, imag, pi
29 import scipy
30 import scipy.integrate
31 import scipy.interpolate
32 from scipy.interpolate import UnivariateSpline
33 import scipy.io
34 import scipy.special
35 from scipy.special import j0,j1,jn_zeros,jvp
36
37 from Functions import flat2matrix, matrix2flat
38
40 """ Class implementing the Zorumski multimodal radiation impedance matrix.
41
42 [1] N. Amir, V. Pagneux, and J. Kergomard,
43 "A study of wave propagation in varying cross-section waveguides by
44 modal decomposition. Part II. Results,"
45 The Journal of the Acoustical Society of America,
46 vol. 101, May. 1997, pp. 2504-2517.
47
48 [2] W.E. Zorumski, "Generalized radiation impedances and reflection
49 coefficients of circular and annular ducts,"
50 The Journal of the Acoustical Society of America,
51 vol. 54, Dec. 1973, pp. 1667-1673.
52
53 [3] Jonathan Kemp, "Theoretical and experimental study of wave
54 propagation in brass musical instruments",
55 Ph.D. Thesis, University of Edinburgh, 2002
56
57 """
58 N = 15
59
60 - def __init__(self,diameter,number_of_modes = N, do_interpolation = True):
61 self.radius = diameter / 2.
62 self.number_of_modes = number_of_modes
63
64 assert number_of_modes >=1, 'Minimal number of modes is 1'
65 if number_of_modes == 1:
66 self.gamma = [0.]
67 else:
68 self.gamma = numpy.concatenate(
69 ([0.],jn_zeros(1,self.number_of_modes-1)))
70
71
72 self.do_interpolation = do_interpolation
73 self.backup_filename = os.path.join(os.path.dirname(__file__),'Znm')
74 if do_interpolation:
75 try:
76 self.data_table = scipy.io.loadmat(self.backup_filename)
77 N = int(self.data_table['number_of_modes'])
78 Znm = numpy.reshape(self.data_table['Z_nm'],
79 (N,N,self.data_table['length_ka']))
80 self.data_table['Z_nm'] = Znm
81
82
83 self.spl_real = []
84 self.spl_imag = []
85 for i in range(N):
86 self.spl_real.append([])
87 self.spl_imag.append([])
88 for j in range(N):
89
90
91 self.spl_real[i].append(
92 UnivariateSpline(self.data_table['ka'],
93 numpy.real(self.data_table['Z_nm'][i][j]),
94 s=0.0000001))
95 self.spl_imag[i].append(
96 UnivariateSpline(self.data_table['ka'],
97 numpy.imag(self.data_table['Z_nm'][i][j]),
98 s=0.0000001))
99
100 except IOError:
101
102 print 'Calculating radiation data table for interpolation.'
103
104 ka = numpy.arange(0.,15.,0.1)
105 self.do_interpolation = False
106 self.data_table = {'number_of_modes': self.number_of_modes,
107 'length_ka': numpy.size(ka,-1),
108 'ka': ka,
109 'Z_nm': self.calculateZnm(ka/self.radius)}
110 self.do_interpolation = True
111 scipy.io.savemat(self.backup_filename, self.data_table)
112
114 assert N <= self.number_of_modes,\
115 'number of modes exceed radiation impedance maximum'
116 Z = numpy.empty((N,N),dtype=complex)
117 for i in range(N):
118 for j in range(N):
119 Z[i][j] = self.Z_ij(i,j,k)
120 return matrix2flat(Z)
121
123 return j0(self.gamma[i]*r/self.radius)/j0(self.gamma[i])
124
125 - def D(self,tau,i,k):
126 """ from [3] eq. 4.1 """
127 lambdan = self.gamma[i]/(k*self.radius)
128 if i == 0 and tau == 0: return 0.
129 return -sqrt(2.)*tau*j1(tau*k*self.radius) / (lambdan**2-tau**2)
130
132 return sin(phi) * self.D(sin(phi),i,k) * self.D(sin(phi),j,k)
133
135 return cosh(xhi) * self.D(cosh(xhi),i,k) * self.D(cosh(xhi),j,k)
136
137 - def Z_ij(self,i,j,k):
138
139 if self.do_interpolation:
140 ka = k * self.radius
141 if ka >= self.data_table['ka'][-1]:
142 print 'Warning: value of ka not in radiation matrix table'
143 Z_ij = complex(self.spl_real[i][j](ka)[0],
144 self.spl_imag[i][j](ka)[0])
145 else:
146 if k == 0.:
147 Z_ij = complex(0.,0.)
148 else:
149 realpart = scipy.integrate.quad(self.integrand_Z_ij_real,
150 0., numpy.pi/2,args=(i,j,k),limit=5000)
151 imagpart = scipy.integrate.quad(self.integrand_Z_ij_imag,
152 0., 100, args=(i,j,k),limit=5000)
153
154
155
156
157
158
159 Z_ij = complex(realpart[0], -imagpart[0])
160
161 return Z_ij
162
164 Zs = numpy.empty((number_of_modes, number_of_modes,len(ks)),
165 dtype=complex)
166 l = 0
167 print "Calculating flanged modal radiation matrix..."
168 for k in ks:
169 for i in range(number_of_modes):
170 for j in range(number_of_modes):
171 Zs[i][j][l] = self.Z_ij(i,j,k)
172 l = l+1
173 print "done."
174
175 return Zs
176
177
178
179
180
181
182
183
184
185
189
191 ka = k * self.a
192 R0 = (1 + 0.2*ka - 0.084*ka**2)/(1 + 0.2*ka + (0.5 - 0.084)*ka**2)
193 delta = 0.6113 * ((1+0.044*ka**2)/(1+0.19*ka**2) - 0.02*(numpy.sin(2*ka))**2 )
194 R = - R0 * numpy.exp( -2 * 1j * ka * delta)
195 Zl = (1+R)/(1-R)
196 M = numpy.diag(Zl*numpy.ones(N))
197 return matrix2flat(M)
198
199
200
203
206
208 """ Rigid wall admittance matrix is zero (N x N)
209 they are complex valued so we should return a flat vector of 2*N**2 values
210 """
211 return numpy.zeros(2*N**2)
212
213
214
215
216