/ concept-collection / seqlab
Sign in
concept-collection / seqlab
seqlab / src / engine / pulseq / +mr / makeArbitraryGrad.m
102 lines · 3.2 KBCodeBlameHistory
78d04f1seqlab: write and view pulseq MRI sequences in the browserJeremy Magland 1function grad=makeArbitraryGrad(channel,varargin)
2%makeArbitraryGrad Create an gradient event with arbitrary waveform.
3% g=makeArbitraryGrad(channel, waveform) Create gradient on
4% the given channel with the specified waveform.
5%
6% g=makeArbitraryGrad(channel,waveform,lims) Ensure the waveform
7% satisfies the gradient hardware constraints.
8%
9% See also Sequence.addBlock
11persistent parser
13if isempty(parser)
14 validChannels = {'x','y','z'};
15 parser = mr.aux.InputParserCompat;
16 parser.FunctionName = 'makeArbitraryGrad';
17 parser.addRequired('channel',...
18 @(x) any(validatestring(x,validChannels)));
19 parser.addRequired('waveform');
20 parser.addOptional('system', [], @isstruct);
21 parser.addParamValue('oversampling',false,@islogical);
22 parser.addParamValue('maxGrad',0,@isnumeric);
23 parser.addParamValue('maxSlew',0,@isnumeric);
24 parser.addParamValue('delay',0,@isnumeric);
25 parser.addParamValue('first',NaN,@isnumeric);
26 parser.addParamValue('last',NaN,@isnumeric);
27end
28parse(parser,channel,varargin{:});
29opt = parser.Results;
31if isempty(opt.system)
32 system=mr.opts();
33else
34 system=opt.system;
35end
37maxSlew=system.maxSlew;
38maxGrad=system.maxGrad; % TODO: use this when no duration is supplied
39if opt.maxGrad>0
40 maxGrad=opt.maxGrad;
41end
42if opt.maxSlew>0
43 maxSlew=opt.maxSlew;
44end
46g=opt.waveform(:);
48if isfinite(opt.first)
49 first = opt.first;
50else
51 warning('it will be compulsory to provide the first point of the gradient shape in the future releases; finding the first by extrapolation for now...');
52 if opt.oversampling
53 first = 2*g(1)-g(2); % extrapolate by 1 gradient raster
54 else
55 first = (3*g(1)-g(2))*0.5; % extrapolate by 1/2 gradient of the raster
56 end
57end
59if isfinite(opt.last)
60 last = opt.last;
61else
62 warning('it will be compulsory to provide the last point of the gradient shape in the future releases; finding the last by extrapolation for now...');
63 if opt.oversampling
64 last = g(end)*2-g(end-1); % extrapolate by 1 gradient raster
65 else
66 last = (g(end)*3-g(end-1))*0.5; % extrapolate by 1/2 gradient of the raster
67 end
68end
70if opt.oversampling
71 slew=[(first-g(1)); (g(2:end)-g(1:end-1)); (last-g(end))]./system.gradRasterTime*2;
72else
73 slew=[(first-g(1))*2; (g(2:end)-g(1:end-1)); (g(end)-last)*2]./system.gradRasterTime;
74end
75if ~isempty(slew) && max(abs(slew))>maxSlew
76 error('Slew rate violation (%.0f%%)',max(abs(slew))/maxSlew*100);
77end
78if max(abs(g))>maxGrad
79 error('Gradient amplitude violation (%.0f%%)',max(abs(g))/maxGrad*100);
80end
82grad.type = 'grad';
83grad.channel = opt.channel;
84grad.waveform = g;
85grad.delay = opt.delay;
86% true timing and aux shape data
87if opt.oversampling
88 grad.area=sum(grad.waveform(1:2:end))*system.gradRasterTime; % undo oversamping
89 if (mod(length(g),2)~=1)
90 error('when oversampling is active the gradient shape vector must contain an odd number of samples');
91 end
92 grad.tt = (1:length(g))'*0.5*system.gradRasterTime;
93 grad.shape_dur = (length(g)+1)*0.5*system.gradRasterTime;
94else
95 grad.area=sum(grad.waveform)*system.gradRasterTime;
96 grad.tt = ((1:length(g))'-0.5)*system.gradRasterTime;
97 grad.shape_dur = length(g)*system.gradRasterTime;
98end
99grad.first = first;
100grad.last = last;
102end
moveopenescclose