Build Sequences with @addblock
A Koma Sequence is a list of sequence blocks. Each block stores RF events, one gradient per axis, ADC events, a duration, and extensions such as labels, triggers, or rotations.
This page shows the block-oriented style for building pulse programs. It maps closely to MATLAB Pulseq and PyPulseq addBlock / add_block code, but Koma can also append named Sequence parts, such as a readout or prephaser, in one statement.
Use @addblock to append block expressions:
seq = Sequence() # or Sequence(sys) for scanner export checks
@addblock seq += (rf, z=gz)After +=, each tuple becomes a Sequence of length one and its events are copied into seq. Each Sequence on the right-hand side contributes all of its blocks. + appends them left-to-right:
@addblock seq += (rf, z=gz) + (x=gx, adc) + (Delay(TR), LabelInc(1, "ECO"))Gradient Axes
Koma Grad events are axis-neutral. Choose the axis when adding the block with x=, y=, or z=. RF, ADC, and extensions are positional.
@addblock seq += (rf, LabelSet(ky, "LIN"), z=gz)Named tuples are useful when a block has gradients on several axes:
slice_select = (x=gx_slice, y=gy_slice, z=gz_slice)
rewinder = (x=gx_rewind, y=gy_rewind, z=gz_rewind)
excitation = Sequence()
@addblock excitation += (rf; slice_select...) + (; rewinder...)Block Duration
Use Delay(T) for a minimum block duration. Use Duration(T) for an exact block duration; it errors if any RF, gradient, or ADC event is longer than T.
@addblock seq += (rf, Delay(TR), z=gz) # at least TR
@addblock seq += (rf, Duration(TR), z=gz) # exactly TR, or errorsDelay and Duration are construction helpers: they update block DUR; they are not stored as RF, gradient, ADC, or extension events.
Scanner and Raster Times
Use Sequence(sys) when export checks should use a scanner. write_seq checks raster timing and event-local hardware limits from seq.DEF, or from sys when passed. Plain Sequence() uses Pulseq file rasters and non-limiting hardware limits.
sys = Scanner(Gmax=40e-3, Smax=150)
seq = Sequence(sys)
@addblock seq += (rf, z=gz)
write_seq(seq, "sequence.seq") # checks raster and hw limits in seq.DEFAdd Blocks in Loops
Use @addblocks around loops that append to a sequence. Inside the macro, seq += ... appends in place.
@addblocks for ky in 1:Ny
seq += (rf, z=gz)
seq += (x=gx, y=phase_blip(ky), adc)
endDo not use plain seq += readout in long loops. In Julia it means seq = seq + readout; Koma's + returns a copied sequence so reused events do not share mutable events. That is safe, but can be more than 800x slower in long loops.
Reuse Named Sequences
Name a small part of the pulse program as a normal Sequence, then append it. For example, readout below is a one-block Sequence, not a new event type.
readout = Sequence()
@addblock readout += (ADC(num_readout_samples, adc_duration, ζ), x=Grad(G_readout, T_readout, ζ))
prephaser = Sequence()
@addblock prephaser += (x=Grad(Gx_prephaser, T_prephaser, ζ_prephaser), y=Grad(Gy_prephaser, T_prephaser, ζ_prephaser))
@addblock seq += prephaser + readoutAppend named sequences in loops with @addblocks:
@addblocks for ky in 1:Ny
seq += rf_preparation + readout(ky)
endTransform Sequences
Koma defines arithmetic on Sequence values. Each operation returns a copy, so the original sequence can be reused. Inside @addblock, left-multiplying a block tuple applies the same operation to that one-block sequence.
Scale Gradients
Use real scalars to scale gradient amplitudes.
@addblock seq += 0.5 * (x=gx, adc)Rotate Gradients
real_matrix * sequence mixes gradient axes and leaves RF and ADC unchanged.
@addblock seq += rotz(π / 6) * (x=gx, adc)Phase RF and ADC
complex_scalar * sequence phase-shifts RF and ADC. Gradients are unchanged. Use cis(ϕ) for exp(im * ϕ).
phase = cis(π / 2) # exp(im * π / 2)
@addblock seq += phase * (rf, z=gz) + phase * (x=gx, adc)Build Radial Spokes
Rotate the readout block for each spoke:
@addblocks for spoke in 0:Nspokes-1
θ = π * spoke / Nspokes
seq += (rf, z=gz) + rotz(θ) * (x=gx, adc)
endAppend Semantics
Use this section when you need to reason about copies or performance. Tuple terms become one new block through addblock!. Existing Sequence terms append all of their blocks through append!.
@addblock seq += (rf, z=gz) + (x=gx, adc)@addblocks applies the same rewrite to += expressions in its scope when the left-hand side is a Sequence.