1 | function S = hw2physics(Family, Field, value, DeviceList, Energy) |
---|
2 | %HW2PHYSICS - Converts from 'Hardware' units to 'Physics' units |
---|
3 | % ValPhysics = hw2physics(Family, Field, ValHW, DeviceList, Energy) |
---|
4 | % |
---|
5 | % For data structure inputs: |
---|
6 | % ValPhysics = hw2physics(DataStructure, Energy) |
---|
7 | % |
---|
8 | % HW2PHYSICS converts the values in 'Hardware' units read from PV's |
---|
9 | % to 'Physics' units using the conversion function and conversion paramaters |
---|
10 | % stored in the AO fields HW2PhysicsFcn and HW2PhysicsParams |
---|
11 | % |
---|
12 | % Energy can be anything getenergy accepts, like 'Model' or 'Online' {Default: 'Production'} |
---|
13 | % |
---|
14 | % INPUTS |
---|
15 | % 1. Family - Familyname |
---|
16 | % 2. Field - Typically 'Monitor' or 'Setpoint' |
---|
17 | % 3. value - Data for conversion |
---|
18 | % 4. DeviceList - List of devices |
---|
19 | % 5. Energy - Extra parameter for energy. Default is 'Production' |
---|
20 | % |
---|
21 | % OUTPUTS |
---|
22 | % 1. S - Result of conversion from hardwareto physics units |
---|
23 | % |
---|
24 | % NOTES |
---|
25 | % 1. Field is typically 'Monitor' or 'Setpoint' |
---|
26 | % 2. For structure inputs, if the data is already in physics units |
---|
27 | % then no conversion will be done! |
---|
28 | % 3. Energy may not be dealt with directly in this function, it |
---|
29 | % depends on how HW2PhysicsFcn deals with energy change. |
---|
30 | % 4. The gain/offset conversions are done in raw2real & real2raw. |
---|
31 | % |
---|
32 | % See also hw2physic, raw2real, real2raw |
---|
33 | % |
---|
34 | % Written by A. Terebilo and G. Portmann |
---|
35 | |
---|
36 | S = []; |
---|
37 | |
---|
38 | if nargin < 1 |
---|
39 | error('1 (data structure), 3, or 4 inputs required'); |
---|
40 | end |
---|
41 | |
---|
42 | if ischar(Family) |
---|
43 | if nargin < 3 |
---|
44 | error('3-4 inputs required'); |
---|
45 | end |
---|
46 | if nargin < 4 |
---|
47 | DeviceList = []; |
---|
48 | end |
---|
49 | if isempty(DeviceList) |
---|
50 | DeviceList = family2dev(Family); |
---|
51 | end |
---|
52 | if nargin < 5 |
---|
53 | Energy = 'Production'; |
---|
54 | end |
---|
55 | |
---|
56 | if size(DeviceList,1) ~= size(value,1) |
---|
57 | if size(value,1) == 1 |
---|
58 | value = ones(size(DeviceList,1),1) * value; |
---|
59 | else |
---|
60 | error('The length of ValHW must match the number of devices'); |
---|
61 | end |
---|
62 | end |
---|
63 | |
---|
64 | FunctionStr = getfamilydata(Family, Field, 'HW2PhysicsFcn'); |
---|
65 | Params = getfamilydata(Family, Field, 'HW2PhysicsParams', DeviceList); |
---|
66 | |
---|
67 | |
---|
68 | % First convert to "corrected" hardware units (usually based on LOCO gains) |
---|
69 | value = raw2real(Family, Field, value, DeviceList); |
---|
70 | |
---|
71 | if isempty(FunctionStr) |
---|
72 | if isempty(Params) |
---|
73 | % No info on how to convert, so use a gain of 1 |
---|
74 | S = value; |
---|
75 | else |
---|
76 | % If no function, use a constant scaling |
---|
77 | for i = 1:size(value,2) |
---|
78 | S(:,i) = value(:,i) .* Params(:,1); |
---|
79 | end |
---|
80 | end |
---|
81 | |
---|
82 | % Energy scaling this way works for magnets but not BPMs, RF, or maybe other stuff! |
---|
83 | % So if you want energy scaling do it with a function like amp2k |
---|
84 | % if ~ismemberof(Family,'BPM') |
---|
85 | % if isempty(Energy) |
---|
86 | % Energy = getenergy; |
---|
87 | % elseif ischar(Energy) |
---|
88 | % Energy = getenergy(Energy); |
---|
89 | % end |
---|
90 | % S(:,i) = S(:,i) * getbrho(getenergy('Production')) / getbrho(Energy); |
---|
91 | % end |
---|
92 | if ~ischar(Energy) |
---|
93 | % Expand to the length of Energy input |
---|
94 | if size(S,1) == 1 |
---|
95 | S = S * ones(1,size(Energy,2)); |
---|
96 | end |
---|
97 | end |
---|
98 | |
---|
99 | else |
---|
100 | % Use inline or user specified function |
---|
101 | if isempty(Energy) |
---|
102 | Energy = getenergy; |
---|
103 | elseif ischar(Energy) |
---|
104 | Energy = getenergy(Energy); |
---|
105 | end |
---|
106 | if iscell(Params) |
---|
107 | S = feval(FunctionStr, Family, Field, value, DeviceList, Energy, Params{:}); |
---|
108 | elseif isempty(Params) |
---|
109 | S = feval(FunctionStr, Family, Field, value, DeviceList, Energy); |
---|
110 | elseif isstr(Params) |
---|
111 | S = feval(FunctionStr, Family, Field, value, DeviceList, Energy, Params); |
---|
112 | else |
---|
113 | % This will make all elements in the row vector a separate input |
---|
114 | ParamsList = num2cell(Params,1); |
---|
115 | S = feval(FunctionStr, Family, Field, value, DeviceList, Energy, ParamsList{:}); |
---|
116 | end |
---|
117 | end |
---|
118 | |
---|
119 | elseif isstruct(Family) |
---|
120 | % Convert entire data structure e.g. response matrix |
---|
121 | S = Family; |
---|
122 | |
---|
123 | for j = 1:size(S,1) |
---|
124 | for k = 1:size(S,2) |
---|
125 | |
---|
126 | if isfield(S(j,k),'Monitor') & isfield(S(j,k),'Actuator') |
---|
127 | % Response matrix structure |
---|
128 | |
---|
129 | if nargin < 2 |
---|
130 | %Energy = 'Production'; |
---|
131 | Energy = S(j,k).GeV; |
---|
132 | else |
---|
133 | Energy = Field; |
---|
134 | end |
---|
135 | |
---|
136 | % Note: Chromaticity and Dispersion are special cases |
---|
137 | if strcmpi(S(j,k).Monitor.FamilyName, 'Chromaticity') |
---|
138 | % Chromaticity response matrix |
---|
139 | if ~strcmpi(S(j,k).Units, 'Physics') |
---|
140 | RF = S(j,k).Monitor.Actuator.Data; |
---|
141 | MCF = S(j,k).Monitor.MCF; |
---|
142 | S(j,k).Data = - S(j,k).Data * RF(1) * MCF; |
---|
143 | S(j,k).Monitor = hw2physics(S(j,k).Monitor); % Chromaticity structure (also a response structure) |
---|
144 | |
---|
145 | ActuatorDeltaHardware = S(j,k).ActuatorDelta; |
---|
146 | S(j,k).ActuatorDelta = hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).ActuatorDelta + S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV) - ... |
---|
147 | hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV); |
---|
148 | ActuatorScaleFactor = S(j,k).ActuatorDelta ./ ActuatorDeltaHardware; |
---|
149 | ActuatorScaleFactor = ActuatorScaleFactor(:)'; |
---|
150 | S(j,k).Actuator = hw2physics(S(j,k).Actuator, S(j,k).GeV); % Sextupole |
---|
151 | |
---|
152 | % Scalar row by the actuator scaling |
---|
153 | for i = 1:size(S(j,k).Data,1) |
---|
154 | S(j,k).Data(i,:) = S(j,k).Data(i,:) ./ ActuatorScaleFactor; |
---|
155 | end |
---|
156 | |
---|
157 | % Change units and UnitsString fields |
---|
158 | if isfield(S(j,k),'Units') |
---|
159 | S(j,k).Units = 'Physics'; |
---|
160 | end |
---|
161 | if isfield(S(j,k),'UnitsString') |
---|
162 | if isfield(S(j,k).Monitor,'UnitsString') & isfield(S(j,k).Actuator,'UnitsString') |
---|
163 | %S(j,k).UnitsString = '(Fractional Tune/(dp/p))/meter^-3'; |
---|
164 | S(j,k).UnitsString = [S(j,k).Monitor.UnitsString , '/', S(j,k).Actuator.UnitsString]; |
---|
165 | else |
---|
166 | S(j,k).UnitsString = ''; |
---|
167 | end |
---|
168 | end |
---|
169 | end |
---|
170 | elseif strcmpi(S(j,k).Monitor.FamilyName, 'TUNE') & strcmpi(S(j,k).Actuator.FamilyName, 'RF') |
---|
171 | % Chromaticity measurement |
---|
172 | if ~strcmpi(S(j,k).Units, 'Physics') |
---|
173 | RF = S(j,k).Actuator.Data; |
---|
174 | MCF = S(j,k).MCF; |
---|
175 | S(j,k).Data = - S(j,k).Data * RF(1) * MCF; |
---|
176 | |
---|
177 | if isfield(S(j,k),'Tune') & isfield(S(j,k),'PolyFit') |
---|
178 | p = polyfit(S(j,k).dp, S(j,k).Tune(1,:), 2); |
---|
179 | S(j,k).PolyFit(1,:) = p; |
---|
180 | % S(j,k).Data(1,1) = p(2); |
---|
181 | p = polyfit(S(j,k).dp, S(j,k).Tune(2,:), 2); |
---|
182 | S(j,k).PolyFit(2,:) = p; |
---|
183 | % S(j,k).Data(2,1) = p(2); |
---|
184 | end |
---|
185 | |
---|
186 | % Convert the Monitor and Actuator fields |
---|
187 | %S(j,k).Monitor = hw2physics(S(j,k).Monitor); % Tune structure (same in Hardware and Physics) |
---|
188 | S(j,k).ActuatorDelta = hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).ActuatorDelta + S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV) - ... |
---|
189 | hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV); |
---|
190 | S(j,k).Actuator = hw2physics(S(j,k).Actuator, S(j,k).GeV); % RF |
---|
191 | |
---|
192 | S(j,k).Units = 'Physics'; |
---|
193 | %S(j,k).UnitsString = '1/(dp/p)'; |
---|
194 | S(j,k).UnitsString = [S(j,k).Monitor.UnitsString,'/(dp/p)']; |
---|
195 | end |
---|
196 | elseif ismemberof(S(j,k).Monitor.FamilyName, 'BPM') & strcmpi(S(j,k).Actuator.FamilyName, 'RF') |
---|
197 | % Dispersion measurement |
---|
198 | if ~strcmpi(S(j,k).Units, 'Physics') |
---|
199 | % Change to physics units |
---|
200 | |
---|
201 | % Change the numerator as if it was a BPM (but remove the offset) |
---|
202 | d = S(j,k).Monitor; |
---|
203 | d.Data = S(j,k).Data + getoffset(S(j,k).Monitor.FamilyName, 'Monitor', S(j,k).Monitor.DeviceList, 'Hardware'); |
---|
204 | d = hw2physics(d, S(j,k).GeV); |
---|
205 | S(j,k).Data = d.Data; |
---|
206 | |
---|
207 | % Change to denominator to energy shift (dp/p) |
---|
208 | RF = S(j,k).Actuator.Data; |
---|
209 | MCF = S(j,k).MCF; |
---|
210 | S(j,k).Data = -RF(1) * MCF * S(j,k).Data; |
---|
211 | |
---|
212 | % Change the Monitor and Actuator fields |
---|
213 | S(j,k).Monitor = hw2physics(S(j,k).Monitor, S(j,k).GeV); |
---|
214 | S(j,k).ActuatorDelta = hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).ActuatorDelta + S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV) - ... |
---|
215 | hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV); |
---|
216 | S(j,k).Actuator = hw2physics(S(j,k).Actuator, S(j,k).GeV); |
---|
217 | |
---|
218 | S(j,k).Units = 'Physics'; |
---|
219 | S(j,k).UnitsString = [S(j,k).Monitor.UnitsString,'/(dp/p)']; |
---|
220 | end |
---|
221 | |
---|
222 | else |
---|
223 | % Typical response matrix (usually orbit/corrector) |
---|
224 | % Need to determine the hw2physics scaling for delta monitor / delta actuator |
---|
225 | |
---|
226 | % Only change units if in 'Hardware' units |
---|
227 | if strcmpi(S(j,k).Actuator.Units, 'Hardware') |
---|
228 | % Convert .ActuatorDelta |
---|
229 | ActuatorDeltaHW = S(j,k).ActuatorDelta; |
---|
230 | |
---|
231 | % Scale Factor without energy scaling (since physics units are the same at all energies) |
---|
232 | S(j,k).ActuatorDelta = hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).ActuatorDelta + S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV) - ... |
---|
233 | hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, S(j,k).Actuator.Data, S(j,k).Actuator.DeviceList, S(j,k).GeV); |
---|
234 | |
---|
235 | % Physics units / HW units |
---|
236 | ActuatorScaleFactor = S(j,k).ActuatorDelta ./ ActuatorDeltaHW; |
---|
237 | ActuatorScaleFactor = ActuatorScaleFactor(:)'; |
---|
238 | |
---|
239 | % Convert .Actuator field |
---|
240 | S(j,k).Actuator = hw2physics(S(j,k).Actuator, S(j,k).GeV); |
---|
241 | |
---|
242 | %ActuatorData = S(j,k).Actuator.Data; |
---|
243 | %S(j,k).Actuator = physics2hw(S(j,k).Actuator); |
---|
244 | %if any(ActuatorData == 0) |
---|
245 | % ActuatorScaleFactor = hw2physics(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, 1, S(j,k).Actuator.DeviceList, S(j,k).GeV); |
---|
246 | %else |
---|
247 | % ActuatorScaleFactor = S(j,k).Actuator.Data ./ ActuatorData; |
---|
248 | %end |
---|
249 | else |
---|
250 | % Don't include energy scaling of actuator if already in physics units |
---|
251 | ActuatorScaleFactor = 1; %Energy/S(j,k).GeV; |
---|
252 | ActuatorDeltaHW = S(j,k).ActuatorDelta; |
---|
253 | end |
---|
254 | |
---|
255 | |
---|
256 | % Only change units if in 'Hardware' units |
---|
257 | if strcmpi(S(j,k).Monitor.Units, 'Hardware') |
---|
258 | % Just to get an approximate scaling for the monitor size |
---|
259 | %MonitorDeltaHW = max(abs(S(j,k).Data(:,1) * ActuatorDeltaHW(1))); |
---|
260 | %MonitorDelta = hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, MonitorDeltaHW + S(j,k).Monitor.Data, S(j,k).Monitor.DeviceList, S(j,k).GeV) - ... |
---|
261 | % hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, S(j,k).Monitor.Data, S(j,k).Monitor.DeviceList, S(j,k).GeV); |
---|
262 | %%MonitorDelta = hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, MonitorDeltaHW, S(j,k).Monitor.DeviceList, Energy) - getoffset(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 'Hardware'); |
---|
263 | % |
---|
264 | %MonitorScaleFactor = MonitorDelta ./ MonitorDeltaHW; |
---|
265 | %MonitorScaleFactor = MonitorScaleFactor(:); |
---|
266 | |
---|
267 | % hw2physics must be linear for this to work, but the other methods have issues with small numbers |
---|
268 | %MonitorScaleFactor = hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 1+getoffset(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field), S(j,k).Monitor.DeviceList, S(j,k).GeV, 'Hardware'); |
---|
269 | MonitorScaleFactor = hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 1, S(j,k).Monitor.DeviceList, S(j,k).GeV) - ... |
---|
270 | hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 0, S(j,k).Monitor.DeviceList, S(j,k).GeV); |
---|
271 | |
---|
272 | % Convert .Monitor field |
---|
273 | S(j,k).Monitor = hw2physics(S(j,k).Monitor, S(j,k).GeV); |
---|
274 | |
---|
275 | %MonitorData = S(j,k).Monitor.Data; |
---|
276 | %S(j,k).Monitor = physics2hw(S(j,k).Monitor); |
---|
277 | %if any(MonitorData == 0) |
---|
278 | % % This might introduce an error if physics2hw is nonlinear |
---|
279 | % MonitorScaleFactor = hw2physics(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 1, S(j,k).Monitor.DeviceList, S(j,k).GeV); |
---|
280 | %else |
---|
281 | % MonitorScaleFactor = S(j,k).Monitor.Data ./ MonitorData; |
---|
282 | %end |
---|
283 | else |
---|
284 | MonitorScaleFactor = 1; |
---|
285 | end |
---|
286 | |
---|
287 | |
---|
288 | % Scalar column by the monitor scaling |
---|
289 | for i = 1:size(S(j,k).Data,2) |
---|
290 | S(j,k).Data(:,i) = MonitorScaleFactor .* S(j,k).Data(:,i); |
---|
291 | end |
---|
292 | %S(j,k).MonitorScaleFactor = MonitorScaleFactor; |
---|
293 | |
---|
294 | % Scalar row by the actuator scaling |
---|
295 | for i = 1:size(S(j,k).Data,1) |
---|
296 | S(j,k).Data(i,:) = S(j,k).Data(i,:) ./ ActuatorScaleFactor; |
---|
297 | end |
---|
298 | %S(j,k).ActuatorScaleFactor = ActuatorScaleFactor; |
---|
299 | |
---|
300 | S(j,k).GeV = Energy; |
---|
301 | |
---|
302 | % Change units and unitsstring fields |
---|
303 | if isfield(S(j,k),'Units') |
---|
304 | S(j,k).Units = 'Physics'; |
---|
305 | end |
---|
306 | if isfield(S(j,k),'UnitsString') |
---|
307 | if isfield(S(j,k).Monitor,'UnitsString') && isfield(S(j,k).Actuator,'UnitsString') |
---|
308 | S(j,k).UnitsString = [ ... |
---|
309 | S(j,k).Monitor.UnitsString , '/', ... |
---|
310 | S(j,k).Actuator.UnitsString]; |
---|
311 | %S(j,k).UnitsString = [ ... |
---|
312 | % getfamilydata(S(j,k).Monitor.FamilyName, S(j,k).Monitor.Field, 'PhysicsUnits') , '/', ... |
---|
313 | % getfamilydata(S(j,k).Actuator.FamilyName, S(j,k).Actuator.Field, 'PhysicsUnits')]; |
---|
314 | else |
---|
315 | S(j,k).UnitsString = ''; |
---|
316 | end |
---|
317 | end |
---|
318 | end |
---|
319 | |
---|
320 | elseif isfield(S(j,k),'FamilyName') & isfield(S(j,k),'Field') |
---|
321 | % Data structure |
---|
322 | |
---|
323 | if nargin < 2 |
---|
324 | if isfield(S(j,k), 'GeV') |
---|
325 | Energy = S(j,k).GeV; |
---|
326 | else |
---|
327 | Energy = 'NoEnergyScaling'; |
---|
328 | %Energy = 'Production'; |
---|
329 | end |
---|
330 | else |
---|
331 | Energy = Field; |
---|
332 | end |
---|
333 | |
---|
334 | % Only change units if in 'Hardware' units |
---|
335 | if ~strcmpi(S(j,k).Units, 'Physics') |
---|
336 | % First convert to "corrected" hardware units |
---|
337 | S(j,k) = raw2real(S(j,k)); % Done in hw2physics for FamilyName inputs |
---|
338 | |
---|
339 | S(j,k).Data = hw2physics(S(j,k).FamilyName, S(j,k).Field, S(j,k).Data, S(j,k).DeviceList, Energy); |
---|
340 | S(j,k).Units = 'Physics'; |
---|
341 | S(j,k).UnitsString = getfamilydata(S(j,k).FamilyName, S(j,k).Field, 'PhysicsUnits'); |
---|
342 | end |
---|
343 | |
---|
344 | else |
---|
345 | error('Unknown data structure type'); |
---|
346 | end |
---|
347 | end |
---|
348 | end |
---|
349 | |
---|
350 | elseif iscell(Family) |
---|
351 | error('Cell array inputs not programmed yet'); |
---|
352 | |
---|
353 | else |
---|
354 | error('Input #1 type unknown'); |
---|
355 | end |
---|
356 | |
---|
357 | |
---|