IoHeaterBand.cs 36 KB

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