Reception¶
Pulse-echo RF simulator. See the Reception user guide for the method taxonomy, PSF, and phantom recipes.
Reception¶
The single pulse-echo class. Its method selector chooses how the two-way SIR is
evaluated — all methods give the same RF, they trade speed only:
"spectral"(default) — fast sparse-delta kernel via closed-form one-way SIR spectra."fst"/"sdi"/"auto"— sampled two-way SIR convolution (delegated to the conventionalReceptionConventionalbackend; the string names its SIR-sampling kernel)."paired"— exact but slow pedagogic reference (warns on selection).
Reception
¶
Reception(
tx,
rx,
*,
c=1540.0,
rho=1.0,
fs=100000000.0,
alpha0=None,
freq_power=1.0,
excitation=None,
method="spectral",
n_depth_bins="auto",
verbose=True,
)
Bases: ReceptionBase
Compute pulse-echo RF from point scatterers via sparse delta integration (SDI).
Implements Jensen's spatial-impulse-response pulse-echo model
p_pe = v_pe ⊛ h_tx ⊛ h_rx under the Tupholme-Stepanishen far-field trapezoidal
rectangular-patch SIR (full derivation of the three formulations in the module
docstring above). Each one-way SIR is the double integral of a sparse train of
trapezoid-corner deltas; the two-way SIR is recovered with the four integrations
I⁴ = ÷(jω)⁴. All formulations evaluate the same RF equation and agree to
correlation ~1.0 with each other and with Field II. method picks how the TX/RX
corner trains are combined (speed trade-off only):
"spectral"(default) — multiply the two closed-form one-way SIR spectra on the in-band bins only. No forward FFT, cost linear in patches, exact, and folds per-patch one-way attenuation in for free."fst"/"sdi"/"auto"— sampleh_tx/h_rxand convolve, delegated toReceptionConventional. The string names its SIR-sampling kernel:"fst"fully samples each trapezoid,"sdi"places sparse corner deltas,"auto"lets the delegate choose per grid."paired"— pedagogic reference only. Splats the integrated drivew = I⁴ v_peat the 16 corner events of every TX–RX patch pair (no FFT, no cumsum): exact but O(M²) per pair, so far slower thanspectral. Warns on selection. No attenuation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tx
|
TransducerBase
|
Transmit transducer (with delays, apodization, optional impulse_response and excitation). |
required |
rx
|
TransducerBase
|
Receive transducer (with apodization, optional impulse_response). Can be the same object as tx for monostatic pulse-echo. |
required |
c
|
float
|
Speed of sound (m/s). |
1540.0
|
rho
|
float
|
Medium density (kg/m^3). |
1.0
|
fs
|
float
|
Sampling frequency (Hz). |
100e6
|
alpha0
|
float or None
|
Attenuation in dB/(MHz^y·cm). None = no attenuation. |
None
|
freq_power
|
float
|
Attenuation power-law exponent. |
1.0
|
excitation
|
ndarray or None
|
TX excitation pulse |
None
|
method
|
str
|
Pulse-echo formulation: |
"spectral"
|
n_depth_bins
|
auto or int
|
Spectral speed knob. Scatterers are grouped into this many depth bins so each bin
uses a short time window — a small |
"auto"
|
verbose
|
bool
|
Print diagnostic information during simulation. |
True
|
pulse_echo_rf
¶
pulse_echo_rf(
scatterer_positions_mm,
amplitudes=None,
*,
per_scatterer=False,
downsampling=None,
out_path=None,
checkpoint_chunks=1,
)
Pulse-echo RF from point scatterers.
The core reception primitive: amplitude-weighted superposition of each
scatterer's pulse-echo response. The SDI cores carry a second derivative on
each one-way SIR (D²h_tx, D²h_rx), so the public RF applies the four
integrations I⁴ = ÷(jω)⁴ in the frequency domain to recover the two-way SIR
h_tx ⊛ h_rx; the single physical ∂³ stays on the band-limited excitation /
impulse-response chain (e ⊛ h_e ⊛ h_r). Frequency-domain integration carries
no group delay, so the result stays sample-aligned with the conventional
ReceptionConventional backend.
Field II uses the same convention, so this equals Field II calc_scat
(≡ calc_hhp for a unit point, corr 1.0000).
per_scatterer=True keeps each scatterer separate (PSF); False sums
them. coords["t0"] is beam-axis referenced (TX bulk delays.max()
subtracted) so downstream beamforming needs no per-line correction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
per_scatterer
|
bool
|
If False, sum over scatterers → |
False
|
downsampling
|
int or None
|
Anti-aliased time decimation factor. |
None
|
out_path
|
str or Path or None
|
Checkpoint folder (an |
None
|
checkpoint_chunks
|
int
|
Scatterer chunks checkpointed separately (requires |
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(Erx, Nt) or (N_scat, Erx, Nt) numpy.ndarray
|
Pulse-echo RF per receive element (channels before time). |
coords |
dict
|
Keys |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
sequence_rf
¶
sequence_rf(
scatterer_positions_mm,
amplitudes,
tx_events,
*,
downsampling=None,
out_path=None,
checkpoint_chunks=1,
)
Pulse-echo RF for a sequence of TX events (emission basis: PW/DW/...).
Each event sets the TX delays/apodization, then pulse_echo_rf is run
(summed over scatterers). Useful as the emission basis for matrix imaging.
With out_path, the sequence is CHECKPOINTED: each event's RF is
written to disk (one compressed file per event + a contents file) the
moment it finishes, and re-running the same call on the same folder skips
the completed events and resumes from the first missing one. The contents
file fingerprints the full simulation (probe, medium, excitation,
scatterers, events); re-running with anything changed raises instead of
silently mixing incompatible data.
checkpoint_chunks bounds the work lost to a crash WITHIN one event:
the RF is linear in the scatterers, so the cloud is split into chunks
that are simulated and checkpointed one file at a time, then summed.
Every chunk carries four zero-amplitude "grid sentinel" points (just
nearer than the nearest scatterer and just farther than the farthest,
per aperture) so all chunks of an event share one time grid and their
sum is sample-exact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray
|
Scattering amplitude of each scatterer. |
required |
tx_events
|
list of dict
|
Each dict has |
required |
downsampling
|
int or None
|
Anti-aliased time decimation factor applied per event. |
None
|
out_path
|
str or Path or None
|
Checkpoint folder (created if missing). Events already completed there are skipped; each new event is written atomically on completion, so a crash costs at most the event in flight. |
None
|
checkpoint_chunks
|
int
|
Number of scatterer chunks checkpointed per TX event (requires
|
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(N_events, Erx, Nt) numpy.ndarray
|
Per-event, per-receive-element RF (channels before time). |
coords |
dict
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
synthetic_aperture_rf
¶
synthetic_aperture_rf(
scatterer_positions_mm,
amplitudes=None,
*,
tx_groups="element",
decimation=10,
out_path=None,
countdown=True,
checkpoint_chunks=1,
)
Synthetic-aperture RF: each TX element/group fires alone, all RX record.
Canonical diverging-wave emission basis for matrix imaging: every group
fires FLAT (zero delay, unit apodization) — this OVERRIDES any TX delays/
apodization set on the transducer. tx_groups="element" is full FMC
(= Field II calc_scat_all); int N uses N-element sub-apertures;
a list[list[int]] gives custom groups.
Each group is one TX event of sequence_rf, so it shares that
method's checkpointing: with out_path every group (or scatterer
chunk, with checkpoint_chunks) lands on disk the moment it
finishes, a re-run resumes at the first missing file, and a changed
setup refuses. Output Ntx_grp·Erx·Nt can be huge, hence the
anti-aliased decimation (default 10×); a 10 s countdown precedes an
in-RAM run so it can be aborted (a checkpointed run is always
interruptible, so it starts straight away).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
tx_groups
|
str or int or list[list[int]]
|
Transmit grouping: |
"element"
|
decimation
|
int
|
Anti-aliased time decimation factor. |
10
|
out_path
|
str or Path or None
|
Checkpoint folder (an |
None
|
countdown
|
bool
|
Print a 10 s abortable countdown before an in-RAM computation
(skipped if stdout is not a TTY or |
True
|
checkpoint_chunks
|
int
|
Scatterer chunks checkpointed per group (requires |
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(Ntx_grp, Erx, Nt) numpy.ndarray
|
Per-group, per-receive-element RF. |
coords |
dict
|
|
scan_focusline
¶
scan_focusline(
focus_mm,
scatterer_positions_mm,
amplitudes=None,
*,
FoverD=None,
apodization_type=None,
rx_FoverD=None,
rx_apodization_type=None,
output="envelope",
downsampling=None,
)
One conventional focused scan line (Field II calc_scat match).
Recomputes the TX and RX focus + apodization FROM focus_mm (reusing
each transducer's compute_delays / compute_apodization), then
beamforms ON RECEIVE INSIDE THE SIR KERNEL via _focused_sum_rf
(focused_sum=True): every RX patch carries its focusing delay +
apodization and the kernel sums them into one line — exactly Field II
calc_scat's internal receive beamforming. This replaces the old
per-element-RF + external DAS_focused_scanline path, so it is ~E_rx×
cheaper (one FFT pair, no per-channel loop) and applies the receive focus at
corner-time resolution (no sample-interpolation loss). Loop focus_mm
externally to build a B-mode, e.g. img[i] = sim.scan_focusline(...)[0].
By default the RX aperture mirrors the TX focus + apodization (the usual
focused-imaging case, and what Field II's sesr.m does: identical
xdc_apodization on emit and receive). Pass rx_FoverD /
rx_apodization_type to give the receive aperture a different profile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
focus_mm
|
(3,) array_like
|
Focal point |
required |
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
FoverD
|
float or None
|
TX F-number for the active aperture. Used only when
|
None
|
apodization_type
|
str or None
|
TX apodization: |
None
|
rx_FoverD
|
float or None
|
RX F-number. None → mirror |
None
|
rx_apodization_type
|
str or None
|
RX apodization type. None → mirror |
None
|
output
|
(envelope, rf)
|
Return the Hilbert envelope (default) or the raw beamformed RF line. |
"envelope"
|
downsampling
|
int or None
|
Anti-aliased time decimation factor. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
out |
(Nt,) numpy.ndarray
|
Envelope (or RF line) of the beamformed scan line at lateral focus[0]. |
coords |
dict
|
|
show
¶
show(
scatterer_positions_mm=None,
amplitudes=None,
*,
TX_color="Delays",
RX_color="Delays",
TX_show_edges=False,
RX_show_edges=False,
TX_kwargs=None,
RX_kwargs=None,
window_size=(900, 700),
notebook=False,
jupyter_backend=None,
legend=True,
scale=1.0,
save_path=None,
off_screen=None,
return_plotter=False,
db_scale=True,
**kwargs,
)
Interactive 3-D preview of the pulse-echo setup (TX, RX, scatterers).
Renders the transmit and receive apertures (their patch meshes, in mm) and the scatterer cloud, each point coloured by its scattering amplitude and faded in proportion to it — a quick visual check that positions, units and aperture poses are what the simulation will see. When TX and RX are the same object the aperture is drawn once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) array-like
|
Scatterer positions in mm. None draws only the apertures. |
None
|
amplitudes
|
(N_scat,) array-like
|
Scattering amplitude per point. None defaults to ones (all points fully opaque). |
None
|
TX_color
|
str or tuple
|
Colour of the transmit aperture. Any PyVista colour (name, hex
string or RGB tuple) paints the mesh uniformly. The special strings
|
"Delays"
|
RX_color
|
str or tuple
|
Same as |
"Delays"
|
TX_show_edges
|
bool
|
Draw the patch edges of the transmit aperture mesh. |
False
|
RX_show_edges
|
bool
|
Draw the patch edges of the receive aperture mesh. |
False
|
TX_kwargs
|
dict
|
Extra keyword arguments for the transmit aperture's
|
None
|
RX_kwargs
|
dict
|
Same as |
None
|
window_size
|
(int, int)
|
Pixel dimensions of the render window. |
(900, 700)
|
notebook
|
bool
|
Enable Jupyter notebook rendering. |
False
|
jupyter_backend
|
str
|
Backend string passed to PyVista ( |
None
|
legend
|
bool
|
Draw the TX/RX/Scatterers legend. Note the colour bars belong to
the |
True
|
scale
|
float
|
Global resolution multiplier. Enlarges the render window, every font
(grid, aperture tags, colour bars) and the saved screenshot together,
so a higher value yields a larger, sharper image without changing the
framing (e.g. |
1.0
|
save_path
|
str or Path
|
Screenshot file path (e.g. |
None
|
off_screen
|
bool
|
Render without opening a window. |
None
|
return_plotter
|
bool
|
Return the PyVista |
False
|
db_scale
|
bool
|
When True, the scatterer amplitudes are converted to dB scale for visualization. |
True
|
**kwargs
|
Forwarded to the scatterer |
{}
|
Returns:
| Type | Description |
|---|---|
Plotter or None
|
The plotter (scene assembled, grid and rendering left to the
caller) when |
set
¶
Update a parameter at runtime, then invalidate the conventional delegate.
Extends ReceptionBase.set with validation of the "method" selector and by
dropping the cached ReceptionConventional (rebuilt on the next conventional call,
picking up the new tx/rx/medium/excitation state).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Parameter name (a key of |
required |
value
|
object
|
New value; for |
required |
ReceptionConventional (backend)¶
The conventional Tupholme-Stepanishen sampled-convolution backend that Reception
delegates to for method="fst"/"sdi"/"auto". Same API; normally reached through
Reception, documented here for reference.
ReceptionConventional
¶
ReceptionConventional(
tx,
rx,
*,
c=1540.0,
rho=1.0,
fs=100000000.0,
alpha0=None,
freq_power=1.0,
excitation=None,
method="auto",
n_depth_bins="auto",
verbose=True,
)
Bases: ReceptionBase
Pulse-echo RF by direct two-way SIR convolution (Jensen's model).
Computes the received echo from point scatterers using the standard SIR
formulation (model and citations in the module docstring above): the one-way SIRs
h_tx and h_rx are built without differentiation, and the recorded RF is the
amplitude-weighted sum over scatterers
rf(t) = (ρ₀/2c₀²) Σ_p σ_p · (exc ⊛ ir_tx ⊛ ir_rx ⊛ h_pe)|_{r_p}
where the sum runs over scatterers p at positions r_p with scattering
amplitudes σ_p (the amplitudes argument), and
h_pe = h_tx(r₁→r_p) ⊛_t h_rx(r_p→r₁) is the plain two-way SIR for that
scatterer. The three physical excitation derivatives are carried by the
band-limited exc/IR chain, so no extra explicit ∂/∂t is applied (Field II's
calc_scat ≡ calc_hhp convention). Public API via pulse_echo_rf (core)
plus sequence_rf / synthetic_aperture_rf / scan_focusline from ReceptionBase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tx
|
TransducerBase
|
Transmit transducer (with delays, apodization, optional impulse_response and excitation). |
required |
rx
|
TransducerBase
|
Receive transducer (with apodization, optional impulse_response). Can be the same object as tx for monostatic pulse-echo. |
required |
c
|
float
|
Speed of sound (m/s). |
1540.0
|
rho
|
float
|
Medium density (kg/m^3). |
1.0
|
fs
|
float
|
Sampling frequency (Hz). |
100e6
|
alpha0
|
float or None
|
Attenuation in dB/(MHz^y·cm). None = no attenuation. |
None
|
freq_power
|
float
|
Attenuation power-law exponent. |
1.0
|
excitation
|
ndarray or None
|
TX excitation pulse |
None
|
method
|
str
|
SIR computation method: |
"auto"
|
n_depth_bins
|
auto or int
|
Pulse-echo speed knob (result is unchanged). Scatterers at different depths
echo at different times, so one FFT over all of them must span the whole
depth range; grouping them into depth bins lets each bin use an FFT only as
long as its own arrival window — a big speedup at high scatterer counts.
Bins recombine sample-exactly on a shared time axis. |
"auto"
|
verbose
|
bool
|
Print diagnostic information during simulation. |
True
|
pulse_echo_rf
¶
pulse_echo_rf(
scatterer_positions_mm,
amplitudes=None,
*,
per_scatterer=False,
downsampling=None,
out_path=None,
checkpoint_chunks=1,
)
Pulse-echo RF from point scatterers.
The core reception primitive. The recorded pulse-echo signal is the amplitude-weighted superposition of each scatterer's pulse-echo response::
rf = (ρ₀/2c₀²) Σ_i a_i (exc ⊛ ir_tx ⊛ ir_rx ⊛ h_pe)|_{r_i}
The three physical excitation derivatives are carried by the band-limited
exc ⊛ ir_tx ⊛ ir_rx chain, so NO extra explicit ∂/∂t is applied. Field II
uses the same convention, so this equals its calc_scat (≡ calc_hhp for a
unit point, corr 1.0000).
per_scatterer=True keeps each scatterer separate — the point-spread
function (PSF) use; False sums them (the recorded echo).
coords["t0"] is referenced to the beam axis (the TX focusing bulk
tx.delays.max() is subtracted), so downstream beamforming needs no
per-line bulk correction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
per_scatterer
|
bool
|
If False, sum over scatterers → |
False
|
downsampling
|
int or None
|
Anti-aliased time decimation factor. |
None
|
out_path
|
str or Path or None
|
Checkpoint folder (an |
None
|
checkpoint_chunks
|
int
|
Scatterer chunks checkpointed separately (requires |
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(Erx, Nt) or (N_scat, Erx, Nt) numpy.ndarray
|
Pulse-echo RF per receive element (channels before time). |
coords |
dict
|
Keys |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
sequence_rf
¶
sequence_rf(
scatterer_positions_mm,
amplitudes,
tx_events,
*,
downsampling=None,
out_path=None,
checkpoint_chunks=1,
)
Pulse-echo RF for a sequence of TX events (emission basis: PW/DW/...).
Each event sets the TX delays/apodization, then pulse_echo_rf is run
(summed over scatterers). Useful as the emission basis for matrix imaging.
With out_path, the sequence is CHECKPOINTED: each event's RF is
written to disk (one compressed file per event + a contents file) the
moment it finishes, and re-running the same call on the same folder skips
the completed events and resumes from the first missing one. The contents
file fingerprints the full simulation (probe, medium, excitation,
scatterers, events); re-running with anything changed raises instead of
silently mixing incompatible data.
checkpoint_chunks bounds the work lost to a crash WITHIN one event:
the RF is linear in the scatterers, so the cloud is split into chunks
that are simulated and checkpointed one file at a time, then summed.
Every chunk carries four zero-amplitude "grid sentinel" points (just
nearer than the nearest scatterer and just farther than the farthest,
per aperture) so all chunks of an event share one time grid and their
sum is sample-exact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray
|
Scattering amplitude of each scatterer. |
required |
tx_events
|
list of dict
|
Each dict has |
required |
downsampling
|
int or None
|
Anti-aliased time decimation factor applied per event. |
None
|
out_path
|
str or Path or None
|
Checkpoint folder (created if missing). Events already completed there are skipped; each new event is written atomically on completion, so a crash costs at most the event in flight. |
None
|
checkpoint_chunks
|
int
|
Number of scatterer chunks checkpointed per TX event (requires
|
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(N_events, Erx, Nt) numpy.ndarray
|
Per-event, per-receive-element RF (channels before time). |
coords |
dict
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
synthetic_aperture_rf
¶
synthetic_aperture_rf(
scatterer_positions_mm,
amplitudes=None,
*,
tx_groups="element",
decimation=10,
out_path=None,
countdown=True,
checkpoint_chunks=1,
)
Synthetic-aperture RF: each TX element/group fires alone, all RX record.
Canonical diverging-wave emission basis for matrix imaging: every group
fires FLAT (zero delay, unit apodization) — this OVERRIDES any TX delays/
apodization set on the transducer. tx_groups="element" is full FMC
(= Field II calc_scat_all); int N uses N-element sub-apertures;
a list[list[int]] gives custom groups.
Each group is one TX event of sequence_rf, so it shares that
method's checkpointing: with out_path every group (or scatterer
chunk, with checkpoint_chunks) lands on disk the moment it
finishes, a re-run resumes at the first missing file, and a changed
setup refuses. Output Ntx_grp·Erx·Nt can be huge, hence the
anti-aliased decimation (default 10×); a 10 s countdown precedes an
in-RAM run so it can be aborted (a checkpointed run is always
interruptible, so it starts straight away).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
tx_groups
|
str or int or list[list[int]]
|
Transmit grouping: |
"element"
|
decimation
|
int
|
Anti-aliased time decimation factor. |
10
|
out_path
|
str or Path or None
|
Checkpoint folder (an |
None
|
countdown
|
bool
|
Print a 10 s abortable countdown before an in-RAM computation
(skipped if stdout is not a TTY or |
True
|
checkpoint_chunks
|
int
|
Scatterer chunks checkpointed per group (requires |
1
|
Returns:
| Name | Type | Description |
|---|---|---|
rf |
(Ntx_grp, Erx, Nt) numpy.ndarray
|
Per-group, per-receive-element RF. |
coords |
dict
|
|
scan_focusline
¶
scan_focusline(
focus_mm,
scatterer_positions_mm,
amplitudes=None,
*,
FoverD=None,
apodization_type=None,
rx_FoverD=None,
rx_apodization_type=None,
output="envelope",
downsampling=None,
)
One conventional focused scan line (Field II calc_scat match).
Recomputes the TX and RX focus + apodization FROM focus_mm (reusing
each transducer's compute_delays / compute_apodization), then
beamforms ON RECEIVE INSIDE THE SIR KERNEL via _focused_sum_rf
(focused_sum=True): every RX patch carries its focusing delay +
apodization and the kernel sums them into one line — exactly Field II
calc_scat's internal receive beamforming. This replaces the old
per-element-RF + external DAS_focused_scanline path, so it is ~E_rx×
cheaper (one FFT pair, no per-channel loop) and applies the receive focus at
corner-time resolution (no sample-interpolation loss). Loop focus_mm
externally to build a B-mode, e.g. img[i] = sim.scan_focusline(...)[0].
By default the RX aperture mirrors the TX focus + apodization (the usual
focused-imaging case, and what Field II's sesr.m does: identical
xdc_apodization on emit and receive). Pass rx_FoverD /
rx_apodization_type to give the receive aperture a different profile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
focus_mm
|
(3,) array_like
|
Focal point |
required |
scatterer_positions_mm
|
(N_scat, 3) numpy.ndarray
|
Scatterer positions in mm. |
required |
amplitudes
|
(N_scat,) numpy.ndarray or None
|
Scattering coefficient at each position. None defaults to ones. |
None
|
FoverD
|
float or None
|
TX F-number for the active aperture. Used only when
|
None
|
apodization_type
|
str or None
|
TX apodization: |
None
|
rx_FoverD
|
float or None
|
RX F-number. None → mirror |
None
|
rx_apodization_type
|
str or None
|
RX apodization type. None → mirror |
None
|
output
|
(envelope, rf)
|
Return the Hilbert envelope (default) or the raw beamformed RF line. |
"envelope"
|
downsampling
|
int or None
|
Anti-aliased time decimation factor. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
out |
(Nt,) numpy.ndarray
|
Envelope (or RF line) of the beamformed scan line at lateral focus[0]. |
coords |
dict
|
|
show
¶
show(
scatterer_positions_mm=None,
amplitudes=None,
*,
TX_color="Delays",
RX_color="Delays",
TX_show_edges=False,
RX_show_edges=False,
TX_kwargs=None,
RX_kwargs=None,
window_size=(900, 700),
notebook=False,
jupyter_backend=None,
legend=True,
scale=1.0,
save_path=None,
off_screen=None,
return_plotter=False,
db_scale=True,
**kwargs,
)
Interactive 3-D preview of the pulse-echo setup (TX, RX, scatterers).
Renders the transmit and receive apertures (their patch meshes, in mm) and the scatterer cloud, each point coloured by its scattering amplitude and faded in proportion to it — a quick visual check that positions, units and aperture poses are what the simulation will see. When TX and RX are the same object the aperture is drawn once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scatterer_positions_mm
|
(N_scat, 3) array-like
|
Scatterer positions in mm. None draws only the apertures. |
None
|
amplitudes
|
(N_scat,) array-like
|
Scattering amplitude per point. None defaults to ones (all points fully opaque). |
None
|
TX_color
|
str or tuple
|
Colour of the transmit aperture. Any PyVista colour (name, hex
string or RGB tuple) paints the mesh uniformly. The special strings
|
"Delays"
|
RX_color
|
str or tuple
|
Same as |
"Delays"
|
TX_show_edges
|
bool
|
Draw the patch edges of the transmit aperture mesh. |
False
|
RX_show_edges
|
bool
|
Draw the patch edges of the receive aperture mesh. |
False
|
TX_kwargs
|
dict
|
Extra keyword arguments for the transmit aperture's
|
None
|
RX_kwargs
|
dict
|
Same as |
None
|
window_size
|
(int, int)
|
Pixel dimensions of the render window. |
(900, 700)
|
notebook
|
bool
|
Enable Jupyter notebook rendering. |
False
|
jupyter_backend
|
str
|
Backend string passed to PyVista ( |
None
|
legend
|
bool
|
Draw the TX/RX/Scatterers legend. Note the colour bars belong to
the |
True
|
scale
|
float
|
Global resolution multiplier. Enlarges the render window, every font
(grid, aperture tags, colour bars) and the saved screenshot together,
so a higher value yields a larger, sharper image without changing the
framing (e.g. |
1.0
|
save_path
|
str or Path
|
Screenshot file path (e.g. |
None
|
off_screen
|
bool
|
Render without opening a window. |
None
|
return_plotter
|
bool
|
Return the PyVista |
False
|
db_scale
|
bool
|
When True, the scatterer amplitudes are converted to dB scale for visualization. |
True
|
**kwargs
|
Forwarded to the scatterer |
{}
|
Returns:
| Type | Description |
|---|---|
Plotter or None
|
The plotter (scene assembled, grid and rendering left to the
caller) when |