sfs.td.nfchoa

Compute NFC-HOA driving functions.

import matplotlib.pyplot as plt
import numpy as np
import sfs
from scipy.signal import unit_impulse

# Plane wave
npw = sfs.util.direction_vector(np.radians(-45))

# Point source
xs = -1.5, 1.5, 0
rs = np.linalg.norm(xs)  # distance from origin
ts = rs / sfs.default.c  # time-of-arrival at origin

# Impulsive excitation
fs = 44100
signal = unit_impulse(512), fs

# Circular loudspeaker array
N = 32  # number of loudspeakers
R = 1.5  # radius
array = sfs.array.circular(N, R)

grid = sfs.util.xyz_grid([-2, 2], [-2, 2], 0, spacing=0.02)

def plot(d, selection, secondary_source, t=0):
    p = sfs.td.synthesize(d, selection, array, secondary_source, grid=grid,
                          observation_time=t)
    sfs.plot2d.level(p, grid)
    sfs.plot2d.loudspeakers(array.x, array.n, selection * array.a, size=0.15)

Functions

driving_signals_25d(delay, weight, sos, …)

Get 2.5-dimensional NFC-HOA driving signals.

driving_signals_3d(delay, weight, sos, …)

Get 3-dimensional NFC-HOA driving signals.

matchedz_zpk(s_zeros, s_poles, s_gain, fs)

Matched-z transform of poles and zeros.

plane_25d(x0, r0, npw, fs[, max_order, c, s2z])

Virtual plane wave by 2.5-dimensional NFC-HOA.

plane_3d(x0, r0, npw, fs[, max_order, c, s2z])

Virtual plane wave by 3-dimensional NFC-HOA.

point_25d(x0, r0, xs, fs[, max_order, c, s2z])

Virtual Point source by 2.5-dimensional NFC-HOA.

point_3d(x0, r0, xs, fs[, max_order, c, s2z])

Virtual point source by 3-dimensional NFC-HOA.

sfs.td.nfchoa.matchedz_zpk(s_zeros, s_poles, s_gain, fs)[source]

Matched-z transform of poles and zeros.

Parameters
  • s_zeros (array_like) – Zeros in the Laplace domain.

  • s_poles (array_like) – Poles in the Laplace domain.

  • s_gain (float) – System gain in the Laplace domain.

  • fs (int) – Sampling frequency in Hertz.

Returns

  • z_zeros (numpy.ndarray) – Zeros in the z-domain.

  • z_poles (numpy.ndarray) – Poles in the z-domain.

  • z_gain (float) – System gain in the z-domain.

sfs.td.nfchoa.plane_25d(x0, r0, npw, fs, max_order=None, c=None, s2z=<function matchedz_zpk>)[source]

Virtual plane wave by 2.5-dimensional NFC-HOA.

\[D(\phi_0, s) = 2\e{\frac{s}{c}r_0} \sum_{m=-M}^{M} (-1)^m \Big(\frac{s}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu \prod_{l=1}^{\nu} \frac{s^2}{(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2} \e{\i m(\phi_0 - \phi_\text{pw})}\]

The driving function is represented in the Laplace domain, from which the recursive filters are designed. \(\sigma_l + \i\omega_l\) denotes the complex roots of the reverse Bessel polynomial. The number of second-order sections is \(\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor\), whereas the number of first-order section \(\mu\) is either 0 or 1 for even and odd \(|m|\), respectively.

Parameters
  • x0 ((N, 3) array_like) – Sequence of secondary source positions.

  • r0 (float) – Radius of the circular secondary source distribution.

  • npw ((3,) array_like) – Unit vector (propagation direction) of plane wave.

  • fs (int) – Sampling frequency in Hertz.

  • max_order (int, optional) – Ambisonics order.

  • c (float, optional) – Speed of sound in m/s.

  • s2z (callable, optional) – Function transforming s-domain poles and zeros into z-domain, e.g. matchedz_zpk(), scipy.signal.bilinear_zpk().

Returns

  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of numpy.ndarray) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) numpy.ndarray) – Phase shift in radians.

  • selection ((N,) numpy.ndarray) – Boolean array containing only True indicating that all secondary source are “active” for NFC-HOA.

  • secondary_source_function (callable) – A function that can be used to create the sound field of a single secondary source. See sfs.td.synthesize().

Examples

delay, weight, sos, phaseshift, selection, secondary_source = \
    sfs.td.nfchoa.plane_25d(array.x, R, npw, fs)
d = sfs.td.nfchoa.driving_signals_25d(
        delay, weight, sos, phaseshift, signal)
plot(d, selection, secondary_source)
_images/sfs-td-nfchoa-2.svg
sfs.td.nfchoa.point_25d(x0, r0, xs, fs, max_order=None, c=None, s2z=<function matchedz_zpk>)[source]

Virtual Point source by 2.5-dimensional NFC-HOA.

\[D(\phi_0, s) = \frac{1}{2\pi r_\text{s}} \e{\frac{s}{c}(r_0-r_\text{s})} \sum_{m=-M}^{M} \Big(\frac{s-\frac{c}{r_\text{s}}\sigma_0}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu \prod_{l=1}^{\nu} \frac{(s-\frac{c}{r_\text{s}}\sigma_l)^2-(\frac{c}{r_\text{s}}\omega_l)^2} {(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2} \e{\i m(\phi_0 - \phi_\text{s})}\]

The driving function is represented in the Laplace domain, from which the recursive filters are designed. \(\sigma_l + \i\omega_l\) denotes the complex roots of the reverse Bessel polynomial. The number of second-order sections is \(\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor\), whereas the number of first-order section \(\mu\) is either 0 or 1 for even and odd \(|m|\), respectively.

Parameters
  • x0 ((N, 3) array_like) – Sequence of secondary source positions.

  • r0 (float) – Radius of the circular secondary source distribution.

  • xs ((3,) array_like) – Virtual source position.

  • fs (int) – Sampling frequency in Hertz.

  • max_order (int, optional) – Ambisonics order.

  • c (float, optional) – Speed of sound in m/s.

  • s2z (callable, optional) – Function transforming s-domain poles and zeros into z-domain, e.g. matchedz_zpk(), scipy.signal.bilinear_zpk().

Returns

  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of numpy.ndarray) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) numpy.ndarray) – Phase shift in radians.

  • selection ((N,) numpy.ndarray) – Boolean array containing only True indicating that all secondary source are “active” for NFC-HOA.

  • secondary_source_function (callable) – A function that can be used to create the sound field of a single secondary source. See sfs.td.synthesize().

Examples

delay, weight, sos, phaseshift, selection, secondary_source = \
    sfs.td.nfchoa.point_25d(array.x, R, xs, fs)
d = sfs.td.nfchoa.driving_signals_25d(
        delay, weight, sos, phaseshift, signal)
plot(d, selection, secondary_source, t=ts)
_images/sfs-td-nfchoa-3.svg
sfs.td.nfchoa.plane_3d(x0, r0, npw, fs, max_order=None, c=None, s2z=<function matchedz_zpk>)[source]

Virtual plane wave by 3-dimensional NFC-HOA.

\[D(\phi_0, s) = \frac{\e{\frac{s}{c}r_0}}{r_0} \sum_{n=0}^{N} (-1)^n (2n+1) P_{n}(\cos\Theta) \Big(\frac{s}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu \prod_{l=1}^{\nu} \frac{s^2}{(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}\]

The driving function is represented in the Laplace domain, from which the recursive filters are designed. \(\sigma_l + \i\omega_l\) denotes the complex roots of the reverse Bessel polynomial. The number of second-order sections is \(\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor\), whereas the number of first-order section \(\mu\) is either 0 or 1 for even and odd \(|m|\), respectively. \(P_{n}(\cdot)\) denotes the Legendre polynomial of degree \(n\), and \(\Theta\) the angle between \((\theta, \phi)\) and \((\theta_\text{pw}, \phi_\text{pw})\).

Parameters
  • x0 ((N, 3) array_like) – Sequence of secondary source positions.

  • r0 (float) – Radius of the spherical secondary source distribution.

  • npw ((3,) array_like) – Unit vector (propagation direction) of plane wave.

  • fs (int) – Sampling frequency in Hertz.

  • max_order (int, optional) – Ambisonics order.

  • c (float, optional) – Speed of sound in m/s.

  • s2z (callable, optional) – Function transforming s-domain poles and zeros into z-domain, e.g. matchedz_zpk(), scipy.signal.bilinear_zpk().

Returns

  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of numpy.ndarray) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) numpy.ndarray) – Phase shift in radians.

  • selection ((N,) numpy.ndarray) – Boolean array containing only True indicating that all secondary source are “active” for NFC-HOA.

  • secondary_source_function (callable) – A function that can be used to create the sound field of a single secondary source. See sfs.td.synthesize().

sfs.td.nfchoa.point_3d(x0, r0, xs, fs, max_order=None, c=None, s2z=<function matchedz_zpk>)[source]

Virtual point source by 3-dimensional NFC-HOA.

\[D(\phi_0, s) = \frac{\e{\frac{s}{c}(r_0-r_\text{s})}}{4 \pi r_0 r_\text{s}} \sum_{n=0}^{N} (2n+1) P_{n}(\cos\Theta) \Big(\frac{s-\frac{c}{r_\text{s}}\sigma_0}{s-\frac{c}{r_0}\sigma_0}\Big)^\mu \prod_{l=1}^{\nu} \frac{(s-\frac{c}{r_\text{s}}\sigma_l)^2-(\frac{c}{r_\text{s}}\omega_l)^2} {(s-\frac{c}{r_0}\sigma_l)^2+(\frac{c}{r_0}\omega_l)^2}\]

The driving function is represented in the Laplace domain, from which the recursive filters are designed. \(\sigma_l + \i\omega_l\) denotes the complex roots of the reverse Bessel polynomial. The number of second-order sections is \(\nu = \big\lfloor\tfrac{|m|}{2}\big\rfloor\), whereas the number of first-order section \(\mu\) is either 0 or 1 for even and odd \(|m|\), respectively. \(P_{n}(\cdot)\) denotes the Legendre polynomial of degree \(n\), and \(\Theta\) the angle between \((\theta, \phi)\) and \((\theta_\text{s}, \phi_\text{s})\).

Parameters
  • x0 ((N, 3) array_like) – Sequence of secondary source positions.

  • r0 (float) – Radius of the spherial secondary source distribution.

  • xs ((3,) array_like) – Virtual source position.

  • fs (int) – Sampling frequency in Hertz.

  • max_order (int, optional) – Ambisonics order.

  • c (float, optional) – Speed of sound in m/s.

  • s2z (callable, optional) – Function transforming s-domain poles and zeros into z-domain, e.g. matchedz_zpk(), scipy.signal.bilinear_zpk().

Returns

  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of numpy.ndarray) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) numpy.ndarray) – Phase shift in radians.

  • selection ((N,) numpy.ndarray) – Boolean array containing only True indicating that all secondary source are “active” for NFC-HOA.

  • secondary_source_function (callable) – A function that can be used to create the sound field of a single secondary source. See sfs.td.synthesize().

sfs.td.nfchoa.driving_signals_25d(delay, weight, sos, phaseshift, signal)[source]

Get 2.5-dimensional NFC-HOA driving signals.

Parameters
  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of array_like) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) array_like) – Phase shift in radians.

  • signal ((L,) array_like + float) – Excitation signal consisting of (mono) audio data and a sampling rate (in Hertz). A DelayedSignal object can also be used.

Returns

DelayedSignal – A tuple containing the delayed signals (in a numpy.ndarray with shape (L, N)), followed by the sampling rate (in Hertz) and a (possibly negative) time offset (in seconds).

sfs.td.nfchoa.driving_signals_3d(delay, weight, sos, phaseshift, signal)[source]

Get 3-dimensional NFC-HOA driving signals.

Parameters
  • delay (float) – Overall delay in seconds.

  • weight (float) – Overall weight.

  • sos (list of array_like) – Second-order section filters scipy.signal.sosfilt().

  • phaseshift ((N,) array_like) – Phase shift in radians.

  • signal ((L,) array_like + float) – Excitation signal consisting of (mono) audio data and a sampling rate (in Hertz). A DelayedSignal object can also be used.

Returns

DelayedSignal – A tuple containing the delayed signals (in a numpy.ndarray with shape (L, N)), followed by the sampling rate (in Hertz) and a (possibly negative) time offset (in seconds).