- Config name
model: b1_afiBIDS suffixTB1AFIMethod family- Field Mapping Acquired volumes
- 2 Fit granularity
- voxelwise
Maps the transmit (B1+) field from a single spoiled gradient-echo sequence that interleaves two excitation repetition times at one nominal flip angle. In the pulsed steady state the ratio of the two signals depends on the achieved flip angle alone, so proton density and receive sensitivity cancel. The result is dimensionless — the achieved flip angle as a fraction of the nominal one — and feeds the B1 correction of models such as MTsat and VFA. The closed form assumes the repetition times are short against T1, and underestimates B1 as that assumption weakens.
Signal model¶
| Symbol | Quantity | Unit |
|---|---|---|
B1 | Relative transmit field | — |
T1 | Longitudinal relaxation time | s |
What the model reads¶
A series of 2 volumes indexed by RepetitionTimeExcitation. Volumes are matched to these identities by value, so reordering the acquisition yields an identical fit.
| # | RepetitionTimeExcitation |
|---|---|
| 1 | 0.02 |
| 2 | 0.1 |
Where the protocol comes from¶
In a BIDS dataset these values are resolved for you:
| Protocol parameter | Source | Key | Resolved |
|---|---|---|---|
RepetitionTimeExcitation | sidecar field | RepetitionTimeExcitation | per volume |
FlipAngle | sidecar field | FlipAngle | whole collection |
Inputs¶

Figure 1:The 2 acquired volumes, each labeled with the identity the model reads it by.
Outputs¶
| Map | BIDS suffix | Unit | Fit bounds | Fitted |
|---|---|---|---|---|
B1 | TB1map | — | 0 … 2 | free |

Figure 2:Fitted maps for one example subject.
Usage¶
The acquisition comes from the sidecars, so recipes/bids/b1_afi_config.yaml carries only algorithm options:
model: b1_afi
# B1 = acos((r*n - 1) / (n - r)) / nomFA, with r the signal ratio of the two
# interleaved repetition times, n = TR2/TR1, and the map dimensionless
# (1.0 = the nominal flip angle was achieved). BIDS input:
# RepetitionTimeExcitation and FlipAngle are read from the JSON sidecars via
# the model's protocol_schema(), so neither is declared here. The TB1AFI
# collection is assembled by the `acq` entity (acq-tr1 / acq-tr2). Example:
#
# qmrust fit --bids-dir <dataset> \
# --config recipes/bids/b1_afi_config.yaml --output-dir out
# BIDS mask selection. Left blank: this example dataset ships no mask, and
# naming one here would claim otherwise. Blank means "whatever mask is
# present", so a dataset of your own that has one is masked by it.
mask:
desc: ""qmrust fit --bids-dir ds-mydata \
--config recipes/bids/b1_afi_config.yaml --output-dir outFitted maps are written as BIDS derivatives:
out/derivatives/qmrust/sub-01/fmap/
sub-01_TB1map.nii.gz
sub-01_TB1map.jsonNo sidecars, so recipes/non-bids/b1_afi_config.yaml declares the acquisition itself:
model: b1_afi
# non-BIDS: protocol from this file; mask via --mask.
# Times in seconds (BIDS/SI), flip angle in degrees (BIDS-MRI convention).
# qMRLab's b1_afi default protocol is nomFA = 60 deg with TR1/TR2 of 20/100 ms;
# its Sequence matrix records those two in milliseconds, so they are converted
# once here at the shell boundary. Only their ratio enters the estimate.
repetition_times:
- 0.02
- 0.10
flip_angle: 60
# There are no fit options: the estimate is closed form.
#
# Two uses:
# - bidsify a qMRLab dataset (AFIData1.nii.gz / AFIData2.nii.gz) by naming
# one --nii-data per volume, in acquisition order:
#
# qmrust bidsify --model b1_afi \
# --nii-data AFIData1.nii.gz --nii-data AFIData2.nii.gz \
# --config recipes/non-bids/b1_afi_config.yaml --subject 01 --out ds
#
# - fit a stacked 4D NIfTI whose two volumes are [TR1, TR2]:
#
# qmrust fit --data afi.nii.gz --mask Mask.nii.gz \
# --config recipes/non-bids/b1_afi_config.yaml --output-dir out_b1qmrust fit --data data.nii.gz --mask mask.nii.gz \
--config recipes/non-bids/b1_afi_config.yaml \
--output-dir outSee Fitting without BIDS.
model: b1_afi
# Simulation: the acquisition comes from this file. Times in seconds (BIDS/SI),
# flip angle in degrees (BIDS-MRI convention). Only the ratio of the two
# repetition times enters the estimate.
repetition_times:
- 0.02
- 0.10
flip_angle: 60
# Ground truth: B1 is a normalized scaling of the nominal flip angle, so 1.0 is
# a perfectly delivered pulse.
sim:
params: { B1: 1.0, T1: 1.0 }
noise: { type: rician, snr: 100.0 }
seed: 0
trials: 100
sweep: { param: B1, start: 0.6, stop: 1.4, steps: 10 }
distributions:
B1: { mean: 1.0, std: 0.1 }qmrust sim signal --config recipes/sim/b1_afi_sim.yaml --output signal.json
qmrust sim single-voxel --config recipes/sim/b1_afi_sim.yaml --output sv.json
qmrust sim sensitivity --config recipes/sim/b1_afi_sim.yaml --output sens.json
qmrust sim montecarlo --config recipes/sim/b1_afi_sim.yaml --output mc.jsonSee Simulation.
The same core, compiled to WebAssembly:
import init, { fit_volume } from './pkg/qmrust_wasm.js';
await init();
const maps = fit_volume(configYaml, data, [nx, ny, nz, nt],
JSON.stringify(volumeIds), mask, '{}');Try it on real data in the playground, or read Browser & wasm.
Implementation¶
model.rs— theModelimplementation: measurement contract, protocol schema, BIDS outputs.fit.rs— the numerical fit.config.rs— configuration and validation.
Fully-resolved configuration
Every default materialized, as qmrust dump-config prints it.
model: b1_afi
repetition_times:
- 0.02
- 0.1
flip_angle: 60.0References¶
Yarnykh (2007)
- Yarnykh, V. L. (2007). Actual flip-angle imaging in the pulsed steady state: A method for rapid three-dimensional mapping of the transmitted radiofrequency field. Magnetic Resonance in Medicine, 57(1), 192–200.