-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pulse Designer #305
base: master
Are you sure you want to change the base?
Pulse Designer #305
Conversation
@@ -0,0 +1,26 @@ | |||
""" | |||
""" | |||
function make_adc(num_samles; Δtadc=0, duration=0, delay=0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo num_samles to num_samples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will be completelly replaced
delay = dead_time; # adcDeadTime is added before the actual sampling (and also second time after the sampling period) | ||
end | ||
|
||
adc = ADC(num_samles, duration, delay, freq_offset, phase_offset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should output a Sequence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will be completelly replaced, all the outpus will be of type Sequence
@assert maximum(abs.(waveform)) <= max_grad "Gradient amplitude violation ($(maximum(abs.(waveform)) / max_grad * 100)%)" | ||
|
||
duration = (length(waveform)-1) * Δtgr | ||
return Grad(waveform, duration, 0, 0, delay) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should output a Sequence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will be completelly replaced, all the outpus will be of type Sequence
dly = Delay(delay + duration + ring_down_time) # I NEED a review | ||
end | ||
|
||
return RF(amplitude, duration, freq_offset, delay), dly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should output a Sequence. The DUR variable is not set using Delay objects, we may need to change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea now is to add a duration to the ouput Sequence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seq.DUR needs to be a vector of Delay's. To be able to combine them as we talked #4
dly = Delay(rf.delay + rf.T + ring_down_time) # I NEED a review | ||
end | ||
|
||
return rf, gz, gzr, dly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should output a Sequence. The Delay should be the DUR.
dly = Delay(rf.delay + rf.T + ring_down_time) # I NEED a review | ||
end | ||
|
||
return rf, gz, gzr, delay |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should output a Sequence
KomaMRIBase/test/runtests.jl
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests should verify that the gradient/rf/adc satisfies the design inputs (area of the gradiet, duration, etc)
if !isnothing(sys) | ||
dead_time = sys.ADC_dead_time_T | ||
Δtadc = sys.ADC_Δt | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be required, set the default for optional parameter sys = Scanner()
if (Δtadc == 0 && duration == 0) || (Δtadc > 0 && duration > 0) | ||
@error "Either dwell or duration must be defined" | ||
end | ||
if duration > 0 | ||
Δtadc = duration / num_samles | ||
elseif Δtadc > 0 | ||
duration = Δtadc * num_samles; | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use multiple dispatch
if !isnothing(sys) | ||
max_grad = sys.Gmax | ||
max_slew = sys.Smax | ||
Δtgr = sys.GR_Δt | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be required, set the default for optional parameter sys = Scanner()
if area == 0 && flat_area == 0 && amplitude == 0 | ||
@error "trapezoid: invalid keywords. Must supply either 'area', 'flat_area' or 'amplitude'" | ||
end | ||
if fall_time > 0 && rise_time == 0 | ||
@error "trapezoid: invalid keywords. Must always supply 'rise_time' if 'fall_time' is specified explicitly." | ||
end | ||
|
||
if flat_time > 0 | ||
if amplitude == 0 | ||
if flat_area == 0 | ||
@error "trapezoid: invalid keyworks. When 'flat_time' is provided either 'flat_area' or 'amplitude' must be provided as well; you may consider providing 'duration', 'area' and optionally ramp times instead." | ||
end | ||
amplitude = flat_area / flat_time | ||
end | ||
if rise_time == 0 | ||
rise_time = abs(amplitude) / max_slew; | ||
rise_time = ceil(rise_time / Δtgr) * Δtgr; | ||
if rise_time == 0 | ||
rise_time = Δtgr | ||
end | ||
end | ||
if fall_time == 0 | ||
fall_time = rise_time | ||
end | ||
elseif duration > 0 | ||
if amplitude == 0 | ||
if rise_time == 0 | ||
dC = 1 / abs(2 * max_slew) + 1 / abs(2 * max_slew) | ||
possible = duration^2 > 4 * abs(area) * dC; | ||
@assert possible "Requested area is too large for this gradient. Minimum required duration (assuming triangle gradient can be realized) is $(round(sqrt(4 * abs(area) * dC) * 1e6)) us" | ||
amplitude = (duration - sqrt(duration^2 - 4 * abs(area) * dC)) / (2 * dC) | ||
else | ||
if fall_time == 0 | ||
fall_time = rise_time | ||
end | ||
amplitude = area / (duration - 0.5 * rise_time - 0.5 * fall_time) | ||
possible = duration > (rise_time + fall_time) && abs(amplitude) < max_grad | ||
@assert possible "Requested area is too large for this gradient. Probably amplitude is violated ($(round(abs(amplitude) / max_grad * 100))%)" | ||
end | ||
end | ||
if rise_time == 0 | ||
rise_time = ceil(abs(amplitude) / max_slew / Δtgr) * Δtgr | ||
if rise_time == 0 | ||
rise_time = Δtgr | ||
end | ||
end | ||
if fall_time == 0 | ||
fall_time = rise_time | ||
end | ||
flat_time = duration - rise_time - fall_time | ||
if amplitude == 0 | ||
# Adjust amplitude (after rounding) to achieve given area | ||
amplitude = area / (rise_time / 2 + fall_time / 2 + flat_time) | ||
end | ||
else | ||
if area == 0 | ||
@error "trapezoid: invalid keywords. Must supply area or duration" | ||
else | ||
# find the shortest possible duration | ||
# first check if the area can be realized as a triangle | ||
# if not we calculate a trapezoid | ||
rise_time = ceil(sqrt(abs(area) / max_slew) / Δtgr) * Δtgr | ||
if rise_time < Δtgr # the "area" was probably 0 or almost 0 ... | ||
rise_time = Δtgr; | ||
end | ||
amplitude = area / rise_time | ||
t_eff = rise_time | ||
if abs(amplitude) > max_grad | ||
t_eff = ceil(abs(area) / max_grad / Δtgr) * Δtgr | ||
amplitude = area / t_eff | ||
if rise_time == 0 | ||
rise_time = Δtgr | ||
end | ||
end | ||
flat_time = t_eff - rise_time | ||
fall_time = rise_time | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use multiple dispatch to simplify this, the code is too convoluted
end | ||
end | ||
|
||
@assert abs(amplitude) <= max_grad "trapezoid: invalid amplitude. Amplitude violation ($(round(abs(amplitude) / max_grad * 100))%)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use functions to check hardware limits for the input sys
.
if !isnothing(sys) | ||
max_grad = sys.Gmax | ||
max_slew = sys.Smax | ||
Δtgr = sys.GR_Δt | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not required
slew = (waveform[2:end] - waveform[1:end-1]) / Δtgr | ||
if !isempty(slew) | ||
@assert maximum(abs.(slew)) <= max_slew "Slew rate violation ($(maximum(abs.(slew)) / max_slew * 100)%)" | ||
end | ||
@assert maximum(abs.(waveform)) <= max_grad "Gradient amplitude violation ($(maximum(abs.(waveform)) / max_grad * 100)%)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use functions to check this.
if duration == 0 | ||
if time_bw_product > 0 | ||
duration = time_bw_product / bandwidth | ||
elseif bandwidth > 0 | ||
duration = 1 / (4 * bandwidth) | ||
else | ||
@error "Either bandwidth or duration must be defined" | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mulitiple dispatch
if !isnothing(sys) | ||
dead_time = sys.RF_dead_time_T | ||
ring_down_time = sys.RF_ring_down_T | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not required
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #305 +/- ##
==========================================
- Coverage 92.60% 90.77% -1.84%
==========================================
Files 33 36 +3
Lines 2245 2417 +172
==========================================
+ Hits 2079 2194 +115
- Misses 166 223 +57
Flags with carried forward coverage won't be shown. Click here to find out more.
|
if dead_time > delay | ||
delay = dead_time | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delay = max(dead_time, delay)
if !isnothing(sys) | ||
dead_time = sys.RF_dead_time_T | ||
ring_down_time = sys.RF_ring_down_T | ||
Δtrf = sys.RF_Δt | ||
Δtgr = sys.GR_Δt | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate functions in different files. All of them, not only the ones in ADC.
if dead_time > delay | ||
delay = dead_time | ||
end | ||
rf = RF(signal, duration, freq_offset, delay) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation problem.
if dead_time > delay | ||
delay = dead_time | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delay = max(delay, dead_time)
amplitude = BW / slice_thickness | ||
area = amplitude * duration | ||
gz = trapezoid(; flat_time=duration, flat_area=area, sys=sys); | ||
gz_area = gz.A * (gz.T + gz.rise / 2 + gz.fall / 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need a function to calculate the area of a Grad (get_kspace almost does this)
|
||
N = length(signal) | ||
duration = (N-1) * Δtrf | ||
t = range(0, duration; length=N) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this even being used? ( t = range(0, duration; length=N)
)
if rf.delay < gz.rise + gz.delay | ||
rf.delay = gz.rise + gz.delay # these are on the grad raster already which is coarser | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delay = max(...)
dly = Delay(0) | ||
if ring_down_time > 0 | ||
dly = Delay(rf.delay + rf.T + ring_down_time) # I NEED a review | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ring_down_time is not > 0, it must be zero, therefore dly = Delay(rf.delay + rf.T + ring_down_time)
is always correct
t = range(0, duration; length=N) | ||
window = (1 - apodization) .+ apodization * cos.(2π * ((t .- (centerpos * duration)) / duration)) | ||
signal = window .* sinc.(BW * (t .- (centerpos * duration))) | ||
flip = 0.5 * sum(signal[2:end] + signal[1:end-1]) * Δtrf * 2π |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use get_flip_angle function, I think this assumes that signal is in a particular unit. Is missing the multiplication by gamma.
#Angle{T} = Union{Quantity{T, NoDims, typeof(u"rad")}, Quantity{T, NoDims, typeof(u"°")}} where T | ||
|
||
function KomaMRIBase.block_pulse(x::Real) | ||
return "Hola" | ||
end | ||
|
||
#function KomaMRIBase.block_pulse(duration::Unitful.Time; | ||
# phase_offset::Angle=0u"°", freq_offset::Frequency=0u"Hz", delay=0u"s", sys=Scanner()) | ||
# duration, phase_offset, freq_offset, delay = upreferred.((duration, phase_offset, freq_offset, delay)) | ||
# return PulseDesigner.block_pulse(FlipAngle(π/2), Duration(duration); phase_offset, freq_offset, delay, sys) | ||
#end | ||
|
||
|
||
#function PulseDesigner.block_pulse(flip_angle::Angle, duration::Unitful.Time; | ||
# phase_offset::Angle=0u"°", freq_offset::Frequency=0u"Hz", delay=0u"s", sys=Scanner()) | ||
# flip_angle, duration, phase_offset, freq_offset, delay = upreferred.((flip_angle, duration, phase_offset, freq_offset, delay)) | ||
# return PulseDesigner.block_pulse(FlipAngle(flip_angle), Duration(duration); phase_offset, freq_offset, delay, sys) | ||
#end | ||
# | ||
#function PulseDesigner.block_pulse(flip_angle::Angle, bandwidth::Unitful.Frequency; | ||
# phase_offset::Angle=0u"°", freq_offset::Frequency=0u"Hz", delay=0u"s", sys=Scanner()) | ||
# flip_angle, bandwidth, phase_offset, freq_offset, delay = upreferred.((flip_angle, bandwidth, phase_offset, freq_offset, delay)) | ||
# return PulseDesigner.block_pulse(FlipAngle(flip_angle), Bandwidth(bandwidth); phase_offset, freq_offset, delay, sys) | ||
#end | ||
# | ||
#function PulseDesigner.block_pulse(flip_angle::Angle, bandwidth::Unitful.Frequency, time_bw_product::DimensionlessQuantity; | ||
# phase_offset::Angle=0u"°", freq_offset::Frequency=0u"Hz", delay=0u"s", sys=Scanner()) | ||
# flip_angle, bandwidth, time_bw_product, phase_offset, freq_offset, delay = upreferred.((flip_angle, bandwidth, time_bw_product, phase_offset, freq_offset, delay)) | ||
# return PulseDesigner.block_pulse(FlipAngle(flip_angle), Bandwidth(bandwidth), TimeBwProduct(time_bw_product); phase_offset, freq_offset, delay, sys) | ||
#end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
??
KomaMRIBase/src/KomaMRIBase.jl
Outdated
struct Duration val end | ||
struct Bandwidth val end | ||
struct TimeBwProduct val end | ||
struct Angle end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct Angle end | |
struct Angle val end |
dead_time = sys.RF_dead_time_T | ||
ring_down_time = sys.RF_ring_down_T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why define these?
block_duration = delay + duration + ring_down_time | ||
|
||
rf = RF(amplitude, duration, freq_offset, delay) | ||
return Sequence([Grad(0, 0);;], [rf;;], [ADC(0, 0)], block_duration) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need a way to combine events so this is easier, seq += [rf, block_duration]
where rf::RF
and block_duration::Delay
, issue #4.
No description provided.