hedrekao
HF deploy: clean snapshot without local artifacts
a361db3
"""Spatial audio processing and Direction-of-Arrival (DoA) estimation."""
import logging
import numpy as np
log = logging.getLogger(__name__)
def estimate_direction_from_mixing_matrix(
mixing_matrix_column: np.ndarray,
) -> float:
"""
Estimate Direction of Arrival (DoA) from ICA mixing matrix column.
Assumes 4-channel hearing aid microphone array:
- Channel 0: Left Front (LF)
- Channel 1: Left Rear (LR)
- Channel 2: Right Front (RF)
- Channel 3: Right Rear (RR)
Args:
mixing_matrix_column: Single column from ICA mixing matrix (length 4)
Returns:
Azimuth angle in degrees (0°=front, 90°=right, 180°=rear, 270°=left)
"""
if len(mixing_matrix_column) != 4:
log.warning(f"Expected 4 channel weights, got {len(mixing_matrix_column)}")
return 0.0
w = mixing_matrix_column
# Left (0,1) vs Right (2,3) balance
left_energy = (np.abs(w[0]) + np.abs(w[1])) / 2
right_energy = (np.abs(w[2]) + np.abs(w[3])) / 2
lr_ratio = (right_energy - left_energy) / (right_energy + left_energy + 1e-10)
# Front (0,2) vs Back (1,3) balance
front_energy = (np.abs(w[0]) + np.abs(w[2])) / 2
back_energy = (np.abs(w[1]) + np.abs(w[3])) / 2
fb_ratio = (front_energy - back_energy) / (front_energy + back_energy + 1e-10)
# Convert to angle using arctan2
azimuth = np.degrees(np.arctan2(lr_ratio, fb_ratio))
azimuth = (azimuth + 360) % 360 # Normalize to [0, 360)
return float(azimuth)
def estimate_direction_from_tdoa(
tdoa_estimates: dict,
) -> float:
"""
Estimate direction from Time Difference of Arrival (TDOA).
Args:
tdoa_estimates: Dictionary with keys like 'lr_tdoa', 'fb_tdoa'
containing time differences in samples
Returns:
Azimuth angle in degrees
"""
# This is a placeholder for TDOA-based DoA estimation
# Actual implementation depends on microphone geometry and TDOA calculation
log.warning("TDOA-based DoA estimation not yet implemented")
return 0.0