/ concept-collection / seqlab
Sign in
concept-collection / seqlab
seqlab / src / engine / pulseq / +mr / checkTiming.m
114 lines · 4.4 KBBlameHistoryRaw
1function [ is_ok, text_error, total_dur ] = checkTiming( system, varargin )
2%checkTiming(sys, objects, ...)
3% Function checks whether timing of the specified evets is aligned to
4% the corresponding raster
6 if (isempty(varargin))
7 text_error=['empty or damaged block detected' ];
8 is_ok=false;
9 return;
10 end
11 total_dur=mr.calcDuration(varargin{:});
12 is_ok=div_check(total_dur,system.blockDurationRaster);
13 if (is_ok)
14 text_error='';
15 else
16 text_error=['total duration:' num2str(total_dur*1e6) 'us' ];
17 end
18 for i=1:length(varargin)
19 e=varargin{i};
20 if isnumeric(e) % special handling for blockDuration
21 continue;
22 end
23 assert(isstruct(e), 'wrong format of the variable aguments, list of structures is expected');
24 ok=true;
25 if length(e)>1
26 % for now this is only the case for arrays of extensions, but
27 % we actually cannot check extensons anyway...
28 continue;
29 end
30 if isfield(e, 'type') && (strcmp(e.type,'adc') || strcmp(e.type,'rf') || strcmp(e.type,'output'))
31 raster=system.rfRasterTime;
32 else
33 raster=system.gradRasterTime;
34 end
35 if isfield(e, 'delay')
36 if e.delay<-eps
37 ok=false;
38 end
39 if ~div_check(e.delay,raster)
40 ok=false;
41 end
42 end
43 if isfield(e, 'duration')
44 if ~div_check(e.duration,raster)
45 ok=false;
46 end
47 end
48 if isfield(e, 'dwell') % special case ADC
49 if e.dwell<system.adcRasterTime || abs(round(e.dwell/system.adcRasterTime)*system.adcRasterTime - e.dwell)>1e-10
50 ok=false;
51 end
52 end
53 if isfield(e, 'type') && strcmp(e.type,'rf')
54 % check time vector
55 if ~div_check(e.shape_dur,system.rfRasterTime)
56 ok=false;
57 end
58 if length(e.t)>=4
59 rt=e.t/system.rfRasterTime;
60 drt=diff(rt);
61 if all(abs(drt(2:end)-drt(1))<1e-9/system.rfRasterTime) % 1ns -- /system.rfRasterTime is necessary because 'rt' is in RF raster units
62 % equal stepping case -- constant dwell time
63 e.dwell=e.t(2)-e.t(1); % add dummy dwell so that it can be logged in case of error
64 if ~div_check(e.dwell,min(system.adcRasterTime,system.rfRasterTime)) % should we check against rfRasterTime or adcRasterTime?
65 ok=false;
66 end
67 else
68 % "extended"-shape -- all points should be on RF raster edges
69 if any(abs(rt-round(rt))>1e-6)
70 ok=false; % TODO: add a meaninfull error message, for now it will look very cryptic
71 end
72 end
73 end
74 end
75 if isfield(e, 'type') && strcmp(e.type,'trap')
76 if ~div_check(e.riseTime, system.gradRasterTime) || ~div_check(e.flatTime, system.gradRasterTime) || ~div_check(e.fallTime, system.gradRasterTime)
77 ok=false;
78 end
79 end
80 if ~ok
81 is_ok=false;
82 if ~isempty(text_error)
83 text_error = [text_error ' '];
84 end
85 text_error = [text_error '[ '];
86 if isfield(e, 'type')
87 text_error = [text_error 'type:' e.type ' ' ];
88 end
89 if isfield(e, 'delay')
90 text_error = [text_error 'delay:' num2str(e.delay*1e6) 'us ' ];
91 end
92 if isfield(e, 'duration')
93 text_error = [text_error 'duration:' num2str(e.duration*1e6) 'us ' ];
94 end
95 if isfield(e, 'shape_dur')
96 text_error = [text_error 'shape_dur:' num2str(e.shape_dur*1e6) 'us ' ];
97 end
98 if isfield(e, 'dwell')
99 text_error = [text_error 'dwell:' num2str(e.dwell*1e9) 'ns ' ];
100 end
101 if isfield(e, 'type') && strcmp(e.type,'trap')
102 text_error = [text_error 'riseTime:' num2str(e.riseTime*1e6) 'us flatTime:' num2str(e.flatTime*1e6) 'us fallTime:' num2str(e.fallTime*1e6) 'us '];
103 end
104 text_error = [text_error ']'];
105 end
106 end
107end
109function out = div_check(a, b)
110% checks wheher a can be divided by b to an accuracy of 1e-9
111 c = a / b;
112 out = (abs( c - round(c) ) < 1e-9);
113end
moveopenescclose