@@ -227,3 +227,171 @@ def repeat_n_m(v):
227227 """
228228 krlist = [np .tile (v , (2 * i + 1 , 1 )).T for i , v in enumerate (v .T .tolist ())]
229229 return np .squeeze (np .concatenate (krlist , axis = - 1 ))
230+
231+
232+ def circular_pw (N , k , r , setup ):
233+ r"""Radial coefficients for a plane wave.
234+
235+ Computes the radial component of the circular harmonics expansion of a
236+ plane wave impinging on a circular array.
237+
238+ .. math::
239+
240+ \mathring{P}_n(k) = i^{-n} b_n(kr)
241+
242+ Parameters
243+ ----------
244+ N : int
245+ Maximum order.
246+ k : (M,) array_like
247+ Wavenumber.
248+ r : float
249+ Radius of microphone array.
250+ setup : {'open', 'card', 'rigid'}
251+ Array configuration (open, cardioids, rigid).
252+
253+ Returns
254+ -------
255+ bn : (M, N+1) numpy.ndarray
256+ Radial weights for all orders up to N and the given wavenumbers.
257+ """
258+ kr = util .asarray_1d (k * r )
259+ n = np .arange (N + 1 )
260+
261+ bn = circ_radial_weights (N , kr , setup )
262+ for i , x in enumerate (kr ):
263+ bn [i , :] = bn [i , :] * (1j )** (n )
264+ return bn
265+
266+
267+ def circular_ls (N , k , r , rs , setup ):
268+ r"""Radial coefficients for a line source.
269+
270+ Computes the radial component of the circular harmonics expansion of a
271+ line source impinging on a circular array.
272+
273+ .. math::
274+
275+ \mathring{P}_n(k) = \frac{-i}{4} H_n^{(2)}(k r_s) b_n(kr)
276+
277+ Parameters
278+ ----------
279+ N : int
280+ Maximum order.
281+ k : (M,) array_like
282+ Wavenumber.
283+ r : float
284+ Radius of microphone array.
285+ rs : float
286+ Distance of source.
287+ setup : {'open', 'card', 'rigid'}
288+ Array configuration (open, cardioids, rigid).
289+
290+ Returns
291+ -------
292+ bn : (M, N+1) numpy.ndarray
293+ Radial weights for all orders up to N and the given wavenumbers.
294+ """
295+ k = util .asarray_1d (k )
296+ krs = k * rs
297+ n = np .arange (N + 1 )
298+
299+ bn = circ_radial_weights (N , k * r , setup )
300+ for i , x in enumerate (krs ):
301+ Hn = special .hankel2 (n , x )
302+ bn [i , :] = bn [i , :] * - 1j / 4 * Hn
303+ return bn
304+
305+
306+ def circ_radial_weights (N , kr , setup ):
307+ r"""Radial weighing functions.
308+
309+ Computes the radial weighting functions for diferent array types
310+
311+ For instance for an rigid array
312+
313+ .. math::
314+
315+ b_n(kr) = J_n(kr) - \frac{J_n^\prime(kr)}{H_n^{(2)\prime}(kr)}H_n^{(2)}(kr)
316+
317+ Parameters
318+ ----------
319+ N : int
320+ Maximum order.
321+ kr : (M,) array_like
322+ Wavenumber * radius.
323+ setup : {'open', 'card', 'rigid'}
324+ Array configuration (open, cardioids, rigid).
325+
326+ Returns
327+ -------
328+ bn : (M, N+1) numpy.ndarray
329+ Radial weights for all orders up to N and the given wavenumbers.
330+
331+ """
332+ n = np .arange (N + 1 )
333+ Bns = np .zeros ((len (kr ), N + 1 ), dtype = complex )
334+ for i , x in enumerate (kr ):
335+ Jn = special .jv (n , x )
336+ if setup == 'open' :
337+ bn = Jn
338+ elif setup == 'card' :
339+ bn = Jn - 1j * special .jvp (n , x , n = 1 )
340+ elif setup == 'rigid' :
341+ Jnd = special .jvp (n , x , n = 1 )
342+ Hn = special .hankel2 (n , x )
343+ Hnd = special .h2vp (n , x )
344+ bn = Jn - Jnd / Hnd * Hn
345+ else :
346+ raise ValueError ('setup must be either: open, card or rigid' )
347+ Bns [i , :] = bn
348+ return np .squeeze (Bns )
349+
350+
351+ def circ_diagonal_mode_mat (bk ):
352+ """Diagonal matrix of radial coefficients for all modes/wavenumbers.
353+
354+ Parameters
355+ ----------
356+ bk : (M, N+1) numpy.ndarray
357+ Vector containing values for all wavenumbers :math:`M` and modes up to
358+ order :math:`N`
359+
360+ Returns
361+ -------
362+ Bk : (M, 2*N+1, 2*N+1) numpy.ndarray
363+ Multidimensional array containing diagnonal matrices with input
364+ vector on main diagonal.
365+ """
366+ bk = mirror_vec (bk )
367+ if len (bk .shape ) == 1 :
368+ bk = bk [np .newaxis , :]
369+ K , N = bk .shape
370+ Bk = np .zeros ([K , N , N ], dtype = complex )
371+ for k in range (K ):
372+ Bk [k , :, :] = np .diag (bk [k , :])
373+ return np .squeeze (Bk )
374+
375+
376+ def mirror_vec (v ):
377+ """Mirror elements in a vector.
378+
379+ Returns a vector of length *2*len(v)-1* with symmetric elements.
380+ The first *len(v)* elements are the same as *v* and the last *len(v)-1*
381+ elements are *v[:0:-1]*. The function can be used to order the circular
382+ harmonic coefficients. If *v* is a matrix, it is treated as a stack of
383+ vectors residing in the last index and broadcast accordingly.
384+
385+ Parameters
386+ ----------
387+ v : (, N+1) numpy.ndarray
388+ Input vector of stack of input vectors
389+
390+ Returns
391+ -------
392+ : (, 2*N+1) numpy.ndarray
393+ Vector of stack of vectors containing mirrored elements
394+ """
395+ if len (v .shape ) == 1 :
396+ v = v [np .newaxis , :]
397+ return np .concatenate ((v , v [:, :0 :- 1 ]), axis = 1 )
0 commit comments