Total focusing method#

Original paper on TFM: [Holmes2005]

Related modules:

Definition#

The most generic definition available in arim is:

\[I(r) = \sum_{i,j \in S} A_{ij}(r) g_{ij}( \tau_{i}(r) + \tau'_{j}(r) )\]

\(g_{ij}(t)\) is the timetrace of the transmitter i and the receiver j, obtained from arim.core.Frame.timetraces. The set S of the transmitters and receivers is obtained from arim.core.Frame.tx and arim.core.Frame.rx. Its size is denoted numtimetraces. TFM is always applied on all timetraces in the frame; to apply TFM on a subset of the timetraces, create a new Frame with only the selected timetraces and pass it to TFM.

\(\tau_{i}(r)\) is the time of flight for the transmission path between the element i and the grid point r. These times are stored in lookup_times_tx, a 2d array of shape (numgridpoints, numelements). Similarly, the times of fight for the reception path are stored in lookup_times_rx.

The weights \(A_{ij}(r)\) are stored in a (numgridpoints, numtimetraces) array named amplitudes. Because this array may be too big for the memory, chunking it may be necessary (example: arim.model.ModelAmplitudes).

If the following decomposition is possible

\[A_{ij}(r) = B_{i}(r) B'_{j}(r)\]

then amplitudes can be a arim.model.TxRxAmplitudes object where amplitudes_tx and amplitudes_rx, which contain respectively \(B_{i}(r)\) and \(B'_{j}(r)\), are arrays of shape (numelements, numtimetraces).

Finally if for all i, j and r

\[A_{ij}(r) = 1,\]

amplitudes may be set to None. Internally a faster implementation of delay-and-sum will be used.

Perfoming TFM#

See arim.im.tfm and arim.im.das

TFM with HMC frame#

In linear imaging, it is assumed that \(g_{ij}(t) = g_{ji}(t)\), which leads to acquire only half the full matrix response (half matrix capture, HMC).

Under this assumption, if for all i and r, \(B_i(r) = B'_i(r)\) and \(\tau_i(r) = \tau'_i(r)\), then

\[\begin{split}I(r) &= \sum_{i,j = 1}^{n} B_{i}(r) B'_{j}(r) g_{ij}(\tau_{i}(r) + \tau'_{j}(r))) \\ &= \sum_{i,j = 1}^{n} B_{i}(r) B_{j}(r) g_{ij}(\tau_{i}(r) + \tau_{j}(r))) \\ &= \sum_{i = 1}^{n} B_{i}(r)^2 g_{ii}(2 \tau_{i}(r)) + 2 \sum_{i,j = 1\\i < j}^{n} B_{i}(r) B_{j}(r) g_{ij}(\tau_{i}(r) + \tau_{j}(r)) \\ &= \sum_{i,j = 1\\i \leq j}^{n} B_{i}(r) B_{j}(r) g'_{ij}(\tau_{i}(r) + \tau_{j}(r))\end{split}\]

where

\[\begin{split}g'_{ij}(t) = \begin{cases} g_{ij}, & \text{if $i=j$} \\ 2 g_{ij}, & \text{if $i \neq j$} \end{cases}\end{split}\]

This reduces the number of summands and therefore the computation time. This last equation is used in contact_tfm(). Internally, the weighted timetraces \(g'_{ij}\) are obtained with FocalLaw.weigh_timetraces().

This technique is not used tfm_for_view() because the times of flight in transmission and reception are not the same in general.