HOA7-Spatial-Decoder / tests /test_phase3_vision.py
woodfireind's picture
HOA7 Spatial Field Decoder (hoa64 v0.5.0): 7th-order Ambisonics encode/decode, Wigner-D rotation, DOA analysis, vision fuse, diffusion conditioning
570b87b verified
Raw
History Blame Contribute Delete
3.02 kB
"""Phase 3 vision + Qwythos API smoke tests."""
from __future__ import annotations
import json
import sys
import threading
import time
from pathlib import Path
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from hoa64.analysis import angular_error_deg
from hoa64.server import TOOL_SCHEMA, handle_analyze
from hoa64.vision import encode_boxes_to_hoa, fuse_reports, report_from_boxes
def test_vision_point_doa():
rep = report_from_boxes(
[{"az": 45.0, "el": -10.0, "kind": "point", "weight": 1.0, "label": "p"}],
max_order=3,
)
err = angular_error_deg(45.0, -10.0, rep.doa_az_deg, rep.doa_el_deg)
# intensity on static field works; peak should be tight
perr = angular_error_deg(45.0, -10.0, rep.peak_az_deg, rep.peak_el_deg)
assert perr < 8.0, f"peak err={perr} doa=({rep.doa_az_deg},{rep.doa_el_deg})"
assert rep.kind == "spatial_vision"
assert rep.sources_hint[0]["label"] == "p"
def test_vision_box_lobe_near_center():
hoa = encode_boxes_to_hoa(
[{"az": 0.0, "el": 0.0, "w_deg": 15, "h_deg": 15, "weight": 1.0}],
max_order=3,
n_azi=48,
n_el=24,
)
assert hoa.shape[0] == 64
assert np.linalg.norm(hoa) > 0
# W channel should dominate for broad front lobe
assert abs(hoa[0]) > 0
def test_fuse_agreement():
audio = {"doa_az_deg": 10.0, "doa_el_deg": 0.0, "energy": 1.0}
vision = {"doa_az_deg": 12.0, "doa_el_deg": 1.0, "energy": 0.8}
f = fuse_reports(audio, vision)
assert f["agreement"] is True
assert f["angular_separation_deg"] < 15
assert "one_liner" in f
def test_fuse_disagreement():
audio = {"doa_az_deg": 0.0, "doa_el_deg": 0.0, "energy": 1.0}
vision = {"doa_az_deg": 90.0, "doa_el_deg": 0.0, "energy": 1.0}
f = fuse_reports(audio, vision)
assert f["agreement"] is False
assert f["angular_separation_deg"] > 80
def test_handle_analyze_vision_and_demo():
d = handle_analyze({"mode": "demo_scene", "order": 2})
assert d["schema"].startswith("spatial-hoa")
assert "one_liner" in d
v = handle_analyze(
{
"mode": "vision",
"order": 3,
"boxes": [{"az": -30, "el": 5, "kind": "ray", "label": "x"}],
}
)
assert v["kind"] == "spatial_vision"
err = angular_error_deg(-30, 5, v["peak_az_deg"], v["peak_el_deg"])
assert err < 10.0
def test_tool_schema_shape():
assert TOOL_SCHEMA["type"] == "function"
assert TOOL_SCHEMA["function"]["name"] == "spatial_analyze"
if __name__ == "__main__":
test_vision_point_doa()
print("OK test_vision_point_doa")
test_vision_box_lobe_near_center()
print("OK test_vision_box_lobe_near_center")
test_fuse_agreement()
print("OK test_fuse_agreement")
test_fuse_disagreement()
print("OK test_fuse_disagreement")
test_handle_analyze_vision_and_demo()
print("OK test_handle_analyze_vision_and_demo")
test_tool_schema_shape()
print("OK test_tool_schema_shape")