IoHeaterBand2.cs 35 KB

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