| measure_res(tools,center,spans,average,avenum,verbose)
|
function retval = measure_res(tools,center,spans,average,avenum,verbose)
% RETVAL = MEASURE_RES(TOOLS, CENTER, SPANS, 'AVERAGE', AVENUM, VERBOSE).
% MEASURE_RES performs a resonator measurement consisting of multiple
% frequency sweeps. After each sweep, the frequency of the peak response is
% determined, and this peak frequency becomes the center value for the next sweep.
% Each sweep should be smaller than the previous, and the results (peak frequency,
% amplitude, etc) are taken from the final sweep.
%
% TOOLS The instruments that will be used for the measurement.
% CENTER The starting value for the center frequency. Default is the current
% center frequency of the analyzer.
% SPANS An array of the spans to be used in the "zoom in" series. Default
% is 5 kHz (i.e. one sweep with span 5 kHz). Three sweeps are typical.
% AVERAGE ('on' | 'off') The analyzers can average the results of multiple
% sweeps to get a single result. Often used with HP89410.
% AVENUM The number of sweeps for averaging, if averaging is 'on'. If averaging
% is off, then wait AVENUM seconds for signal to stabilize (HP89410 only).
% Default is 5.
% VERBOSE The level of messages reported in the command window (0-3). Default is 1.
%
% The results are returned in the structure RETVAL, which has the following
% fields:
%
% retval.mark1.x X position of marker on trace 1 (frequency peak)
% retval.mark1.y Y position of marker on trace 1 (amplitude at peak)
% retval.mark2.x X position of marker on trace 2
% retval.mark2.y Y position of marker on trace 2
% retval.trace1.x X data for trace 1 (frequency)
% retval.trace1.y Y data for trace 1 (amplitude)
% retval.trace2.x X data for trace 2 (frequency)
% retval.trace2.y Y data for trace 1 (phase)
% retval.bandwidth 3db bandwidth of trace
% retval.Q Q of resonator calculated from 3db bandwidth
% retval.equ_circuit Rx and Cft estimated for default gain
% retval.db the index of the 3db points
% retval.phase_shift the total phase shift in degrees
% retval.Hn the "Hopcroft Number", i.e., the nonlinearity ratio
% retval.clock the time of the measurement
% retval.meas_span the span used for the measurement saved in trace
%
% TOOLS *must* include a Network Analyzer:
%
% tools.analyzer.instr='HP_4395A'; % or any other supported by kpib
% tools.analyzer.gpib=17; % the gpib address
% tools.analyzer.ampchannel=1; % the channel for amplitude data (default 1)
% tools.analyzer.phasechannel=2; % the channel for phase data (default 2)
% tools.analyzer.averaging='off'; % Use measurement averaging ('on'|'off') (default 'off')
% tools.analyzer.avenum=5; % How many sweeps to average or minimum sweep time
%
% TOOLS *may* also include these optional instruments:
%
% tools.biasset % power supply for bias voltage
% tools.biasread % multimeter for reading bias voltage
% tools.oven % temperature controller
% tools.sensor % temperature sensor for temp. chamber (may be == oven)
% tools.heater % power supply for heating voltage
% tools.circuittemp % temperature sensor for circuit board
% tools.roomtemp % temperature sensor for room
%
%
% The fields below are returned if the appropriate instruments are listed
% in TOOLS:
%
% retval.Vbias_set bias voltage, as reported by voltage supply
% retval.Vbias_read bias voltage, as read by multimeter
% retval.Toven Oven temperature from oven controller
% retval.Tsensor temperature reported by temperature sensor
% retval.Vheat Heating voltage
% retval.Aheat Heating current
% retval.Pheat Heating power (Vheat * Aheat)
% retval.Tcircuit Measurement Circuit temperature
% retval.Troom Room temperature
%
%
% The "mark" fields contain the position of the peak in the amplitude
% response, "trace" fields contain the complete data set, suitable for
% plotting.
%
% requires: kpib.m (v3.98+), bandqr.m (v1.4+)
%
%
% M.A. Hopcroft
% hopcroft at mems stanford edu
%
% MH Apr2010
% v4.3 sensor read update
versionstr = 'measure_res v4.22';
% MH NOV2009
% v4.22 use Cells
% update for Berkeley; typo fix, etc.
% remove 'close' after sensor read improves AO_800 performance
% DW NOV2009
% v4.2 modify average mode (line 368-370)
% MH MAR2008
% v4.1 incorporate additions by HKL (v3.83):
% uses retval.dbfreq
% for "slow analyzers", only averages final span,
% avenum limited to < 1000,
% affirmative channel select
% MH FEB2008
% v4.0 use additional tools.analyzer fields (averaging, channels)
%
% MH FEB2008
% v3.91 add Hn field
%
% MH JAN2008
% 3.9 add support for HP_4195A
% generalize Analyzer types (either 89410 or other)
% MH MAY2007
% v3.8 added close commands
% default channel for bias
% fix bias read ('V')
% MH FEB2007
% v3.72 fixed source level inconsistency
% removed units as separate field
% MH JAN2007
% v3.7 consistent behaviour for optional tools (circuittemp)
% fix help comments and verbose=3
% MH NOV2006
% v3.64 fix marker query for "slow sweep" analyzers
% MH OCT2006
% v3.6 fixed averaging for 89410A
% disable screen labels
% v3.54 fixed verbose outputs
% MH AUG2006
% v3.52 all fields return values (1776 for no value)
% MH JUL2006
% v3.301
% added 8753ES
% MH JUN2006
% (based on measure 89410/4395A)
% v3.21 Made measure_res into general function to use either 89410, 4395
% fixed 4395A str/num issue
%
% Programming note: the following kpib commands are required for Analyzers to be
% compatible with measure_res:
%
% init
% channel (channel select)
% center
% span
% averaging (on/off)
% marker (on/query)
% mark2peak (marker to peak/max)
% getdata
% sweep (sweep control: single, complete, group)
% wait
%
%% Set defaults
if nargin < 6
verbose = 1;
end
if nargin < 1 % set default analyzer
tools.analyzer.instr = 'HP_89410A'; %'HP_89410A' or 'HP_4395A'
tools.analyzer.gpib = 16; %16 = HP_89410A %17 = HP_4359A
if verbose >= 1, fprintf(1,'measure_res: Default to %s\n',tools.analyzer.instr); end
end
if nargin < 5
if isfield(tools.analyzer,'avenum') && isnumeric(tools.analyzer.avenum)
avenum=tools.analyzer.avenum;
if verbose >= 2, fprintf(1,'measure_res: tools.analyzer.avenum: %d\n',avenum); end
else
avenum=5;
end
end
if nargin < 4 % default averaging
if isfield(tools.analyzer,'averaging')
if strcmpi(tools.analyzer.averaging,'on')
average = 'on';
else
average = 'off';
end
if verbose >= 2, fprintf(1,'measure_res: tools.analyzer.averaging: %s\n',average); end
else
switch tools.analyzer.instr
case {'HP_89410A'}
average = 'on';
otherwise
average = 'off';
end
end
end
if nargin < 3
spans = [100e6 20e6 5e6];
end
if nargin < 2 || center <= 0
center = kpib(tools.analyzer.instr,tools.analyzer.gpib,'center','query',0,0,verbose);
if verbose >= 2, fprintf(1,'measure_res: Using center value from Analyzer: %g Hz\n',center); end
end
% Define the which channel is which on the Analyzer.
% ampchannel = 1;
% phasechannel = 2;
if isfield(tools.analyzer,'ampchannel') && isnumeric(tools.analyzer.ampchannel)
ampchannel=tools.analyzer.ampchannel;
if verbose >= 2, fprintf(1,'measure_res: tools.analyzer.ampchannel: %d\n',ampchannel); end
else
ampchannel=1;
end
if isfield(tools.analyzer,'phasechannel') && isnumeric(tools.analyzer.phasechannel)
phasechannel=tools.analyzer.phasechannel;
if verbose >= 2, fprintf(1,'measure_res: tools.analyzer.phasechannel: %d\n',phasechannel); end
else
phasechannel=2;
end
%% Begin measurement
if verbose >= 1, fprintf(1,'measure_res: Resonator measurement using %s\n',tools.analyzer.instr); end
%%%%
% first, measure frequency. This is the most difficult part, involving
% multiple steps. The HP_89410 has a slightly different procedure from
% other analyzers.
switch tools.analyzer.instr
%% Measure with HP_89410A
case {'HP_89410A'}
% make sure that peak tracking is on
kpib(tools.analyzer.instr,tools.analyzer.gpib,'peaktrack','on',ampchannel,0,verbose);
% Set averaging 'on' or 'off'
switch average
case {'Average','average','On','on','Yes','yes'}
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','type','normal',0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','on',0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average',avenum,0,0,verbose);
retval.avenum=avenum;
% clear the previous averaging values, if any
%kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','restart',0,0,verbose);
%if verbose >= 2, fprintf(1,'measure_res: Averaging on with factor %d\n',avenum); end
case {'Wait','wait','Off','off','No','no'}
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','off',0,0,verbose);
if verbose >= 2, fprintf(1,'%s\n','measure_res: Averaging off'); end
otherwise
if verbose >= 2, fprintf(1,'%s\n','measure_res: Warning: Averaging command not understood'); end
end
%%%%
% Loop for taking measurements
% loop over spans values
% skip steps if a spans value is zero
% first, set the center to the specified center value
centfreq=center;
numsweeps=length(spans); j=0;
for spanit = spans
if spanit ~= 0
j=j+1;
% pause to catch our breath
kpib(tools.analyzer,'pause',0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','off',0,0,verbose);
% set the center and span
kpib(tools.analyzer.instr,tools.analyzer.gpib,'center',centfreq,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'span',spanit,0,0,verbose);
if verbose >= 1, fprintf(1,'%s %.0f %s %.0f\n','measure_res: Center:',centfreq,'Span:',spanit); end
kpib(tools.analyzer.instr,tools.analyzer.gpib,'wait',0,0,0,verbose); pause(1); % the 'wait' should be enough, but its not...
kpib(tools.analyzer.instr,tools.analyzer.gpib,'continue',0,0,0,verbose);
switch average
case {'Average','average','On','on','Yes','yes'}
% start the averaging
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','on',0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'wait',0,0,0,verbose); pause(1); % the 'wait' should be enough, but its not...
% Wait until the averaging sweeps are done
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','finish',0,0,verbose);
if verbose >= 2, num=kpib(tools.analyzer,'average','count?',0,0,verbose); fprintf(1,'measure_res: Averaging done (%d sweeps).\n',num); end
case {'Wait','wait','Off','off','No','no'}
if verbose >= 1, fprintf(1,'measure_res: Wait %d seconds for data to stabilize\n',avenum); end
pause(avenum);
end
% autoscale the display
kpib(tools.analyzer.instr,tools.analyzer.gpib,'auto y','once',0,0,verbose);
drawnow;
if j < numsweeps
% find the peak... (peak tracking is on, so no command is necessary)
% ...and make it the new center value
markerpos = kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker?',ampchannel,'auto',0,verbose);
centfreq=markerpos.x;
if verbose >= 2, fprintf(1,'measure_res: New Center value: %.2f\n',centfreq); end
end
end
end
%%%%
% Format output data
%(peak tracking is on, so no "peak to center" command is necessary)
kpib(tools.analyzer.instr,tools.analyzer.gpib,'pause',0,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'auto y','once',0,0,verbose);
% time check
retval.clock=clock;
retval.mark1 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker?',ampchannel,0,0,verbose);
retval.trace1 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'getdata',0,ampchannel,'pow',verbose);
retval.mark2 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker?',phasechannel,0,0,verbose);
retval.trace2 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'getdata',0,phasechannel,'angl',verbose);
retval.meas_span = spans(end);
source = kpib(tools.analyzer.instr,tools.analyzer.gpib,'source','?',0,0,verbose);
retval.source = source.level;
[retval.bandwidth retval.Q retval.equ_circuit retval.db retval.phase_shift retval.Hn retval.dbfreq]=bandqr(retval);
% pause the instrument
kpib(tools.analyzer.instr,tools.analyzer.gpib,'pause',0,0,0,verbose);
%% Measure with Other Analyzers
%case {'HP_4395A','HP_8753ES','HP_4195A','AG_E5071B'}
otherwise
kpib(tools.analyzer.instr,tools.analyzer.gpib,'init',0,0,0,verbose);
% turn on markers
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker','on',0,0,verbose);
%This turns 'On' averaging for the alloted AVENUM or single sweep
switch average
case {'Average','average','On','on','Yes','yes'}
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','on',avenum,0,verbose);
warning off instrument:fscanf:unsuccessfulRead
if verbose >= 1, fprintf(1,'%s %d\n','measure_res: Averaging on, factor:',avenum); end
case {'Wait','wait','Off','off','No','no'}
kpib(tools.analyzer.instr,tools.analyzer.gpib,'average','off',0,0,verbose);
if verbose >= 2, fprintf(1,'%s \n','measure_res: Averaging off'); end
end
%%%%
% Loop for taking measurements
% loop over span values
% skip steps if a span value is zero
% first, set the center to the specified center value
centfreq=center;
numsweeps=length(spans); j=0;
for spanit = spans
if spanit ~= 0
j=j+1;
kpib(tools.analyzer.instr,tools.analyzer.gpib,'center',centfreq,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'span',spanit,0,0,verbose);
if verbose >= 1, fprintf(1,'%s %.0f %s %.0f\n','measure_res: Center:',centfreq,'Span:',spanit); end
% Determines the number of sweeps that are needed.
switch average
case {'Average','average','On','on','Yes','yes'}
% check avenum, it should be 1< avenum <1000. if not,
% enforce it to be default avenum(=2)
if(avenum<2||avenum>1000)
avenum = 2;
if verbose >=1, fprintf(1,'measure_res: avenum is out of range, enforce it to be 2\n'); end
end
% do average only for the last span value
if j < numsweeps
if verbose >=1, fprintf(1,'measure_res: (averaging on) single sweep with this span\n'); end
kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','single',0,0,verbose);
else
if verbose >=1, fprintf(1,'measure_res: (averaging on) averaging multiple sweeps with the final span\n'); end
kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','group',avenum,0,verbose);
%kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','cont',0,0,verbose); % DW v4.2
%pause(avenum+1); % allow averaging to finish % DW v4.2
end
case {'Wait','wait','Off','off','No','no'}
kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','single',0,0,verbose);
% case {'Average','average','On','on','Yes','yes'}
% kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','group',avenum,0,verbose);
% case {'Wait','wait','Off','off','No','no'}
% kpib(tools.analyzer.instr,tools.analyzer.gpib,'sweep','single',0,0,verbose);
end
% wait until sweep is finished
kpib(tools.analyzer.instr,tools.analyzer.gpib,'complete',0,0,0,verbose);
% Auto scale both channels
% set active channel to amplitude channel, then auto-scale
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'scale','auto',0,0,verbose);
% set active channel to phase channel, then auto-scale
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',phasechannel,0,0,verbose);
kpib(tools.analyzer.instr,tools.analyzer.gpib,'scale','auto',0,0,verbose);
% reset active channel to amplitude channel
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
% wait until previous command is finished
while(~kpib(tools.analyzer.instr,tools.analyzer.gpib,'wait',0,0,0,verbose))
pause(.1);
end
drawnow;
if j < numsweeps
% move peak to center...
kpib(tools.analyzer.instr,tools.analyzer.gpib,'mark2peak','center',0,0,verbose);
% ...and get the new center value
centfreq=kpib(tools.analyzer.instr,tools.analyzer.gpib,'center','query',0,0,verbose);
if verbose >= 2, fprintf(1,'measure_res: New Center value: %.2f\n',centfreq); end
end
end
end
%%%%
% Format output data
% where is the peak?
kpib(tools.analyzer.instr,tools.analyzer.gpib,'mark2peak','peak',0,0,verbose);
%kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker','peak',0,0,verbose);
% time check
retval.clock=clock;
%kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
retval.mark1 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker','query',ampchannel,0,verbose);
retval.trace1 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'getdata',0,ampchannel,0,verbose);
%kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',phasechannel,0,0,verbose);
retval.mark2 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'marker','query',phasechannel,0,verbose);
retval.trace2 = kpib(tools.analyzer.instr,tools.analyzer.gpib,'getdata',0,phasechannel,0,verbose);
% reset the active channel
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
source = kpib(tools.analyzer.instr,tools.analyzer.gpib,'source?',0,0,0,verbose);
retval.source = source.level;
%[retval.bandwidth retval.Q retval.motional]=bandq(retval.trace1.x,retval.trace1.y,retval.mark1.x);
[retval.bandwidth retval.Q retval.equ_circuit retval.db retval.phase_shift retval.Hn retval.dbfreq]=bandqr(retval);
% reset the active channel
kpib(tools.analyzer.instr,tools.analyzer.gpib,'channel',ampchannel,0,0,verbose);
retval.meas_span = spans(end);
end % sweep measurements
% print the result
if verbose >= 1
fprintf(1,'%s%s%s %.2f %s\n', 'measure_res(',tools.analyzer.instr,'): Final Marker Position:', retval.mark1.x, 'Hz');
end
%% Additional Measurements
% Now we can record additional measurements (bias, oven, etc)
% bias voltage read and set
if isfield(tools,'biasset');
if ~isfield(tools.biasset,'channel'), tools.biasset.channel=1; end
if verbose >= 3, fprintf(1,'measure_res: tools.biasset: %s/%s/%d\n',tools.biasset.instr,num2str(tools.biasset.gpib),tools.biasset.channel); end
try
retval.Vbias_set = kpib(tools.biasset,'read','V',0,verbose); % specify read 'V'
retval.V_bias = retval.Vbias_set; % old format, deprecated
%kpib('close',tools.biasset.gpib,0,0,0,0,verbose);
catch
retval.Vbias_set = 0.0;
if verbose >= 1, fprintf(1,'measure_res: Bias set voltage not available\n'); end
end
else
retval.Vbias_set = 1776;
end
if isfield(tools,'biasread');
if verbose >= 3, fprintf(1,'measure_res: tools.biasread: %s/%s\n',tools.biasread.instr,num2str(tools.biasread.gpib)); end
try
retval.Vbias_read = kpib(tools.biasread,'read','V',0,0,verbose); % specify read 'V'
%kpib('close',tools.biasread.gpib,0,0,0,0,verbose);
catch
retval.Vbias_read=retval.Vbias_set;
if verbose >= 1, fprintf(1,'measure_res: Bias read voltage not available\n'); end
end
else
retval.Vbias_read=retval.Vbias_set;
end
% oven temperature
if isfield(tools,'oven');
if verbose >= 3, fprintf(1,'measure_res: tools.oven: %s/%s\n',tools.oven.instr,num2str(tools.oven.gpib)); end
try
retval.Toven = kpib(tools.oven.instr,tools.oven.gpib,'read','T',0,0,verbose);
catch
retval.Toven = 1776;
if verbose >= 1, fprintf(1,'measure_res: Oven temperature not available\n'); end
end
else
retval.Toven = 1776;
end
% sensor temperature
if isfield(tools,'sensor');
if verbose >= 3, fprintf(1,'measure_res: tools.sensor: %s/%s\n',tools.sensor.instr,num2str(tools.sensor.gpib)); end
try
retval.Tsensor = kpib(tools.sensor.instr,tools.sensor.gpib,'read','T',0,0,verbose);
%kpib('close',tools.sensor.gpib,0,0,0,0,verbose);
catch
retval.Tsensor = 1776;
if verbose >= 1, fprintf(1,'measure_res: Sensor temperature not available\n'); end
end
else
retval.Tsensor = 1776;
end
% heater voltage
if isfield(tools,'heater');
if verbose >= 3, fprintf(1,'measure_res: tools.heater: %s/%s\n',tools.heater.instr,num2str(tools.heater.gpib)); end
try
heater = kpib(tools.heater.instr,tools.heater.gpib,'read',0,tools.heater.channel,0,verbose);
catch
heater.volt = 1776; heater.curr = 0;
if verbose >= 1, fprintf(1,'measure_res: Heater voltage not available\n'); end
end
retval.Vheat = heater.volt;
retval.Aheat = heater.curr;
retval.Pheat = heater.volt*heater.curr;
else
heater.volt = 1776; heater.curr = 0;
retval.Vheat = heater.volt;
retval.Aheat = heater.curr;
retval.Pheat = heater.volt*heater.curr;
end
% circuit temperature
if isfield(tools,'circuittemp');
if verbose >= 3, fprintf(1,'measure_res: tools.circuittemp: %s/%s\n',tools.circuittemp.instr,num2str(tools.circuittemp.gpib)); end
try
retval.Tcircuit = kpib(tools.circuittemp.instr,tools.circuittemp.gpib,'read','temp',0,0,verbose);
catch
retval.Tcircuit = 1776;
if verbose >= 1, fprintf(1,'measure_osc: Circuit temperature not available\n'); end
end
end
% room temperature
if isfield(tools,'roomtemp');
if verbose >= 3, fprintf(1,'measure_res: tools.roomtemp: %s/%s\n',tools.roomtemp.instr,num2str(tools.roomtemp.gpib)); end
try
retval.Troom = kpib(tools.roomtemp.instr,tools.roomtemp.gpib,'read','temp',0,0,verbose);
catch
retval.Troom = 1776;
if verbose >= 1, fprintf(1,'measure_res: Room temperature not available\n'); end
end
else
retval.Troom = 1776;
end
retval.version=versionstr;
return
|
|