Torso Phantom Technical Specification

This document provides a detailed mathematical specification of the default Torso Phantom implementation.

1. Geometric Primitives

The phantom involves two primary geometric primitives:

Superellipsoid defined by:

\[\left( \left| \frac{x - c_x}{R_x} \right|^{\epsilon_x} + \left| \frac{y - c_y}{R_y} \right|^{\epsilon_y} \right)^{\frac{\epsilon_z}{\epsilon_x}} + \left| \frac{z - c_z}{R_z} \right|^{\epsilon_z} \le 1\]

Ellipsoid (Special case of Superellipsoid with $\epsilon = (2, 2, 2)$):

\[\left( \frac{x - c_x}{R_x} \right)^2 + \left( \frac{y - c_y}{R_y} \right)^2 + \left( \frac{z - c_z}{R_z} \right)^2 \le 1\]

2. Default Tissue Parameters

The default TissueIntensities are:

TissueIntensity Value
lung0.08
heart0.65
vessels_blood1.00
bones0.85
liver0.55
stomach0.90
body0.25
lv_blood0.98
rv_blood0.99
la_blood0.97
ra_blood0.96

3. Rendering Order and Overlap Behavior

CRITICAL: The phantom is designed in a way that the order in which anatomical structures are drawn onto the phantom is essential. Later structures overwrite earlier ones at overlapping voxels.

Rendering Algorithm

The phantom generation follows a two-phase rendering process:

  1. Static Phase: Structures that do not change with respiratory or cardiac motion are drawn once and copied to all time frames for enhanced efficiency. This includes some parts of the torso shell, arms, and spine.
  2. Dynamic Phase: For each time frame, motion-dependent structures are drawn on top of the static base image.
  3. Bone Overlay: Bones are drawn last to ensure they appear on top of all soft tissue structures.

Exact Drawing Order

Phase 1: Static Structures (drawn once)

OrderStructureFunctionDescription
1Static Torsodraw_torso_static_shapes!(ctx, ti)Neck (2 segments), shoulders, arms (left/right, 3 segments each), posterior back coverage (upper/mid/lower)

Phase 2: Dynamic Structures (drawn per frame)

OrderStructureFunctionDescriptionMotion Dependencies
2Dynamic Torsodraw_torso_dynamic_parts!(ctx, ...)Chest (upper/mid/lower), abdomen (upper/lower)Respiratory: $S_{body}$, $y_{offset}$
3Lungsdraw_lungs!(ctx, ...)Left/right upper and lower lobes, diaphragm domesRespiratory: scale, diaphragm displacement, $R_{z,low}$
4Heart Backgrounddraw_heart_background!(ctx, ...)Pericardium/outer heart envelopeCardiac: max chamber scales
5Vesselsdraw_vessels!(ctx, ...)Aorta, pulmonary trunk + branches, superior vena cavaStatic (no motion)
6Heart Chambersdraw_heart_chambers!(ctx, ...)LV/RV/LA/RA myocardium and blood cavities (20 components)Cardiac: chamber scales, dynamic separation
7Ribsdraw_ribs!(ctx, ...)Rib cage with curvatureRespiratory: body scales
8Stomachdraw_stomach!(ctx, ...)Body and pyloric antrumRespiratory: diaphragm displacement, visceral scaling
9Liverdraw_liver!(ctx, ...)Main lobe and right lobeRespiratory: diaphragm displacement, visceral scaling

Phase 3: Bone Overlay (drawn last per frame)

OrderStructureFunctionDescription
10Arm Bonesdraw_arm_bones!(ctx, ...)Left and right humerus, radius, ulna segments
11Spinedraw_spine!(ctx, ...)Cervical, thoracic, and lumbar vertebrae with spinal curvature

Code Reference

The complete rendering sequence is implemented in:

  • src/torso_phantom/create_3D_torso_phantom.jl: Main rendering loop
  • src/torso_phantom/motion_calculations.jl: calculate_motion_parameters(...) computes per-frame motion parameters; draw_dynamic_shapes!(ctx, ...) orchestrates drawing all dynamic structures
  • src/torso_phantom/geometry_definitions.jl: Individual draw_*!() functions for each anatomical structure (e.g. draw_lungs!, draw_heart_chambers!)

4. Static Structures

These structure do not deform with physiological motion.

Body / Torso Shells (Static)

Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
Neck 10.00.1650.850.3120.3360.264(2.5, 2.5, 2.5)Body
Neck 20.00.1651.000.3120.3120.18(2.5, 2.5, 2.5)Body
Shoulders0.00.1650.700.80.280.25(2.5, 2.5, 2.5)Body
Spine (Upper)0.00.280.350.700.430.50(2.5, 2.5, 2.5)Body
Spine (Mid)0.00.28-0.100.750.470.55(2.5, 2.5, 2.5)Body
Spine (Lower)0.00.15-0.600.780.480.55(2.5, 2.5, 2.5)Body

Arms

Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
L Arm (Up)-0.680.1650.620.180.180.28(2.5, 2.5, 2.5)Body
L Arm (Mid)-0.880.1650.500.170.170.26(2.5, 2.5, 2.5)Body
L Arm (Low)-1.050.1650.380.160.160.24(2.5, 2.5, 2.5)Body
R Arm (Up)0.680.1650.620.180.180.28(2.5, 2.5, 2.5)Body
R Arm (Mid)0.880.1650.500.170.170.26(2.5, 2.5, 2.5)Body
R Arm (Low)1.050.1650.380.160.160.24(2.5, 2.5, 2.5)Body

5. Dynamic Motion Model

Respiratory Parameters

Given respiratory signal $S_{resp}$ (Liters), default range [1.2, 6.0]. Normalized signal $\hat{r}$:

\[\hat{r} = \frac{S_{resp} - 1.2}{6.0 - 1.2}\]

Polynomial Coefficients:

\[\begin{aligned} a &= (0.598, 0.842, -0.175, -0.0320625) \\ b &= (1.819140625, 0.831375, -1.7111875, 1.24575) \end{aligned}\]

Global Scaling Factors:

\[\begin{aligned} S_{scale} &= a_0 + a_1\hat{r} + a_2\hat{r}^2 + a_3\hat{r}^3 \\ S_{lower\_rz} &= b_0 + b_1\hat{r} + b_2\hat{r}^2 + b_3\hat{r}^3 \end{aligned}\]

Derived Parameters:

\[\begin{aligned} S_{body} &= 0.4 + 0.63 \cdot S_{scale} \\ y_{offset} &= -0.40 + S_{body} \cdot 0.45 \\ \Delta z_{dia} &= -0.5 \cdot (S_{lower\_rz} - 1.0) \\ S_{dia} &= S_{lower\_rz} \end{aligned}\]

Dynamic Torso Shells (Main Body)

Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
Chest (Upper)0.0$-y_{offset}$0.45$0.86 S_{body}$$0.69 S_{body}$0.35(2.5, 2.5, 2.5)Body
Chest (Mid)0.0$-y_{offset}$0.17$0.93 S_{body}$$0.72 S_{body}$0.32(2.5, 2.5, 3.5)Body
Chest (Lower)0.0$-y_{offset}$-0.11$0.91 S_{body}$$0.71 S_{body}$0.32(2.5, 2.5, 3.5)Body
Abd (Upper)0.0$-y_{offset}$-0.45$0.87 S_{body}$$0.67 S_{body}$0.40(2.5, 2.5, 3.5)Body
Abd (Lower)0.0$-y_{offset}$-0.85$0.83 \sqrt{S_{body}}$$0.62 \sqrt{S_{body}}$0.45(2.5, 2.5, 3.5)Body

Lungs

Constants:

\[\begin{aligned} x_{off} &= 0.32 \text{(Lung Center Offset)} \\ R_{top} &= 0.25 + 0.22 S_{scale} \\ R_{low} &= 0.430 S_{scale} \\ R_{z,low} &= 0.480 S_{lower\_rz} \end{aligned}\]

Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
L Upper$-(x_{off}-0.1)$$-y_{offset}$$-0.1 - 0.5 \Delta z_{dia}$$R_{top}$$R_{low}$0.70(2, 2, 1.2)Lung
L Lower$-x_{off}$$-y_{offset}$$-0.17 + 0.5 \Delta z_{dia}$$R_{low}$$R_{low}$$R_{z,low}$(2, 2, 2.5)Lung
R Upper$x_{off} - 0.1$$-y_{offset}$$-0.1 - 0.5 \Delta z_{dia}$$R_{top}$$R_{low}$0.70(2, 2, 1.2)Lung
R Lower$x_{off}$$-y_{offset}$$-0.17 + 0.5 \Delta z_{dia}$$R_{low}$$R_{low}$$R_{z,low}$(2, 2, 2.5)Lung
L Diaphragm$-x_{off}$$-y_{offset}$$-0.50 + \Delta z_{dia}$$R_{low}$$R_{low}$0.40(2.5, 2.5, 1.5)Body
R Diaphragm$x_{off}$$-y_{offset}$$-0.50 + \Delta z_{dia}$$R_{low}$$R_{low}$0.40(2.5, 2.5, 1.5)Body

6. Heart

Motion Parameters

Given chamber scales $s_{LV}, s_{RV}, s_{LA}, s_{RA}$:

Corrected cavity scales:

\[s'_{LV} = 1.10 s_{LV}, \quad s'_{RV} = 1.06 s_{RV}, \quad s'_{LA} = 0.95 s_{LA}, \quad s'_{RA} = 1.00 s_{RA}\]

Displacements:

\[\begin{aligned} dx_{LV} &= 0.45 \cdot 0.251 \cdot (s_{LV} - 1.0) \\ dx_{RV} &= 0.45 \cdot 0.209 \cdot (s_{RV} - 1.0) \\ dx_{LA} &= 0.15048 \cdot (s_{LA} - 1.0) \\ dx_{RA} &= 0.15048 \cdot (s_{RA} - 1.0) \\ dz_{LV} &= 0.209(s_{LV}-1), \quad dz_{LA} = 0.188(s_{LA}-1) \\ dz_{RV} &= 0.195(s_{RV}-1), \quad dz_{RA} = 0.188(s_{RA}-1) \\ z_{sep, L} &= 0.9(dz_{LV} + dz_{LA}) \\ z_{sep, R} &= 0.9(dz_{RV} + dz_{RA}) \end{aligned}\]

Constants: $z_{off} = 0.2$.

Heart Components Table

The heart is composed of 20 ellipsoids/superellipsoids.

Tuning parameters used in the cavity definitions:

\[\begin{aligned} \text{myocardium\_bottom\_z\_scale} &= 1.2 \\ \text{lv\_rad\_offset} &= 0.006 \\ \text{rv\_rad\_offset} &= 0.004, \\ \text{la\_rad\_offset} &= -0.001 \\ \text{ra\_rad\_offset} &= 0.0005 \\ \text{lv\_c\_base\_factor} &= 1.02 \\ \text{rv\_c\_base\_factor} &= 0.98 \end{aligned}\]

Define cavity scales $s_{LV,c}, s_{RV,c}, s_{LA,c}, s_{RA,c}$ as:

\[s_{LV,c} = 1.10 s_{LV},\quad s_{RV,c} = 1.06 s_{RV},\quad s_{LA,c} = 0.95 s_{LA},\quad s_{RA,c} = 1.00 s_{RA}\]

ComponentType$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
LV outer myocardium (base)Ellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$-0.1+z_{off}$$0.1595 s_{LV}$$0.2145 s_{LV}$$0.242 s_{LV}$$(2,2,2)$heart
RV outer myocardium (base)Ellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$-0.1+z_{off}$$0.1595 s_{RV}$$0.2145 s_{RV}$$0.242 s_{RV}$$(2,2,2)$heart
LV outer myocardium (mid)Superellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$0.0+z_{off}$$0.1485 s_{LV}$$0.2035 s_{LV}$$0.1782 s_{LV}$$(2.5,2.5,2.5)$heart
RV outer myocardium (mid)Superellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$0.0+z_{off}$$0.1485 s_{RV}$$0.2035 s_{RV}$$0.1782 s_{RV}$$(2.5,2.5,2.5)$heart
LV myocardium (base)Superellipsoid$-0.063-dx_{LV}$$0.02-y_{offset}$$(0.0+z_{off})-z_{sep,L}$$0.251 s_{LV}$$0.251 s_{LV}$$(0.209 s_{LV})\,\text{myocardium\_bottom\_z\_scale}$$(2,2,2)$heart
LV myocardium (mid)Superellipsoid$-0.063-dx_{LV}$$0.02-y_{offset}$$(0.08+z_{off})-z_{sep,L}$$0.195 s_{LV}$$0.195 s_{LV}$$0.157 s_{LV}$$(3,3,2)$heart
LV cavity (base)Superellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$(-0.1+z_{off})-z_{sep,L}$$(0.112125 s_{LV,c}+\text{lv\_rad\_offset})\,\text{lv\_c\_base\_factor}$$(0.160875 s_{LV,c}+\text{lv\_rad\_offset})\,\text{lv\_c\_base\_factor}$$(0.156 s_{LV,c})\,\text{lv\_c\_base\_factor}$$(2,2,2)$lv_blood
LV cavity (mid A)Superellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$(0.0+z_{off})-z_{sep,L}$$0.102375 s_{LV,c}+\text{lv\_rad\_offset}$$0.151125 s_{LV,c}+\text{lv\_rad\_offset}$$0.1404 s_{LV,c}$$(2.5,2.5,2.5)$lv_blood
LV cavity (mid B)Superellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$(0.0+z_{off})-z_{sep,L}$$0.193288 s_{LV,c}$$0.193288 s_{LV,c}$$0.14366 s_{LV,c}$$(2,2,2)$lv_blood
LV cavity (apex)Superellipsoid$-0.06-dx_{LV}$$0.02-y_{offset}$$(0.04+z_{off})-z_{sep,L}$$0.151496 s_{LV,c}$$0.151496 s_{LV,c}$$0.094032 s_{LV,c}$$(3,3,2)$lv_blood
RV myocardium (base)Superellipsoid$0.143+dx_{RV}$$0.0-y_{offset}$$(0.0+z_{off})-z_{sep,R}$$0.209 s_{RV}$$0.209 s_{RV}$$(0.195 s_{RV})\,\text{myocardium\_bottom\_z\_scale}$$(2,2,2)$heart
RV myocardium (mid)Superellipsoid$0.143+dx_{RV}$$0.0-y_{offset}$$(0.08+z_{off})-z_{sep,R}$$0.167 s_{RV}$$0.167 s_{RV}$$0.136 s_{RV}$$(3,3,2)$heart
RV cavity (base)Superellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$(-0.1+z_{off})-z_{sep,R}$$(0.11822 s_{RV,c}+\text{rv\_rad\_offset})\,\text{rv\_c\_base\_factor}$$(0.16962 s_{RV,c}+\text{rv\_rad\_offset})\,\text{rv\_c\_base\_factor}$$(0.16448 s_{RV,c})\,\text{rv\_c\_base\_factor}$$(2,2,2)$rv_blood
RV cavity (mid A)Superellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$(0.0+z_{off})-z_{sep,R}$$0.10794 s_{RV,c}+\text{rv\_rad\_offset}$$0.15934 s_{RV,c}+\text{rv\_rad\_offset}$$0.148032 s_{RV,c}$$(2.5,2.5,2.5)$rv_blood
RV cavity (mid B)Superellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$(0.0+z_{off})-z_{sep,R}$$0.172112 s_{RV,c}$$0.172112 s_{RV,c}$$0.133248 s_{RV,c}$$(2,2,2)$rv_blood
RV cavity (apex)Superellipsoid$0.14+dx_{RV}$$0.0-y_{offset}$$(0.04+z_{off})-z_{sep,R}$$0.1388 s_{RV,c}$$0.1388 s_{RV,c}$$0.094384 s_{RV,c}$$(3,3,2)$rv_blood
LA myocardiumSuperellipsoid$-0.101-dx_{LA}$$-0.05-y_{offset}$$(0.25+z_{off})+z_{sep,L}$$0.15 s_{LA}$$0.15 s_{LA}$$0.188 s_{LA}$$(2.2,2.2,2.2)$heart
LA cavitySuperellipsoid$-0.101$$-0.05-y_{offset}$$(0.25+z_{off})+z_{sep,L}$$0.134352 s_{LA,c}+\text{la\_rad\_offset}$$0.134352 s_{LA,c}+\text{la\_rad\_offset}$$0.16794 s_{LA,c}$$(2.2,2.2,2.2)$la_blood
RA myocardiumSuperellipsoid$0.161+dx_{RA}$$-0.07-y_{offset}$$(0.25+z_{off})+z_{sep,R}$$0.15 s_{RA}$$0.15 s_{RA}$$0.188 s_{RA}$$(2.2,2.2,2.2)$heart
RA cavitySuperellipsoid$0.161$$-0.07-y_{offset}$$(0.25+z_{off})+z_{sep,R}$$0.126468 s_{RA,c}+\text{ra\_rad\_offset}$$0.126468 s_{RA,c}+\text{ra\_rad\_offset}$$0.158085 s_{RA,c}$$(2.2,2.2,2.2)$ra_blood

7. Abdominal Organs

Liver

The liver is positioned in the left upper abdomen and moves with diaphragm motion. It consists of two lobes with respiratory-dependent positioning.

Constants:

  • Moves with: $\Delta z_{dia}$ (diaphragm vertical displacement)
  • Size scaling: $xy_{scale}$ (respiratory-dependent transverse scaling)
Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
Main Lobe-0.3$-0.15 - y_{offset}$$-0.55 + \Delta z_{dia}$$0.385 \cdot xy_{scale}$$0.33 \cdot xy_{scale}$0.3(2.5, 2.5, 2.5)Liver
Right Lobe-0.05$-0.12 - y_{offset}$$-0.5 + \Delta z_{dia}$$0.35 \cdot xy_{scale}$$0.275 \cdot xy_{scale}$0.25(1.5, 2.5, 2.5)Liver

Stomach

The stomach is positioned in the right upper abdomen and moves with diaphragm motion. It consists of the body and pyloric antrum.

Component$c_x$$c_y$$c_z$$R_x$$R_y$$R_z$$\epsilon$Intensity
Body0.45$0.0 - y_{offset}$$-0.55 + \Delta z_{dia}$$0.176 \cdot xy_{scale}$$0.176 \cdot xy_{scale}$0.3(2.5, 2.5, 2.5)Stomach
Pyloric Antrum0.25$-0.02 - y_{offset}$$-0.65 + \Delta z_{dia}$$0.12 \cdot xy_{scale}$$0.115 \cdot xy_{scale}$0.16(2.5, 2.5, 2.5)Stomach

8. Major Vessels

Major blood vessels are modeled as curved tubular structures using superellipsoids positioned along parameterized centerlines. All vessel structures use static positioning (no cardiac or respiratory motion).

Vessel Centerline Functions

Vessels follow 3D curved paths defined by sinusoidal functions to simulate anatomical curvature:

Aorta (Ascending):

\[\begin{aligned} x_{aorta}(z) &= -0.08 + 0.03 \sin(\pi (z - 0.2)) \\ y_{aorta}(z) &= -0.05 + 0.035 \sin(0.7\pi (z - 0.2) + 0.4) \end{aligned}\]

Pulmonary Trunk:

\[\begin{aligned} x_{pulm}(z) &= -0.05 + 0.02 \sin(\pi (z - 0.22) + 0.2) \\ y_{pulm}(z) &= -0.05 + 0.03 \sin(0.9\pi (z - 0.22) - 0.3) \end{aligned}\]

Superior Vena Cava:

\[\begin{aligned} x_{svc}(z) &= 0.1 + 0.05 \sin(0.8\pi (z - 0.3)) \\ y_{svc}(z) &= -0.05 + 0.03 \sin(0.6\pi (z - 0.3) + 0.2) \end{aligned}\]

Constants: $z_{offset} = 0.2$ (vertical offset for vessel centerlines)

Aorta (Ascending)

The aorta is composed of superellipsoid segments along its curved centerline. Radius: 0.04.

Segment$z_{center}$Height $R_z$Notes
11.00.08Upper thoracic
20.950.08
30.90.08
40.750.12Aortic arch region
50.60.12
60.450.12
70.320.1Descending (heart base)

Pulmonary Arteries

The pulmonary circulation consists of a main trunk that bifurcates into left and right branches extending laterally toward the lungs.

Main Pulmonary Trunk:

Segment$z_{center}$Height $R_z$Radius $R_x, R_y$
10.340.120.05
20.30.10.05

Left Pulmonary Branch:

The left branch follows a curved arc trajectory (rising then leveling to horizontal) extending from the bifurcation at $(x, y, z) = (-0.05, -0.05, 0.48 + z_{offset})$ to the left lung at $(-0.31, -0.01, 0.59 + z_{offset})$.

Segment$z$ (rel)$c_x$$c_y$$R_{xy}$$R_z$
10.48-0.05$-0.05 - y_{offset}$0.0450.06
20.53-0.09$-0.04 - y_{offset}$0.0430.06
30.57-0.14$-0.035 - y_{offset}$0.0410.06
40.60-0.19$-0.03 - y_{offset}$0.0390.06
50.61-0.23$-0.025 - y_{offset}$0.0370.06
60.61-0.26$-0.02 - y_{offset}$0.0350.06
70.60-0.29$-0.015 - y_{offset}$0.0330.06
80.59-0.31$-0.01 - y_{offset}$0.0310.06

Right Pulmonary Branch:

The right branch mirrors the left branch trajectory, extending from $(0.0, -0.05, 0.48 + z_{offset})$ to the right lung at $(0.26, -0.01, 0.59 + z_{offset})$.

Segment$z$ (rel)$c_x$$c_y$$R_{xy}$$R_z$
10.480.00$-0.05 - y_{offset}$0.0450.06
20.530.04$-0.04 - y_{offset}$0.0430.06
30.570.09$-0.035 - y_{offset}$0.0410.06
40.600.14$-0.03 - y_{offset}$0.0390.06
50.610.18$-0.025 - y_{offset}$0.0370.06
60.610.21$-0.02 - y_{offset}$0.0350.06
70.600.24$-0.015 - y_{offset}$0.0330.06
80.590.26$-0.01 - y_{offset}$0.0310.06

All pulmonary branch segments use $\epsilon = (2.5, 2.5, 2.5)$. The z-coordinates show an arc pattern: initially rising (0.48→0.61), then leveling and slightly descending (0.61→0.59), creating a curved trajectory that converges toward horizontal as the branches extend laterally to the lungs.

Superior Vena Cava

The superior vena cava extends from the upper thorax to the right atrium. Radius: 0.04.

Segment$z_{center}$Height $R_z$Notes
11.00.08Upper thoracic
20.950.08
30.820.1
40.680.12Mid thoracic
50.550.12
60.450.08Approaches right atrium

All vessel segments use intensity value vessels_blood (1.00) and $\epsilon = (2.5, 2.5, 2.5)$ for smooth, rounded tubular geometry.

9. Physiological Signal Generation

Respiratory Signal

The default respiratory signal $S_{resp}(t)$ (in Liters) is generated with a fundamental frequency $f_{resp} = RR/60$ Hz.

  1. Phase Evolution (with Rate Variability $A_{rr}, f_{rr}$):

\[\theta(t) = 2\pi f_{resp} t - \frac{f_{resp} A_{rr}}{f_{rr}} (\cos(2\pi f_{rr} t) - 1)\]

  1. Base Waveform (Asymmetric):

\[W(t) = \sin(\theta(t)) + A_{asym} \sin(2\theta(t))\]

  1. Amplitude Modulation (Depth Variability $A_{am}, f_{am}$):

\[\begin{aligned} &M(t) = 1 + A_{am} \sin(2\pi f_{am} t) \\ &S_{raw}(t) = W(t) \cdot M(t) \end{aligned}\]

  1. Normalization:

\[\begin{aligned} S_{norm} &= \frac{S_{raw}(t) - \min(S_{raw})}{\max(S_{raw}) - \min(S_{raw})} \\ S_{resp}(t) &= physiology.minL .+ (physiology.maxL - physiology.minL) .* S_{norm} \end{aligned}\]

where physiology refers to the respiratory signal generation parameters defined, defaulting to minL = 1.2 and maxL = 6.0 Liters. For more details, see API Reference.

Cardiac Signals

The function generate_cardiac_signals(duration, fs, HR; physiology=CardiacPhysiology()) generates chamber-volume time series for LV, RV, LA, and RA (mL).

Given sampling frequency $f_s$ and duration $D$, the time axis is:

\[t_n = n/f_s, \quad n=0,1,\dots,\lfloor D f_s \rfloor-1\]

Heart rate and cycle period are:

\[f_{HR} = HR/60, \qquad T = 1/f_{HR}\]

Phase Model and Time-Varying Systole Fraction

To model mild beat-to-beat variability, the implementation uses a warped time variable:

\[t_{var}(t) = t + A_{HR}\sin(2\pi f_{HR,var} t)\]

where $A_{HR} = physiology.hr\_var\_amp$ and $f_{HR,var} = physiology.hr\_var\_freq$.

Phase is then:

\[\phi(t) = (t_{var}(t) \bmod T)/T \in [0,1)\]

Systole fraction is not constant; it oscillates around $s\_frac\_base$:

\[\gamma(t) = s_{frac,base}\left(1 + 0.08\sin(2\pi\cdot0.1\,t)\right)\]

with $s_{frac,base} = physiology.s\_frac\_base$ (default 0.35).

Normalized coordinates in each phase are:

\[x_s = \mathrm{clamp}(\phi/\gamma,\,0,1), \qquad x_d = \mathrm{clamp}((\phi-\gamma)/(1-\gamma),\,0,1)\]

Ventricular Volumes (LV, RV)

Define stroke ranges:

\[\Delta V_{LV} = V_{LV,ED} - V_{LV,ES}, \qquad \Delta V_{RV} = V_{RV,ED} - V_{RV,ES}\]

Systole (ejection, both ventricles):

\[V_{LV,s} = V_{LV,ED} - \Delta V_{LV}\left(1-(1-x_s)^3\right)\]

\[V_{RV,s} = V_{RV,ED} - \Delta V_{RV}\left(1-(1-x_s)^3\right)\]

Diastole (passive filling + late atrial kick):

\[V_{LV,d} = V_{LV,ES} + \Delta V_{LV}x_d^{2.2} + A_{LV,kick}\,\Delta V_{LV}\exp\!\left[-\left(\frac{x_d-\mu_{LV,kick}}{\sigma_{LV,kick}}\right)^2\right]\]

\[V_{RV,d} = V_{RV,ES} + \Delta V_{RV}x_d^{2.0} + A_{RV,kick}\,\Delta V_{RV}\exp\!\left[-\left(\frac{x_d-\mu_{RV,kick}}{\sigma_{RV,kick}}\right)^2\right]\]

with $A_{LV,kick}=physiology.lv\_kick\_amp\_frac$, $\mu_{LV,kick}=physiology.lv\_kick\_center$, $\sigma_{LV,kick}=physiology.lv\_kick\_width$ and analogous RV parameters.

The final piecewise ventricular signals are:

\[V_{LV}(t)=\begin{cases} V_{LV,s}, & \phi < \gamma\\ V_{LV,d}, & \phi \ge \gamma \end{cases}, \qquad V_{RV}(t)=\begin{cases} V_{RV,s}, & \phi < \gamma\\ V_{RV,d}, & \phi \ge \gamma \end{cases}\]

Atrial Volumes (LA, RA)

Define atrial ranges:

\[\Delta V_{LA} = V_{LA,max} - V_{LA,min}, \qquad \Delta V_{RA} = V_{RA,max} - V_{RA,min}\]

Systole (atria filling while ventricles eject):

\[V_{LA,s} = V_{LA,min} + \Delta V_{LA}x_s^{1.5}, \qquad V_{RA,s} = V_{RA,min} + \Delta V_{RA}x_s^{1.5}\]

Diastole (atria emptying + contraction notch):

\[V_{LA,d} = V_{LA,max} - \Delta V_{LA}\left(1-(1-x_d)^3\right) - A_{LA,contr}\,\Delta V_{LA}\exp\!\left[-\left(\frac{x_d-\mu_{LA,contr}}{\sigma_{LA,contr}}\right)^2\right]\]

\[V_{RA,d} = V_{RA,max} - \Delta V_{RA}\left(1-(1-x_d)^3\right) - A_{RA,contr}\,\Delta V_{RA}\exp\!\left[-\left(\frac{x_d-\mu_{RA,contr}}{\sigma_{RA,contr}}\right)^2\right]\]

with contraction parameters from la_contr_amp_frac, la_contr_center, la_contr_width and ra_contr_amp_frac, ra_contr_center, ra_contr_width.

Piecewise atrial signals are:

\[V_{LA}(t)=\begin{cases} V_{LA,s}, & \phi < \gamma\\ V_{LA,d}, & \phi \ge \gamma \end{cases}, \qquad V_{RA}(t)=\begin{cases} V_{RA,s}, & \phi < \gamma\\ V_{RA,d}, & \phi \ge \gamma \end{cases}\]

Slow Modulation and Baseline Wander

After piecewise synthesis, slow modulations are applied:

\[M_V(t)=1 + A_V\sin(2\pi f_V t), \qquad M_A(t)=1 + A_A\sin(2\pi f_A t + 0.7)\]

\[B(t)=A_{BW}\sin(2\pi f_{BW} t)\]

where $A_V=physiology.v\_amp\_amp$, $f_V=physiology.v\_amp\_freq$, $A_A=physiology.a\_amp\_amp$, $f_A=physiology.a\_amp\_freq$, $A_{BW}=physiology.bw\_amp$, and $f_{BW}=physiology.bw\_freq$.

Final output signals are:

\[\widetilde V_{LV}=V_{LV}M_V + B, \qquad \widetilde V_{RV}=V_{RV}M_V + B\]

\[\widetilde V_{LA}=V_{LA}M_A + 0.8B, \qquad \widetilde V_{RA}=V_{RA}M_A + 0.8B\]

The function returns $(t, (lv=\widetilde V_{LV}, rv=\widetilde V_{RV}, la=\widetilde V_{LA}, ra=\widetilde V_{RA}))$.