spaudiopy.parsa

Parametric Spatial Audio (PARSA).

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['axes.grid'] = True

import spaudiopy as spa

N_sph = 3
# Three sources
x_nm = spa.sph.src_to_sh(np.random.randn(3, 10000),
                        [np.pi/2, -np.pi/4, np.pi/3],
                        [np.pi/3, np.pi/2, 2/3 * np.pi], N_sph)
# Diffuse noise
x_nm += np.sqrt(16/(4*np.pi)) * np.random.randn(16, 10000)
spa.plot.sh_rms_map(x_nm, title="Input SHD Signal")

(png, hires.png, pdf)

_images/spaudiopy-parsa-1.png

Memory cached functions

spaudiopy.parsa.pseudo_intensity(ambi_b, win_len=33, f_bp=None, smoothing_order=5, jobs_count=1)[source]

Memoized version of pseudo_intensity(ambi_b, win_len=33, f_bp=None, smoothing_order=5, jobs_count=1)

Direction of arrival (DOA) for each time sample from pseudo-intensity.

Parameters:
  • ambi_b (sig.AmbiBSignal) – Input signal, B-format.

  • win_len (int optional) – Sliding window length.

  • f_bp (tuple(f_lo, f_hi), optional) – Cutoff frequencies for bandpass, ‘None’ to disable.

  • smoothing_order (int, optional) – Apply hanning(smoothing_order) smoothing to output.

  • jobs_count (int or None, optional) – Number of parallel jobs, ‘None’ employs ‘cpu_count’.

Returns:

I_azi, I_zen, I_r (array_like) – Pseudo intensity vector for each time sample.

spaudiopy.parsa.render_bsdm(sdm_p, sdm_phi, sdm_theta, hrirs, jobs_count=None)[source]

Memoized version of render_bsdm(sdm_p, sdm_phi, sdm_theta, hrirs, jobs_count=1)

Binaural SDM Render. Convolves each sample with corresponding hrir. No Post-EQ.

Parameters:
  • sdm_p ((n,) array_like) – Pressure p(t).

  • sdm_phi ((n,) array_like) – Azimuth phi(t).

  • sdm_theta ((n,) array_like) – Colatitude theta(t).

  • hrirs (sig.HRIRs)

  • jobs_count (int or None, optional) – Number of parallel jobs, ‘None’ employs ‘cpu_count’.

Returns:

  • bsdm_l (array_like) – Left binaural impulse response.

  • bsdm_r (array_like) – Right binaural impulse response.

Functions

estimate_num_sources(cov_x[, a, w])

Active source count estimate from signal covariance.

render_binaural_loudspeaker_sdm(sdm_p, ...)

Render sdm signal on loudspeaker setup as binaural synthesis.

render_stereo_sdm(sdm_p, sdm_phi, sdm_theta)

Stereophonic SDM Render IR, with a cos(phi) pannign law.

sdm_post_equalization(ls_sigs, sdm_p, fs, ...)

Post equalization to compensate spectral whitening.

sdm_post_equalization2(ls_sigs, sdm_p, fs, ...)

Post equalization to compensate spectral whitening.

separate_cov(cov_x[, num_cut])

Separate Covariance matrix in signal and noise components.

sh_beamform(w_nm, sig_nm)

Apply spherical harmonics domain (SHD) beamformer.

sh_beamformer_from_pattern(pattern, N_sph, ...)

Get spherical harmonics domain (SHD) beamformer coefficients.

sh_lcmv(cov_x, dirs_azi_c, dirs_zen_c, c_gain)

Spherical Harmonics domain LCMV beamformer.

sh_music(cov_x, num_src, dirs_azi, dirs_zen)

SH domain / Eigenbeam Multiple Signal Classification (EB-MUSIC).

sh_mvdr(cov_x, dirs_azi, dirs_zen)

Spherical Harmonics domain MVDR beamformer.

sh_sector_beamformer(A_nm)

Get sector pressure and intensity beamformers.

spaudiopy.parsa.sh_beamformer_from_pattern(pattern, N_sph, azi_steer, zen_steer)[source]

Get spherical harmonics domain (SHD) beamformer coefficients.

Parameters:
  • pattern (string , or (N+1, ) array_like) – Pattern description, e.g. ‘cardioid’ or modal weights.

  • N_sph (int) – SH order.

  • azi_steer ((J,) array_like) – Azimuth steering directions.

  • zen_steer ((J,) array_like) – Zenith/colatitude steering directions.

Returns:

w_nm ((J, (N+1)**2) numpy.ndarray) – SHD Beamformer weights.

Examples

See spaudiopy.parsa.sh_beamform().

spaudiopy.parsa.sh_beamform(w_nm, sig_nm)[source]

Apply spherical harmonics domain (SHD) beamformer.

Parameters:
  • w_nm (((N+1)**2,) array_like, or (J, (N+1)**2) np.ndarray) – SHD beamformer weights (for J beamformers)

  • sig_nm (((N+1)**2, l) np.ndarray) – SHD signal of length l.

Returns:

y ((J, l) np.ndarray) – Beamformer output signals.

Examples

vecs, _ = spa.grids.load_maxDet(50)
dirs = spa.utils.vec2dir(vecs)
w_nm = spa.parsa.sh_beamformer_from_pattern('cardioid', N_sph,
                                            dirs[:,0], dirs[:,1])
y = spa.parsa.sh_beamform(w_nm, x_nm)
spa.plot.spherical_function_map(spa.utils.rms(y), dirs[:,0], dirs[:,1],
                                TODB=True, title="Output RMS")

(png, hires.png, pdf)

_images/spaudiopy-parsa-2.png
spaudiopy.parsa.estimate_num_sources(cov_x, a=None, w=None)[source]

Active source count estimate from signal covariance.

Based on the relation of consecutive eigenvalues.

Parameters:
  • cov_x ((L, L) numpy.2darray) – Signal covariance.

  • a (float, optional) – Threshold condition (ratio), defaults to 1 + 2/len(cov_x)

  • w ((L,) array_like, optional) – Eigenvalues in ascending order, not using cov_x if available.

Returns:

num_src_est (int) – Number of active sources estimate.

Examples

See spaudiopy.parsa.sh_music().

spaudiopy.parsa.separate_cov(cov_x, num_cut=None)[source]

Separate Covariance matrix in signal and noise components.

Parameters:
  • S_xx ((L, L) numpy.2darray) – Covariance.

  • num_cut (int, optional) – Split point of Eigenvalues, default: parsa.estimate_num_sources().

Returns:

  • S_pp ((L, L) numpy.2darray) – Signal covariance.

  • S_nn ((L, L) numpy.2darray) – Noise (residual) covariance.

Notes

Signal model is \(S_x = S_p + S_n\) .

Examples

S_xx = x_nm @ x_nm.T
S_pp, S_nn = spa.parsa.separate_cov(S_xx, num_cut=3)
fig, axs = plt.subplots(1, 3, constrained_layout=True)
axs[0].matshow(S_xx)
axs[0].set_title("X")
axs[1].matshow(S_pp)
axs[1].set_title("S")
axs[2].matshow(S_nn)
axs[2].set_title("N")

(png, hires.png, pdf)

_images/spaudiopy-parsa-3.png
spaudiopy.parsa.sh_music(cov_x, num_src, dirs_azi, dirs_zen)[source]

SH domain / Eigenbeam Multiple Signal Classification (EB-MUSIC).

Parameters:
  • cov_x ((L, L) numpy.2darray) – SH signal covariance.

  • num_src (int) – Number of sources.

  • dirs_azi ((g,) array_like)

  • dirs_zen ((g,) array_like)

Returns:

P_music ((g,) array_like) – MUSIC (psuedo-) spectrum.

Examples

S_xx = x_nm @ x_nm.T
num_src_est = spa.parsa.estimate_num_sources(S_xx)

vecs, _ = spa.grids.load_maxDet(50)
dirs = spa.utils.vec2dir(vecs)
P_music = spa.parsa.sh_music(S_xx, num_src_est, dirs[:,0], dirs[:,1])
spa.plot.spherical_function_map(P_music, dirs[:,0], dirs[:,1],
                                TODB=True, title="MUSIC spectrum")

(png, hires.png, pdf)

_images/spaudiopy-parsa-4.png
spaudiopy.parsa.sh_mvdr(cov_x, dirs_azi, dirs_zen)[source]

Spherical Harmonics domain MVDR beamformer. SH / Eigenbeam domain minimum variance distortionless response (EB-MVDR). Often employed on signal cov_x = S_xx, instead of noise cov_x = S_nn, then called minimum power distortionless response (MPDR) beamformer.

Parameters:
  • cov_x ((L, L) numpy.2darray) – SH signal (noise) covariance.

  • dirs_azi ((g,) array_like)

  • dirs_zen ((g,) array_like)

Returns:

W_nm ((g, L) numpy.2darray) – MVDR beampattern weights.

References

Rafaely, B. (2015). Fundamentals of Spherical Array Processing. Springer. ch. 7.2.

Examples

S_xx = x_nm @ x_nm.T
num_src_est = spa.parsa.estimate_num_sources(S_xx)
_, S_nn = spa.parsa.separate_cov(S_xx, num_cut=num_src_est)

vecs, _ = spa.grids.load_maxDet(50)
dirs = spa.utils.vec2dir(vecs)
W_nm = spa.parsa.sh_mvdr(S_nn, dirs[:,0], dirs[:,1])
y = spa.parsa.sh_beamform(W_nm, x_nm)
spa.plot.spherical_function_map(spa.utils.rms(y), dirs[:,0], dirs[:,1],
                                TODB=True, title="MVDR output RMS")

(png, hires.png, pdf)

_images/spaudiopy-parsa-5.png
spaudiopy.parsa.sh_lcmv(cov_x, dirs_azi_c, dirs_zen_c, c_gain)[source]

Spherical Harmonics domain LCMV beamformer. SH / Eigenbeam domain Linearly Constrained Minimum Variance (LCMV) beamformer. Often employed on signal cov_x = S_xx, instead of noise cov_x = S_nn, then called linearly constrained minimum power (LCMP) beamformer.

Parameters:
  • cov_x ((L, L) numpy.2darray) – SH signal (noise) covariance.

  • dirs_azi ((g,) array_like)

  • dirs_zen ((g,) array_like)

  • c_gain ((g,) array_like) – Constraints (gain) on points [dirs_azi, dirs_zen].

Returns:

w_nm ((L,) array_like) – LCMV beampattern weights.

References

Rafaely, B. (2015). Fundamentals of Spherical Array Processing. Springer. ch. 7.5.

Examples

S_xx = x_nm @ x_nm.T
num_src_est = spa.parsa.estimate_num_sources(S_xx)
_, S_nn = spa.parsa.separate_cov(S_xx, num_cut=num_src_est)

dirs_azi_c = [np.pi/2, 0., np.pi]
dirs_zen_c = [np.pi/2, np.pi/2, np.pi/4]
c = [1, 0.5, 0]
w_nm = spa.parsa.sh_lcmv(S_nn, dirs_azi_c, dirs_zen_c, c)
spa.plot.sh_coeffs(w_nm)

(png, hires.png, pdf)

_images/spaudiopy-parsa-6.png
spaudiopy.parsa.sh_sector_beamformer(A_nm)[source]

Get sector pressure and intensity beamformers.

Parameters:

A_nm ((J, (N+1)**2), np.ndarray) – SH beamformer matrix, see spa.sph.design_sph_filterbank().

Returns:

A_wxyz (((4*J), (N+2)**2)) – SH sector pattern beamformers.

spaudiopy.parsa.render_stereo_sdm(sdm_p, sdm_phi, sdm_theta)[source]

Stereophonic SDM Render IR, with a cos(phi) pannign law. This is only meant for quick testing.

Parameters:
  • sdm_p ((n,) array_like) – Pressure p(t).

  • sdm_phi ((n,) array_like) – Azimuth phi(t).

  • sdm_theta ((n,) array_like) – Colatitude theta(t).

Returns:

  • ir_l (array_like) – Left impulse response.

  • ir_r (array_like) – Right impulse response.

spaudiopy.parsa.render_binaural_loudspeaker_sdm(sdm_p, ls_gains, ls_setup, fs, post_eq_func='default', **kwargs)[source]

Render sdm signal on loudspeaker setup as binaural synthesis.

Parameters:
  • sdm_p ((n,) array_like) – Pressure p(t).

  • ls_gains ((n, l)) – Loudspeaker (l) gains.

  • ls_setup (decoder.LoudspeakerSetup)

  • fs (int)

  • post_eq_func (None, ‘default’ or function) – Post EQ applied to the loudspeaker signals. ‘default’ calls ‘parsa.post_equalization’, ‘None’ disables (not recommended). You can also provide your custom post-eq-function with the signature post_eq_func(ls_sigs, sdm_p, fs, ls_setup, **kwargs).

Returns:

  • ir_l (array_like) – Left binaural impulse response.

  • ir_r (array_like) – Right binaural impulse response.

spaudiopy.parsa.sdm_post_equalization(ls_sigs, sdm_p, fs, ls_setup, soft_clip=True)[source]

Post equalization to compensate spectral whitening.

Parameters:
  • ls_sigs ((L, S) np.ndarray) – Input loudspeaker signals.

  • sdm_p (array_like) – Reference (sdm) pressure signal.

  • fs (int)

  • ls_setup (decoder.LoudspeakerSetup)

  • soft_clip (bool, optional) – Limit the compensation boost to +6dB.

Returns:

ls_sigs_compensated ((L, S) np.ndarray) – Compensated loudspeaker signals.

References

Tervo, S., et. al. (2015). Spatial Analysis and Synthesis of Car Audio System and Car Cabin Acoustics with a Compact Microphone Array. Journal of the Audio Engineering Society.

spaudiopy.parsa.sdm_post_equalization2(ls_sigs, sdm_p, fs, ls_setup, blocksize=4096, smoothing_order=5)[source]

Post equalization to compensate spectral whitening. This alternative version works on fixed blocksizes with octave band gain smoothing. Sonically, this seems not the preferred version, but it can gain some insight through the band gains which are returned.

Parameters:
  • ls_sigs ((L, S) np.ndarray) – Input loudspeaker signals.

  • sdm_p (array_like) – Reference (sdm) pressure signal.

  • fs (int)

  • ls_setup (decoder.LoudspeakerSetup)

  • blocksize (int)

  • smoothing_order (int) – Block smoothing, increasing Hanning window up to this order.

Returns:

  • ls_sigs_compensated ((L, S) np.ndarray) – Compensated loudspeaker signals.

  • band_gains_list (list) – Each element contains the octave band gain applied as post eq.