GCC-PHAT → SRP-PHAT acoustic source localization over a known microphone-array geometry, backed by a Rust NIF.
One solve fuses a single time-aligned frame-set (one PCM frame per
emplacement) against the array's known WGS-84 ECEF geometry into zero or
more localized ExSrpPhat.Source structs.
Coordinate frame & units
- Positions are WGS-84 ECEF meters. Slant range is straight-line Euclidean (chord) distance — sound travels the chord, not a surface arc.
- Speed of sound is
343.0 m/s(~20 °C). - Use
ExSrpPhat.Geoto convert lat/lon/alt → ECEF when building geometry.
Example
iex> geometry = %{
...> sample_rate_hz: 4_000,
...> emplacements: [
...> %{emplacement_id: :a, ecef: ExSrpPhat.Geo.latlon_to_ecef(35.0, -106.0, 1600.0)},
...> %{emplacement_id: :b, ecef: ExSrpPhat.Geo.latlon_to_ecef(35.0006, -106.0, 1600.0)},
...> %{emplacement_id: :c, ecef: ExSrpPhat.Geo.latlon_to_ecef(35.0, -106.0008, 1600.0)},
...> %{emplacement_id: :d, ecef: ExSrpPhat.Geo.latlon_to_ecef(35.0004, -106.0004, 1670.0)}
...> ]
...> }
iex> frames = Enum.map(geometry.emplacements, &%{emplacement_id: &1.emplacement_id, samples: List.duplicate(0.0, 16)})
iex> {:ok, sources} = ExSrpPhat.localize(frames, geometry)
iex> is_list(sources)
true
Summary
Functions
Localize acoustic sources from a time-aligned frame-set.
Types
Functions
@spec localize([frame()], geometry(), keyword()) :: {:ok, [ExSrpPhat.Source.t()]} | {:error, term()}
Localize acoustic sources from a time-aligned frame-set.
frames is a list of %{emplacement_id: id, samples: [float]}; every frame
must share the same sample length. geometry carries the sample rate and one
ECEF position per emplacement. Frames are matched to geometry by
emplacement_id (order-independent); the two id sets must be identical.
opts (all optional) tune the search — see ExSrpPhat.Codec.pack_opts/1 for
keys and defaults (:grid_extent_m, :coarse_res_m, :fine_res_m,
:min_peak_ratio, :max_sources).
Returns {:ok, [%ExSrpPhat.Source{}]} or {:error, reason}. Input is fully
validated in Elixir before crossing the NIF boundary.