Ultrasound
fpc.ultrasound
ultrasound.py - diagnostic ultrasound (sonography) physics.
An ultrasound scanner sends a short pulse into the body and times the echoes. It assumes sound always travels at 1540 m/s in soft tissue - that single assumption explains depth calculation, many artefacts, and the trade-off between frequency, resolution, and penetration. Doppler adds blood-flow velocity from the frequency shift of moving red cells.
Ultrasound
Pulse-echo, attenuation, and Doppler calculations for sonography.
Source code in fpc/ultrasound.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
wavelength(*, frequency_mhz, speed=SOFT_TISSUE_SPEED)
Wavelength lambda = c / f.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frequency_mhz
|
transducer frequency [MHz] |
required | |
speed
|
speed of sound [m/s] (default: soft tissue) |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
wavelength [mm] (5 MHz in soft tissue -> 0.308 mm) |
Source code in fpc/ultrasound.py
33 34 35 36 37 38 39 40 41 | |
echo_depth(*, round_trip_time_us, speed=SOFT_TISSUE_SPEED)
Reflector depth from echo time: d = c * t / 2.
Divide by two because the pulse travels down AND back. This "13 us per cm" rule is hard-wired into every scanner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
round_trip_time_us
|
time from pulse to echo [microseconds] |
required | |
speed
|
speed of sound [m/s] |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
depth [cm] |
Source code in fpc/ultrasound.py
43 44 45 46 47 48 49 50 51 52 53 | |
acoustic_impedance(*, density, speed)
Acoustic impedance Z = rho * c [rayl = kg/(m^2*s)].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
density
|
density [kg/m^3] |
required | |
speed
|
speed of sound [m/s] |
required |
Returns:
| Type | Description |
|---|---|
|
impedance [rayl] |
Source code in fpc/ultrasound.py
55 56 57 58 59 60 61 62 | |
intensity_reflection_coefficient(*, impedance_1, impedance_2)
Fraction of intensity reflected at a boundary: R = ((Z2-Z1)/(Z2+Z1))^2.
Soft-tissue/soft-tissue boundaries reflect < 1% (good: the beam carries on to deeper structures). Tissue/air reflects ~99.9% - which is why we need coupling gel and why bowel gas blocks the view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
impedance_1
|
Z of the first medium [rayl] |
required | |
impedance_2
|
Z of the second medium [rayl] |
required |
Returns:
| Type | Description |
|---|---|
|
reflected fraction R [0..1] |
Source code in fpc/ultrasound.py
64 65 66 67 68 69 70 71 72 73 74 75 | |
reflection_between(*, medium_1, medium_2)
Reflection coefficient between two named media from :attr:MEDIA.
A convenience wrapper that chains the two methods above - a small example of building higher-level helpers from simple ones.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
medium_1
|
name of the first medium, e.g. "soft_tissue" |
required | |
medium_2
|
name of the second medium, e.g. "air" |
required |
Returns:
| Type | Description |
|---|---|
|
reflected intensity fraction R [0..1] |
Source code in fpc/ultrasound.py
77 78 79 80 81 82 83 84 85 86 87 88 89 | |
attenuation_db(*, frequency_mhz, path_length_cm, coefficient_db_per_cm_mhz=0.5)
Total attenuation A = alpha * f * L [dB].
Soft tissue loses ~0.5 dB per cm per MHz. Higher frequency gives better resolution but less penetration - the central trade-off when choosing a probe. For a pulse-echo, the path length is TWICE the depth.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frequency_mhz
|
frequency [MHz] |
required | |
path_length_cm
|
distance travelled [cm] |
required | |
coefficient_db_per_cm_mhz
|
attenuation coefficient [dB/(cm*MHz)] |
0.5
|
Returns:
| Type | Description |
|---|---|
|
attenuation [dB] |
Source code in fpc/ultrasound.py
91 92 93 94 95 96 97 98 99 100 101 102 103 | |
axial_resolution(*, frequency_mhz, cycles_per_pulse=2, speed=SOFT_TISSUE_SPEED)
Axial resolution = spatial pulse length / 2 = n * lambda / 2.
Two reflectors along the beam closer than this blur into one echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frequency_mhz
|
frequency [MHz] |
required | |
cycles_per_pulse
|
number of cycles in each pulse |
2
|
|
speed
|
speed of sound [m/s] |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
axial resolution [mm] |
Source code in fpc/ultrasound.py
105 106 107 108 109 110 111 112 113 114 115 | |
maximum_depth(*, pulse_repetition_frequency_hz, speed=SOFT_TISSUE_SPEED)
Deepest unambiguous echo for a given PRF: d_max = c / (2 * PRF).
Each echo must return before the next pulse is fired, so imaging deeper forces a lower PRF (and lower frame rate).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pulse_repetition_frequency_hz
|
PRF [Hz] |
required | |
speed
|
speed of sound [m/s] |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
maximum depth [cm] |
Source code in fpc/ultrasound.py
117 118 119 120 121 122 123 124 125 126 127 | |
doppler_shift(*, transmitted_frequency_mhz, velocity, angle_deg, speed=SOFT_TISSUE_SPEED)
Doppler frequency shift df = 2 * f0 * v * cos(theta) / c.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transmitted_frequency_mhz
|
transmitted frequency f0 [MHz] |
required | |
velocity
|
reflector (blood) speed [m/s] |
required | |
angle_deg
|
angle between beam and flow [degrees] |
required | |
speed
|
speed of sound [m/s] |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
Doppler shift [Hz] (conveniently in the audible range) |
Source code in fpc/ultrasound.py
129 130 131 132 133 134 135 136 137 138 139 140 141 | |
doppler_velocity(*, transmitted_frequency_mhz, doppler_shift_hz, angle_deg, speed=SOFT_TISSUE_SPEED)
Blood velocity from a measured Doppler shift (the inverse problem).
v = df * c / (2 * f0 * cos(theta)). Because cos(theta) sits in the denominator, angle errors explode near 90 deg - keep the insonation angle at or below 60 deg in clinical practice.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transmitted_frequency_mhz
|
f0 [MHz] |
required | |
doppler_shift_hz
|
measured shift [Hz] |
required | |
angle_deg
|
insonation angle [degrees] |
required | |
speed
|
speed of sound [m/s] |
SOFT_TISSUE_SPEED
|
Returns:
| Type | Description |
|---|---|
|
velocity [m/s] |
Source code in fpc/ultrasound.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |