Modeling arrays¶
In array signal processing, sensor arrays consists a group of sensors (acoustic,
electromagnetic, etc.) arranged in special geometry patterns. They find wide
applications in radar, sonar, audio and speech processing, geophysics, and
communications. In doatools
, we focus on their application in
direction-of-arrival (DOA) estimation.
import doatools.model as model
# Create a 10-element ULA with inter-element spacing 0.5.
ula = model.UniformLinearArray(10, 0.5)
API references¶
-
class
doatools.model.arrays.
ArrayDesign
(locations, name, perturbations=[], element=<doatools.model.array_elements.IsotropicScalarSensor object>)[source]¶ Bases:
object
Base class for all array designs.
Arrays can be 1D, 2D, or 3D. Consider the standard cartesian coordinate system. We define 1D, 2D, and 3D arrays as follows:
- 1D arrays are linear arrays along the x-axis.
- 2D arrays are planar arrays lying within the xy-plane.
- 3D arrays are not restricted, whose element can exist anywhere in the 3D space.
We store the element locations with an m x d array, where m denotes the number of elements (size) of the array.
- For 1D arrays, d equals one, and the i-th row of the m x 1 array stores the x coordinate of the i-th element.
- For 2D arrays, d equals two, and the i-th row of the m x 2 array stores the x and y coordinates of the i-th element.
- For 3D arrays, d equals three, and the i-th row of the m x 3 array stores the x, y, and z coordinates of the i-th element.
While this class is generally intended for internal use. You can also use this class to create custom arrays. Just to make sure that you do not modify
locations
after creating the array.Parameters: - locations – A list or ndarray specifying the element locations. For
1D arrays,
locations
can be either a 1D list/ndarray, or an m x 1 list/ndarray, where m is the number of elements. For 2D or 3D arrays,locations
must be a 2D list/ndarray of shape m x d, where d is 2 or 3. If the input is an ndarray, it will not be copied and should not be changed after creating the array design. - name (str) – Name of the array design.
- perturbations (list or dict) –
If a list is given, it should be a list of
ArrayPerturbation
.If a dictionary is given, it should be a dictionary containing the perturbation definitions. Correspinding
ArrayPerturbation
will be created automatically. The keys should be among the following:'location_errors'
'gain_errors'
(relative, -0.2 means 0.8 * original gain)'phase_errors'
(in radians)'mutual_coupling'
The values in the dictionary are two-element tuples. The first element is an
ndarray
representing the parameters, and the second element is a boolean specifying whether these parameters are known in prior. - element (ArrayElement) – Array element
(sensor) used in this array. Default value is an instance of
IsotropicScalarSensor
.
Notes
Array designs are generally not changed after creation. Because array design objects are passed around when computing steering matrices, weight functions, etc., having a mutable internal state leads to more complexities and potential unexpected results. Although the internal states are generally accessible in Python, please refrain from modifying them unless you are aware of the side effects.
-
name
¶ Retrieves the name of this array.
-
size
¶ Retrieves the number of elements in the array.
-
output_size
¶ Retrieves the output size of the array.
In generate, the output size should be equal to
size
. However, for vector sensor arrays, the output size is greater than the array size.
-
element_locations
¶ Retrieves the nominal element locations.
Returns: An M x d matrix, where M is the number of elements and d is the number of dimensions of the nominal array.
-
actual_element_locations
¶ Retrieves the actual element locations, considering location errors.
Returns: An M x d matrix, where M is the number of elements and d is the maximum of the following two: - number of dimensions of the nominal array;
- number of dimensions of the sensor location errors.
-
element
¶ Retrieves the array element.
-
is_perturbed
¶ Returns if the array contains perturbations.
-
ndim
¶ Retrieves the number of dimensions of the nominal array.
The number of dimensions is defined as the number of columns of the ndarray storing the nominal array element locations. It does not reflect the number of dimensions of the minimal subspace in which the nominal array lies. For instance, if the element locations are given by
[[0, 0], [1, 1], [2, 2]]
,ndim
equals to 2 instead of 1, despite the fact that this array is a linear array.Perturbations do not affect this value.
-
actual_ndim
¶ Retrieves the number of dimensions of the array, considering location errors.
-
get_perturbation_params
(ptype)[source]¶ Retrieves the parameters for the specified perturbation type.
-
perturbations
¶ Retrieves a list of all perturbations.
-
get_perturbed_copy
(perturbations, new_name=None)[source]¶ Returns a copy of this array design but with the specified perturbations.
The specified perturbations will replace the existing ones.
Notes
The default implementation performs a shallow copy of all existing fields using :meth:
~copy.copy
. Override this method if special operations are required.Parameters: - perturbations (list or dict) –
If a list is given, it should be a list of
ArrayPerturbation
.If a dictionary is given, it should be a dictionary containing the perturbation definitions. Correspinding
ArrayPerturbation
will be created automatically. The keys should be among the following:'location_errors'
'gain_errors'
(relative, -0.2 means 0.8 * original gain)'phase_errors'
(in radians)'mutual_coupling'
The values in the dictionary are two-element tuples. The first element is an
ndarray
representing the parameters, and the second element is a boolean specifying whether these parameters are known in prior. - new_name (str) – An optional new name for the resulting array design. If not provided, the name of the original array design will be used.
- perturbations (list or dict) –
-
get_perturbation_free_copy
(new_name=None)[source]¶ Returns a perturbation-free copy of this array design.
Notes
The default implementation performs a shallow copy of all existing fields using :meth:
~copy.copy
. Override this method if special operations are required.Parameters: new_name (str) – An optional new name for the resulting array design. If not provided, the name of the original array design will be used.
-
steering_matrix
(sources, wavelength, compute_derivatives=False, perturbations='all', flatten=True)[source]¶ Creates the steering matrix for the given DOAs.
Given \(K\) sources, denoted by \(\mathbf{\theta}\), and \(M\) sensors whose the actual sensor locations (after considering locations errors if exist) are denoted by \(\mathbf{d}\), the steering matrix is calculated as
\[\mathbf{A} = \mathbf{C} (\mathbf{F}(\mathbf{\theta}, \mathbf{d}) \odot \mathbf{A}_0(\mathbf{\theta}, \mathbf{d})).\]Here \(\odot\) denotes the Hadamard product.
\(\mathbf{A}_0\) is an \(M \times K\) matrix calculated from the phase delays between the sourcess, \(\mathbf{\theta}\), and the sensor locations, \(\mathbf{d}\):
\[\mathbf{A}_0 = \begin{bmatrix} \mathbf{a}_0(\mathbf{\theta}_1, \mathbf{d}) & \mathbf{a}_0(\mathbf{\theta}_2, \mathbf{d}) & \cdots & \mathbf{a}_0(\mathbf{\theta}_K, \mathbf{d}) \end{bmatrix}.\]\(\mathbf{F}\) is the spatial response matrix. For isotropic scalar sensors, \(\mathbf{F}\) is an \(M \times K\) matrix of ones. For vectors sensor arrays, each sensor’s output is a vector of size \(L\). Consequently, \(\mathbf{F}\) is an \(L \times M \times K\) tensor and the broadcasting rule applies when computing the element-wise multiplication between \(\mathbf{F}\) and \(\mathbf{A}_0\).
\(\mathbf{C}(\cdot)\) is a matrix function that applies other perturbations such as gain errors, phase errors, and mutual coupling.
When
compute_derivatives
isTrue
, this method also computes the derivative matrices associated with the source location parameters. The \(k\)-th column of the steering matrix, \(\mathbf{A}\), should depend only on the \(k\)-th source. Consequently, \(\mathbf{A}\) can be expressed as\[\mathbf{A} = \begin{bmatrix} \mathbf{a}(\mathbf{\theta}_1) & \mathbf{a}(\mathbf{\theta}_2) & \cdots & \mathbf{a}(\mathbf{\theta}_K) \end{bmatrix}.\]Then the \(i\)-th derivative matrix is computed as
\[\dot{\mathbf{A}}_i = \begin{bmatrix} \frac{\partial \mathbf{a}(\mathbf{\theta}_1)}{\partial \theta_{1i}} & \frac{\partial \mathbf{a}(\mathbf{\theta}_2)}{\partial \theta_{2i}} & \cdots & \frac{\partial \mathbf{a}(\mathbf{\theta}_K)}{\partial \theta_{Ki}} \end{bmatrix},\]where \(\theta_{ki}\) is the \(i\)-th parameter of the \(k\)-th source location.
The current implementation cannot compute the derivative matrices when the array element is non-isotropic or non-scalar.
Parameters: - sources (SourcePlacement) –
An instance of
SourcePlacement
.- 1D arrays are placed along the x-axis. 2D arrays are placed within the xy-plane.
- If you pass in 1D DOAs for an 2D or 3D array, these DOAs will be assumed to be within the xy-plane. The azimuth angles are calculated as \(\pi/2\) minus the original 1D DOA values (broadside -> azimuth). The elevation angles are set to zeros (within the xy-plane).
- wavelength (float) – Wavelength of the carrier wave.
- compute_derivatives (bool) – If set to True, also outputs the derivative matrices with respect to the DOAs. The k-th column of the i-th derivative matrix contains the derivatives of the k-th column of A with respect to the i-th parameter associated with the k-th DOA. The derivative matrices are used when computing the CRBs. Not always available.
- perturbations (str) –
Specifies which perturbations are considered when constructing the steering matrix:
'all'
- All perturbations are considered. This is the default value.'known'
- Only known perturbations (we have prior knowledge of the perturbation parameters) are considered. This option is used by DOA estimators when the exact knowledge of these perturbations are known in prior.'none'
- None of the perturbations are considered.
- flatten (bool) – Specifies whether the output should be flattend to
matrices. This option does not have any effect if the array
element has a scalar output. For an array element of non-scalar
outputs (e.g., a vector sensor), the resulting steering matrix
is actually a \(L \times M \times K\) tensor, where]
\(L\) is the output size of each array element, \(M\) is
the array size, and \(K\) is the number of sources. Setting
flatten
toTrue
will flatten the tensor into a \(LM \times K\) matrix. Default value isTrue
.
Notes
The steering matrix calculation is bound to array designs. This is a generic implementation, which can be overridden for special types of arrays.
-
class
doatools.model.arrays.
GridBasedArrayDesign
(indices, d0=None, name=None, bases=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.ArrayDesign
Base class for all grid-based array designs.
For grid based arrays, each elements is placed on a predefined grid. A \(d\)-dimensional grid in a \(k\)-dimensional space (\(d \leq k\)) is generated by \(d\) \(k\)-dimensional basis vectors: \(\mathbf{v}_1, \mathbf{v}_2, \ldots, \mathbf{v}_d\). The location of the \((i_1, i_2, \ldots, i_d)\)-th element is given by
\[i_1 \mathbf{v}_1 + i_2 \mathbf{v}_2 + \cdots + i_d \mathbf{v}_d.\]Parameters: - indices (ndarray) – m x d matrix denoting the grid indices of each element. The input ndarray is not copied and should never be changed after creating this array design.
- d0 (float) – Grid size (or base inter-element spacing). For 2D and 3D
arrays, d0 can either be a scalar (if the base inter-element
spacing remains the same along all axes), or a list-like object
such that d0[i] specifies the base inter-element spacing along
the i-th axis. When using
d0
to specify the grid size, the grid is assumed to be aligned with the x-, y-, and z-axis. - bases (ndarray) – Grid bases. Each row represents a basis vector.
Given a
d
-dimensional grid, the element with the grid index(i1, i2,...,id)
is located ati1 * bases[0,:] + ... + id * bases[d-1, :]
. Whenbases
is specified,d0
will be ignored. Usebases
instead ofd0
if the underlying grid is not aligned with the x-, y-, and z-axis. - name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
-
d0
¶ Retrieves the base inter-element spacing(s) along each grid axis.
You are not supposed to modified the returned array.
Returns: A 1D vector containing the inter-element spacings along each grid axis. Return type: ndarray
-
bases
¶ Retrieves the basis vectors for the grid.
You are not supposed to modify the returned array.
Returns: A matrix where each row respresents a basis vector. Return type: ndarray
-
element_indices
¶ Retrieves the element indices.
You are not supposed to modify the returned array.
-
class
doatools.model.arrays.
UniformLinearArray
(n, d0, name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.GridBasedArrayDesign
Creates an n-element uniform linear array (ULA).
The ULA is placed along the x-axis, whose the first sensor is placed at the origin.
Parameters: - n (int) – Number of elements.
- d0 (float) – Fundamental inter-element spacing (usually smallest).
- name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
-
class
doatools.model.arrays.
NestedArray
(n1, n2, d0, name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.GridBasedArrayDesign
Creates a 1D nested array.
Parameters: - n1 (int) – Parameter N1.
- n2 (int) – Parameter N2.
- d0 (float) – Fundamental inter-element spacing (usually smallest).
- name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
References
[1] P. Pal and P. P. Vaidyanathan, “Nested arrays: A novel approach to array processing with enhanced degrees of freedom,” IEEE Transactions on Signal Processing, vol. 58, no. 8, pp. 4167-4181, Aug. 2010.
-
n1
¶ Retrieves the parameter, N1, used when creating this nested array.
-
n2
¶ Retrieves the parameter, N2, used when creating this nested array.
-
class
doatools.model.arrays.
CoPrimeArray
(m, n, d0, mode='2m', name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.GridBasedArrayDesign
Creates a 1D co-prime array.
Parameters: - m (int) – The smaller number in the co-prime pair.
- n (int) – The larger number in the co-prime pair.
- d0 (float) – Fundamental inter-element spacing (usually smallest).
- mode (str) – Either
'm'
or'2m'
. - name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
References
[1] P. Pal and P. P. Vaidyanathan, “Coprime sampling and the music algorithm,” in 2011 Digital Signal Processing and Signal Processing Education Meeting (DSP/SPE), 2011, pp. 289-294.
-
coprime_pair
¶ Retrieves the co-prime pair used when creating this co-prime array.
-
mode
¶ Retrieves the mode used when creating this co-prime array.
-
class
doatools.model.arrays.
MinimumRedundancyLinearArray
(n, d0, name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.GridBasedArrayDesign
Creates an n-element minimum redundancy linear array (MRLA).
Parameters: - n (int) – Number of elements. Up to 20.
- d0 (float) – Fundamental inter-element spacing (usually smallest).
- name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
References
[1] M. Ishiguro, “Minimum redundancy linear arrays for a large number of antennas,” Radio Sci., vol. 15, no. 6, pp. 1163-1170, Nov. 1980.
[2] A. Moffet, “Minimum-redundancy linear arrays,” IEEE Transactions on Antennas and Propagation, vol. 16, no. 2, pp. 172-175, Mar. 1968.
-
class
doatools.model.arrays.
UniformCircularArray
(n, r, name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.ArrayDesign
Creates a uniform circular array (UCA).
The UCA is centered at the origin, in the xy-plane.
Parameters: - n (int) – Number of elements.
- r (float) – Radius of the circle.
- name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
-
radius
¶ Retrieves the radius of the uniform circular array.
-
class
doatools.model.arrays.
UniformRectangularArray
(m, n, d0, name=None, **kwargs)[source]¶ Bases:
doatools.model.arrays.GridBasedArrayDesign
Creates an m x n uniform rectangular array (URA).
The URA is placed on the xy-plane, and the (0,0)-th sensor is placed at the origin.
Parameters: - m (int) – Number of elements along the x-axis.
- n (int) – Number of elements along the y-axis.
- d0 (float) – Fundamental inter-element spacing. Can be either a scalar or a two-element list-like object.
- name (str) – Name of the array design.
- **kwargs – Other keyword arguments supported by
ArrayDesign
.
-
shape
¶ Retrieves the shape of this uniform rectangular array.