Range and depth dependence

When describing underwater environments, we often need to work with quantities that vary with position. Some quantities are constant, while others may vary with depth, range, or 3D position (e.g. sound speed profile, bathymetry, etc). We introduce a consistent representation of fields to help formalize position-dependent quantities.

Interface

Fields that do not vary with position are considered constant, and are represented by scalars. If a field may vary only with depth, but not with horizontal position, it is considered DepthDependent. On the other hand, if it may vary with any positional coordinate, it is considered PositionDependent. Varying fields are represented by data types that are subtypes of the appropriate abstract type (DepthDependent or PositionDependent).

DepthDependent

Quantity that may vary with depth, but not with range (x or y coordinate).

PositionDependent

Quantity that may vary with depth and range (x, y and/or z coordinate).

To get the value of a field at a given position, we use the value function:

value(q)
value(q, pos)

Get the value of the varying quantity q at the given position pos. pos may be specified as a (x, y, z) tuple, a (x, z) tuple, or a z value.

Examples

value(q)             # get value of a constant quantity
value(q, -10)        # get value of a depth-dependent quantity at z=-10
value(q, (1000,-10)) # get value of a position-dependent quantity at x=1000, z=-10
value(q, (0,0,-10))  # get value of a position-dependent quantity at (0,0,-10)

We can also check if a field is constant or range-dependent:

is_constant(q)

Return true if the quantity q is a constant, false if it could depend on position.

is_range_dependent(q)

Return true if the quantity q may be range-dependent, false if it is guaranteed to not depend on x or y coordinate.

Fields that only vary with depth are neither constant nor range-dependent.

Some propagation models require knowledge of the extreme values of a field. These can be obtained using the minimum and maximum functions:

minimum(q)

Get the minimum value of a field quantity q.

maximum(q)

Get the maximum value of a field quantity q.

Implementations

Constants

Scalars are trivially constant fields:

let q = 1500
  @show q
  @show is_constant(q)
  @show is_range_dependent(q)
  @show value(q)
  @show value(q, -10)
  @show value(q, (1000, -10))
  @show value(q, (0, 0, -10))
  @show minimum(q)
  @show maximum(q)
end;
q = 1500
is_constant(q) = true
is_range_dependent(q) = false
value(q) = 1500
value(q, -10) = 1500
value(q, (1000, -10)) = 1500
value(q, (0, 0, -10)) = 1500
minimum(q) = 1500
maximum(q) = 1500

They can be used in environmental descriptions. For example, iso-velocity environments can be described using a constant sound speed:

env = UnderwaterEnvironment(soundspeed=1500)

Sampled fields

Position-dependent fields can be defined using data samples at a set of positions. Values at other positions are obtained by interpolation. The SampledField() function creates a sampled field from a set of data samples:

SampledField(v; x)
SampledField(v; z)
SampledField(v; x, y)
SampledField(v; x, z)
SampledField(v; x, y, z)

Create a sampled field from a data v that may depend on position. For 1D fields, the x or z coordinate is required, and v is a vector. For 2D fields, the x and y coordinates or the x and z coordinates are required, and v is a matrix. For 3D fields, the x, y, and z coordinates are required, and v is a 3D array.

Keyword argument interp is used to specify the interpolation method. :linear interpolation is supported for 1D, 2D and 3D fields. For 2D and 3D fields, the data must be sampled on a regular grid. For uniformly sampled 1D fields, :cubic interpolation is also supported.

We can understand how to use SampledField by looking at some examples. Let’s create an environment with a depth-dependent sound speed profile:

env = UnderwaterEnvironment(
  soundspeed = SampledField([1500, 1520]; z=[0, -100])
)

let q = env.soundspeed
  @show q
  @show is_constant(q)
  @show is_range_dependent(q)
  @show value(q, 0)
  @show value(q, -50)
  @show value(q, -100)
  @show value(q, (1000, -50))
  @show value(q, (0, 0, -50))
  @show minimum(q)
  @show maximum(q)
  plot(q)
end
q = SampledField(z-varying, 2 samples)
is_constant(q) = false
is_range_dependent(q) = false
value(q, 0) = 1500.0
value(q, -50) = 1510.0
value(q, -100) = 1520.0
value(q, (1000, -50)) = 1510.0
value(q, (0, 0, -50)) = 1510.0
minimum(q) = 1500.0
maximum(q) = 1520.0

The default interpolation method is linear, but we can use cubic interpolation by specifying interp=:cubic:

plot(SampledField([1500, 1490, 1520]; z=0:-10:-20))
plot!(SampledField([1500, 1490, 1520]; z=0:-10:-20, interp=:cubic))

Another example is a range-dependent bathymetry:

env = UnderwaterEnvironment(
  bathymetry = SampledField([100, 110, 105, 110]; x=[0, 1000, 1500, 2000])
)

plot(env; xlims=(0,2000))

2D and 3D sampled fields can be created by specifying the x, y, and z coordinates. For example, a 2D field can be created using:

let q = SampledField([0.0 1.0; 1.0 2.0]; x=[0.0, 20.0], y=[0.0, 20.0])
  @show q
  @show is_constant(q)
  @show is_range_dependent(q)
  @show value(q, (10, 10, 0))
  @show value(q, (10, 10, -10))
  @show minimum(q)
  @show maximum(q)
  plot(q)
end
q = SampledField(xy-varying, 2×2 samples)
is_constant(q) = false
is_range_dependent(q) = true
value(q, (10, 10, 0)) = 1.0
value(q, (10, 10, -10)) = 1.0
minimum(q) = 0.0
maximum(q) = 2.0

Custom fields

We may define a custom field type by subtyping DepthDependent or PositionDependent. For example, we can define a Munk sound speed profile:

struct MunkSSP <: UnderwaterAcoustics.DepthDependent end

function (::MunkSSP)(pos)
  ϵ = 0.00737
= 2.0 * (-pos.z - 1300.0) / 1300.0
  1500.0 * (1.0 + ϵ * (z̃ - 1 + exp(-z̃)))
end

Base.minimum(::MunkSSP) = 1500.0    # 1.3 km depth
Base.maximum(::MunkSSP) = 1654.0    # 11 km depth (maximum depth of the ocean)

let q = MunkSSP()
  @show q
  @show is_constant(q)
  @show is_range_dependent(q)
  @show value(q, -1300)
  @show value(q, (100, 100, -1500))
  @show minimum(q)
  @show maximum(q)
  plot(q, -11000:0; xlabel="Sound speed (m/s)")
end
q = Main.Notebook.MunkSSP()
is_constant(q) = false
is_range_dependent(q) = false
value(q, -1300) = 1500.0
value(q, (100, 100, -1500)) = 1500.4735275294795
minimum(q) = 1500.0
maximum(q) = 1654.0