1 | function ffgettbl(Sector, BPMFlag) |
---|
2 | %FFGETTBL - Measures an insertion device feed forward table for the vertical gap |
---|
3 | % ffgettbl(Sector, BPMFlag (0=Bergoz BPMs, else=All BPMs)) |
---|
4 | % |
---|
5 | % This function generates the feed forward tables necessary for insertion device compensation. |
---|
6 | % |
---|
7 | % This function is under development |
---|
8 | |
---|
9 | |
---|
10 | % 2002-04-05 T.Scarvie |
---|
11 | % modified to perform a tune FF correction after each move and prior to each orbit correction |
---|
12 | % to produce FF tables that are more accurate while running orbit FB |
---|
13 | % |
---|
14 | % 2003-04-25 C. Steier |
---|
15 | % IDBPMs in sectors 1 and 3 are not used anymore since they are noisy at low beam current |
---|
16 | % and therefore compromise the FF tables. |
---|
17 | % |
---|
18 | % 2004-07-06 T.Scarvie |
---|
19 | % made tune FF correction active for 5W as well as other gaps because 5W FF table no longer |
---|
20 | % includes quadrupoles - all tune FF is handled by orbit feedback |
---|
21 | % |
---|
22 | % 2004-10-18 T. Scarvie |
---|
23 | % removed quad generation option from routine - tune compensation is handled by orbit feedback algorithm now |
---|
24 | % |
---|
25 | % 2005-02-06 G. Portmann |
---|
26 | % Upgrate to new middlelayer format |
---|
27 | % To do: 1. Slow/fast correctors? |
---|
28 | % 2. Use FF channels? |
---|
29 | % 3. Use center chicane BPMs and correctors? |
---|
30 | |
---|
31 | |
---|
32 | % Initialization |
---|
33 | |
---|
34 | % Need to change this to a question dialog to allow for local tune compensation; hard-coded for now - 2004-07-06, T.Scarvie |
---|
35 | FFTypeFlag = 'Global'; |
---|
36 | |
---|
37 | if nargin < 2 |
---|
38 | BPMFlag = []; |
---|
39 | end |
---|
40 | if isempty(BPMFlag) |
---|
41 | BPMFlag = 0; % menu1('Which BPM family to use for table generation?','96 arc sector BPMs only.','Straight section IDBPMs only.','Exit program.'); |
---|
42 | end |
---|
43 | |
---|
44 | |
---|
45 | |
---|
46 | IDFF.GapVelocity = 3.33; |
---|
47 | IDFF.GeV = getenergy; |
---|
48 | |
---|
49 | |
---|
50 | disp([' ']); disp(' '); |
---|
51 | disp([' INSERTION DEVICE FEED FORWARD TABLE GENERATION APPLICATION']); |
---|
52 | disp([' ']); |
---|
53 | disp([' This program will generate a feed forward table at ',num2str(IDFF.GeV), ' GeV.']); |
---|
54 | disp(' Before continuing, make sure the following conditions are true. '); |
---|
55 | disp(' 1. Multi-bunch mode.'); |
---|
56 | disp(' 2. FF disabled.'); |
---|
57 | disp(' 3. Gap Control disabled.'); |
---|
58 | disp(' 4. Current range: typically 35-45 mAmps, but any current should be OK.'); |
---|
59 | disp(' 5. Production corrector magnet set.'); |
---|
60 | disp(' 6. Bumps off and BTS 3 and 4 set to zero current.'); |
---|
61 | disp(' 7. Set the insertion device Velocity Profiling off (0) (just for speed).'); |
---|
62 | disp(' 8. Slow orbit feedback off.'); |
---|
63 | if BPMFlag |
---|
64 | disp(' 9. BPMs calibrated.'); |
---|
65 | end |
---|
66 | |
---|
67 | |
---|
68 | if nargin < 1 |
---|
69 | SectorIn = menu(str2mat(sprintf('%.1f GeV Feed Forward Generation',IDFF.GeV),'Feed forward must be off!',' ','Which insertion device?'),'4-vertical','4-longitudinal','5','7','8','9','10','11-vertical','11-longitudinal','12','Cancel'); |
---|
70 | if SectorIn == 1 |
---|
71 | % Sector 4 vertical using new feedforward method |
---|
72 | Sector = 4; |
---|
73 | ffgettblepugap(Sector); |
---|
74 | return |
---|
75 | elseif SectorIn == 2 |
---|
76 | % Sector 4 longitudinal using new feedforward method |
---|
77 | Sector = 4; |
---|
78 | ffgettblepushift(Sector); |
---|
79 | %ffgettblepu; % old method |
---|
80 | return |
---|
81 | elseif SectorIn == 3 |
---|
82 | Sector = 5; |
---|
83 | elseif SectorIn == 4 |
---|
84 | Sector = 7; |
---|
85 | elseif SectorIn == 5 |
---|
86 | Sector = 8; |
---|
87 | elseif SectorIn == 6 |
---|
88 | Sector = 9; |
---|
89 | elseif SectorIn == 7 |
---|
90 | Sector = 10; |
---|
91 | elseif SectorIn == 8 |
---|
92 | % Sector 11 vertical using new feedforward method |
---|
93 | Sector = 11; |
---|
94 | ffgettblepugap(Sector); |
---|
95 | return |
---|
96 | elseif SectorIn == 9 |
---|
97 | % Sector 11 longitudinal using new feedforward method |
---|
98 | Sector = 11; |
---|
99 | ffgettblepushift(Sector); |
---|
100 | return |
---|
101 | elseif SectorIn == 10 |
---|
102 | Sector = 12; |
---|
103 | elseif SectorIn == 11 |
---|
104 | disp(' ffgettbl aborted. No changes to correctors or insertion device.'); |
---|
105 | return |
---|
106 | end |
---|
107 | end |
---|
108 | disp(' '); |
---|
109 | if Sector == 0 |
---|
110 | disp(' ffgettbl aborted. No changes to correctors or insertion device.'); |
---|
111 | return; |
---|
112 | end |
---|
113 | |
---|
114 | |
---|
115 | |
---|
116 | %%%%%%%%%%%%% |
---|
117 | % BPM Setup % |
---|
118 | %%%%%%%%%%%%% |
---|
119 | IDFF.BPMxFamily = 'BPMx'; |
---|
120 | IDFF.BPMyFamily = 'BPMy'; |
---|
121 | |
---|
122 | if BPMFlag |
---|
123 | % Use all BPMs |
---|
124 | BPMTol = .005; |
---|
125 | BPMIter = 5; |
---|
126 | IDFF.BPMxList = getbpmlist('x'); |
---|
127 | IDFF.BPMyList = getbpmlist('y'); |
---|
128 | else |
---|
129 | % Only use Bergoz BPMs |
---|
130 | BPMTol = .0003; |
---|
131 | BPMIter = 5; |
---|
132 | IDFF.BPMxList = getbpmlist('x', 'Bergoz', '1 2 3 4 5 6 7 8 9 10'); % 11 12 ??? |
---|
133 | IDFF.BPMyList = getbpmlist('y', 'Bergoz', '1 2 3 4 5 6 7 8 9 10'); |
---|
134 | end |
---|
135 | |
---|
136 | % Remove the BPMs in the sector where the ID is located |
---|
137 | iRemove = findrowindex([Sector-1 10; Sector-1 11; Sector-1 12; Sector 1], IDFF.BPMxList); |
---|
138 | IDFF.BPMxList(iRemove,:) = []; |
---|
139 | |
---|
140 | iRemove = findrowindex([Sector-1 10; Sector-1 11; Sector-1 12; Sector 1], IDFF.BPMyList); |
---|
141 | IDFF.BPMyList(iRemove,:) = []; |
---|
142 | |
---|
143 | % % Remove the BPMs in sectors 1 and 3 which are noisy at low current). |
---|
144 | % iRemove = findrowindex([12 9; 1 2], BPMlist); |
---|
145 | % BPMlist(iRemove,:) = []; |
---|
146 | |
---|
147 | |
---|
148 | %%%%%%%%%%%%%%%%%%% |
---|
149 | % Corrector Setup % |
---|
150 | %%%%%%%%%%%%%%%%%%% |
---|
151 | IDFF.HCMFamily = 'HCM'; |
---|
152 | IDFF.VCMFamily = 'VCM'; |
---|
153 | |
---|
154 | |
---|
155 | % Corrector magnet and BPM lists |
---|
156 | if Sector == 6 & IDDeviceList(1,2) == 1 % ??? |
---|
157 | IDFF.HCMList = [Sector-1 8; |
---|
158 | Sector-1 10]; |
---|
159 | IDFF.VCMList = [Sector-1 8; |
---|
160 | Sector-1 10]; |
---|
161 | else |
---|
162 | IDFF.HCMList = [Sector-1 8; |
---|
163 | Sector 1]; |
---|
164 | IDFF.VCMList = [Sector-1 8; |
---|
165 | Sector 1]; |
---|
166 | end |
---|
167 | |
---|
168 | |
---|
169 | % Fast setpoints |
---|
170 | HCMRampRate0 = getpv(IDFF.HCMFamily, 'RampRate', IDFF.HCMList); |
---|
171 | VCMRampRate0 = getpv(IDFF.VCMFamily, 'RampRate', IDFF.VCMList); |
---|
172 | setpv(IDFF.HCMFamily, 'RampRate', 1000, IDFF.HCMList, 0); |
---|
173 | setpv(IDFF.VCMFamily, 'RampRate', 1000, IDFF.VCMList, 0); |
---|
174 | |
---|
175 | |
---|
176 | %%%%%%%%%%%%%%%%% |
---|
177 | % End ALS Setup % |
---|
178 | %%%%%%%%%%%%%%%%% |
---|
179 | |
---|
180 | |
---|
181 | |
---|
182 | % Multiple FF-tables |
---|
183 | if size(Sector,1) ~= 1 |
---|
184 | for iSector = 1:size(Sector,1) |
---|
185 | measidfftable(Sector(iSector,:), BPMFlag); |
---|
186 | end |
---|
187 | return; |
---|
188 | end |
---|
189 | |
---|
190 | |
---|
191 | % Minimum and maximum gap |
---|
192 | [IDFF.GAPmin, IDFF.GAPmax] = gaplimit(Sector); |
---|
193 | |
---|
194 | |
---|
195 | disp([' The insertion device for sector ',num2str(Sector),' has been selected.']); |
---|
196 | disp([' Maximum Gap = ',num2str(IDFF.GAPmax),' mm']); |
---|
197 | disp([' Mimimum Gap = ',num2str(IDFF.GAPmin),' mm']); |
---|
198 | |
---|
199 | |
---|
200 | disp([' Data collection started. Figures 1 and 2 show the difference orbits between the maximum']); |
---|
201 | disp([' gap and the current gap position after the feed forward correction has been applied.']); |
---|
202 | disp([' Ideally, these plots should be a straight line thru zero, however, due to orbit drift, BPM']); |
---|
203 | disp([' noise, and feed forward imperfections one can expect 10 or 20 microns of combined errors']); |
---|
204 | disp([' to accumulate before minimum gap is reached (hopefully not any more than that).']); |
---|
205 | disp([' ']); |
---|
206 | |
---|
207 | |
---|
208 | % Setup figures |
---|
209 | Buffer = .01; |
---|
210 | HeightBuffer = .05; |
---|
211 | |
---|
212 | h1 = gcf; |
---|
213 | set(h1,'units','normal','position',[.0+Buffer .5+Buffer .5-2*Buffer .5-2*Buffer-HeightBuffer]); |
---|
214 | |
---|
215 | |
---|
216 | % Set gap to maximum, set velocity to maximum, velocity profile off, FF off, |
---|
217 | setff([], 0, 0); |
---|
218 | setid(Sector, IDFF.GAPmax, IDFF.GapVelocity, 1, 0); |
---|
219 | |
---|
220 | |
---|
221 | % Load and set QF and QD setpoints from the golden lattice |
---|
222 | ConfigSetpoint = getproductionlattice; |
---|
223 | setpv(ConfigSetpoint.QF.Setpoint); |
---|
224 | setpv(ConfigSetpoint.QD.Setpoint); |
---|
225 | QFsp = ConfigSetpoint.QF.Setpoint.Data; |
---|
226 | QDsp = ConfigSetpoint.QD.Setpoint.Data; |
---|
227 | |
---|
228 | |
---|
229 | % Setbumps w/o sextupole correctors |
---|
230 | setbumps(Sector, 1); |
---|
231 | |
---|
232 | |
---|
233 | % Starting orbit and corrector magnet |
---|
234 | IDFF.Xmax = getam(IDFF.BPMxFamily, IDFF.BPMxList, 'Struct'); |
---|
235 | IDFF.Ymax = getam(IDFF.BPMyFamily, IDFF.BPMyList, 'Struct'); |
---|
236 | BPMxs = getspos(IDFF.Xmax); |
---|
237 | BPMys = getspos(IDFF.Ymax); |
---|
238 | |
---|
239 | IDFF.HCM = getsp(IDFF.HCMFamily, IDFF.HCMList, 'Struct'); |
---|
240 | IDFF.VCM = getsp(IDFF.VCMFamily, IDFF.VCMList, 'Struct'); |
---|
241 | HCM0 = IDFF.HCM.Data; |
---|
242 | VCM0 = IDFF.VCM.Data; |
---|
243 | QF0 = getsp('QF'); |
---|
244 | QD0 = getsp('QD'); |
---|
245 | |
---|
246 | |
---|
247 | % Main loop |
---|
248 | i=1; |
---|
249 | IDFF.GapMonitor(i,1) = getid(Sector); |
---|
250 | hcm(i,:) = (getsp(IDFF.HCMFamily, IDFF.HCMList)-HCM0)'; % First entry is zero |
---|
251 | vcm(i,:) = (getsp(IDFF.VCMFamily, IDFF.VCMList)-VCM0)'; |
---|
252 | |
---|
253 | X(:,i) = IDFF.Xmax.Data; |
---|
254 | Y(:,i) = IDFF.Ymax.Data; |
---|
255 | Xrms(i) = std(IDFF.Xmax.Data - X(:,i)); |
---|
256 | Yrms(i) = std(IDFF.Ymax.Data - Y(:,i)); |
---|
257 | IterOut(i) = 1; |
---|
258 | |
---|
259 | |
---|
260 | if IDFF.GAPmin < 14 |
---|
261 | Gaps = [(IDFF.GAPmax-10):-10:60 56:-4:36 34.5:-1.5:19.5 19:-.5:15 14.75:-.25:IDFF.GAPmin]; |
---|
262 | elseif IDFF.GAPmin < 17 |
---|
263 | Gaps = [(IDFF.GAPmax-10):-10:60 56:-4:36 34.5:-1.5:19.5 19:-.5:IDFF.GAPmin]; |
---|
264 | elseif IDFF.GAPmin < 34 |
---|
265 | Gaps = [(IDFF.GAPmax-10):-10:60 56:-4:36 34.5:-1.5:IDFF.GAPmin]; |
---|
266 | elseif IDFF.GAPmin < 55 |
---|
267 | Gaps = [(IDFF.GAPmax-10):-10:60 56:-4:IDFF.GAPmin]; |
---|
268 | else |
---|
269 | Gaps = [(IDFF.GAPmax-10):-10:IDFF.GAPmin]; |
---|
270 | end |
---|
271 | |
---|
272 | if Gaps(length(Gaps)) > IDFF.GAPmin |
---|
273 | Gaps = [Gaps IDFF.GAPmin]; |
---|
274 | end |
---|
275 | |
---|
276 | TUNEresp = gettuneresp; |
---|
277 | |
---|
278 | for i = 2:length(Gaps)+1 |
---|
279 | g = Gaps(i-1); |
---|
280 | |
---|
281 | % Set gap |
---|
282 | setid(Sector, g, IDFF.GapVelocity); |
---|
283 | |
---|
284 | % Set to old table first |
---|
285 | %setsp(IDFF.HCMFamily, HCM0+Xtableold(i,2:3)', IDFF.HCMList); % this does not seem to be a good idea |
---|
286 | %setsp(IDFF.VCMFamily, VCM0+Ytableold(i,2:3)', IDFF.VCMList); % need to linear fit the data if you do use this??? |
---|
287 | |
---|
288 | % Change Quads via Tune FF to simulate conditions during production |
---|
289 | % using tune feed forward code from orbit feedback |
---|
290 | |
---|
291 | % Change in tune and [QF;QD] from maximum gap |
---|
292 | if strcmpi(getfamilydata('OperationalMode'), '1.9 GeV, High Tune') |
---|
293 | if i==2 |
---|
294 | fprintf(' Generating feedforward table for %s mode\n', getfamilydata('OperationalMode')); |
---|
295 | end |
---|
296 | |
---|
297 | |
---|
298 | if strcmp(FFTypeFlag,'Local') |
---|
299 | disp(' Using local tune compensation.'); |
---|
300 | |
---|
301 | addQFsp = zeros(24,1); |
---|
302 | addQDsp = zeros(24,1); |
---|
303 | |
---|
304 | % Change in tune and [QF;QD] from maximum gap |
---|
305 | actualgap = getid(Sector); |
---|
306 | if actualgap < (IDFF.GAPmin-1) |
---|
307 | actualgap = IDFF.GAPmax; |
---|
308 | end |
---|
309 | DeltaNuY = gap2tune(Sector, actualgap); |
---|
310 | fraccorr = 1.15*DeltaNuY./gap2tune(5,13.23,1.9); |
---|
311 | |
---|
312 | % Find which quads to change |
---|
313 | QuadList = [Sector-1 1;Sector-1 2;Sector 1;Sector 2]; |
---|
314 | QuadElem = dev2elem('QF',QuadList); |
---|
315 | |
---|
316 | if (Sector==7) | (Sector==10) | (Sector==11) |
---|
317 | QFfac=(fraccorr.*([2.227520/2.237111;2.239570/2.237111;2.239570/2.237111;2.227520/2.237111]-1)); |
---|
318 | QDfac=(fraccorr.*([2.432264/2.511045;2.543089/2.511045;2.54308/2.511045;2.432264/2.511045]-1)); |
---|
319 | elseif (Sector==5) | (Sector==9) |
---|
320 | QFfac=(fraccorr.*([2.208418/2.219784;2.225926/2.219784;2.231777/2.237111;2.233775/2.237111]-1)); |
---|
321 | QDfac=(fraccorr.*([2.386512/2.483259;2.545907/2.483259;2.474571/2.511045;2.491079/2.511045]-1)); |
---|
322 | elseif (Sector==4) | (Sector==8) | (Sector==12) |
---|
323 | QFfac=(fraccorr.*([2.233775/2.237111;2.231777/2.237111;2.225926/2.219784;2.208418/2.219784]-1)); |
---|
324 | QDfac=(fraccorr.*([2.491079/2.511045;2.474571/2.511045;2.545907/2.483259;2.386512/2.483259]-1)); |
---|
325 | else |
---|
326 | QFfac=zeros(4,1); |
---|
327 | QDfac=zeros(4,1); |
---|
328 | end |
---|
329 | |
---|
330 | addQFsp(QuadElem) = addQFsp(QuadElem)+QFfac.*QFsp(QuadElem); |
---|
331 | addQDsp(QuadElem) = addQDsp(QuadElem)+QDfac.*QDsp(QuadElem); |
---|
332 | |
---|
333 | elseif strcmp(FFTypeFlag,'Global') |
---|
334 | |
---|
335 | addQFsp = zeros(24,1); |
---|
336 | addQDsp = zeros(24,1); |
---|
337 | |
---|
338 | % Change in tune and [QF;QD] from maximum gap |
---|
339 | actualgap = getid(Sector); |
---|
340 | if actualgap < (IDFF.GAPmin-1) |
---|
341 | actualgap = IDFF.GAPmax; |
---|
342 | end |
---|
343 | DeltaNuY = gap2tune(Sector, actualgap); |
---|
344 | DeltaNuX = 0; |
---|
345 | fraccorr = DeltaNuY./gap2tune(5,13.23,1.9); |
---|
346 | |
---|
347 | % Find which quads to change |
---|
348 | QuadList = [Sector-1 2;Sector 1]; |
---|
349 | QuadElem = dev2elem('QF',QuadList); |
---|
350 | |
---|
351 | DeltaAmps = inv(TUNEresp) * [(fraccorr*6.23e-4)-DeltaNuX;fraccorr*(-0.05301)]; % DelAmps = [QF; QD]; |
---|
352 | addQFsp = addQFsp+DeltaAmps(1,1); |
---|
353 | addQDsp = addQDsp+DeltaAmps(2,1); |
---|
354 | |
---|
355 | if (Sector==7) | (Sector==10) | (Sector==11) |
---|
356 | QFfac=(fraccorr.*([2.243127/2.237111;2.243127/2.237111]-1)); |
---|
357 | QDfac=(fraccorr.*([2.556392/2.511045;2.556392/2.511045]-1)); |
---|
358 | elseif (Sector==5) | (Sector==9) |
---|
359 | QFfac=(fraccorr.*([2.225965/2.219784;2.243096/2.237111]-1)); |
---|
360 | QDfac=(fraccorr.*([2.528950/2.483259;2.556345/2.511045]-1)); |
---|
361 | elseif (Sector==4) | (Sector==8) | (Sector==12) |
---|
362 | QFfac=(fraccorr.*([2.243096/2.237111;2.225965/2.219784]-1)); |
---|
363 | QDfac=(fraccorr.*([2.556345/2.511045;2.528950/2.483259]-1)); |
---|
364 | else |
---|
365 | QFfac=zeros(4,1); |
---|
366 | QDfac=zeros(4,1); |
---|
367 | end |
---|
368 | |
---|
369 | addQFsp(QuadElem) = addQFsp(QuadElem)+QFfac.*QFsp(QuadElem); |
---|
370 | addQDsp(QuadElem) = addQDsp(QuadElem)+QDfac.*QDsp(QuadElem); |
---|
371 | |
---|
372 | else |
---|
373 | error('Unknown type selected for tune FF'); |
---|
374 | end |
---|
375 | |
---|
376 | AmpsQF = QFsp+addQFsp; |
---|
377 | AmpsQD = QDsp+addQDsp; |
---|
378 | |
---|
379 | % Set quadrupoles |
---|
380 | setsp('QF', AmpsQF,[], 0); |
---|
381 | setsp('QD', AmpsQD,[], 0); |
---|
382 | |
---|
383 | |
---|
384 | else |
---|
385 | |
---|
386 | % Change in tune and [QF;QD] from maximum gap |
---|
387 | actualgap = getid(Sector); |
---|
388 | if actualgap < (IDFF.GAPmin-1) |
---|
389 | actualgap = IDFF.GAPmax; |
---|
390 | end |
---|
391 | DeltaNuY = gap2tune(Sector, actualgap); |
---|
392 | |
---|
393 | if (Sector==7) | (Sector==10) | (Sector==11) |
---|
394 | DeltaAmps = inv(TUNEresp/12) * [0; -DeltaNuY]; % DelAmps = [QF; QD]; |
---|
395 | DeltaAmpsQF=[DeltaAmps(1,1);DeltaAmps(1,1)]; |
---|
396 | DeltaAmpsQD=[DeltaAmps(2,1);DeltaAmps(2,1)]; |
---|
397 | elseif (Sector==5) | (Sector==9) |
---|
398 | DeltaAmpsQF=DeltaNuY/0.0181*0.37*[-1.0637;-0.5132]; |
---|
399 | DeltaAmpsQD=DeltaNuY/0.0181*0.37*[-6.6328;-3.3434]; |
---|
400 | elseif (Sector==4) | (Sector==8) | (Sector==12) |
---|
401 | DeltaAmpsQF=DeltaNuY/0.0181*0.37*[-0.5132;-1.0637]; |
---|
402 | DeltaAmpsQD=DeltaNuY/0.0181*0.37*[-3.3434;-6.6328]; |
---|
403 | else |
---|
404 | DeltaAmpsQF=[0;0]; |
---|
405 | DeltaAmpsQD=[0;0]; |
---|
406 | end |
---|
407 | |
---|
408 | % Find which quads to change |
---|
409 | QuadList = [Sector-1 1;Sector 2]; |
---|
410 | QuadElem = dev2elem('QF',QuadList); |
---|
411 | AmpsQF = QFsp(QuadElem) + DeltaAmpsQF; |
---|
412 | AmpsQD = QDsp(QuadElem) + DeltaAmpsQD; |
---|
413 | |
---|
414 | % Set quadrupoles |
---|
415 | setsp('QF', AmpsQF, QuadList, 0); |
---|
416 | setsp('QD', AmpsQD, QuadList, 0); |
---|
417 | |
---|
418 | end |
---|
419 | |
---|
420 | |
---|
421 | pause(1); |
---|
422 | |
---|
423 | |
---|
424 | % Correct orbit |
---|
425 | [STDfinal, IterOut(i,1)] = setbpm(IDFF.HCMFamily, IDFF.Xmax.Data, IDFF.HCMList, IDFF.BPMxList, ... |
---|
426 | IDFF.VCMFamily, IDFF.Ymax.Data, IDFF.VCMList, IDFF.BPMyList, BPMIter, BPMTol); |
---|
427 | |
---|
428 | % Record the gap AM |
---|
429 | IDFF.GapMonitor(i,1) = getid(Sector); |
---|
430 | |
---|
431 | |
---|
432 | % Record data |
---|
433 | hcm(i,:) = (getsp(IDFF.HCMFamily, IDFF.HCMList)-HCM0)'; |
---|
434 | vcm(i,:) = (getsp(IDFF.VCMFamily, IDFF.VCMList)-VCM0)'; |
---|
435 | X(:,i) = getam(IDFF.BPMxFamily, IDFF.BPMxList); |
---|
436 | Y(:,i) = getam(IDFF.BPMyFamily, IDFF.BPMyList); |
---|
437 | |
---|
438 | |
---|
439 | % Statistics |
---|
440 | Xrms(i) = std(IDFF.Xmax.Data - X(:,i)); |
---|
441 | Yrms(i) = std(IDFF.Ymax.Data - Y(:,i)); |
---|
442 | |
---|
443 | |
---|
444 | % plot results |
---|
445 | figure(h1); |
---|
446 | plot(BPMxs,(X(:,i)-IDFF.Xmax.Data)*1000,'r', BPMys,(Y(:,i)-IDFF.Ymax.Data)*1000,'g'); |
---|
447 | title(['BPM Orbit Error at a ', num2str(IDFF.GapMonitor(i,1)),' mm Gap']); |
---|
448 | ylabel('X (red), Y (grn) Error [microns]'); |
---|
449 | xlabel('BPM Position [meters]'); |
---|
450 | pause(0); |
---|
451 | end |
---|
452 | |
---|
453 | |
---|
454 | % Minimum gap orbits |
---|
455 | IDFF.Xmin = getam(IDFF.BPMxFamily, IDFF.BPMxList, 'Struct'); |
---|
456 | IDFF.Ymin = getam(IDFF.BPMyFamily, IDFF.BPMyList, 'Struct'); |
---|
457 | |
---|
458 | |
---|
459 | % Make the FF-tables |
---|
460 | Xtable = [IDFF.GapMonitor hcm(:,1)-hcm(1,1) hcm(:,2)-hcm(1,2)]; |
---|
461 | Ytable = [IDFF.GapMonitor vcm(:,1)-vcm(1,1) vcm(:,2)-vcm(1,2)]; |
---|
462 | tableQ = []; |
---|
463 | |
---|
464 | |
---|
465 | % Go to max gap |
---|
466 | disp(' The insertion device gap, quads, and correctors are being reset.'); |
---|
467 | setid(Sector, IDFF.GAPmax, IDFF.GapVelocity); |
---|
468 | |
---|
469 | % Reset to maximum gap values |
---|
470 | setsp(IDFF.HCMFamily, HCM0, IDFF.HCMList, 0); |
---|
471 | setsp(IDFF.VCMFamily, VCM0, IDFF.VCMList, 0); |
---|
472 | setpv(ConfigSetpoint.QF.Setpoint, 0); |
---|
473 | setpv(ConfigSetpoint.QD.Setpoint, 0); |
---|
474 | |
---|
475 | % Then wait on setpoints |
---|
476 | setsp(IDFF.HCMFamily, HCM0, IDFF.HCMList, -1); |
---|
477 | setsp(IDFF.VCMFamily, VCM0, IDFF.VCMList, -1); |
---|
478 | setpv(ConfigSetpoint.QF.Setpoint, -1); |
---|
479 | setpv(ConfigSetpoint.QD.Setpoint, -1); |
---|
480 | |
---|
481 | |
---|
482 | % Ending orbits |
---|
483 | IDFF.XmaxEnd = getam(IDFF.BPMxFamily, IDFF.BPMxList, 'Struct'); |
---|
484 | IDFF.YmaxEnd = getam(IDFF.BPMyFamily, IDFF.BPMyList, 'Struct'); |
---|
485 | |
---|
486 | |
---|
487 | % Structure output |
---|
488 | IDFF.Sector = Sector; |
---|
489 | IDFF.Gaps = Gaps; |
---|
490 | IDFF.Xtable = Xtable; |
---|
491 | IDFF.Ytable = Ytable; |
---|
492 | IDFF.tableQ = tableQ; |
---|
493 | IDFF.BPMFlag = BPMFlag; |
---|
494 | IDFF.Xrms = Xrms; |
---|
495 | IDFF.Yrms = Yrms; |
---|
496 | IDFF.IterOut = IterOut; |
---|
497 | IDFF.TimeStamp = clock; |
---|
498 | IDFF.GeV = getenergy; |
---|
499 | IDFF.DataDescriptor = 'ID Feed Forward Table'; |
---|
500 | IDFF.CreatedBy = 'measidfftable'; |
---|
501 | |
---|
502 | |
---|
503 | |
---|
504 | % Change to DataRoot/ID/FeedForward directory |
---|
505 | DirStart = pwd; |
---|
506 | DataRoot = getfamilydata('Directory','DataRoot'); |
---|
507 | DirectoryName = [DataRoot, 'ID', filesep, 'FeedForward', filesep]; |
---|
508 | [DirectoryName, ErrorFlag] = gotodirectory(DirectoryName); |
---|
509 | FileName = sprintf('id%02de%2.0f', Sector, 10*getenergy); |
---|
510 | FileName = appendtimestamp(FileName); |
---|
511 | save(FileName, 'IDFF'); |
---|
512 | fprintf(' Insertion device feed forward table saved to %s.mat\n', [DirectoryName FileName]); |
---|
513 | if ErrorFlag |
---|
514 | fprintf(' Warning: %s was not the desired directory\n', DirectoryName); |
---|
515 | end |
---|
516 | FileName = [DirectoryName FileName]; |
---|
517 | cd(DirStart); |
---|
518 | |
---|
519 | |
---|
520 | % Close figures |
---|
521 | close(h1); |
---|
522 | FigureHandles = plotidfftable(FileName); |
---|
523 | |
---|
524 | fprintf(' Measurement complete. The gap position and correctors have been set back to their original setpoints.'); |
---|
525 | fprintf(' A new table has been generated and saved to directory %s\n', FileName); |
---|
526 | fprintf(' Figure ', num2str(FigureHandles(1)),' -> Corrector strength verses gap position.'); |
---|
527 | fprintf(' Figure ', num2str(FigureHandles(2)),' -> RMS orbit distortion verses gap position.'); |
---|
528 | fprintf(' -> Orbit drift during table generation verses BPM position.'); |
---|
529 | fprintf(' Figure ', num2str(FigureHandles(3)),' -> Rate of Change of the Corrector Magnets.'); |
---|
530 | fprintf(' Insertion device feedforward table generation complete.\n'); |
---|
531 | |
---|
532 | |
---|
533 | % ALS resets |
---|
534 | |
---|
535 | CPTableFlag = questdlg(sprintf('Copy %.1f GeV Table to the IOC?',IDFF.GeV),'Feed Forward Table Complete','Yes','No','No'); |
---|
536 | if strcmp(CPTableFlag,'No') |
---|
537 | fprintf(' Use ffcopy(%d,%.1f) to copy the table over to the feed forward program.\n', Sector, IDFF.GeV); |
---|
538 | fprintf(' Use ffread(%d) (or the "Undulator Server" application) to force the IOC to read the new table.\n', Sector); |
---|
539 | else |
---|
540 | ffcopy(textfn1); |
---|
541 | fprintf(' For the IOC to read the new table use the "Undulator Server"\n'); |
---|
542 | fprintf(' application or run ffread(%d) from Matlab.\n', Sector); |
---|
543 | end |
---|
544 | |
---|
545 | % Switch correctors to slow mode |
---|
546 | setpv(IDFF.HCMFamily, 'RampRate', HCMRampRate0, IDFF.HCMList, 0); |
---|
547 | setpv(IDFF.VCMFamily, 'RampRate', VCMRampRate0, IDFF.VCMList, 0); |
---|