/ATF2/FlightSim/trustedApps/bpmcal/nmCavCal.m
MATLAB | 638 lines | 502 code | 17 blank | 119 comment | 108 complexity | edafce2c78d1da646639f8d7f13c6731 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.0, IPL-1.0, BSD-3-Clause
- function [stat varargout] = nmCavCal(cmd,varargin)
- % NMCAVCAL
- % Non-Mover-Based Cavity BPM calibration routines
- % Also for use with EXT striplines
- %
- % stat = nmCavCal('init')
- % Run initialisation steps
- % - Setup default bump calibration parameters
- % - Define correctors used for bpm bumps
- % - Setup multiknobs for bumps
- % NOTE: This step runs automatically on first call, call again if optics
- % change requiring a recalculation of multiknobs
- %
- % [stat pars] = nmCavCal('GetPars')
- % Readout internal parameters (see pars list below)
- %
- % stat = nmCavCal('SetPars',newpars)
- % Fields of newpars get written to internal pars structure
- %
- % stat = nmCavCal('SetBump',bpmname,axis,val,nocal)
- % Set bump value at desired BPM
- % bpmname = BEAMLINE name of BPM
- % axis = 'x' or 'y' or 'xp' or 'yp'
- % val = bump size / m
- % If calibration data exists for this bump, the expected extra kick is
- % removed from the last corrector unless nocal=true specified
- %
- % stat = nmCavCal('RestoreBumps',bpmname,axis)
- % Restore bumps on all BPMs to their zero value if 1 argument provided
- % If bpmname and axis provided, just do that one bump
- %
- % stat = nmCavCal('ResetBumps',bpmname,axis)
- % Set zero value of all bumps to represent current location if 1 argument
- % provided
- % If bpmname and axis provided, just do that one bump
- %
- % stat = nmCavCal('CalibBump',bpmname,axis)
- % Perform a calibration of requested BPM bump
- % bpmname = BEAMLINE name
- % axis = 'x' or 'y' 'xp' or 'yp'
- % Calibrates over pars.bumpcalib.nsteps
- % of moving over a range +/- pars.bumpcalib.size (m)
- % using average of pars.bumpcalib.nbpm BPM readings to calculate orbit at
- % each step
- %
- % stat = nmCavCal('CalibBpm',bpmname,axis)
- % Perform calibration of bpm bpmname (axis 'x' or 'y' or 'xp' or 'yp')
- % pars.bpmcalib.usesvd use SVD technique to remove main jitter modes
- % Calibrates over pars.bpmcalib.nsteps
- % of moving over a range +/- pars.bpmcalib.size (m)
- % using average of pars.bpmcalib.nbpm BPM readings to calculate orbit at
- % each step
- %
- % =====================================
- % Internal Data Parameters
- % =====================================
- % pars.
- % bpmnames : name list of all cavity non-mover bpms
- % bpmele(.x | .y) : corresponding BEAMLINE elements
- % cornames(.x | .y) : corrector names used for bumps
- % corele(.x | .y) : corresponding BEAMLINE elements
- % bumpknob.(.x | .y){ibpm} : Lucretia MultiKnob for bpms
- % bumpcalib.
- % nbpm : num bpm readings per calibration step
- % size : range (+/-) of calibration sweep
- % nstep : number of steps across range
- % (bpmname).(x | .y) : calibration slope for bpm
- % (bpmname).(xdate | .ydate): last calibration date
- % :: calibration slope gives expected extra kick from last
- % in bump corrector given by multiplying calibration
- % value with bump size
- % bpmcalib.
- % nbpm : num bpm readings per calibration step
- % size : range (+/-) of calibration sweep
- % nstep : number of steps across range
- % nrepeat : number of times to iterate calibration sweep
- % usesvd : use SVD to remove jitter modes
- global INSTR PS BEAMLINE GIRDER %#ok<NUSED>
- persistent pars
- stat{1}=1;
- % Load any previously saved data
- if isempty(pars)
- if exist('userData/nmCavCal.mat','file')
- cavdata=load('userData/nmCavCal');
- else
- cavdata.pars=[];
- end
- if ~isfield(cavdata,'pars')
- cavdata.pars=[];
- end
- pars=init(cavdata.pars);
- if strcmpi(cmd,'init')
- return
- end
- end
- switch lower(cmd)
- case 'init'
- pars=init(pars);
- case 'getpars'
- varargout{1}=pars;
- case 'setpars'
- if nargin==2
- newpars=varargin{1};
- if isstruct(newpars)
- pf=fields(newpars);
- for ipar=1:length(pf)
- if isstruct(newpars.(pf{ipar}))
- pf2=fields(newpars.(pf{ipar}));
- for ipar2=1:length(pf2)
- pars.(pf{ipar}).(pf2{ipar2})=newpars.(pf{ipar}).(pf2{ipar2});
- end
- else
- pars.(pf{ipar})=newpars.(pf{ipar});
- end
- end
- end
- end
- case 'calibbpm'
- if nargin~=3 || ~ischar(varargin{1}) || (~isequal(varargin{2},'x') && ~isequal(varargin{2},'y') && ~isequal(varargin{2},'xp') && ~isequal(varargin{2},'yp'))
- error('Incorrect input arguments for CalibBpm')
- end
- stat=calibrateBPM(pars,varargin{1},varargin{2});
- if stat{1}~=1; error(stat{2}); end;
- case 'restorebumps'
- if nargin==3
- wk=find(ismember(pars.bpmnames,varargin{1}), 1);
- pars.bumpknob.(varargin{2}){wk}.Value=0;
- for ichan=1:length(pars.bumpcomp.(varargin{2}){wk})
- evalc([pars.bumpknob.(varargin{2}){wk}.Channel(ichan).Parameter,'=',num2str(pars.bumpcomp.(varargin{2}){wk}(ichan),10)]);
- if ~isempty(strfind(pars.bumpknob.(varargin{2}){wk}.Channel(ichan).Parameter,'GIRDER'))
- MoverTrim(pars.bumpknob.(varargin{2}){wk}.Channel(ichan).Unit,1);
- else
- PSTrim(pars.bumpknob.(varargin{2}){wk}.Channel(ichan).Unit,1);
- end
- end
- else
- disp('Putting all correctors to their zero-bump positions...')
- for ibpm=1:length(pars.bpmnames)
- for ichan=1:length(pars.bumpcomp.x{ibpm})
- evalc([pars.bumpknob.x{ibpm}.Channel(ichan).Parameter,'=',num2str(pars.bumpcomp.x{ibpm}(ichan),10)]);
- evalc([pars.bumpknob.xp{ibpm}.Channel(ichan).Parameter,'=',num2str(pars.bumpcomp.xp{ibpm}(ichan),10)]);
- if ~isempty(strfind(pars.bumpknob.x{ibpm}.Channel(ichan).Parameter,'GIRDER'))
- MoverTrim(pars.bumpknob.x{ibpm}.Channel(ichan).Unit,1);
- else
- PSTrim(pars.bumpknob.x{ibpm}.Channel(ichan).Unit,1);
- end
- if ~isempty(strfind(pars.bumpknob.xp{ibpm}.Channel(ichan).Parameter,'GIRDER'))
- MoverTrim(pars.bumpknob.xp{ibpm}.Channel(ichan).Unit,1);
- else
- PSTrim(pars.bumpknob.xp{ibpm}.Channel(ichan).Unit,1);
- end
- end
- for ichan=1:length(pars.bumpcomp.y{ibpm})
- evalc([pars.bumpknob.y{ibpm}.Channel(ichan).Parameter,'=',num2str(pars.bumpcomp.y{ibpm}(ichan),10)]);
- if ~isempty(strfind(pars.bumpknob.y{ibpm}.Channel(ichan).Parameter,'GIRDER'))
- MoverTrim(pars.bumpknob.y{ibpm}.Channel(ichan).Unit,1);
- else
- PSTrim(pars.bumpknob.y{ibpm}.Channel(ichan).Unit,1);
- end
- if ~isempty(strfind(pars.bumpknob.yp{ibpm}.Channel(ichan).Parameter,'GIRDER'))
- MoverTrim(pars.bumpknob.yp{ibpm}.Channel(ichan).Unit,1);
- else
- PSTrim(pars.bumpknob.yp{ibpm}.Channel(ichan).Unit,1);
- end
- end
- end
- end
- case 'resetbumps'
- if nargin==3
- wk=find(ismember(pars.bpmnames,varargin{1}), 1);
- pars.bumpknob.(varargin{2}){wk}.Value=0;
- for ichan=1:length(pars.bumpcomp.(varargin{2}){wk})
- evalc(['pars.bumpcomp.(varargin{2}){wk}(ichan)=',pars.bumpknob.(varargin{2}){wk}.Channel(ichan).Parameter]);
- end
- else
- disp('Setting all bump references to zero here...')
- for ibpm=1:length(pars.bpmnames)
- pars.bumpknob.x{ibpm}.Value=0;
- pars.bumpknob.y{ibpm}.Value=0;
- pars.bumpknob.xp{ibpm}.Value=0;
- pars.bumpknob.yp{ibpm}.Value=0;
- end
- pars=init(pars);
- end
- case 'setbump'
- if nargin<4 || ~ischar(varargin{1}) || (~isequal(varargin{2},'x') && ~isequal(varargin{2},'y') && ...
- ~isequal(varargin{2},'xp') && ~isequal(varargin{2},'yp')) || ~isnumeric(varargin{3}) || length(varargin{3})~=1
- error('Incorrect arguments to ''set''')
- end
- wk=find(ismember(pars.bpmnames,varargin{1}), 1);
- if isempty(wk)
- stat{1}=-1;
- stat{2}='Unknown knob for this BPM name';
- return
- end
- stat = SetMultiKnob( 'pars.bumpknob.(varargin{2}){wk}', varargin{3}, 1);
- % fine tune bump if calibration exists
- if isfield(pars.bumpcalib,varargin{1}) && isfield(pars.bumpcalib.(varargin{1}),varargin{2}) &&...
- (nargin<5 || ~varargin{4})
- extrakick=varargin{3}*pars.bumpcalib.(varargin{1}).(varargin{2});
- PS(BEAMLINE{pars.corele.(varargin{2}){wk}(end)}.PS).SetPt=...
- PS(BEAMLINE{pars.corele.(varargin{2}){wk}(end)}.PS).SetPt-extrakick;
- stat=PSTrim(BEAMLINE{pars.corele.(varargin{2}){wk}(end)}.PS,1);
- if stat{1}~=1; return; end;
- end
- case 'calibbump'
- if nargin~=3 || ~ischar(varargin{1}) || (~isequal(varargin{2},'x') && ~isequal(varargin{2},'y') && ~isequal(varargin{2},'xp') && ~isequal(varargin{2},'yp'))
- error('Incorrect arguments to ''set''')
- end
- wk=find(ismember(pars.bpmnames,varargin{1}), 1);
- if isempty(wk)
- stat{1}=-1;
- stat{2}='Unknown knob for this BPM name';
- return
- end
- [stat data] = FlBpmToolFn('GetData');
- if stat{1}~=1; return; end;
- % Get good bpms to use
- goodbpm=data.global.hw & data.global.use; % & data.global.cal;
- % Get bpms downstream of last corrector used in this bump
- bpmele=cellfun(@(x) x.Index,INSTR);
- bpmind=bpmele>pars.corele.(varargin{2}){wk}(end);
- bpms=goodbpm&bpmind;
- if ~any(bpms)
- errordlg('No good BPMs to use!','Bump Calibration Error')
- return
- end
- % Reset bump value
- pars.bumpknob.(varargin{2}){wk}.Value=0;
- % Get reference orbit
- disp('Calibrating Bump...')
- disp('Getting reference orbit...')
- FlHwUpdate('wait',pars.bumpcalib.nbpm);
- [stat bpmdata]=FlHwUpdate('bpmave',pars.bumpcalib.nbpm); if stat{1}~=1; return; end;
- bpmref.x=bpmdata{1}(1,:); bpmref.y=bpmdata{1}(2,:);
- nanbpm=isnan(bpmref.x) | isnan(bpmref.y);
- % Ramp bump and collect orbit data
- ibump=0;
- bumps=linspace(-pars.bumpcalib.size,pars.bumpcalib.size,pars.bumpcalib.nstep);
- for bumpsize=bumps
- ibump=ibump+1;
- dispstr=sprintf('Bump calibration position %d of %d...',ibump,length(bumps));
- disp(dispstr)
- stat = SetMultiKnob( 'pars.bumpknob.(varargin{2}){wk}', bumpsize, 1); if stat{1}~=1; return; end;
- pause(3); % wait for correctors to settle
- FlHwUpdate('wait',pars.bumpcalib.nbpm);
- [stat bpmdata]=FlHwUpdate('bpmave',pars.bumpcalib.nbpm); if stat{1}~=1; return; end;
- nanbpm=nanbpm | isnan(bpmdata{1}(1,:)) | isnan(bpmdata{1}(2,:));
- [stat X Xerr] = bpmfit(bpmele(bpms&~nanbpm),bpmdata{1}(1,bpms&~nanbpm)-bpmref.x(bpms&~nanbpm),...
- bpmdata{1}(2,bpms&~nanbpm)-bpmref.y(bpms&~nanbpm),...
- pars.corele.(varargin{2}){wk}(end),bpmdata{1}(4,bpms&~nanbpm),bpmdata{1}(5,bpms&~nanbpm));
- if stat{1}~=1; return; end;
- extrakick.x(ibump)=X(2); extrakick.y(ibump)=X(4);
- extrakickerr.x(ibump)=Xerr(2); extrakickerr.y(ibump)=Xerr(4);
- end
- % Return bump and get calibration slope
- disp('Returning bump to initial setting and calculating calibration...')
- stat = SetMultiKnob( 'pars.bumpknob.(varargin{2}){wk}', 0, 1); if stat{1}~=1; return; end;
- figure
- if varargin{2}=='x'
- [q,dq]=plot_polyfit(bumps,extrakick.x,extrakickerr.x,1);
- if queryCalib(1)
- pars.bumpcalib.(varargin{1}).x=q(end); pars.bumpcalib.(varargin{1}).xerr=dq(end);
- pars.bumpcalib.(varargin{1}).xdate=now;
- end
- else
- [q,dq]=plot_polyfit(bumps,extrakick.y,extrakickerr.y,1);
- if queryCalib(2)
- pars.bumpcalib.(varargin{1}).y=q(end); pars.bumpcalib.(varargin{1}).yerr=dq(end);
- pars.bumpcalib.(varargin{1}).ydate=now;
- end
- end
- drawnow('expose')
- otherwise
- error('Unknown command')
- end
- % store pars data
- save userData/nmCavCal pars
- %% Internal Functions
- function resp = queryCalib(dim)
- global FL PS GIRDER %#ok<NUSED>
- resp=true;
- if ~isfield(FL,'Gui') || ~isfield(FL.Gui,'bpmcal') || ~isfield(FL.Gui.bpmcal,'figure1') || ...
- ~ishandle(FL.Gui.bpmcal.figure1)
- return
- end
- if dim==1
- set(FL.Gui.bpmcal.pushbutton8,'Visible','on')
- set(FL.Gui.bpmcal.pushbutton11,'Visible','on')
- else
- set(FL.Gui.bpmcal.pushbutton9,'Visible','on')
- set(FL.Gui.bpmcal.pushbutton10,'Visible','on')
- end
- uiwait(FL.Gui.bpmcal.figure1)
- if ~ishandle(FL.Gui.bpmcal.figure1) || ...
- (get(FL.Gui.bpmcal.figure1,'CurrentObject')~=FL.Gui.bpmcal.pushbutton8 && ...
- get(FL.Gui.bpmcal.figure1,'CurrentObject')~=FL.Gui.bpmcal.pushbutton9)
- resp=false;
- end
- if ishandle(FL.Gui.bpmcal.figure1) && dim==1
- set(FL.Gui.bpmcal.pushbutton8,'Visible','off')
- set(FL.Gui.bpmcal.pushbutton11,'Visible','off')
- elseif ishandle(FL.Gui.bpmcal.figure1)
- set(FL.Gui.bpmcal.pushbutton9,'Visible','off')
- set(FL.Gui.bpmcal.pushbutton10,'Visible','off')
- end
- function pars = init(pars)
- global BEAMLINE PS GIRDER INSTR %#ok<NUSED>
- disp('Initialising data structures and generating bumps...')
- % List of BPMs
- pars.bpmnames={'MQD10X' 'MQF11X' 'MQD12X' 'MQD16X' 'MQF17X' 'MQD18X' 'MQF19X' 'MQD20X' 'MQF21X' 'MQM16FF'... % 'FONTP1' 'FONTP2' 'FONTP3' ...
- 'MQF1X' 'MQD2X' 'MQF3X' 'MQF4X' 'MQD5X' 'MQF6X' 'MQF7X' 'MQD8X' 'MQF9X' 'MQF13X' 'MQD14X' 'MQF15X' 'LW1X'};
- pars.bpmele=zeros(size(pars.bpmnames));
- try
- for ibpm=1:length(pars.bpmnames)
- pars.bpmele(ibpm)=findcells(BEAMLINE,'Name',pars.bpmnames{ibpm});
- pars.bpminst(ibpm)=findcells(INSTR,'Index',pars.bpmele(ibpm));
- pars.bpmtype{ibpm}=INSTR{pars.bpminst(ibpm)}.Type;
- end
- catch ME
- error(ME.message)
- end
- % Corrector list for orbit bumps
- % Use 3-corrector bumps where there are not 2 downstream correctors to bpm
- % for now, later use a downstream quad on a mover as 4th corrector
- pars.cornames.x={};
- pars.cornames.y={};
- pars.cornames.x{1}={'ZH3X' 'ZH4X' 'ZH5X' 'ZH6X'};
- pars.cornames.x{2}={'ZH4X' 'ZH5X' 'ZH6X' 'ZH7X'};
- pars.cornames.x{3}={'ZH4X' 'ZH5X' 'ZH6X' 'ZH7X'};
- pars.cornames.x{4}={'ZH6X' 'ZH7X' 'ZH8X' 'ZH9X'};
- pars.cornames.x{5}={'ZH7X' 'ZH8X' 'ZH9X' 'ZH10X'};
- pars.cornames.x{6}={'ZH7X' 'ZH8X' 'ZH9X' 'ZH10X'};
- pars.cornames.x{7}={'ZH8X' 'ZH9X' 'ZH10X' 'ZH1FF'};
- pars.cornames.x{8}={'ZH8X' 'ZH9X' 'ZH10X' 'ZH1FF'};
- pars.cornames.x{9}={'ZH9X' 'ZH10X' 'ZH1FF' 'QD10BFF'};
- pars.cornames.x{10}={'ZH9X' 'ZH10X' 'ZH1FF' 'QD10BFF'};
- % pars.cornames.x{11}={'ZH4X' 'ZH5X' 'ZH6X'};
- % pars.cornames.x{12}={'ZH5X' 'ZH6X' 'ZH7X'};
- % pars.cornames.x{13}={'ZH5X' 'ZH6X' 'ZH7X'};
- pars.cornames.x{11}={'ZH101RX' 'ZX1X' 'ZH1X'};
- pars.cornames.x{12}={'ZX1X' 'ZH1X' 'ZH2X'};
- pars.cornames.x{13}={'ZX1X' 'ZH1X' 'ZH2X'};
- pars.cornames.x{14}={'ZH1X' 'ZH2X' 'ZH3X'};
- pars.cornames.x{15}={'ZH2X' 'ZH3X' 'ZH4X'};
- pars.cornames.x{16}={'ZH2X' 'ZH3X' 'ZH4X'};
- pars.cornames.x{17}={'ZH2X' 'ZH3X' 'ZH4X'};
- pars.cornames.x{18}={'ZH3X' 'ZH4X' 'ZH5X'};
- pars.cornames.x{19}={'ZH3X' 'ZH4X' 'ZH5X'};
- pars.cornames.x{20}={'ZH6X' 'ZH7X' 'ZH8X'};
- pars.cornames.x{21}={'ZH6X' 'ZH7X' 'ZH8X'};
- pars.cornames.x{22}={'ZH7X' 'ZH8X' 'ZH9X'};
- pars.cornames.x{23}={'ZH8X' 'ZH9X' 'ZH10X' 'ZH1FF'};
- pars.cornames.y{1}={'ZV6X' 'ZV7X' 'ZV8X' 'ZV9X'};
- pars.cornames.y{2}={'ZV6X' 'ZV7X' 'ZV8X' 'ZV9X'};
- pars.cornames.y{3}={'ZV7X' 'ZV8X' 'ZV9X' 'ZV10X'};
- pars.cornames.y{4}={'ZV8X' 'ZV9X' 'ZV10X' 'ZV11X'};
- pars.cornames.y{5}={'ZV8X' 'ZV9X' 'ZV10X' 'ZV11X'};
- pars.cornames.y{6}={'ZV9X' 'ZV10X' 'ZV11X' 'ZV1FF'};
- pars.cornames.y{7}={'ZV9X' 'ZV10X' 'ZV11X' 'ZV1FF'};
- pars.cornames.y{8}={'ZV10X' 'ZV11X' 'ZV1FF' 'QD10BFF'};
- pars.cornames.y{9}={'ZV10X' 'ZV11X' 'ZV1FF' 'QD10BFF'};
- pars.cornames.y{10}={'ZV10X' 'ZV11X' 'ZV1FF' 'QD10BFF'};
- % pars.cornames.y{11}={'ZV7X' 'ZV8X' 'ZV9X'};
- % pars.cornames.y{12}={'ZV8X' 'ZV9X' 'ZV10X'};
- % pars.cornames.y{13}={'ZV8X' 'ZV9X' 'ZV10X'};
- pars.cornames.y{11}={'ZV1X' 'ZV2X' 'ZV3X'};
- pars.cornames.y{12}={'ZV2X' 'ZV3X' 'ZV4X'};
- pars.cornames.y{13}={'ZV2X' 'ZV3X' 'ZV4X'};
- pars.cornames.y{14}={'ZV3X' 'ZV4X' 'ZV5X'};
- pars.cornames.y{15}={'ZV3X' 'ZV4X' 'ZV5X'};
- pars.cornames.y{16}={'ZV5X' 'ZV6X' 'ZV7X'};
- pars.cornames.y{17}={'ZV5X' 'ZV6X' 'ZV7X'};
- pars.cornames.y{18}={'ZV5X' 'ZV6X' 'ZV7X'};
- pars.cornames.y{19}={'ZV6X' 'ZV7X' 'ZV8X'};
- pars.cornames.y{20}={'ZV8X' 'ZV9X' 'ZV10X'};
- pars.cornames.y{21}={'ZV8X' 'ZV9X' 'ZV10X'};
- pars.cornames.y{22}={'ZV8X' 'ZV9X' 'ZV10X'};
- pars.cornames.y{23}={'ZV10X' 'ZV11X' 'ZV1FF' 'QD10BFF'};
- pars.corele.x=cell(1,length(pars.bpmnames));
- pars.corele.y=cell(1,length(pars.bpmnames));
- for icor=1:length(pars.bpmnames)
- for icor2=1:length(pars.cornames.x{icor})
- ele=findcells(BEAMLINE,'Name',pars.cornames.x{icor}{icor2});
- pars.corele.x{icor}(icor2)=ele(1);
- end
- for icor2=1:length(pars.cornames.y{icor})
- ele=findcells(BEAMLINE,'Name',pars.cornames.y{icor}{icor2});
- pars.corele.y{icor}(icor2)=ele(1);
- end
- end
- % Form bump multiknobs
- useApp('bumpgui');
- pars.bumpknob.x={}; pars.bumpknob.y={};
- for ibpm=1:length(pars.bpmnames)
- pars.bumpknob.x{ibpm} = bumpgui(1,length(pars.corele.x{ibpm}),pars.bpmele(ibpm),pars.corele.x{ibpm});
- pars.bumpknob.y{ibpm} = bumpgui(3,length(pars.corele.y{ibpm}),pars.bpmele(ibpm),pars.corele.y{ibpm});
- pars.bumpknob.xp{ibpm} = bumpgui(2,length(pars.corele.x{ibpm}),pars.bpmele(ibpm),pars.corele.x{ibpm});
- pars.bumpknob.yp{ibpm} = bumpgui(4,length(pars.corele.y{ibpm}),pars.bpmele(ibpm),pars.corele.y{ibpm});
- end
- % Bump Calibration parameters
- if ~isfield(pars,'bumpcalib')
- pars.bumpcalib.nbpm=10; % nuber of bpm readings to average
- pars.bumpcalib.nstep=5; % number of bump steps to use
- pars.bumpcalib.size=500e-6; % +/- size of bump to calibrate over
- end
- % BPM Calibration parameters
- if ~isfield(pars,'bpmcalib')
- pars.bpmcalib.nbpm=20; % nuber of bpm readings to average
- pars.bpmcalib.nstep=5; % number of bump steps to use
- pars.bpmcalib.size=1e-3; % +/- size of bump to calibrate over
- pars.bpmcalib.usesvd=false;
- pars.bpmcalib.nrepeat=1; % number of times to repeat the calibration process
- end
- % Initial bump component settings
- for ibpm=1:length(pars.bpmnames)
- for ichan=1:length(pars.bumpknob.x{ibpm}.Channel)
- evalc(['pars.bumpcomp.x{ibpm}(ichan)=',pars.bumpknob.x{ibpm}.Channel(ichan).Parameter]);
- evalc(['pars.bumpcomp.xp{ibpm}(ichan)=',pars.bumpknob.xp{ibpm}.Channel(ichan).Parameter]);
- end
- for ichan=1:length(pars.bumpknob.y{ibpm}.Channel)
- evalc(['pars.bumpcomp.y{ibpm}(ichan)=',pars.bumpknob.y{ibpm}.Channel(ichan).Parameter]);
- evalc(['pars.bumpcomp.yp{ibpm}(ichan)=',pars.bumpknob.yp{ibpm}.Channel(ichan).Parameter]);
- end
- end
- function stat=calibrateBPM(pars,bpmname,axis)
- global INSTR FL
- stat{1}=1;
- % BPM index
- wk=find(ismember(pars.bpmnames,bpmname), 1);
- if isempty(wk)
- stat{1}=-1;
- stat{2}='BPM name not found in internal structure';
- return
- end
- bpminst=findcells(INSTR,'Index',pars.bpmele(wk));
- % Is there a GUI out there?
- if isfield(FL,'Gui') && isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- isgui=true;
- else
- isgui=false;
- end
- % Take the data and calculate calibration slopes
- for irep=1:pars.bpmcalib.nrepeat
- bsteps=linspace(-pars.bpmcalib.size,pars.bpmcalib.size,pars.bpmcalib.nstep);
- bpmcal(1).xraw=[]; bpmcal(1).yraw=[];
- bpmcal(1).xraw_bump=[]; bpmcal(1).yraw_bump=[];
- for istep=randperm(length(bsteps))
- bpmcal(irep).bpmname=bpmname;
- % Set bump
- bpmcal(irep).bump(istep)=bsteps(istep);
- stat = SetMultiKnob( 'pars.bumpknob.(axis){wk}', bsteps(istep), 1); if stat{1}~=1; return; end;
- % Take averaged orbit data or collect data for svd
- % wait for pulses
- [stat,pnum]=FlHwUpdate('getpulsenum'); if stat{1}~=1; return; end;
- pnum_end=pnum+pars.bpmcalib.nbpm;
- while pnum<pnum_end
- % Is stop button pushed?
- if isgui
- resp=exitTest('commit',bpmcal);
- if resp
- return
- elseif isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- set(FL.Gui.bpmcal_calFig.text2,'String',sprintf('Taking New Data (%d of %d)...',pnum,pnum_end))
- drawnow('expose')
- end
- end
- pause(FL.Period_floodland);
- FlHwUpdate;
- [stat,pnum]=FlHwUpdate('getpulsenum'); if stat{1}~=1; return; end;
- end
- if pars.bpmcalib.usesvd
- [stat bpmdata]=FlHwUpdate('bpmave',pars.bpmcalib.nbpm); if stat{1}~=1; return; end;
- xbad=bpmdata{1}(7,:) & bpmdata{1}(9,:);
- ybad=bpmdata{1}(8,:) & bpmdata{1}(9,:);
- [stat bpmdata]=FlHwUpdate('readbuffer',pars.bpmcalib.nbpm); if stat{1}~=1; return; end;
- % store EXT and FFS BPMs
- ibpm1=findcells(INSTR,'Index',findcells(BEAMLINE,'Name','MQF1X'));
- bpmcal(1).ibpm=bpminst-ibpm1+1;
- if ((strcmp(axis,'x') || strcmp(axis,'xp')) && all(xbad)) || ((strcmp(axis,'y') || strcmp(axis,'yp')) && all(ybad))
- continue
- else
- if any(~xbad)
- bpmcal(1).xraw(end+1:end+sum(~xbad),:)=bpmdata(~xbad,ibpm1*3-1:3:end);
- bpmcal(1).xraw_bump(end+1:end+sum(~xbad),1)=bsteps(istep);
- end
- if any(~ybad)
- bpmcal(1).yraw(end+1:end+sum(~ybad),:)=bpmdata(~ybad,ibpm1*3:3:end);
- bpmcal(1).yraw_bump(end+1:end+sum(~ybad),1)=bsteps(istep);
- end
- end
- bpmcal=calib_calc('svd',bpmcal,axis);
- else
- npulse=pars.bpmcalib.nbpm;
- [stat bpmdata]=FlHwUpdate('bpmave',npulse); if stat{1}~=1; return; end;
- nbad=sum(bpmdata{1}(7,:) & bpmdata{1}(8,:) & bpmdata{1}(9,:));
- % if any bad pulses, take more
- while npulse-nbad < pars.bpmcalib.nbpm
- npulse=pars.bpmcalib.nbpm+nbad;
- % wait for new pulses
- [stat,pnum]=FlHwUpdate('getpulsenum'); if stat{1}~=1; return; end;
- pnum_end=pnum+nbad;
- while pnum<pnum_end
- % Is stop button pushed?
- if isgui
- resp=exitTest('commit',bpmcal);
- if resp
- return
- elseif isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- set(FL.Gui.bpmcal_calFig.text2,'String',sprintf('Taking New Data (%d of %d)...',npulse-nbad,pars.bpmcalib.nbpm))
- drawnow('expose')
- end
- end
- pause(FL.Period_floodland);
- FlHwUpdate;
- [stat,pnum]=FlHwUpdate('getpulsenum'); if stat{1}~=1; return; end;
- end
- [stat bpmdata]=FlHwUpdate('bpmave',npulse); if stat{1}~=1; return; end;
- nbad=sum(bpmdata{1}(7,:) & bpmdata{1}(8,:) & bpmdata{1}(9,:));
- end
- bpmcal(irep).x(istep)=bpmdata{1}(1,bpminst); bpmcal(irep).y(istep)=bpmdata{1}(2,bpminst);
- bpmcal(irep).xerr(istep)=bpmdata{1}(4,bpminst); bpmcal(irep).yerr(istep)=bpmdata{1}(4,bpminst);
- bpmcal=calib_calc('standard',bpmcal,axis);
- end
- rawdata(istep).bpmdata=bpmdata; %#ok<NASGU>
- end
- end
- % Commit results
- if isgui
- calib_calc('commit',bpmcal);
- end
- % Save data
- if ~exist('userData/nmCavCal','dir')
- mkdir('userData','nmCavCal');
- save(sprintf('userData/nmCavCal/bpmcalibdata-%s.mat',datestr(now,FL.tstamp)),'rawdata','bpmcal');
- end
- save userData
- function bpmcal=calib_calc(cmd,bpmcal,axis)
- global FL
- if strcmp(cmd,'commit')
- if isfield(bpmcal,'xscale') && strcmp(questdlg(sprintf('%s\nx slope = %g +/- %g','Commit New Calibration?',bpmcal(1).xscale,bpmcal(1).xscale_err),'Commit Cal'),'Yes')
- lcaPut([bpmcal(1).bpmname,':SCALE_X'],lcaGet([bpmcal(1).bpmname,':SCALE_X'])*bpmcal(1).xscale);
- elseif ~isfield(bpmcal,'xscale') && strcmp(questdlg(sprintf('%s\ny slope = %g +/- %g','Commit New Calibration?',bpmcal(1).yscale,bpmcal(1).yscale_err),'Commit Cal'),'Yes')
- lcaPut([bpmcal(1).bpmname,':SCALE_Y'],lcaGet([bpmcal(1).bpmname,':SCALE_Y'])*bpmcal(1).yscale);
- end
- else
- if isfield(FL,'Gui') && isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- figure(FL.Gui.bpmcal_calFig.figure1)
- else
- FL.Gui.bpmcal_calFig.figure1=bpmcal_calFig;
- end
- if strcmp(cmd,'standard')
- % average over multiple scans
- for iscan=1:length(bpmcal)
- % change order by x-axis
- [Y Ix]=sort(bpmcal(iscan).bump);
- bpmval(iscan,1:length(bpmcal(iscan).(axis)))=bpmcal(iscan).(axis)(Ix);
- bpmval_err(iscal,1:length(bpmcal(iscan).(axis)))=bpmcal(iscan).([axis 'err'])(Ix);
- xval(iscan,:)=Y;
- end
- % Only average over completed scan steps
- for iscan=1:length(xval(1,:))
- bpmval(iscan)=mean(bpmval(ismember(xval,xval(1,iscan))&bpmval~=0));
- bpmval_err(iscan)=sqrt(sum(bpmval_err(ismember(xval,xval(1,iscan))&bpmval~=0).^2))/sum(ismember(xval,xval(1,iscan)));
- end
- elseif strcmp(cmd,'svd')
- % Unpack raw data and compute SVD
- xval=bpmcal(1).xraw_bump;
- yval=bpmcal(1).([axis 'raw']);
- [xval xind]=sort(xval);
- yval=yval(xind,:);
- [Ux,Sx,Vtx]=svd(yval);
- Vx=Vtx';
- % Correlate modes with orbit bump
- for imode=1:10
- [r,p] = corrcoef(xval,yval*Vx(imode,:)');
- if ~isempty(find(p<0.1, 1))
- rcor(imode)=r(1,2);
- else
- rcor(imode)=0;
- end % if any significant correlations
- end % for imode
- if ~any(rcor)
- return
- end % if no correlations found, return
- % throw away all modes but that most correlated to bump, reform bpm
- % data and pull out BPM of interest
- Sx_new=zeros(size(Sx));
- [~, rind]=max(rcor);
- Sx_new(rind,rind)=Sx(rind,rind);
- bpmval_all=Ux*Sx_new*Vx;
- uxval=unique(xval);
- for ix=1:length(uxval)
- bpmval(ix)=mean(bpmval_all(ismember(xval,uxval(ix)),bpmcal(1).ibpm));
- bpmval_err(ix)=std(bpmval_all(ismember(xval,uxval(ix)),bpmcal(1).ibpm));
- end
- xval=uxval;
- end
- plot_polyfit(FL.Gui.bpmcal_calFig.axes1); % set polyfit plot axes
- [q dq]=plot_polyfit(xval.*1e3,bpmval.*1e3,bpmval_err.*1e3,2,[axis ' Bump Size'],'BPM reading','mm','mm');
- bpmcal(1).([axis 'scale'])=q/1e3; bpmcal(1).([axis 'scale_err'])=dq/1e3;
- if isfield(FL,'Gui') && isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- set(FL.Gui.bpmcal_calFig.text1,'String',sprintf('%.3f +/- %.3f (mm)',q,dq))
- drawnow('expose')
- end
- end
- function resp=exitTest(bpmcal)
- global FL
- resp=false;
- if isfield(FL,'Gui') && isfield(FL.Gui,'bpmcal_calFig') && ishandle(FL.Gui.bpmcal_calFig.figure1)
- if get(FL.Gui.bpmcal_calFig,'togglebutton2')
- resp=true;
- guiCloseFn('bpmcal_calFig',FL.Gui.bpmcal_calFig);
- elseif get(FL.Gui.bpmcal_calFig,'togglebutton1')
- resp=true;
- calib_calc('commit',bpmcal);
- guiCloseFn('bpmcal_calFig',FL.Gui.bpmcal_calFig);
- end
- else
- resp=true;
- end