source: MML/trunk/mml/orbitcorrectionmethods.m @ 4

Last change on this file since 4 was 4, checked in by zhangj, 10 years ago

Initial import--MML version from SOLEIL@2013

File size: 25.8 KB
Line 
1function [OCS, SmatNoWeights, S, U, V] = orbitcorrectionmethods(OCS, Smat, S, U, V)
2%ORBITCORRECTIONMETHODS - Some the orbit correction methods used on light sources
3%
4%  [OCS, Smat, S, U, V] = orbitcorrectionmethods(OCS)                 % Get response matrix & compute SVD correction
5%  [OCS, Smat, S, U, V] = orbitcorrectionmethods(OCS, Smat)           % Compute SVD & correction
6%  [OCS, Smat, S, U, V] = orbitcorrectionmethods(OCS, Smat, S, U, V)  % Compute correction
7%
8%  OCS.FitRF - Determines which RF freqency method to use
9%  See setorbit for information on all the different flags.
10
11%  NOTES
12%  1. OCS.CM.Data is not changed by this function
13%     OCS.CM.Delta is the delta correction
14%  2. Both row and column weighting of the response matrix can be done.
15%     The default is unity row weights and column weight by the std of each column.
16%
17%  See also setorbit, setorbitbump, rmdisp, plotcm
18
19%
20%  Written by Gregory J. Portmann
21%  Addition for Soleil by Laurent S. Nadolski
22%    Constraints on min and max RF frequency variations
23
24%  T = V(:,OCS.SVDIndex) * diag(S(OCS.SVDIndex).^(-1)) * U(:,OCS.SVDIndex)';
25%  Delcm = T * (BPMWeight .* (GoalOrbitVec - StartOrbitVec));
26%
27
28
29% Initialize
30FitRFDefault = 0;
31
32% Machine dependent
33if strcmpi(getfamilydata('SubMachine'),'StorageRing') && strcmpi(getfamilydata('Machine'),'SOLEIL')
34    DeltaRFmin = 1e-7;   % MHz minimum variation allowed by Master oscillator
35    DeltaRFmax = 100e-6; % MHz maximum variation allowed in one step
36else
37    DeltaRFmin = 1e-17;   % MHz minimum variation allowed by Master oscillator
38    DeltaRFmax = 100e6; % MHz maximum variation allowed in one step
39end
40
41
42% Input checking (should add more)
43if nargin < 2
44    Smat = [];
45end
46if nargin < 3
47    S = [];
48    U = [];
49    V = [];
50end
51
52
53% This function expects .BPM and .CM to be cell arrays.
54% This gets put back at the end of the function.
55if ~iscell(OCS.BPM)
56    NoCellBPMFlag = 1;
57    OCS.BPM = {OCS.BPM};
58    OCS.GoalOrbit = {OCS.GoalOrbit};
59    if isfield(OCS, 'BPMWeight')
60        OCS.BPMWeight = {OCS.BPMWeight};
61    end
62else
63    NoCellBPMFlag = 0;
64end
65if ~iscell(OCS.CM)
66    NoCellCMFlag = 1;
67    OCS.CM = {OCS.CM};
68    if isfield(OCS, 'CMWeight')
69        if ~iscell(OCS.CMWeight)
70            OCS.CMWeight = {OCS.CMWeight};
71        end
72    end
73else
74    NoCellCMFlag = 0;
75end
76
77
78% RF frequency methods in orbit correction
79if ~isfield(OCS, 'FitRF')
80    OCS.FitRF = FitRFDefault;
81end
82if isempty(OCS.FitRF)
83    OCS.FitRF = FitRFDefault;
84end
85
86
87%%%%%%%%%%%%%%%%
88% The SVD Part %
89%%%%%%%%%%%%%%%%
90if isempty(U)
91    %%%%%%%%%%%%%%%%%%%%%%%%%%%
92    % Get the response matrix %
93    %%%%%%%%%%%%%%%%%%%%%%%%%%%
94    if isempty(Smat)
95        for i = 1:length(OCS.BPM)
96            Srow = [];
97            for j = 1:length(OCS.CM)
98                %if ModelRespFlag == 1
99                if any(strcmpi(OCS.Flags,'ModelResp'))
100                    % When using measbpmresp('Model')
101                    % Rmat(1,1) is always horizontal
102                    % Rmat(2,2) is always vertical
103                    Rmat = measbpmresp('model',OCS.BPM{i},OCS.BPM{i}, OCS.CM{j},OCS.CM{j}, OCS.BPM{i}.Units);
104                    if ismemberof(OCS.BPM{i}.FamilyName, gethbpmfamily) && ismemberof(OCS.CM{j}.FamilyName,gethcmfamily)
105                        S = Rmat(1,1).Data;
106                    elseif ismemberof(OCS.BPM{i}.FamilyName, getvbpmfamily) && ismemberof(OCS.CM{j}.FamilyName,gethcmfamily)
107                        S = Rmat(2,1).Data;               
108                    elseif ismemberof(OCS.BPM{i}.FamilyName, gethbpmfamily) && ismemberof(OCS.CM{j}.FamilyName,getvcmfamily)
109                        S = Rmat(1,2).Data;
110                    elseif ismemberof(OCS.BPM{i}.FamilyName, getvbpmfamily) && ismemberof(OCS.CM{j}.FamilyName,getvcmfamily)
111                        S = Rmat(2,2).Data;
112                    else
113                        error('Problem getting the model response matrix');
114                    end
115                else
116                    % Get the golden BPM response matrix
117                    [S, FileName] = getrespmat(OCS.BPM{i}, OCS.CM{j}, 'Numeric');
118                    if any(find(isnan(S)))
119                        error('Not all BPMs and correctors exist in the response matrix.');
120                    end
121                end
122                if length(OCS.GoalOrbit{i}) ~= size(S,1)
123                    error('The goal orbit vector length does not equal the response matrix row length');
124                end
125
126                Srow = [Srow S];
127            end
128            Smat = [Smat; Srow];
129        end
130        %SmatCheck = measbpmresp('Model','Numeric');
131
132
133        %%%%%%%%%%%%%%%%%%
134        % Get Dispersion %
135        %%%%%%%%%%%%%%%%%%
136        Eta = [];
137        if OCS.FitRF
138            for i = 1:length(OCS.BPM)
139                if any(strcmpi(OCS.Flags,'ModelDisp'))
140                    %if strcmpi(DispFlag,'ModelDisp')
141                    DispOrbit = measdisp(OCS.BPM{i}, 'Hardware', 'Numeric', 'Model');
142                elseif any(strcmpi(OCS.Flags,'MeasDisp'))
143                    %elseif strcmpi(DispFlag,'MeasDisp')
144                    DispOrbit = measdisp(OCS.BPM{i}, 'Hardware', 'Numeric');
145                elseif any(strcmpi(OCS.Flags,'GoldenDisp'))
146                    %elseif strcmpi(DispFlag,'GoldenDisp')
147                    DispOrbit = getdisp(OCS.BPM{i}, 'Hardware', 'Numeric');
148                end
149               
150                if strcmpi(OCS.BPM{i}.Units, 'Physics')
151                    % Put the RF change in physics units, not energy change
152                    RFhw = physics2hw(OCS.RF);
153                    DispOrbit = DispOrbit / (OCS.RF.Data / RFhw.Data);
154                end
155               
156                if isempty(DispOrbit)
157                    error('Did not find or generate dispersion orbit properly');
158                end
159                if any(isnan(DispOrbit))
160                    error('The dispersion data has at least one NaN.');
161                end
162               
163                Eta = [Eta; DispOrbit];
164            end
165        end
166        OCS.Eta = Eta;
167    end
168end
169
170
171% Save a weight free response matrix
172SmatNoWeights = Smat;
173
174
175%%%%%%%%%%%%%%%%%%%%%%%%%%%
176% Build the orbit vectors %
177%%%%%%%%%%%%%%%%%%%%%%%%%%%
178StartOrbitVec = [];
179GoalOrbitVec = [];
180BPMWeight = [];
181for i = 1:length(OCS.BPM)
182    StartOrbitVec = [StartOrbitVec; OCS.BPM{i}.Data(:)];
183    GoalOrbitVec  = [GoalOrbitVec; OCS.GoalOrbit{i}(:)];
184
185    if ~isfield(OCS, 'BPMWeight') || isempty(OCS.BPMWeight{i})
186        BPMWeight = [BPMWeight; ones(length(OCS.BPM{i}.Data),1)];
187    elseif isscalar(OCS.BPMWeight{i})
188        BPMWeight = [BPMWeight; ones(length(OCS.BPM{i}.Data),1) * OCS.BPMWeight{i}];
189    else
190        BPMWeight = [BPMWeight; OCS.BPMWeight{i}(:)];
191    end
192end
193
194
195% Build column weight vector
196CMWeight = [];
197for i = 1:length(OCS.CM)
198    if ~isfield(OCS, 'CMWeight') || isempty(OCS.CMWeight{i})
199        % When using all singular values this does not do anything
200        % The amp to radian conversion is probably a better normalizer
201        %CMWeight = 1 ./ sqrt(sum(Smat.^2));
202        CMWeight = 1./std(Smat)';
203
204        % No weight
205        %CMWeight = ones(size(Smat,2),1);
206
207        break;
208        %CMWeight = [CMWeight; ones(length(OCS.CM{i}.Data),1)];
209
210    elseif isscalar(OCS.CMWeight{i})
211        CMWeight = [CMWeight; ones(length(OCS.CM{i}.Data),1) * OCS.CMWeight{i}];
212
213    else
214        CMWeight = [CMWeight; OCS.CMWeight{i}(:)];
215    end
216end
217
218
219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220% Add a column weight to the response matrix %
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222%if isempty(U)
223    for j = 1:length(CMWeight)
224        Smat(:,j) = Smat(:,j) * CMWeight(j);
225    end
226%end
227
228
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% Add a weighted disperion as a column of the response matrix %
231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232if OCS.FitRF == 0
233    % Don't fit the RF frequency
234    OCS.DeltaRF = 0;
235elseif any(OCS.FitRF == [1 2 3 4 5])
236    % Column weighting (changing the units or sensitivity) seems to be a good thing.
237    % (At least at the ALS working in hardware units.)
238    % Weight by more than the average std of Smat also seems to give good results but
239    % I'm not sure it's necessary or should be done.
240    RFWeight = 10 * mean(std(Smat)) / std(OCS.Eta);
241    Smat = [Smat RFWeight*OCS.Eta];
242else
243    error('Unknown RF correction method.');
244end
245
246
247
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249% Add a row weight to the response matrix %
250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251% Weighted LS
252% Weighted LS was developed for heteroscedastic errors but it's used here for other reasons
253% W*(Mmeas - Mmodel) = W*A*b + W*e,  where the e's are gausian, zero mean, independent, but not constant variance
254% W is chosen to make E(Wee'W') = sigma * I  (ie, W * e has a constant variance)
255%
256% The new LS equations are,
257% b = inv(Amod'*W' * W*Amod) * Amod'*W' * W*(Xgoal - Xmeasured);      % Parameter fit
258% b = V(:,Ivec) * b;
259% bvar = inv(Amod'*W'*W*Amod);
260%
261% Since the weight matrix, W, is only going to be diagonal, it is less memory
262% to scaled Amod and (Mmeas-Model) by the diagonal term and not create the matrix W
263if ~all(BPMWeight == 1)
264    for i = 1:size(Smat,1)
265        Smat(i,:) = BPMWeight(i) * Smat(i,:);
266    end
267end
268
269
270%%%%%%%%%%%%%%%%
271% The SVD Part %
272%%%%%%%%%%%%%%%%
273if isempty(U)
274    if any(any(isnan(Smat)))
275        error('The response matrix has at least one NaN.');
276    end
277
278    % Do the SVD
279    [U, S, V] = svd(Smat, 0);  %'econ');
280    S = diag(S);
281end
282
283
284% Determine the singular vector and error check
285if isnumeric(OCS.SVDIndex)
286    if length(OCS.SVDIndex) == 1
287        if rem(OCS.SVDIndex,1) == 0
288            OCS.SVDIndex = 1:OCS.SVDIndex;
289        else
290            % Use threshold
291            Ivec = find(S > max(S)*OCS.SVDIndex);
292            OCS.SVDIndex = Ivec;
293        end
294    end
295elseif ischar(OCS.SVDIndex)
296    if strcmpi(OCS.SVDIndex, 'All')
297        OCS.SVDIndex = 1:length(S);
298    else
299        error('OCS.SVDIndex unknown');
300    end
301else
302    error('OCS.SVDIndex unknown');
303end
304
305% Nothing greater then the total number is singular values
306i = find(OCS.SVDIndex > length(S));
307if ~isempty(i)
308    warning('Requested number of singular values is greater than the total.  Removing %d values.',length(i));
309    OCS.SVDIndex(i) = length(S);
310end
311
312% No non-integers
313OCS.SVDIndex = round(OCS.SVDIndex);
314
315% Nothing less than zero
316i = find(OCS.SVDIndex <= 0);
317OCS.SVDIndex(i) = length(S);
318
319% No repeats
320OCS.SVDIndex = sort(OCS.SVDIndex);
321i = find(diff(OCS.SVDIndex)==0);
322OCS.SVDIndex(i) = [];
323
324if isempty(OCS.SVDIndex)
325    error('Singular values vector is empty');
326end
327
328
329if OCS.FitRF == 2 || OCS.FitRF == 3
330    % Constrained L.S. with SVD
331    % Constraint: Sum of the energy change to zero
332    % Note: Model required
333   
334    R = [];
335    HCMEnergyChangeTotal = 0;
336    for i = 1:length(OCS.CM)
337        if ismemberof(OCS.CM{i}.FamilyName, 'HCOR')
338            L = getfamilydata('Circumference');
339
340            if ~isfield(OCS.CM{i}, 'Dispersion')
341                % Dispersion at the correctors in physics units
342                [OCS.CM{i}.Dispersion, DyHCM] = modeldisp([], OCS.CM{i}.FamilyName, OCS.CM{i}.DeviceList, 'Numeric', 'Physics');
343            end
344           
345            % Present corrector setpoint in physics units
346            HCM = hw2physics(OCS.CM{i});
347
348           
349            % Move ALS specific code to setorbitdefault ???
350            if strcmpi(getfamilydata('Machine'),'ALS')
351                % For the ALS, either the HCMCHICANE families need to be included or
352                % the chicane "part" of the HCMs needs to be removed.  This will remove the chicane.
353                Energy = getfamilydata('Energy');
354
355                % Sector 6
356                %                   Off    1.9 GeV   1.5 GeV
357                % HCMCHICANEM(6,1)  80.0    18.0       ?
358                % HCMCHICANEM(6,1)  80.0    20.0       ?
359                % HCM(6,1)           0.0    18.8       ?
360                ihcm = findrowindex([6 1], OCS.CM{i}.DeviceList);
361                if length(ihcm) == 1
362                    try
363                        if getsp('HCMCHICANEM',[6 1]) < 70
364                            % Assume sector 6 chicane is on
365                            if Energy == 1.9
366                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field, -18.8, [6 1]);
367                            else
368                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field,  -18.8*1.5/1.9, [6 1]);
369                            end
370                        end
371                    catch
372                        fprintf('%s\n', lasterr);
373                        fprintf('Problem reading HCMCHICANEM(6,1).  The chicane "offset" on HCM(6,1) will not be removed.\n\n');
374                    end
375                end
376
377                % Sector 11
378                %                    Off    1.9 GeV   1.5 GeV
379                % HCMCHICANEM(11,1)  80.0    40.5      52.0
380                % HCMCHICANEM(11,1)  80.0    40.5      52.0
381                % HCM(10,8)           0.0   -17.0     -14.0
382                % HCM(11,1)           0.0   -17.0     -14.0
383                ihcm = findrowindex([10 8], OCS.CM{i}.DeviceList);
384                if length(ihcm) == 1
385                    try
386                        if getsp('HCMCHICANEM',[11 1]) < 60
387                            % Assume sector 11 chicane is on
388                            if Energy == 1.9
389                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field, [17; 17], [10 8;11 1]);
390                            else
391                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field, [14; 14], [10 8;11 1]);
392                            end
393                        end
394                    catch
395                        fprintf('%s\n', lasterr);
396                        fprintf('Due to an error, the chicane "offset" on HCM(10,8) will not be removed.n\n');
397                    end
398                end
399                ihcm = findrowindex([11 1], OCS.CM{i}.DeviceList);
400                if length(ihcm) == 1
401                    try
402                        if getsp('HCMCHICANEM',[11 1]) < 60
403                            % Assume sector 11 chicane is on
404                            if Energy == 1.9
405                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field, [17; 17], [10 8;11 1]);
406                            else
407                                HCM.Data(ihcm) = HCM.Data(ihcm) + hw2physics(OCS.CM{i}.FamilyName, OCS.CM{i}.Field, [14; 14], [10 8;11 1]);
408                            end
409                        end
410                    catch
411                        fprintf('%s\n', lasterr);
412                        fprintf('Due to an error, the chicane "offset" on HCM(11,1) will not be removed.n\n');
413                    end
414                end
415            end
416            % END ALS only
417           
418           
419            % Energy change to remove
420            HCMEnergyChangeTotal = HCMEnergyChangeTotal + sum(-1 * HCM.Data .* OCS.CM{i}.Dispersion / getmcf / L);
421           
422            % Energy scaling must be in physics units, hence the (HCM.Data./OCS.CM{i}.Data)
423            if strcmpi(OCS.CM{i}.Units, 'Hardware')
424                % PhysicsUnitsScaling = (HCM.Data./OCS.CM{i}.Data);  %This does not work for zero setpoints
425                PhysicsUnitsScaling = hw2physics(OCS.CM{i}. FamilyName,OCS.CM{i}.Field, 1, OCS.CM{i}.DeviceList);
426            else
427                PhysicsUnitsScaling = 1;
428            end
429            HCMEnergyChangeScalar = -1 * PhysicsUnitsScaling .* OCS.CM{i}.Dispersion / getmcf / L;
430            R = [R HCMEnergyChangeScalar(:)'];
431           
432            % Sum of correctors to zero
433            %R = [R ones(size(HCMEnergyChange(:)'))];
434        else
435            R = [R zeros(1,size(OCS.CM{i}.DeviceList,1))];
436        end
437    end
438   
439    if OCS.FitRF == 2
440        % Also remove the energy change due to the present corrector setpoints
441        r = -HCMEnergyChangeTotal/2;    % Not sure about the divide by 2
442    elseif OCS.FitRF == 3
443        % Only remove energy change due to the incremental change in the correctors
444        r = 0;
445    end
446   
447    % Add a zero for no constaint on the RF
448    R = [R 0];
449   
450
451    % Projection onto the columns of Smat*V (or U)
452    % Since the correctors are V*b, the restriction in corrector strength is R*V
453    X = Smat * V(:,OCS.SVDIndex);
454    R = R * V(:,OCS.SVDIndex);
455    b = inv(X'*X)*X' * (BPMWeight .* (GoalOrbitVec - StartOrbitVec));
456    br = b - inv(X'*X)*R'*inv(R*inv(X'*X)*R')*(R*b-r);
457    Delcm = V(:,OCS.SVDIndex) * br;
458
459elseif OCS.FitRF == 4
460    % Constrained L.S. with SVD
461    % Constraint: dot(DispersionX,   Smat * dHCM) = 0
462    %         or  dot(DispersionX' * Smat,  dHCM) = 0 or total dot(DisperionX, Smat * HCM)
463    R = [];
464    DispDotSmatHCM = 0;
465    for i = 1:length(OCS.BPM)
466        if strcmpi(OCS.BPM{i}.FamilyName, 'BPMx') || ismemberof(OCS.BPM{i}.FamilyName, 'BPMx')
467            if ~isfield(OCS.BPM{i}, 'Dispersion')
468                % Dispersion at the correctors in physics units
469                [OCS.BPM{i}.Dispersion, Dy] = getdisp(OCS.BPM{i}.FamilyName, OCS.BPM{i}.DeviceList, 'Numeric',  OCS.BPM{i}.Units);
470            end
471            R = [R OCS.BPM{i}.Dispersion(:)'];
472           
473            HCM = physics2hw(OCS.CM{i});
474
475           
476            % Move ALS specific code to setorbitdefault ???
477            if strcmpi(getfamilydata('Machine'),'ALS')
478                % For the ALS, either the HCMCHICANE families need to be included or
479                % the chicane "part" of the HCMs needs to be removed.  This will remove the chicane.
480                Energy = getfamilydata('Energy');
481
482                % Sector 6
483                %                   Off    1.9 GeV   1.5 GeV
484                % HCMCHICANEM(6,1)  80.0    18.0       ?
485                % HCMCHICANEM(6,1)  80.0    20.0       ?
486                % HCM(6,1)           0.0    18.8       ?
487                ihcm = findrowindex([6 1], OCS.CM{i}.DeviceList);
488                if length(ihcm) == 1
489                    try
490                        if getsp('HCMCHICANEM',[6 1]) < 70
491                            % Assume sector 6 chicane is on
492                            if Energy == 1.9
493                                HCM.Data(ihcm) = HCM.Data(ihcm) - 18.8;
494                            else
495                                HCM.Data(ihcm) = HCM.Data(ihcm) - 18.8*1.5/1.9;
496                            end
497                        end
498                    catch
499                        fprintf('%s\n', lasterr);
500                        fprintf('Due to an error, the chicane "offset" on HCM(6,1) will not be removed.\n\n');
501                    end
502                end
503
504                % Sector 11
505                %                    Off    1.9 GeV   1.5 GeV
506                % HCMCHICANEM(11,1)  80.0    40.5      52.0
507                % HCMCHICANEM(11,1)  80.0    40.5      52.0
508                % HCM(10,8)           0.0   -17.0     -14.0
509                % HCM(11,1)           0.0   -17.0     -14.0
510                ihcm = findrowindex([10 8], OCS.CM{i}.DeviceList);
511                if length(ihcm) == 1
512                    try
513                        if getsp('HCMCHICANEM',[11 1]) < 60
514                            % Assume sector 11 chicane is on
515                            if Energy == 1.9
516                                HCM.Data(ihcm) = HCM.Data(ihcm) + 17;
517                            else
518                                HCM.Data(ihcm) = HCM.Data(ihcm) + 14;
519                            end
520                        end
521                    catch
522                        fprintf('%s\n', lasterr);
523                        fprintf('Problem reading HCMCHICANEM(11,1).  The chicane "offset" on HCM(10,8) will not be removed.n\n');
524                    end
525                end
526                ihcm = findrowindex([11 1], OCS.CM{i}.DeviceList);
527                if length(ihcm) == 1
528                    try
529                        if getsp('HCMCHICANEM',[11 1]) < 60
530                            % Assume sector 11 chicane is on
531                            if Energy == 1.9
532                                HCM.Data(ihcm) = HCM.Data(ihcm) + 17;
533                            else
534                                HCM.Data(ihcm) = HCM.Data(ihcm) + 14;
535                            end
536                        end
537                    catch
538                        fprintf('%s\n', lasterr);
539                        fprintf('Due to an error, the chicane "offset" on HCM(11,1) will not be removed.n\n');
540                    end
541                end
542            end
543            % END ALS only
544
545
546            % Assumes 1 HCM family and it's first???
547            DispDotSmatHCM = DispDotSmatHCM + OCS.BPM{i}.Dispersion'*Smat(1:size(OCS.BPM{i}.DeviceList,1),1:1:size(OCS.CM{i}.DeviceList,1))*HCM.Data;
548        else
549            R = [R zeros(1,size(OCS.BPM{i}.DeviceList,1))];
550        end
551    end
552    % [OCS.BPM{1}.Dispersion, Dy] = getdisp(OCS.BPM{1}.FamilyName, OCS.BPM{1}.DeviceList, 'Numeric', OCS.BPM{1}.Units);
553    % RR = [OCS.BPM{1}.Dispersion(:); zeros(size(OCS.BPM{2}.DeviceList,1),1)]';
554
555    %r = 0;
556    r = -1*DispDotSmatHCM;  % Not sure if this should be divided by 2
557    R = [R*Smat(:,1:end-1) 0];
558
559
560    % Projection onto the columns of Smat*V (or U)
561    % Since the correctors are V*b, the restriction in corrector strength is R*V
562    X = Smat * V(:,OCS.SVDIndex);
563    R = R * V(:,OCS.SVDIndex);
564    b = inv(X'*X)*X' * (BPMWeight .* (GoalOrbitVec - StartOrbitVec));
565    br = b - inv(X'*X)*R'*inv(R*inv(X'*X)*R')*(R*b-r);
566    Delcm = V(:,OCS.SVDIndex) * br;
567   
568    %DelcmNoR = V(:,OCS.SVDIndex) * b;
569    %fprintf('   dRF=%g  dRF(NoR)=%g\n',  RFWeight * Delcm(end),  RFWeight * DelcmNoR(end));
570   
571elseif OCS.FitRF == 5
572    % Constrained L.S. with SVD
573    % Constraint: dot(HCM(Dispersion), dHCM) = 0
574    R = [];
575    for i = 1:length(OCS.CM)
576        if ismemberof(OCS.CM{i}.FamilyName, 'HCM')
577            % Assume CM{i} is the same plane as BPM{i}
578            if ~isfield(OCS.BPM{i}, 'Dispersion')
579                % Dispersion at the horizontal BPMs
580                [OCS.BPM{i}.Dispersion, Dy] = getdisp(OCS.BPM{i}.FamilyName, OCS.BPM{i}.DeviceList, 'Numeric',  OCS.BPM{i}.Units);
581
582                % Find the corrector pattern of the dispersion orbit
583                %
584                % OCS.SVDIndex ????
585                % Smat???  make an array
586                % Why is Rhcm so different from Rbpmx?
587               
588                % Assumes 1 HCM family and it's first???
589                SmatNoEta = Smat(1:size(OCS.BPM{i}.DeviceList,1),1:size(OCS.CM{i}.DeviceList,1));
590                [UU, SS, VV] = svd(SmatNoEta, 'econ');
591                SS = diag(SS);
592
593                X = SmatNoEta * VV(:,OCS.SVDIndex);
594                b = inv(X'*X)*X' * OCS.BPM{i}.Dispersion;
595                OCS.BPM{i}.DispersionCorrectors = VV(:,OCS.SVDIndex) * b;
596            end
597            R = [R OCS.BPM{i}.DispersionCorrectors(:)'];
598        else
599            R = [R zeros(1,size(OCS.CM{i}.DeviceList,1))];
600        end
601    end
602
603    r = 0;  % Should it be an absolute conditional ???
604    R = [R 0];
605
606
607    % Projection onto the columns of Smat*V (or U)
608    % Since the correctors are V*b, the restriction in corrector strength is R*V
609    X = Smat * V(:,OCS.SVDIndex);
610    R = R * V(:,OCS.SVDIndex);
611    b = inv(X'*X)*X' * (BPMWeight .* (GoalOrbitVec - StartOrbitVec));
612    br = b - inv(X'*X)*R'*inv(R*inv(X'*X)*R')*(R*b-r);
613    Delcm = V(:,OCS.SVDIndex) * br;
614   
615    %DelcmNoR = V(:,OCS.SVDIndex) * b;
616    %fprintf('   dRF=%g  dRF(NoR)=%g\n',  RFWeight * Delcm(end),  RFWeight * DelcmNoR(end));
617
618else
619
620    % L.S. with SVD algorithm
621    % The V matrix columns are the singular vectors in the corrector magnet space
622    % The U matrix columns are the singular vectors in the BPM space
623    % Smat = U*S*V' where U'*U=I and V*V'=I
624    %
625    % b is the coef. of the projection onto the columns of Smat*V(:,Ivec) - the corrector space (same space as spanned by U)
626    % Sometimes it's interesting to look at the size of these coefficients with singular value number.
627    b = U(:,OCS.SVDIndex)' * (BPMWeight .* (GoalOrbitVec - StartOrbitVec));
628    b = diag(S(OCS.SVDIndex).^(-1)) * b;
629
630    % Convert the b vector back to coefficents of response matrix
631    Delcm = V(:,OCS.SVDIndex) * b;
632end
633
634
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636% Remove Weights for the Correction %
637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
638% Separate the RF from the correctors
639if OCS.FitRF
640    % RF frequency is the last actuator
641    OCS.DeltaRF = RFWeight * Delcm(end);
642    if strcmpi(getfamilydata('SubMachine'), 'StorageRing')
643        % Begin Add by Laurent % To be done with variables
644        % test for avoiding to move too often RF frequency
645        %fprintf('Prog %e \n',DelRF);
646        if abs(OCS.DeltaRF) < DeltaRFmin % minimum RF is .1 Hz
647            OCS.DeltaRF = 0;
648        end
649        if abs(OCS.DeltaRF) > DeltaRFmax % maximum is 100 Hz
650            error('RF change too large DeltaRF = %f Hz (> %f Hz) \nRF frequency shift has to be fixed first by hand.\nSee expert steprf command', ...
651                hw2physics('RF','Setpoint',OCS.DeltaRF), hw2physics('RF','Setpoint',DeltaRFmax));
652        end
653    end
654    Delcm = Delcm(1:end-1);
655end
656
657% Remove column weights from Delcm
658Delcm = Delcm .* CMWeight;
659   
660   
661% Predict Orbit
662if OCS.FitRF
663    OrbitDeltaTotal = [SmatNoWeights OCS.Eta] * [Delcm; OCS.DeltaRF];
664else
665    OrbitDeltaTotal = SmatNoWeights * Delcm;
666end
667for j = 1:length(OCS.BPM)
668    N = length(OCS.BPM{j}.Data);
669    OCS.BPM{j}.PredictedOrbitDelta = OrbitDeltaTotal(1:N);
670    OrbitDeltaTotal(1:N) = [];
671end
672
673
674% Don't put the Delcm into OCS.CM so this function can get
675% called multiple times before actually correcting the orbit
676for i = 1:length(OCS.CM)
677    N = length(OCS.CM{i}.Data);
678    %OCS.CM{i}.Data = OCS.CM{i}.Data + Delcm(1:N);
679    OCS.CM{i}.Delta = Delcm(1:N);
680    Delcm(1:N) = [];
681
682    OCS.CMWeight{i} = CMWeight(1:N);
683    CMWeight(1:N) = [];
684end
685
686
687% Remove the cell array if the length is one
688if NoCellBPMFlag
689    OCS.BPM = OCS.BPM{1};
690    OCS.GoalOrbit = OCS.GoalOrbit{1};
691    OCS.BPMWeight = OCS.BPMWeight{1};
692end
693if NoCellCMFlag
694    OCS.CM = OCS.CM{1};
695    OCS.CMWeight = OCS.CMWeight{1};
696end
697
698
699% Output statistics???
700% 1. Correctable orbit
701% 2. Not correctable orbit
702% 3. Error propagation
703
704   
Note: See TracBrowser for help on using the repository browser.