diff --git a/src/MRIBuilder.jl b/src/MRIBuilder.jl
index bedc3c684f1b7583a5f464abadfe1e2cf2e88df9..857f0e69705c843e15c579d7a5df76d2a6029682 100644
--- a/src/MRIBuilder.jl
+++ b/src/MRIBuilder.jl
@@ -13,6 +13,7 @@ include("pulses/pulses.jl")
 include("readouts/readouts.jl")
 include("overlapping/overlapping.jl")
 include("sequences.jl")
+include("alternatives.jl")
 include("pathways.jl")
 include("helper_functions.jl")
 
@@ -46,6 +47,9 @@ export TrapezoidGradient, SpoiltSliceSelect, interruptions, waveform, SingleLine
 import .Sequences: Sequence
 export Sequence
 
+import .Alternatives: AlternativeBlocks
+export AlternativeBlocks
+
 import .Pathways: Pathway, duration_transverse, duration_dephase, bval, bmat
 export Pathway, duration_transverse, duration_dephase, bval, bmat
 
diff --git a/src/alternatives.jl b/src/alternatives.jl
new file mode 100644
index 0000000000000000000000000000000000000000..c46a05e81de8495c37847d8e7294f1839e2c1818
--- /dev/null
+++ b/src/alternatives.jl
@@ -0,0 +1,45 @@
+module Alternatives
+import JuMP: @constraint
+import ..BuildingBlocks: BuildingBlock, match_blocks!
+import ..BuildSequences: global_model
+import ..Variables: duration
+
+"""
+    AlternativeBlocks(name, blocks)
+
+Represents a part of the sequence where there are multiple possible alternatives.
+
+Variables can be matched across these alternatives using [`match_blocks!`](@ref).
+
+The `name` is a symbol that is used to identify this `AlternativeBlocks` in the broader sequence.
+"""
+struct AlternativeBlocks <: BuildingBlock
+    name :: Symbol
+    options :: Vector{<:BuildingBlock}
+end
+
+Base.getindex(alt::AlternativeBlocks, index::Int) = alt.options[index]
+
+duration(alt::AlternativeBlocks) = maximum(duration.(alt.options))
+
+"""
+    match_blocks!(alternatives, function)
+
+Matches the outcome of given `function` on each of the building blocks in [`AlternativeBlocks`](@ref).
+
+For example, `match_blocks!(alternatives, duration)` will ensure that all the alternative building blocks have the same duration.
+"""
+function match_blocks!(alternatives::AlternativeBlocks, func)
+    baseline = func(alternatives[1])
+    for other_block in alternatives.options[2:end]
+        if baseline isa AbstractVector
+            @constraint global_model() baseline == func(other_block)
+        else
+            @constraint global_model() baseline .== func(other_block)
+        end
+    end
+end
+
+
+
+end
\ No newline at end of file
diff --git a/src/helper_functions.jl b/src/helper_functions.jl
index 75e34c53656f9c4b7106c51b4eb16d2b44380d4a..776898c2f33be8e88e9de067acfbd555f106f871 100644
--- a/src/helper_functions.jl
+++ b/src/helper_functions.jl
@@ -5,7 +5,8 @@ import ..BuildSequences: global_model, build_sequence
 import ..Sequences: Sequence
 import ..Pulses: SincPulse, ConstantPulse, InstantRFPulseBlock
 import ..Overlapping: TrapezoidGradient, SpoiltSliceSelect, opposite_kspace_lines
-import ..Variables: qvec
+import ..Variables: qvec, flat_time, rise_time
+import ..Alternatives: AlternativeBlocks, match_blocks!
 
 
 function _get_pulse(shape, flip_angle, phase, frequency, Nzero, scale, bandwidth, duration)
@@ -198,10 +199,18 @@ Helper function used to build the readout for any Cartesian readout, i.e.:
 function cartesian_readout(start_lines, readout_lines, fov, resolution_x; scanner=nothing, optimise=false, kwargs...)
     @assert iszero(readout_lines[1])
     build_sequence(scanner; optimise=optimise) do
-        max_ky = maximum(abs.(start_lines)) * 1e-3 / fov[2]
-        to_scale_ky = length(start_lines) == 1 ? nothing : (nothing, :phase_encode, nothing)
-        prepare_kspace = TrapezoidGradient(scale=to_scale_ky, rotate=:FOV, duration=:min)
         (pos_line, neg_line) = opposite_kspace_lines(; rotate=:FOV, fov=fov[1], resolution=resolution_x, kwargs...)
+        ky = @. start_lines * 1e-3 / fov[2]
+        if length(start_lines) == 1
+            prepare_kspace = TrapezoidGradient(rotate=:FOV, duration=:min, qvec=[-qvec(pos_line, nothing, 1)[1], ky[1], 0.])
+        else
+            prepare_kspace = AlternativeBlocks(
+                :readout_segment,
+                [TrapezoidGradient(rotate=:FOV, duration=:min, qvec=[-qvec(pos_line, nothing, 1)[1], ky_prep, 0.]) for ky_prep in ky]
+            )
+            match_blocks!(prepare_kspace, flat_time)
+            match_blocks!(prepare_kspace, rise_time)
+        end
 
         steps = (readout_lines[2:end] - readout_lines[1:end-1])
         blips = Dict(
@@ -218,9 +227,6 @@ function cartesian_readout(start_lines, readout_lines, fov, resolution_x; scanne
             append!(result, [blips[s], next_line])
             next_line = next_line == pos_line ? neg_line : pos_line
         end
-        @constraint global_model() qvec(prepare_kspace)[1] == -qvec(pos_line, nothing, 1)[1]
-        @constraint global_model() qvec(prepare_kspace)[2] == max_ky
-        @constraint global_model() qvec(prepare_kspace)[3] == 0.
         return Sequence(result...; TR=Inf)
     end
 end