IoHeaterBand3.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. using Aitex.Core.Common.DeviceData;
  2. using Aitex.Core.RT.DataCenter;
  3. using Aitex.Core.RT.Event;
  4. using Aitex.Core.RT.IOCore;
  5. using Aitex.Core.RT.OperationCenter;
  6. using Aitex.Core.RT.SCCore;
  7. using Aitex.Core.RT.Tolerance;
  8. using Aitex.Core.Util;
  9. using MECF.Framework.Common.CommonData;
  10. using MECF.Framework.Common.Device.Bases;
  11. using MECF.Framework.Common.Event;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using System.Text;
  16. using System.Threading.Tasks;
  17. using System.Xml;
  18. namespace FurnaceRT.Devices
  19. {
  20. public class IoHeaterBand3 : HeaterBase
  21. {
  22. public IoHeaterBand3(string module, XmlElement node, string ioModule = "")
  23. {
  24. base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module");
  25. base.Name = node.GetAttribute("id");
  26. base.Display = node.GetAttribute("display");
  27. base.DeviceID = node.GetAttribute("schematicId");
  28. formatString = node.GetAttribute("formatString");
  29. _uniqueName = $"{Module}{Name}";
  30. _aiPV = ParseAiNode("aiPV", node, ioModule);
  31. _aiMV = ParseAiNode("aiMV", node, ioModule);
  32. _aiControlOutput = ParseAiNode("aiControlOutput", node, ioModule);
  33. _aiErrorID = ParseAiNode("aiErrorID", node, ioModule);
  34. _aiSV = ParseAiNode("aiTemperatureSVFeedback", node, ioModule);
  35. _aiAutotuneActivate = ParseAiNode("aiAutotuneActivate", node, ioModule);
  36. _aiAlarmHigher = ParseAiNode("aiAlarmHigher", node, ioModule);
  37. _aiAlarmLower = ParseAiNode("aiAlarmLower", node, ioModule);
  38. _aiEnableIn = ParseAiNode("aiEnableIn", node, ioModule);
  39. _aiUpRate = ParseAiNode("aiUpRate", node, ioModule);
  40. _aiDownRate = ParseAiNode("aiDownRate", node, ioModule);
  41. _aiSBrkOut = ParseAiNode("aiSBrkOut", node, ioModule);
  42. _diAlarmOutput = ParseDiNode("diAlarmOutput", node, ioModule);
  43. _aoSetPoint = ParseAoNode("aoSetPoint", node, ioModule);
  44. _aoPID_P = ParseAoNode("aoPID_P", node, ioModule);
  45. _aoPID_I = ParseAoNode("aoPID_I", node, ioModule);
  46. _aoPID_D = ParseAoNode("aoPID_D", node, ioModule);
  47. _aoManualOutput = ParseAoNode("aoManualOutput", node, ioModule);
  48. _aoControlPeriodTime = ParseAoNode("aoControlPeriodTime", node, ioModule);
  49. _aoAlarmHigher = ParseAoNode("aoAlarmHigher", node, ioModule);
  50. _aoAlarmLower = ParseAoNode("aoAlarmLower", node, ioModule);
  51. _aoAlarmInhibit = ParseAoNode("aoAlarmInhibit", node, ioModule);
  52. _aoUpRate = ParseAoNode("aoUpRate", node, ioModule);
  53. _aoDownRate = ParseAoNode("aoDownRate", node, ioModule);
  54. _aoEnableIn = ParseAoNode("aoEnableIn", node, ioModule);
  55. _aoAutotuneActivate = ParseAoNode("aoAutotuneActivate", node, ioModule);
  56. _diControlDoing = ParseDiNode("diControlDoing", node, ioModule);
  57. _diAutoTuningDoing = ParseDiNode("diAutoTuningDoing", node, ioModule);
  58. _diAutoTuningDone = ParseDiNode("diAutoTuningDone", node, ioModule);
  59. _diPIDControlError = ParseDiNode("diPIDControlError", node, ioModule);
  60. _diTimePropControlError = ParseDiNode("diTimePropControlError", node, ioModule);
  61. _doEnable = ParseDoNode("doEnable", node, ioModule);
  62. _doManualControl = ParseDoNode("doManualControl", node, ioModule);
  63. _doAutoTuning = ParseDoNode("doAutoTuning", node, ioModule);
  64. _doOutRangeAlarmInhibit = ParseDoNode("doOutRangeAlarmInhibit", node, ioModule);
  65. _doF2CLNAlarmInhibit = ParseDoNode("doF2CLNAlarmInhibit", node, ioModule);
  66. _doOutRangeAlarmInhibit = ParseDoNode("doOutRangeAlarmInhibit", node, ioModule);
  67. _scRoot = node.GetAttribute("scRoot");
  68. }
  69. #region fields
  70. private AIAccessor _aiPV;
  71. private AIAccessor _aiMV;
  72. private AIAccessor _aiControlOutput;
  73. private AIAccessor _aiErrorID;
  74. private AIAccessor _aiSV;//gas line heater才有
  75. private AIAccessor _aiAutotuneActivate;//gas line heater才有
  76. private AIAccessor _aiEnableIn;//gas line heater才有
  77. private AIAccessor _aiAlarmHigher;
  78. private AIAccessor _aiAlarmLower;
  79. private AIAccessor _aiUpRate;//gas line heater才有
  80. private AIAccessor _aiDownRate;//gas line heater才有
  81. private AIAccessor _aiSBrkOut;//gas line heater才有
  82. private AOAccessor _aoUpRate;//gas line heater才有
  83. private AOAccessor _aoDownRate;//gas line heater才有
  84. private AOAccessor _aoEnableIn;//gas line heater才有
  85. private AOAccessor _aoAutotuneActivate;//gas line heater才有
  86. private AOAccessor _aoSetPoint;
  87. private AOAccessor _aoPID_P;
  88. private AOAccessor _aoPID_I;
  89. private AOAccessor _aoPID_D;
  90. private AOAccessor _aoManualOutput;
  91. private AOAccessor _aoControlPeriodTime;
  92. private AOAccessor _aoAlarmHigher;
  93. private AOAccessor _aoAlarmLower;
  94. private AOAccessor _aoAlarmInhibit;
  95. private DIAccessor _diControlDoing;
  96. private DIAccessor _diAutoTuningDoing;
  97. private DIAccessor _diAutoTuningDone;
  98. private DIAccessor _diPIDControlError;
  99. private DIAccessor _diTimePropControlError;
  100. private DOAccessor _doEnable;
  101. private DOAccessor _doManualControl;
  102. private DOAccessor _doAutoTuning;
  103. private DOAccessor _doSelect;
  104. private DOAccessor _doCascadeMode;
  105. private DOAccessor _doOutRangeAlarmInhibit;
  106. private DOAccessor _doF2CLNAlarmInhibit;
  107. private DOAccessor _doChannelInhibit;
  108. private DIAccessor _diAlarmOutput;
  109. private string formatString;
  110. private const int physicalMax = 16000;
  111. private ToleranceChecker _toleranceCheckerWarning = new ToleranceChecker();
  112. private ToleranceChecker _toleranceCheckerAlarm = new ToleranceChecker();
  113. //tolerance check
  114. private float _alarmJudgmentRange;
  115. private float _warningJudgmentRange;
  116. private float _alarmJudgmentTime;
  117. private float _warningJudgmentTime;
  118. private float _toleranceJudgmentDelayTime;
  119. private DeviceTimer _toleranceJudgmentDelayTimer = new DeviceTimer();
  120. //stable check
  121. private DeviceTimer _stableJudgmentTimer = new DeviceTimer();
  122. private float _stableJudgmentTime;
  123. private float _stableMinValue;
  124. private float _stableMaxValue;
  125. private SCConfigItem _scEnableCalibration;
  126. private SCConfigItem _scCalibrationTable;
  127. private SCConfigItem _scRange;
  128. private SCConfigItem _scRampRate;//°C/min
  129. private List<CalibrationItem> _calibrationTable = new List<CalibrationItem>();
  130. private string _previousSetting;
  131. private DeviceTimer _rampTimer = new DeviceTimer();
  132. private double _rampTarget;
  133. private double _rampInitValue;
  134. private int _rampTime;
  135. private DeviceTimer _stableTimer = new DeviceTimer();
  136. private bool _isWarned;
  137. private string _uniqueName;
  138. private float _tempSetpoint;
  139. private string _scRoot;
  140. private bool _isStartRamp = false;
  141. private bool _isFloatAioType = true;
  142. #endregion
  143. #region properties
  144. public string InstallZone { get; set; }
  145. public double Range => _scRange.DoubleValue;
  146. public AlarmEventItem AlarmToleranceWarning { get; set; }
  147. public AlarmEventItem AlarmToleranceAlarm { get; set; }
  148. public AlarmEventItem InterlockAlarm { get; set; }
  149. public AlarmEventItem HeaterErrorAlarm { get; set; }
  150. public AlarmEventItem HeaterErrorRecoveryWarning { get; set; }
  151. public AlarmEventItem HeaterStripBreakAlarm { get; set; }
  152. public AlarmEventItem HeaterStripBreakWarning { get; set; }
  153. public bool IsHeaterStripBreak { get; set; }
  154. private RD_TRIG _trigHeaterErrorSignalOn = new RD_TRIG();
  155. public R_TRIG TrigHeaterStripBreakSignalOn = new R_TRIG();
  156. public DeviceTimer HeaterStripBreakTimer = new DeviceTimer();
  157. public string InstallPosition => SC.GetStringValue($"{_scRoot}.Heater.{InstallZone}.{Name}.InstallPosition");
  158. public bool IsError => _diPIDControlError == null || _diTimePropControlError == null ? false : _diPIDControlError.Value || _diTimePropControlError.Value;
  159. public override bool IsPowerOn { get; set; }
  160. public bool IsStable
  161. {
  162. get
  163. {
  164. if (!_stableJudgmentTimer.IsIdle())
  165. {
  166. if (DeviceData.FeedBack < (DeviceData.SetPoint - _stableMinValue) ||
  167. DeviceData.FeedBack > (DeviceData.SetPoint + _stableMaxValue))
  168. {
  169. _stableJudgmentTimer.Start(0);
  170. }
  171. if (_stableJudgmentTimer.GetElapseTime() >= _stableJudgmentTime * 1000)
  172. {
  173. return true;
  174. }
  175. }
  176. else
  177. {
  178. _stableJudgmentTimer.Start(0);
  179. }
  180. return false;
  181. }
  182. }
  183. public override float TempSetPoint
  184. {
  185. get
  186. {
  187. if (_aiSV != null)
  188. {
  189. if (_isFloatAioType)
  190. return _aiSV.FloatValue;
  191. else
  192. return _aiSV.Value;
  193. }
  194. if (_aoSetPoint != null)
  195. {
  196. if (_isFloatAioType)
  197. return _aoSetPoint.FloatValue;
  198. else
  199. return _aoSetPoint.Value;
  200. }
  201. return _tempSetpoint;
  202. }
  203. set
  204. {
  205. _tempSetpoint = value;
  206. if (_aoSetPoint != null)
  207. {
  208. if (_isFloatAioType)
  209. _aoSetPoint.FloatValue = value;
  210. else
  211. _aoSetPoint.Value = (short)value;
  212. }
  213. }
  214. }
  215. public override float TempFeedback
  216. {
  217. get
  218. {
  219. if (_aiPV == null)
  220. return 0;
  221. float feedback = 0.0f;
  222. if (_isFloatAioType)
  223. {
  224. int temp = (int)(_aiPV.FloatValue * 10);
  225. feedback = (float)(temp) / 10;
  226. }
  227. else
  228. {
  229. feedback = _aiPV.Value;
  230. }
  231. return feedback;
  232. }
  233. }
  234. public bool IsEnableMVLimiter { get; set; } = false;
  235. public bool IsEnable
  236. {
  237. get
  238. {
  239. if (_diControlDoing != null)
  240. return _diControlDoing.Value;
  241. if (_aiEnableIn != null)
  242. return _aiEnableIn.FloatValue > 0;
  243. if (_aoEnableIn != null)
  244. return _aoEnableIn.FloatValue > 0;
  245. if (_doEnable != null)
  246. return _doEnable.Value;
  247. return false;
  248. }
  249. }
  250. #endregion
  251. public override bool Initialize()
  252. {
  253. DeviceData = new AITHeaterData()
  254. {
  255. DeviceName = Name,
  256. DeviceSchematicId = DeviceID,
  257. DisplayName = Name,
  258. Module = Module,
  259. //Scale = SC.GetValue<double>($"{_scRoot}.{Name}.Range"),
  260. Scale = 1200,
  261. Unit = "°C",
  262. //SetPoint = TempSetPoint,
  263. FeedBack = TempFeedback,
  264. };
  265. _scEnableCalibration = SC.GetConfigItem($"{_scRoot}.{Name}.EnableCalibration");
  266. _scCalibrationTable = SC.GetConfigItem($"{_scRoot}.{Name}.CalibrationTable");
  267. _scRampRate = SC.GetConfigItem($"{_scRoot}.{Name}.RampRate");
  268. //DATA.Subscribe($"{Module}.{Name}.IsEnable", () => IsEnable);
  269. if (_aiMV != null)
  270. DATA.Subscribe($"{Module}.{Name}.MV", () => _aiMV.FloatValue);
  271. if (_aiControlOutput != null)
  272. DATA.Subscribe($"{Module}.{Name}.ControlOutput", () => _aiControlOutput.FloatValue);
  273. if (_aiErrorID != null)
  274. DATA.Subscribe($"{Module}.{Name}.ErrorID", () => _aiErrorID.FloatValue);
  275. if (_doManualControl != null)
  276. DATA.Subscribe($"{Module}.{Name}.IsManualControl", () => _doManualControl.Value);
  277. if (_diControlDoing != null)
  278. DATA.Subscribe($"{Module}.{Name}.IsControlDoing", () => _diControlDoing.Value);
  279. if (_diAutoTuningDoing != null)
  280. DATA.Subscribe($"{Module}.{Name}.IsAutoTuningDoing", () => _diAutoTuningDoing.Value);
  281. if (_diAutoTuningDone != null)
  282. DATA.Subscribe($"{Module}.{Name}.IsAutoTuningDone", () => _diAutoTuningDone.Value);
  283. OP.Subscribe($"{Module}.{Name}.SetProportioning", SetPID_P);
  284. OP.Subscribe($"{Module}.{Name}.SetIntegral", SetPID_I);
  285. OP.Subscribe($"{Module}.{Name}.SetDerivative", SetPID_D);
  286. OP.Subscribe($"{Module}.{Name}.SetRemoteMode", SetRemoteMode);
  287. OP.Subscribe($"{Module}.{Name}.SetAutoTuning", SetAutoTuning);
  288. OP.Subscribe($"{Module}.{Name}.SetOnOff", SetOnOff);
  289. OP.Subscribe($"{Module}.{Name}.SetAlarmWatchTable", (function, args) =>
  290. {
  291. SetAlarmWatchTable(args[0].ToString());
  292. return true;
  293. });
  294. //for recipe
  295. OP.Subscribe($"{Module}.{Name}.SetParameters", (out string reason, int time, object[] param) =>
  296. {
  297. reason = string.Empty;
  298. SetParameters(param);
  299. return true;
  300. });
  301. //if (_diRunning.Value)
  302. //{
  303. // var temperature = SC.GetValue<double>($"{_scRoot}.{Name}.SetPoint");
  304. // if (temperature != SetpointFeedback)
  305. // {
  306. // var ramp = SC.GetValue<double>($"{_scRoot}.{Name}.RampRate");
  307. // var _rampTime = ramp != 0 ? (Math.Abs(temperature - TempFeedback) / ramp) * 60 * 1000 : 0;
  308. // Ramp(temperature, (int)_rampTime);
  309. // }
  310. //}
  311. return base.Initialize();
  312. }
  313. public override void Monitor()
  314. {
  315. DeviceData.ProportioningSetPoint = _aoPID_P == null ? 0 : _aoPID_P.FloatValue;
  316. DeviceData.IntegralSetPoint = _aoPID_I == null ? 0 : _aoPID_I.FloatValue;
  317. DeviceData.DerivativeSetPoint = _aoPID_D == null ? 0 : _aoPID_D.FloatValue;
  318. DeviceData.FeedBack = TempFeedback;
  319. DeviceData.SetPoint = TempSetPoint;
  320. DeviceData.ManipulatedVariable = _aiMV == null ? 0 : _aiMV.FloatValue;
  321. DeviceData.RampSetPoint = TempSetPoint;//Ramp的过程值
  322. MonitorTolerance();
  323. Ramping();
  324. base.Monitor();
  325. }
  326. private void SetAlarmWatchTable(string table)
  327. {
  328. DeviceData.AlarmWatchTable = table;
  329. SC.SetItemValueFromString($"{_scRoot}.{Name}.TempAlarmTableValue", table);
  330. if (SC.ContainsItem($"AlarmWatchTable.TempAlarmWatch.{table}.DelayTime"))
  331. {
  332. var scPath = $"AlarmWatchTable.TempAlarmWatch.{table}";
  333. _toleranceJudgmentDelayTime = (float)SC.GetValue<double>($"{scPath}.DelayTime");
  334. _alarmJudgmentRange = (float)SC.GetValue<double>($"{scPath}.AlarmJudgment");
  335. _warningJudgmentRange = (float)SC.GetValue<double>($"{scPath}.WarningJudgment");
  336. _alarmJudgmentTime = (float)SC.GetValue<double>($"{scPath}.AlarmJudgmentTime");
  337. _warningJudgmentTime = (float)SC.GetValue<double>($"{scPath}.WarningJudgmentTime");
  338. }
  339. }
  340. public override void SetTemperature(float temperature)
  341. {
  342. SaveSetPoint(temperature.ToString());
  343. //if (temperature != SetpointFeedback)
  344. {
  345. var _rampTime = _scRampRate.DoubleValue != 0 ? (Math.Abs(temperature - TempFeedback) / _scRampRate.DoubleValue) * 60 * 1000 : 0;
  346. Ramp(temperature, (int)_rampTime);
  347. }
  348. }
  349. public void SetRamping(float ramping)
  350. {
  351. SaveRampRate(ramping.ToString("F1"));
  352. }
  353. private void SetParameters(object[] param)
  354. {
  355. if (param != null && param.Length > 0)
  356. {
  357. float temperature = 0.0f;
  358. float ramp = 0.0f;
  359. string alarmWatchTable = "";
  360. string PIDModel = "";
  361. var array = param[0].ToString().Split(';');//tmep;ramp;ControlMode;AlarmTable
  362. if (System.Text.RegularExpressions.Regex.Match(array[0].ToString(), @"[a-zA-Z]").Success)
  363. {
  364. var table = array[0].ToString().Split(':');//AssociateParameterTable
  365. if (SC.ContainsItem($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{InstallZone}"))
  366. {
  367. temperature = (float)SC.GetValue<double>($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{InstallZone}");
  368. }
  369. }
  370. else
  371. {
  372. float.TryParse(array[0].ToString(), out temperature);
  373. }
  374. if (array.Length > 1)
  375. {
  376. float.TryParse(array[1], out ramp);
  377. DeviceData.Ramping = ramp;
  378. }
  379. if (array.Length > 2)
  380. {
  381. PIDModel = array[2].ToString();
  382. if (PIDModel.ToLower().Contains("cascade"))
  383. {
  384. _doSelect.Value = false;
  385. _doCascadeMode.Value = false;
  386. }
  387. else if (PIDModel.ToLower().Contains("spike") && InstallPosition.ToLower().Contains("spike"))
  388. {
  389. _doSelect.Value = false;
  390. _doCascadeMode.Value = true;
  391. }
  392. else if (PIDModel.ToLower().Contains("paddle") && InstallPosition.ToLower().Contains("paddle"))
  393. {
  394. _doSelect.Value = true;
  395. _doCascadeMode.Value = true;
  396. }
  397. else
  398. {
  399. return;
  400. }
  401. }
  402. if (temperature != DeviceData.SetPoint)
  403. {
  404. }
  405. DeviceData.SetPoint = temperature;
  406. SetPID(temperature);
  407. if (array.Length > 3)
  408. {
  409. alarmWatchTable = array[4].ToString();
  410. if (string.IsNullOrEmpty(alarmWatchTable) || alarmWatchTable == "0" || alarmWatchTable == "None")
  411. {
  412. DeviceData.AlarmWatchTable = "None";
  413. _toleranceJudgmentDelayTime = 0;
  414. _alarmJudgmentRange = 0;
  415. _warningJudgmentRange = 0;
  416. _alarmJudgmentTime = 0;
  417. _warningJudgmentTime = 0;
  418. _toleranceJudgmentDelayTimer.Stop();
  419. }
  420. else
  421. {
  422. DeviceData.AlarmWatchTable = $"Table{alarmWatchTable}";
  423. if (SC.ContainsItem($"PM1.RecipeEditParameter.AlarmWatchTable.TempAlarmWatch.Table{alarmWatchTable}.DelayTime"))
  424. {
  425. var scPath = $"PM1.RecipeEditParameter.AlarmWatchTable.TempAlarmWatch.Table{alarmWatchTable}";
  426. _toleranceJudgmentDelayTime = (float)SC.GetValue<double>($"{scPath}.DelayTime");
  427. _alarmJudgmentRange = (float)SC.GetValue<double>($"{scPath}.AlarmJudgment");
  428. _warningJudgmentRange = (float)SC.GetValue<double>($"{scPath}.WarningJudgment");
  429. _alarmJudgmentTime = (float)SC.GetValue<double>($"{scPath}.AlarmJudgmentTime");
  430. _warningJudgmentTime = (float)SC.GetValue<double>($"{scPath}.WarningJudgmentTime");
  431. _toleranceJudgmentDelayTimer.Start(0);
  432. }
  433. else
  434. {
  435. _toleranceJudgmentDelayTime = 0;
  436. _alarmJudgmentRange = 0;
  437. _warningJudgmentRange = 0;
  438. _alarmJudgmentTime = 0;
  439. _warningJudgmentTime = 0;
  440. _toleranceJudgmentDelayTimer.Stop();
  441. }
  442. }
  443. ResetWarningChecker();
  444. ResetAlarmChecker();
  445. AlarmToleranceWarning.Reset();
  446. AlarmToleranceAlarm.Reset();
  447. }
  448. //SaveSetPoint(temperature.ToString());
  449. //SaveRampRate(ramp.ToString());
  450. //if (temperature != SetpointFeedback)
  451. var _rampTime = ramp != 0 ? (Math.Abs(temperature - TempFeedback) / ramp) * 60 * 1000 : 0;
  452. Ramp(temperature, (int)_rampTime);
  453. EV.PostInfoLog(Module, $"{Name} temperature set to {DeviceData.SetPoint} ℃");
  454. }
  455. }
  456. private bool SetPID_P(out string reason, int time, params object[] param)
  457. {
  458. reason = string.Empty;
  459. if (param == null || param.Length == 0)
  460. {
  461. reason = $"invalid parameter";
  462. return false;
  463. }
  464. float.TryParse(param[0].ToString(), out float p);
  465. _aoPID_P.FloatValue = p;
  466. return true;
  467. }
  468. private bool SetPID_I(out string reason, int time, params object[] param)
  469. {
  470. reason = string.Empty;
  471. if (param == null || param.Length == 0)
  472. {
  473. reason = $"invalid parameter";
  474. return false;
  475. }
  476. float.TryParse(param[0].ToString(), out float i);
  477. _aoPID_I.FloatValue = i;
  478. return true;
  479. }
  480. private bool SetPID_D(out string reason, int time, params object[] param)
  481. {
  482. reason = string.Empty;
  483. if (param == null || param.Length == 0)
  484. {
  485. reason = $"invalid parameter";
  486. return false;
  487. }
  488. float.TryParse(param[0].ToString(), out float d);
  489. _aoPID_D.FloatValue = d;
  490. return true;
  491. }
  492. private bool SetRemoteMode(out string reason, int time, params object[] param)
  493. {
  494. reason = string.Empty;
  495. if (param == null || param.Length == 0)
  496. {
  497. reason = $"invalid parameter";
  498. return false;
  499. }
  500. bool.TryParse(param[0].ToString(), out bool isRemoteMode);
  501. //_doRemoteControl.SetValue(isRemoteMode, out _);
  502. return true;
  503. }
  504. private bool SetOnOff(out string reason, int time, params object[] param)
  505. {
  506. reason = string.Empty;
  507. if (param == null || param.Length == 0)
  508. {
  509. reason = $"invalid parameter";
  510. return false;
  511. }
  512. bool.TryParse(param[0].ToString(), out bool isOn);
  513. //if (!_doStartHeating.Check(isOn, out reason))
  514. //{
  515. // return false;
  516. //}
  517. //return _doStartHeating.SetValue(isOn, out reason);
  518. return true;
  519. }
  520. public void SetRun(bool isOn)
  521. {
  522. //_doStartHeating.SetValue(isOn, out _);
  523. EV.PostInfoLog(Name, $"{Name}.SetRun({isOn})");
  524. }
  525. public void SetRemote(bool isRemote)
  526. {
  527. //_doRemoteControl.SetValue(isRemote, out _);
  528. }
  529. private bool SetAutoTuning(out string reason, int time, params object[] param)
  530. {
  531. reason = string.Empty;
  532. if (param == null || param.Length == 0)
  533. {
  534. reason = $"invalid parameter";
  535. return false;
  536. }
  537. bool.TryParse(param[0].ToString(), out bool isAutoSetAutoTuning);
  538. if (isAutoSetAutoTuning)
  539. {
  540. //_doCanWritePara.SetPulseValue(true, 2000);
  541. //_doStopAutoTunningMode.SetValue(false, out _);
  542. //_doStartAutoTunningMode.SetPulseValue(true, 2000);
  543. }
  544. else
  545. {
  546. //_doCanWritePara.SetPulseValue(true, 2000);
  547. //_doStartAutoTunningMode.SetValue(false, out _);
  548. //_doStopAutoTunningMode.SetPulseValue(true, 2000);
  549. }
  550. return true;
  551. }
  552. public override void Terminate()
  553. {
  554. base.Terminate();
  555. }
  556. private void SetPID(float setpoint)
  557. {
  558. //_aoPID_P.FloatValue = (float)proportioning;
  559. //_aoPID_I.FloatValue = (float)integral;
  560. //_aoPID_D.FloatValue = (float)derivative;
  561. }
  562. public void SetStableParameters(string tableId)
  563. {
  564. if (SC.ContainsItem($"PM1.RecipeEditParameter.TempStabilizeTable.Table{tableId}.{InstallZone}.JudgmentTime"))
  565. {
  566. var scPath = $"PM1.RecipeEditParameter.TempStabilizeTable.Table{tableId}.{InstallZone}";
  567. _stableJudgmentTime = (float)SC.GetValue<double>($"{scPath}.JudgmentTime");
  568. _stableMinValue = (float)SC.GetValue<double>($"{scPath}.MinValue");
  569. _stableMaxValue = (float)SC.GetValue<double>($"{scPath}.MaxValue");
  570. _stableJudgmentTimer.Start(0);
  571. }
  572. }
  573. public bool ResetWarningChecker()
  574. {
  575. _toleranceCheckerWarning.Reset(_warningJudgmentTime);
  576. return true;
  577. }
  578. public bool ResetAlarmChecker()
  579. {
  580. _toleranceCheckerAlarm.Reset(_alarmJudgmentTime);
  581. return true;
  582. }
  583. public override void Reset()
  584. {
  585. AlarmToleranceWarning?.Reset();
  586. AlarmToleranceAlarm?.Reset();
  587. _toleranceJudgmentDelayTimer?.Stop();
  588. }
  589. public void ResetHeaterError()
  590. {
  591. _trigHeaterErrorSignalOn.RST = true;
  592. if (HeaterErrorAlarm != null)
  593. HeaterErrorAlarm.IsAcknowledged = true;
  594. }
  595. public void ResetHeaterStripBreak()
  596. {
  597. TrigHeaterStripBreakSignalOn.RST = true;
  598. if (HeaterStripBreakAlarm != null)
  599. HeaterStripBreakAlarm.IsAcknowledged = true;
  600. }
  601. private void MonitorTolerance()
  602. {
  603. if (IsHeaterStripBreak || TempSetPoint < 0.001 || _toleranceJudgmentDelayTimer.IsIdle() || _toleranceJudgmentDelayTimer.GetElapseTime() < _toleranceJudgmentDelayTime * 1000)
  604. {
  605. _toleranceCheckerWarning.RST = true;
  606. _toleranceCheckerAlarm.RST = true;
  607. return;
  608. }
  609. if (_alarmJudgmentRange != 0 && _alarmJudgmentTime > 0)
  610. {
  611. _toleranceCheckerAlarm.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_alarmJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_alarmJudgmentRange), _alarmJudgmentTime);
  612. }
  613. if (_warningJudgmentRange != 0 && _warningJudgmentTime > 0)
  614. {
  615. _toleranceCheckerWarning.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_warningJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_warningJudgmentRange), _warningJudgmentTime);
  616. }
  617. }
  618. public override bool CheckToleranceAlarm()
  619. {
  620. return _toleranceCheckerAlarm.Result;
  621. }
  622. public override bool CheckToleranceWarning()
  623. {
  624. return _toleranceCheckerWarning.Result;
  625. }
  626. public void SetToleranceAlarm()
  627. {
  628. AlarmToleranceAlarm.Description = $"{Display} temperature out of range {_alarmJudgmentRange} °C in {_alarmJudgmentTime:F0} seconds";
  629. AlarmToleranceAlarm.Set();
  630. }
  631. public void SetToleranceWarning()
  632. {
  633. AlarmToleranceWarning.Description = $"{Display} temperature out of range {_warningJudgmentRange} °C in {_warningJudgmentTime:F0} seconds";
  634. AlarmToleranceWarning.Set();
  635. }
  636. public void Ramp(double target, int time)
  637. {
  638. target = Math.Max(0, target);
  639. //target = Math.Min(Range, target);
  640. _rampInitValue = TempFeedback; //ramp 初始值取当前设定值,而非实际读取值.零漂问题
  641. _rampTime = time;
  642. _rampTarget = target;
  643. _rampTimer.Start(_rampTime);
  644. _isStartRamp = true;
  645. }
  646. private void Ramping()
  647. {
  648. //只有修改了温度,才开始ramp,避免一开机温度设定值大于0的问题。
  649. if (!_isStartRamp)
  650. return;
  651. if (_rampTimer.IsTimeout() || _rampTime == 0)
  652. {
  653. TempSetPoint = (float)_rampTarget;
  654. }
  655. else
  656. {
  657. TempSetPoint = (float)(_rampInitValue + (_rampTarget - _rampInitValue) * _rampTimer.GetElapseTime() / _rampTime);
  658. }
  659. }
  660. public void UpdateCalibrationTable()
  661. {
  662. if (_scCalibrationTable == null)
  663. return;
  664. if (_previousSetting == _scCalibrationTable.StringValue)
  665. return;
  666. _previousSetting = _scCalibrationTable.StringValue;
  667. if (string.IsNullOrEmpty(_previousSetting))
  668. {
  669. _calibrationTable = new List<CalibrationItem>();
  670. return;
  671. }
  672. var table = new List<Tuple<float, float>>();
  673. string[] items = _previousSetting.Split(';');
  674. for (int i = 0; i < items.Length; i++)
  675. {
  676. string itemValue = items[i];
  677. if (!string.IsNullOrEmpty(itemValue))
  678. {
  679. string[] pairValue = itemValue.Split('#');
  680. if (pairValue.Length == 2)
  681. {
  682. if (float.TryParse(pairValue[0], out float expectedValue)
  683. && float.TryParse(pairValue[1], out float realValue))
  684. {
  685. table.Add(Tuple.Create(realValue, expectedValue));
  686. }
  687. }
  688. }
  689. }
  690. table = table.OrderBy(x => x.Item1).ToList();
  691. var calibrationTable = new List<CalibrationItem>();
  692. for (int i = 0; i < table.Count; i++)
  693. {
  694. if (((double)table[0].Item1) > Range) continue;
  695. if (i == 0 && table[0].Item1 > 0.001)
  696. {
  697. calibrationTable.Add(new CalibrationItem()
  698. {
  699. RawFrom = 0,
  700. CalibrationFrom = 0,
  701. RawTo = table[0].Item1,
  702. CalibrationTo = table[0].Item2,
  703. });
  704. }
  705. if (i == table.Count - 1)
  706. {
  707. continue;
  708. }
  709. calibrationTable.Add(new CalibrationItem()
  710. {
  711. RawFrom = table[i].Item1,
  712. CalibrationFrom = table[i].Item2,
  713. RawTo = table[i + 1].Item1,
  714. CalibrationTo = table[i + 1].Item2,
  715. });
  716. }
  717. _calibrationTable = calibrationTable;
  718. }
  719. private float CalibrationData(float value, bool output)
  720. {
  721. //default enable
  722. if (_scEnableCalibration != null && !_scEnableCalibration.BoolValue)
  723. return value;
  724. if (_scCalibrationTable == null || !_calibrationTable.Any())
  725. return value;
  726. float ret = value > Range ? (float)Range : value;
  727. if (output)
  728. {
  729. var item = _calibrationTable.FirstOrDefault(x => x.RawFrom <= value && x.RawTo >= value);
  730. if (item == null)
  731. {
  732. item = _calibrationTable.Last();
  733. if (!_isWarned)
  734. {
  735. EV.PostWarningLog(_uniqueName, $"No calibration map for {value}");
  736. _isWarned = true;
  737. }
  738. }
  739. if (Math.Abs(item.RawTo - item.RawFrom) > 0.01)
  740. {
  741. var slope = Math.Abs((item.CalibrationTo - item.CalibrationFrom) / (item.RawTo - item.RawFrom));
  742. ret = (ret - item.RawFrom) * slope + item.CalibrationFrom;
  743. }
  744. }
  745. else
  746. {
  747. var item = _calibrationTable.FirstOrDefault(x => x.CalibrationFrom <= value && x.CalibrationTo >= value);
  748. if (item == null)
  749. {
  750. item = _calibrationTable.Last();
  751. if (!_isWarned)
  752. {
  753. EV.PostWarningLog(_uniqueName, $"No calibration map for {value}");
  754. _isWarned = true;
  755. }
  756. }
  757. if (Math.Abs(item.CalibrationTo - item.CalibrationFrom) > 0.01)
  758. {
  759. var slope = Math.Abs((item.RawTo - item.RawFrom) / (item.CalibrationTo - item.CalibrationFrom));
  760. ret = (ret - item.CalibrationFrom) * slope + item.RawFrom;
  761. }
  762. }
  763. if (ret < 0)
  764. return 0;
  765. if (ret >= float.MaxValue || ret > Range)
  766. ret = value;
  767. return ret;
  768. }
  769. private void SaveSetPoint(string temperature)
  770. {
  771. SC.SetItemValueFromString($"{_scRoot}.{Name}.SetPoint", temperature);
  772. }
  773. private void SaveRampRate(string ramping)
  774. {
  775. SC.SetItemValueFromString($"{_scRoot}.{Name}.RampRate", ramping);
  776. }
  777. public override void SetEnable(bool isEnable)
  778. {
  779. _doEnable?.SetValue(isEnable, out _);
  780. if (_aoEnableIn != null)
  781. {
  782. _aoEnableIn.FloatValue = isEnable ? 1 : 0;
  783. }
  784. }
  785. }
  786. }