14 #include "ui_magnetpsform.h"
15 #include "ui_magnetpsconfigform.h"
17 #include "interface.h"
19 #include "xnodeconnector.h"
22 XMagnetPS::XMagnetPS(
const char *name,
bool runtime,
23 Transaction &tr_meas,
const shared_ptr<XMeasure> &meas) :
26 dynamic_pointer_cast<
XDriver>(shared_from_this()),
"%.8g")),
28 dynamic_pointer_cast<
XDriver>(shared_from_this()),
"%.8g")),
29 m_entries(meas->scalarEntries()),
30 m_targetField(create<
XDoubleNode>(
"TargetField", true)),
31 m_sweepRate(create<
XDoubleNode>(
"SweepRate", true)),
32 m_allowPersistent(create<
XBoolNode>(
"AllowPersistent", true)),
33 m_approach(create<
XComboNode>(
"Approach", false, true)),
34 m_stabilized(create<
XDoubleNode>(
"Stabilized", true)),
35 m_magnetField(create<
XDoubleNode>(
"MagnetField", true)),
36 m_outputField(create<
XDoubleNode>(
"OutpuField", true)),
37 m_outputCurrent(create<
XDoubleNode>(
"OutputCurrent", true)),
38 m_outputVolt(create<
XDoubleNode>(
"OutputVolt", true)),
39 m_pcsHeater(create<
XBoolNode>(
"PCSHeater", true)),
40 m_persistent(create<
XBoolNode>(
"Persistent", true)),
41 m_aborting(create<
XBoolNode>(
"Aborting", true)),
43 m_rateLimit1(create<
XDoubleNode>(
"RateLimit1", false)),
44 m_rateLimit1UBound(create<
XDoubleNode>(
"RateLimit1UBound", false)),
45 m_rateLimit2(create<
XDoubleNode>(
"RateLimit2", false)),
46 m_rateLimit2UBound(create<
XDoubleNode>(
"RateLimit2UBound", false)),
47 m_rateLimit3(create<
XDoubleNode>(
"RateLimit3", false)),
48 m_rateLimit3UBound(create<
XDoubleNode>(
"RateLimit3UBound", false)),
49 m_rateLimit4(create<
XDoubleNode>(
"RateLimit4", false)),
50 m_rateLimit4UBound(create<
XDoubleNode>(
"RateLimit4UBound", false)),
51 m_rateLimit5(create<
XDoubleNode>(
"RateLimit5", false)),
52 m_rateLimit5UBound(create<
XDoubleNode>(
"RateLimit5UBound", false)),
53 m_secondaryPSMultiplier(create<
XDoubleNode>(
"SecondaryPSMultiplier", false)),
56 m_safeCond1Min(create<
XDoubleNode>(
"SafeCond1Min", false)),
57 m_safeCond1Max(create<
XDoubleNode>(
"SafeCond1Max", false)),
59 m_safeCond2Min(create<
XDoubleNode>(
"SafeCond2Min", false)),
60 m_safeCond2Max(create<
XDoubleNode>(
"SafeCond2Max", false)),
62 m_safeCond3Min(create<
XDoubleNode>(
"SafeCond3Min", false)),
63 m_safeCond3Max(create<
XDoubleNode>(
"SafeCond3Max", false)),
65 m_persistentCondMax(create<
XDoubleNode>(
"PersistentCondMax", false)),
67 m_nonPersistentCondMin(create<
XDoubleNode>(
"NonPersistentCondMin", false)),
72 meas->scalarEntries()->
insert(tr_meas, m_field);
73 meas->scalarEntries()->insert(tr_meas, m_current);
74 m_form->statusBar()->hide();
75 m_form->setWindowTitle(
XString(
"Magnet Power Supply - " +
getLabel() ));
76 m_formConfig->statusBar()->hide();
77 m_formConfig->setWindowTitle(
XString(
"Magnet PS Detail Configuration - " +
getLabel() ));
79 m_conConfigShow = xqcon_create<XQButtonConnector>(
80 m_configShow, m_form->m_btnConfig);
82 m_form->m_btnConfig->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogOpenButton));
84 m_conAllowPersistent = xqcon_create<XQToggleButtonConnector>(
85 allowPersistent(), m_form->m_ckbAllowPersistent);
86 m_conTargetField = xqcon_create<XQLineEditConnector>(
87 targetField(), m_form->m_edTargetField);
88 m_conSweepRate = xqcon_create<XQLineEditConnector>(
89 sweepRate(), m_form->m_edSweepRate);
90 m_conMagnetField = xqcon_create<XQLCDNumberConnector>(
91 magnetField(), m_form->m_lcdMagnetField);
92 m_conOutputField = xqcon_create<XQLCDNumberConnector>(
93 outputField(), m_form->m_lcdOutputField);
94 m_conOutputCurrent= xqcon_create<XQLCDNumberConnector>(
95 outputCurrent(), m_form->m_lcdCurrent);
96 m_conOutputVolt = xqcon_create<XQLCDNumberConnector>(
97 outputVolt(), m_form->m_lcdVoltage);
98 m_conPCSH = xqcon_create<XQLedConnector>(
99 pcsHeater(), m_form->m_ledSwitchHeater);
100 m_conPersist = xqcon_create<XQLedConnector>(
101 persistent(), m_form->m_ledPersistent);
102 m_conAborting = xqcon_create<XQLedConnector>(
103 m_aborting, m_form->m_ledAborting);
104 m_conApproach = xqcon_create<XQComboBoxConnector>(
105 m_approach, m_form->m_cmbApproach,
Snapshot( *m_approach));
106 m_conRateLimit1 = xqcon_create<XQLineEditConnector>(
107 m_rateLimit1, m_formConfig->m_edRateLimit1);
108 m_conRateLimit2 = xqcon_create<XQLineEditConnector>(
109 m_rateLimit2, m_formConfig->m_edRateLimit2);
110 m_conRateLimit3 = xqcon_create<XQLineEditConnector>(
111 m_rateLimit3, m_formConfig->m_edRateLimit3);
112 m_conRateLimit4 = xqcon_create<XQLineEditConnector>(
113 m_rateLimit4, m_formConfig->m_edRateLimit4);
114 m_conRateLimit5 = xqcon_create<XQLineEditConnector>(
115 m_rateLimit5, m_formConfig->m_edRateLimit5);
116 m_conRateLimit1UBound = xqcon_create<XQLineEditConnector>(
117 m_rateLimit1UBound, m_formConfig->m_edRateLimit1Bound);
118 m_conRateLimit2UBound = xqcon_create<XQLineEditConnector>(
119 m_rateLimit2UBound, m_formConfig->m_edRateLimit2Bound);
120 m_conRateLimit3UBound = xqcon_create<XQLineEditConnector>(
121 m_rateLimit3UBound, m_formConfig->m_edRateLimit3Bound);
122 m_conRateLimit4UBound = xqcon_create<XQLineEditConnector>(
123 m_rateLimit4UBound, m_formConfig->m_edRateLimit4Bound);
124 m_conRateLimit5UBound = xqcon_create<XQLineEditConnector>(
125 m_rateLimit5UBound, m_formConfig->m_edRateLimit5Bound);
126 m_conSecondaryPS = xqcon_create<XQComboBoxConnector>(
127 m_secondaryPS, m_formConfig->m_cmbSecondaryPS, ref(tr_meas));
128 m_conSecondaryPSMultiplier = xqcon_create<XQLineEditConnector>(
129 m_secondaryPSMultiplier, m_formConfig->m_edSecondaryPSMultiplier);
130 m_conSafeCond1Entry = xqcon_create<XQComboBoxConnector>(
131 m_safeCond1Entry, m_formConfig->m_cmbSafeCond1Entry, ref(tr_meas));
132 m_conSafeCond1Min = xqcon_create<XQLineEditConnector>(
133 m_safeCond1Min, m_formConfig->m_edSafeCond1Min);
134 m_conSafeCond1Max = xqcon_create<XQLineEditConnector>(
135 m_safeCond1Max, m_formConfig->m_edSafeCond1Max);
136 m_conSafeCond2Entry = xqcon_create<XQComboBoxConnector>(
137 m_safeCond2Entry, m_formConfig->m_cmbSafeCond2Entry, ref(tr_meas));
138 m_conSafeCond2Min = xqcon_create<XQLineEditConnector>(
139 m_safeCond2Min, m_formConfig->m_edSafeCond2Min);
140 m_conSafeCond2Max = xqcon_create<XQLineEditConnector>(
141 m_safeCond2Max, m_formConfig->m_edSafeCond2Max);
142 m_conSafeCond3Entry = xqcon_create<XQComboBoxConnector>(
143 m_safeCond3Entry, m_formConfig->m_cmbSafeCond3Entry, ref(tr_meas));
144 m_conSafeCond3Min = xqcon_create<XQLineEditConnector>(
145 m_safeCond3Min, m_formConfig->m_edSafeCond3Min);
146 m_conSafeCond3Max = xqcon_create<XQLineEditConnector>(
147 m_safeCond3Max, m_formConfig->m_edSafeCond3Max);
148 m_conPersistentCondEntry = xqcon_create<XQComboBoxConnector>(
149 m_persistentCondEntry, m_formConfig->m_cmbPersistentCondEntry, ref(tr_meas));
150 m_conPersistentCondMax = xqcon_create<XQLineEditConnector>(
151 m_persistentCondMax, m_formConfig->m_edPersistentCondMax);
152 m_conNonPersistentCondEntry = xqcon_create<XQComboBoxConnector>(
153 m_nonPersistentCondEntry, m_formConfig->m_cmbNonPersistentCondEntry, ref(tr_meas));
154 m_conNonPersistentCondMin = xqcon_create<XQLineEditConnector>(
155 m_nonPersistentCondMin, m_formConfig->m_edNonPersistentCondMin);
156 m_conPCSHWait = xqcon_create<XQLineEditConnector>(
157 m_pcshWait, m_formConfig->m_edPCSHWait);
160 tr[ *allowPersistent()] =
false;
161 tr[ *approach()].add({
"Linear",
"Oscillating"});
162 tr[ *m_pcshWait] = 40.0;
163 tr[ *m_safeCond1Max] = 100.0;
164 tr[ *m_safeCond2Max] = 100.0;
165 tr[ *m_safeCond3Max] = 100.0;
166 tr[ *targetField()].setUIEnabled(
false);
167 tr[ *sweepRate()].setUIEnabled(
false);
168 tr[ *targetField()].setUIEnabled(
false);
169 tr[ *sweepRate()].setUIEnabled(
false);
170 tr[ *allowPersistent()].setUIEnabled(
false);
171 m_lsnConfigShow = tr[ *m_configShow].onTouch().connectWeakly(
172 shared_from_this(), &XMagnetPS::onConfigShow,
173 XListener::FLAG_MAIN_THREAD_CALL | XListener::FLAG_AVOID_DUP);
178 m_form->showNormal();
183 m_formConfig->showNormal();
184 m_formConfig->raise();
188 tr[ *
this].m_magnetField = reader.pop<
float>();
189 tr[ *
this].m_outputCurrent = reader.pop<
float>();
190 m_field->value(tr, tr[ *
this].m_magnetField);
191 m_current->value(tr, tr[*
this].m_outputCurrent);
200 setRate(shot[ *sweepRate()]);
207 XMagnetPS::isSafeConditionSatisfied(
const Snapshot &shot,
const Snapshot &shot_entries) {
208 if(shared_ptr<XScalarEntry> entry = shot[ *m_safeCond1Entry]) {
210 double x = shot_entries[ *entry->value()];
211 if((x >= shot[ *m_safeCond1Max]) || (x <= shot[ *m_safeCond1Min]))
214 catch(NodeNotFoundError &) {
217 if(shared_ptr<XScalarEntry> entry = shot[ *m_safeCond2Entry]) {
219 double x = shot_entries[ *entry->value()];
220 if((x >= shot[ *m_safeCond2Max]) || (x <= shot[ *m_safeCond2Min]))
223 catch(NodeNotFoundError &) {
226 if(shared_ptr<XScalarEntry> entry = shot[ *m_safeCond3Entry]) {
228 double x = shot_entries[ *entry->value()];
229 if((x >= shot[ *m_safeCond3Max]) || (x <= shot[ *m_safeCond3Min]))
232 catch(NodeNotFoundError &) {
238 XMagnetPS::isPersistentStabilized(
const Snapshot &shot,
const Snapshot &shot_entries,
const XTime &pcsh_off_time) {
239 if(shared_ptr<XScalarEntry> entry = shot[ *m_persistentCondEntry]) {
241 double x = shot_entries[ *entry->value()];
242 if(x >= shot[ *m_persistentCondMax])
245 catch(NodeNotFoundError &) {
248 if(XTime::now() - pcsh_off_time < std::max(10.0, (
double)shot[ *m_pcshWait]))
253 XMagnetPS::isNonPersistentStabilized(
const Snapshot &shot,
const Snapshot &shot_entries,
const XTime &pcsh_on_time) {
254 if(shared_ptr<XScalarEntry> entry = shot[ *m_nonPersistentCondEntry]) {
256 double x = shot_entries[ *entry->value()];
257 if(x <= shot[ *m_nonPersistentCondMin])
260 catch(NodeNotFoundError &) {
263 if(XTime::now() - pcsh_on_time < std::max(10.0, (
double)shot[ *m_pcshWait]))
268 XMagnetPS::limitSweepRate(
double field,
double rate,
const Snapshot &shot) {
269 if((shot[ *m_rateLimit1UBound] > 0.0) && (fabs(field) < shot[ *m_rateLimit1UBound])) {
270 return std::min( rate, (
double)shot[ *m_rateLimit1]);
272 if((shot[ *m_rateLimit2UBound] > 0.0) && (fabs(field) < shot[ *m_rateLimit2UBound])) {
273 return std::min( rate, (
double)shot[ *m_rateLimit2]);
275 if((shot[ *m_rateLimit3UBound] > 0.0) && (fabs(field) < shot[ *m_rateLimit3UBound])) {
276 return std::min( rate, (
double)shot[ *m_rateLimit3]);
278 if((shot[ *m_rateLimit4UBound] > 0.0) && (fabs(field) < shot[ *m_rateLimit4UBound])) {
279 return std::min( rate, (
double)shot[ *m_rateLimit4]);
281 if((shot[ *m_rateLimit5UBound] > 0.0) && (fabs(field) < shot[ *m_rateLimit5UBound])) {
282 return std::min( rate, (
double)shot[ *m_rateLimit5]);
287 XMagnetPS::limitTargetField(
double field,
const Snapshot &shot) {
288 double max_h = std::max((
double)shot[ *m_rateLimit1UBound], (
double)shot[ *m_rateLimit2UBound]);
289 max_h = std::max(max_h, (
double)shot[ *m_rateLimit3UBound]);
290 max_h = std::max(max_h, (
double)shot[ *m_rateLimit4UBound]);
291 max_h = std::max(max_h, (
double)shot[ *m_rateLimit5UBound]);
292 if((max_h > 0.0) && (fabs(field) > max_h))
return max_h * field / fabs(field);
299 XTime lasttime = XTime::now();
300 XTime last_unstab_time = XTime::now();
301 XTime pcsh_time = XTime::now();
303 double field_resolution;
306 trans( *m_aborting) =
false;
308 field_resolution = fieldResolution();
310 trans( *sweepRate()) = getSweepRate();
311 trans( *targetField()) = getTargetField();
314 targetField()->setUIEnabled(
true);
315 sweepRate()->setUIEnabled(
true);
317 double target_field_old =
Snapshot( *
this)[ *targetField()];
318 double target_corr = 0.0;
320 if(is_pcs_fitted) allowPersistent()->setUIEnabled(
true);
322 m_lsnRate = tr[ *sweepRate()].onValueChanged().connectWeakly(
323 shared_from_this(), &XMagnetPS::onRateChanged);
326 while( !terminated) {
330 double output_current;
332 double target_field_ps;
333 bool pcs_heater =
true;
339 output_field = getOutputField();
340 output_current = getOutputCurrent();
341 output_volt = getOutputVolt();
342 target_field_ps = getTargetField();
345 if(pcs_heater != last_pcsh)
346 pcsh_time = XTime::now();
347 last_pcsh = pcs_heater;
349 if( !is_pcs_fitted || pcs_heater) {
350 magnet_field = output_field;
353 magnet_field = getPersistentField();
360 auto writer = std::make_shared<RawData>();
361 writer->push((
float)magnet_field);
362 writer->push((
float)output_current);
366 XTime newtime = XTime::now();
370 tr[ *magnetField()] = magnet_field;
371 tr[ *outputField()] = output_field;
372 tr[ *outputCurrent()] = output_current;
373 tr[ *outputVolt()] = output_volt;
374 tr[ *pcsHeater()] = pcs_heater && is_pcs_fitted;
376 tr[ *persistent()] = !pcs_heater && is_pcs_fitted && isPersistentStabilized(shot, shot_entries, pcsh_time);
378 if(shot[ *m_aborting]) {
380 tr[ *targetField()].setUIEnabled(
false);
381 tr[ *targetField()] = 0;
382 tr[ *sweepRate()] = limitSweepRate(magnet_field, 1.0, shot) / 10.0;
385 double sweep_rate = limitSweepRate(magnet_field, shot[ *sweepRate()], shot);
386 if(sweep_rate != shot[ *sweepRate()]) {
387 m_statusPrinter->printMessage(
getLabel() +
" " +
388 i18n(
"Limits sweep rate."));
389 tr[ *sweepRate()] = sweep_rate;
392 double dt = fabs(newtime - lasttime);
394 havg_next = (havg - magnet_field) * exp( -0.1 * dt) + magnet_field;
395 tr[ *
stabilized()] = std::max(fabs(magnet_field - target_field_ps), fabs(havg_next - target_field_ps));
398 double field_resolution_for_stab = field_resolution * 1.3;
399 if(shot[ *
stabilized()] > field_resolution_for_stab)
400 last_unstab_time = XTime::now();
404 if( !shot[ *m_aborting] && !isSafeConditionSatisfied(shot, shot_entries)) {
405 m_statusPrinter->printMessage(
getLabel() +
" " +
407 trans( *m_aborting) =
true;
410 if( shot[ *m_aborting] && isSafeConditionSatisfied(shot, shot_entries)) {
411 m_statusPrinter->printMessage(
getLabel() +
" " +
412 i18n(
"Safe conditions are satisfied."));
413 trans( *m_aborting) =
false;
414 trans( *targetField()).setUIEnabled(
true);
420 if(secondaryps.get() ==
this)
423 if(pcs_heater || !is_pcs_fitted) {
425 if((target_field_old != shot[ *targetField()]) ||
426 ((fabs(target_field_ps - target_field_old - target_corr) > field_resolution) &&
427 (fabs(target_field_ps - magnet_field) < field_resolution))) {
429 if( !is_pcs_fitted || isNonPersistentStabilized(shot, shot_entries, pcsh_time)) {
431 double next_target_ps = shot[ *targetField()];
432 if(target_field_old != shot[ *targetField()])
434 target_field_old = shot[ *targetField()];
435 if(shot[ *approach()] == APPROACH_OSC) {
436 next_target_ps += 0.2 * (next_target_ps - magnet_field) + target_corr;
439 if((next_target_ps * magnet_field < 0) && (fabs(magnet_field) > field_resolution) &&
440 !canChangePolarityDuringSweep()) {
441 target_corr = next_target_ps - shot[ *targetField()];
442 next_target_ps = 0.0;
445 double x = limitTargetField(next_target_ps, shot);
446 if(x != next_target_ps) {
447 m_statusPrinter->printMessage(
getLabel() +
" " +
448 i18n(
"Limits field."));
451 setPoint(next_target_ps);
455 if(fabs(mul) > 0.4) {
456 m_statusPrinter->printMessage(
getLabel() +
" " +
457 i18n(
"Multiplier too large."));
460 double sweep_rate = getSweepRate();
462 tr[ *secondaryps->sweepRate()] = sweep_rate * mul;
463 tr[ *secondaryps->targetField()] = next_target_ps * mul;
464 tr[ *secondaryps->approach()] = (int)shot[ *approach()];
472 (fabs(magnet_field - shot[ *targetField()]) < field_resolution) && shot[ *allowPersistent()]) {
473 if(XTime::now() - last_unstab_time >
474 std::max(30.0, (
double)shot[ *m_pcshWait]) + field_resolution_for_stab * 1.05 / shot[ *sweepRate()] * 60.0) {
476 m_statusPrinter->printMessage(
getLabel() +
" " +
477 i18n(
"Turning on Perisistent mode."));
478 pcsh_time = XTime::now();
486 if(fabs(magnet_field - shot[ *targetField()]) >= field_resolution) {
487 if((fabs(magnet_field - output_field) < field_resolution) &&
488 (fabs(target_field_ps - magnet_field) < field_resolution)) {
490 m_statusPrinter->printMessage(
getLabel() +
" " +
491 i18n(
"Non-Perisistent mode."));
492 double h = getPersistentField();
493 if(fabs(h - output_field) > field_resolution)
495 i18n(
"Huh? Magnet field confusing."), __FILE__, __LINE__);
496 pcsh_time = XTime::now();
501 if(shot[ *m_persistent]) {
502 setPoint(magnet_field);
508 if(shot[ *m_persistent] && (fabs(output_field) > field_resolution)) {
520 targetField()->setUIEnabled(
false);
521 sweepRate()->setUIEnabled(
false);
522 allowPersistent()->setUIEnabled(
false);