1function adc=makeAdc(num,varargin)
2%makeAdc Create an ADC readout event.
3%
4% PURPOSE
5% Build an ADC (analog-to-digital converter) sampling event struct.
6% The returned struct describes when sampling occurs, how many
7% samples are acquired, and at what dwell rate, and is consumed by
8% mr.Sequence/addBlock to add the readout to a sequence.
9%
10% SIGNATURES
11% adc = mr.makeAdc(numSamples, 'Duration', d)
12% adc = mr.makeAdc(numSamples, 'Dwell', dt)
13% adc = mr.makeAdc(numSamples, system, ...) % system as 2nd positional arg
14% adc = mr.makeAdc(numSamples, ..., 'system', system) % system as name/value
15% adc = mr.makeAdc(numSamples, ..., 'Delay', d)
16%
17% Exactly one of 'Duration' or 'Dwell' must be supplied.
18% If system is omitted, mr.opts() is used.
19% Parameter names are case-insensitive.
20%
21% INPUTS
22% numSamples [required] integer, number of ADC samples (must be a whole number)
23% system [optional] struct from mr.opts; defaults to mr.opts() if omitted
24% 'Duration' [name/value] double, total acquisition duration, seconds. Dwell is
25% computed as Duration/numSamples.
26% 'Dwell' [name/value] double, per-sample dwell time, seconds. Total
27% acquisition time is Dwell*numSamples.
28% 'Delay' [name/value] double, delay before sampling starts, seconds,
29% default 0. Silently bumped to system.adcDeadTime
30% if smaller (see NOTES).
31% 'freqOffset' [name/value] double, demodulation frequency offset, Hz, default 0
32% 'phaseOffset' [name/value] double, demodulation phase offset, radians, default 0
33% 'freqPPM' [name/value] double, frequency offset in PPM (relative to system
34% B0 and gamma), default 0
35% 'phasePPM' [name/value] double, phase offset in PPM, default 0
36% 'phaseModulation' [name/value] vector, per-sample phase modulation, length must
37% equal numSamples. Default: [] (no modulation).
38%
39% OUTPUT
40% adc struct with fields (in order returned by fieldnames):
41% .type char, always 'adc'
42% .numSamples integer, number of samples (= input numSamples)
43% .delay double, delay before sampling, seconds
44% (>= system.adcDeadTime; see NOTES)
45% .freqOffset double, Hz
46% .phaseOffset double, radians
47% .freqPPM double, PPM
48% .phasePPM double, PPM
49% .deadTime double, copy of system.adcDeadTime at construction, seconds
50% .phaseModulation double vector or []
51% .dwell double, sample dwell time, seconds
52% (= Duration/numSamples if Duration was given,
53% else the supplied Dwell)
54%
55% ERRORS
56% - 'Either dwell or duration must be defined': both are 0, or both > 0.
57% Exactly one must be specified.
58% - 'ADC Phase modulation vector must have the same length as the number
59% of samples': length(phaseModulation) ~= numSamples.
60% - MATLAB:InputParser:* errors: numSamples is not an integer, or other
61% validator failures (non-numeric where numeric is expected, etc.).
62%
63% NOTES
64% - The .delay field is silently increased to system.adcDeadTime if the
65% requested delay is smaller. If you set 'Delay' to 0 with a nonzero
66% system.adcDeadTime, the returned adc.delay will equal system.adcDeadTime,
67% not 0. Account for this when computing block timing.
68% - system.adcDeadTime is captured into adc.deadTime at construction time;
69% changing system later does not retroactively update existing adc events.
70% - Caches an inputParser in a persistent variable for performance;
71% no other global state.
72%
73% EXAMPLE
74% sys = mr.opts('MaxGrad', 30, 'GradUnit', 'mT/m', ...
75% 'MaxSlew', 170, 'SlewUnit', 'T/m/s', ...
76% 'adcDeadTime', 20e-6);
77% Nx = 256; fov = 256e-3; deltak = 1/fov;
78% gx = mr.makeTrapezoid('x', sys, 'FlatArea', Nx*deltak, 'FlatTime', 6.4e-3);
79% % ADC sampled across the readout flat top
80% adc = mr.makeAdc(Nx, sys, 'Duration', gx.flatTime, 'Delay', gx.riseTime);
81%
82% SEE ALSO
83% mr.opts, mr.makeTrapezoid, mr.Sequence/addBlock, mr.calcDuration
85persistent parser
86if isempty(parser)
87 parser = mr.aux.InputParserCompat;
88 parser.FunctionName = 'makeAdc';
90 addRequired(parser,'numSamples',@(x)(isnumeric(x) && (fix(x)-x)==0));
91 addOptional(parser,'system',[],@isstruct);
92 addParamValue(parser,'dwell',0,@isnumeric);
93 addParamValue(parser,'duration',0,@isnumeric);
94 addParamValue(parser,'delay',0,@isnumeric);
95 addParamValue(parser,'freqOffset',0,@isnumeric);
96 addParamValue(parser,'phaseOffset',0,@isnumeric);
97 addParamValue(parser,'freqPPM', 0, @isnumeric);
98 addParamValue(parser,'phasePPM', 0, @isnumeric);
99 addParamValue(parser,'phaseModulation',[],@isnumeric);
100end
102parse(parser,num,varargin{:});
103opt = parser.Results;
105if isempty(opt.system)
106 system=mr.opts();
107else
108 system=opt.system;
109end
111adc.type = 'adc';
112adc.numSamples = num;
113adc.delay = opt.delay;
114adc.freqOffset = opt.freqOffset;
115adc.phaseOffset = opt.phaseOffset;
116adc.freqPPM = opt.freqPPM;
117adc.phasePPM = opt.phasePPM;
118adc.deadTime = system.adcDeadTime;
120if (opt.dwell==0 && opt.duration==0) || (opt.dwell>0 && opt.duration>0)
121 error('Either dwell or duration must be defined');
122end
124if ~isempty(opt.phaseModulation)
125 if length(opt.phaseModulation)~=num
126 error('ADC Phase modulation vector must have the same length as the number of samples');
127 end
128 adc.phaseModulation=opt.phaseModulation;
129else
130 adc.phaseModulation=[];
131end
133if opt.duration > 0
134 adc.dwell = opt.duration/opt.numSamples;
135else
136 adc.dwell = opt.dwell;
137end
138%if opt.dwell > 0
139% adc.duration = opt.dwell*opt.numSamples;
140%end
141if adc.deadTime > adc.delay
142 adc.delay = adc.deadTime; % adcDeadTime is added before the actual sampling (and also second time after the sampling period)
143end
145end