Channel geometry from impulse response
This tutorial is adapted from Example C
presented in:
- Mandar Chitre, “Differentiable Ocean Acoustic Propagation Modeling,” in OCEANS 2023 IEEE/MTS – Limerick, 5-8 June 2023.
Problem statement
Consider a scenario where a bottom-mounted sensor is deployed on a sub-surface mooring at an unknown altitude over the seabed. The exact location of the sensor is unknown, but we know the general area where it is deployed. The sensor is equipped with an acoustic transponder that we can query from a surface unit when we are within a 250 m range of it. We deploy the transducer of the surface unit from the boat on a 7 m rope with a weight attached. Due to currents, the transducer is not hanging perfectly vertically, and so it’s exact depth d1
is not known. The depth sounder of our boat tells us that the water depth h
is 20 m, and the Captain of the boat assures us that the bathymetry is quite flat. We query the transponder and get a response. The broadband acoustic response from the transponder allows us to estimate the delays of 4 multipath arrivals. We wish to estimate the depth d2
of the sensor and the range r
between the boat and the sensor using the multipath arrival delays.
Dataset
To illustrate this idea, let us generate a synthetic dataset with d1 = 7.2
m, d2 = 12.7
m, h = 20
m, and r = 97.3
m. Since we have an range-independent iso-velocity environment, we can use the PekerisRayTracer
(otherwise we could use the RaySolver
):
using UnderwaterAcoustics
function model(h, r, d1, d2)
= UnderwaterEnvironment(bathymetry=h)
env = PekerisRayTracer(env)
pm = AcousticSource(r, -d2, 1000.0)
tx = AcousticReceiver(0.0, -d1)
rx = arrivals(pm, tx, rx)
arr = getfield.(arr, :t) # get a.t for each arrival a in arr
t 2:end] .- t[1]) .* 1000 # relative time in milliseconds
(t[end
= model(20, 97.3, 7.2, 12.7) data
6-element Vector{Float64}:
1.2078734494638532
1.2340398375722539
6.4705086705396235
3.755897382140966
10.919625105605624
10.987838758289167
Probabilistic model
We can model this as a Bayesian inference problem using Turing.jl
and some reasonable priors:
using Turing
@model function pmodel(data)
~ Normal(20.0, 0.1)
h ~ Uniform(0.0, 250.0)
r ~ Normal(7.0, 1.0)
d1 ~ Uniform(0.0, 20.0)
d2 = model(h, r, d1, d2)
μ ~ MvNormal(μ, 0.1)
data end
= vi(pmodel(data), ADVI(10, 10000))
q
# extract mean values of parameters h, r, d1 and d2
= mean(rand(q, 10000); dims=2) μ
4×1 Matrix{Float64}:
20.001392780917683
96.70268204492135
7.203404350594817
12.764047903939089
We see that the estimated values of h
, r
, d1
and d2
are fairly close to the ground truth values. We can also plot the uncertainty in the estimates:
using StatsPlots
plot(h -> pdf(q, [h, μ[2], μ[3], μ[4]]), 18, 22; xlabel="h", legend=false)
plot(r -> pdf(q, [μ[1], r, μ[3], μ[4]]), 50, 150; xlabel="r", legend=false)
plot(d1 -> pdf(q, [μ[1], μ[2], d1, μ[4]]), 5, 9; xlabel="d1", legend=false)
plot(d2 -> pdf(q, [μ[1], μ[2], μ[3], d2]), 0, 20; xlabel="d2", legend=false)