File size: 2,114 Bytes
a361db3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""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