File size: 2,131 Bytes
570b87b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | """Decode HOA-7 coefficients to samples on the sphere."""
from __future__ import annotations
import numpy as np
from .basis import MAX_ORDER, sh_sn3d, sh_sn3d_batch, sphere_grid
def decode_directions(
hoa: np.ndarray,
azimuths: np.ndarray | float,
elevations: np.ndarray | float,
*,
degrees: bool = True,
max_order: int = MAX_ORDER,
) -> np.ndarray:
"""Sample field a · Y(Ω) at given directions.
hoa: (C,) or (C, T)
returns: (...) or (..., T)
"""
a = np.asarray(hoa, dtype=np.float64)
nch = (max_order + 1) ** 2
# Allow shorter coefficient vectors (truncated order) or longer (ignore tail).
if a.ndim == 1:
aa = np.zeros(nch, dtype=np.float64)
n = min(nch, a.shape[0])
aa[:n] = a[:n]
Y = sh_sn3d(azimuths, elevations, degrees=degrees, max_order=max_order)
return np.einsum("...c,c->...", Y[..., :nch], aa)
if a.ndim == 2:
aa = np.zeros((nch, a.shape[1]), dtype=np.float64)
n = min(nch, a.shape[0])
aa[:n] = a[:n, :]
Y = sh_sn3d(azimuths, elevations, degrees=degrees, max_order=max_order)
return np.einsum("...c,ct->...t", Y[..., :nch], aa)
raise ValueError("hoa must be (C,) or (C,T)")
def decode_grid(
hoa: np.ndarray,
n_azi: int = 72,
n_el: int = 36,
*,
degrees: bool = True,
max_order: int = MAX_ORDER,
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Decode on a product sphere grid.
Returns azi, el, samples with samples shape (n_azi, n_el) or (n_azi, n_el, T).
"""
azi, el, _ = sphere_grid(n_azi, n_el, degrees=degrees)
AA, EE = np.meshgrid(azi, el, indexing="ij")
samp = decode_directions(hoa, AA, EE, degrees=degrees, max_order=max_order)
return azi, el, samp
def beamform(
hoa: np.ndarray,
azimuth: float,
elevation: float,
*,
degrees: bool = True,
max_order: int = MAX_ORDER,
) -> float | np.ndarray:
"""Look / listen toward one direction: scalar (or time series) readout."""
return decode_directions(
hoa, azimuth, elevation, degrees=degrees, max_order=max_order
)
|