| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- using System;
- using System.Linq;
- using SHJX.Service.Dao;
- using System.Threading;
- using System.Diagnostics;
- using SHJX.Service.Model.Dao;
- using SHJX.Service.Model.Control;
- using System.Collections.Generic;
- using SHJX.Service.Common.Camera;
- using SHJX.Service.Control.Modules;
- using SHJX.Service.Common.Calculate;
- using SHJX.Service.Control.Interface;
- using SHJX.Service.Common.UserDelegate;
- using SHJX.Service.Common.Logging;
- using Microsoft.Extensions.Logging;
- using SHJX.Service.Common.ReadXML;
- namespace SHJX.Service.Control.Route.RouteController
- {
- /// <summary>
- /// 开始滴定
- /// </summary>
- /// 硫酸亚铁铵
- public class TitrationOperate : FlowControlOperateImp
- {
- private static readonly ILogger logger = LogFactory.BuildLogger(typeof(TitrationOperate));
- private const string OpName = "FAS";
- private int _signalTimeLen;
- private int _titrationCount;
- private double _amountValue;
- private DropLiquid _liquid;
- private ColorDataGraber _graber;
- private WriteWay _concentrationType;
- private TitrationValue _balanceVals;
- private OperateDataManager _dataManager;
- private string DripNozzleType = "DripNozzle";
- public virtual bool Operate(ReadConfigUtil config, DataEventArgs data)
- {
- _graber = data.LiquidDrop.Graber;
- //if (data.Task.SampleConcentration == "High" || data.Task.To == "D4")
- // { DripNozzleType = "DripNozzle2";
- // _graber = data.LiquidDrop2.Graber;
- //}
- _liquid = data.DataManager.QueryLiquid(OpName);
- if (!_liquid.Enable)
- {
- var dripNozzleRes = DataCentre.GetStorageContent.Factory(DripNozzleType).Stop();
- return dripNozzleRes;
- }
-
- _signalTimeLen = 10;
- _titrationCount = 0;
- _dataManager = data.DataManager;
- _balanceVals = DataCentre.GetBalanceValue;
- var res = data.Task.RouteType switch
- {
- "Wash" => WashLiquid(data),
- _ => SampleDropLiquid(data),
- };
- DataCentre.GetStorageContent.Factory(DripNozzleType).Stop(); // WriteDrip(data);
- return res;
- }
- /// <summary>
- /// 润洗 && 清洗
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- private bool WashLiquid(DataEventArgs data)
- {
- logger.LogInformation("进入润洗(清洗)流程");
- var value = data.Task.TaskType switch
- {
- "润洗" => _liquid.WashVolume,
- "清洗" => _liquid.ClearVolume,
- _ => throw new ArgumentNullException(data.Task.TaskType),
- };
- string[] types = new string[] { "Low", "High" };
- bool res = true;
- foreach (var item in types)
- {
- (_concentrationType, _amountValue) = item switch
- {
- "Low" => (WriteWay.Normotopia, DataCentre.GetConfig.DropOnceAmounts.FirstOrDefault(item => item.Name.Equals("FAS")).LowValue),
- "High" => (WriteWay.Antiposition, DataCentre.GetConfig.DropOnceAmounts.FirstOrDefault(item => item.Name.Equals("FAS")).HighValue),
- _ => throw new ArgumentNullException(data.Task.SampleConcentration),
- };
- ConvertConcentration(_concentrationType);
- var distance = Convert.ToInt64(Math.Round(value / _amountValue * 20000));
- var portArgs = new PortArgs()
- {
- TypeName = OpName,
- WriteWay = WriteWay.Move,
- Distance = distance
- };
- if (data.Task.TaskType== "清洗")
- {
- res = res && DataCentre.GetClient.Factory(OpName).Write(portArgs);
- Thread.Sleep((int)(distance / 20000 * 600));
- }
- if (data.Task.TaskType == "润洗")
- {
- portArgs.Distance *= -1;
- res = res && DataCentre.GetClient.Factory(OpName).Write(portArgs);
- Thread.Sleep((int)(distance / 20000 * 600));
- portArgs.Distance *= -11/10;
- res = res && DataCentre.GetClient.Factory(OpName).Write(portArgs);
- Thread.Sleep((int)(distance / 20000 * 700));
- }
- string liquidname = "FAS";
- if (data.Task.SampleConcentration == "High")
- {
- liquidname = "FAS2";
- }
- LiquidTotal liquid1 = DataCentre._dataManager.Query<LiquidTotal>().Where(it => it.LiquidName.Equals(liquidname)).First();
- liquid1.Total -= value; //硫酸亚铁铵(高)减去20体积
- res = res && DataCentre._dataManager.Update<LiquidTotal>(liquid1) > 0;
- }
-
- logger.LogInformation("润洗(清洗)流程完成");
- return res;
- }
- /// <summary>
- /// 液体滴定
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- private bool SampleDropLiquid(DataEventArgs data)
- {
- (_concentrationType, _amountValue) = data.Task.SampleConcentration switch
- {
- "Low" => (WriteWay.Normotopia, DataCentre.GetConfig.DropOnceAmounts.FirstOrDefault(item => item.Name.Equals("FAS")).LowValue),
- "High" => (WriteWay.Antiposition, DataCentre.GetConfig.DropOnceAmounts.FirstOrDefault(item => item.Name.Equals("FAS")).HighValue),
- _ => throw new ArgumentNullException(data.Task.SampleConcentration),
- };
- ConvertConcentration(_concentrationType);
- var res = true;
-
- data.LiquidDrop.Camera.OpenCamera();
- using (TitrationStirOperate ts = new())
- {
- if (ts.StartStir)
- {
- Thread.Sleep(1000 * _balanceVals.BeforeWaitTime);//滴定之前等待时间
- var task = data.Task;
- AdjustCamera(task.SampleConcentration);
- StartDropLiquid(ref task);
-
- data.Task = task;
- CalculateResult(task); //滴定完成需做计算
- }
- else
- {
- res = ts.StartStir;
- }
- }
- string liquidname = "FAS";
- if (data.Task.SampleConcentration == "High")
- {
- liquidname = "FAS2";
- }
- LiquidTotal liquid1 = DataCentre._dataManager.Query<LiquidTotal>().Where(it => it.LiquidName.Equals(liquidname)).First();
- liquid1.Total -= data.Task.Amount; //硫酸亚铁铵(低)减去滴定体积
- res = res && DataCentre._dataManager.Update<LiquidTotal>(liquid1) > 0;
-
-
- Messager.Send("DropEnd");
- return res;
- }
- /// <summary>
- /// 液体滴定
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- public bool ManualSampleDropLiquid(Dictionary<string ,string> data1)
- {
- EquipmentTask task1 = new EquipmentTask();
- var data2 = task1.GetDataArgs();
- data2.Task.QuickTitration = Convert.ToBoolean(data1["IfFastDiding"]);
- _graber = data2.LiquidDrop.Graber;
- _liquid = data2.DataManager.QueryLiquid(OpName);
- if (!_liquid.Enable)
- {
- var dripNozzleRes = DataCentre.GetStorageContent.Factory(DripNozzleType).Stop();
- return dripNozzleRes;
- }
- _signalTimeLen = 10;
- _titrationCount = 0;
- _dataManager = data2.DataManager;
- _balanceVals = DataCentre.GetBalanceValue;
- _balanceVals.LowValue = Convert.ToDouble(data1["YuZhiValue"]);
- _balanceVals.HighValue = Convert.ToDouble(data1["YuZhiValue"]);
- _balanceVals.MaxVolume = Convert.ToDouble(data1["MaxTiJiValue"]);
- _balanceVals.AfterWaitTime = Convert.ToInt32(data1["CheckTimeValue"]);
- _balanceVals.QuickTitrationValue = Convert.ToDouble(data1["FastDidingValue"]);
- data2.Task.SampleConcentration = data1["NongDuValue"] switch
- {
- "低" =>"Low",
- "高" =>"High",
- _ => throw new ArgumentNullException(data1["NongDuValue"]),
- };
- (_concentrationType, _amountValue) = data2.Task.SampleConcentration switch
- {
- "Low" => (WriteWay.Normotopia, Convert.ToDouble(data1["DropAmountValue"])),
- "High" => (WriteWay.Antiposition, Convert.ToDouble(data1["DropAmountValue"])),
- _ => throw new ArgumentNullException(data2.Task.SampleConcentration),
- };
- ConvertConcentration(_concentrationType);
- var res = true;
- data2.LiquidDrop.Camera.OpenCamera();
- using (TitrationStirOperate ts = new())
- {
- if (ts.StartStir)
- {
- Thread.Sleep(1000 * Convert.ToInt32( data1["DengDaiTimeValue"] ));//滴定之前等待时间
- var task = data2.Task;
- AdjustCamera(task.SampleConcentration);
- StartDropLiquid(ref task);
- data2.Task = task;
- CalculateResult(task); //滴定完成需做计算
- }
- else
- {
- res = ts.StartStir;
- }
- }
- LiquidTotal liquid1 = DataCentre._dataManager.Query<LiquidTotal>().Where(it => it.LiquidName.Equals("FAS")).First();
- liquid1.Total -= data2.Task.Amount; //硫酸亚铁铵(低)减去滴定体积
- res = res && DataCentre._dataManager.Update<LiquidTotal>(liquid1) > 0;
- Messager.Send("DropEnd");
- Messager.Send("DropEndWindows");
- return res;
- }
- /// <summary>
- /// 滴定开始
- /// </summary>
- private void StartDropLiquid(ref EquipmentTask task)
- {
- try
- {
- var jumpCount = 0; //突跃次数
- var slowSpeedCount = 0; //减速次数
- var isRunning = true;
- var balanceVal = GetBalanceVal(task);
- var currSignals = new List<ColorDataPoint>(); // 信号队列
- for (var i = 0; i < 7; i++)
- {
- currSignals.Add(_graber.GrabSignal(500)); // 采集7段信号作为背景
- }
- PortArgs portArgs = new()
- {
- TypeName = OpName,
- WriteWay = WriteWay.Move
- };
- //快速滴定
- if (task.QuickTitration)
- {
- var quickValue = Convert.ToInt32(Math.Round(_balanceVals.QuickTitrationValue / _amountValue * 20000));
- portArgs.Distance = quickValue;
- var res = true;
- do
- {
- res = DataCentre.GetClient.Factory(OpName).Write(portArgs);
- if (res)
- {
- task.Amount += _balanceVals.QuickTitrationValue;
- }
- logger.LogInformation($"快速滴定一次性写入{quickValue},写入{(res ? "成功" : "失败")}");
- } while (!res);
- Thread.Sleep(5 * 1000);
- logger.LogInformation("等待五秒");
- }
- while (true)
- {
- if (!isRunning) break;
- if (task.Amount >= _balanceVals.MaxVolume) break;
- #region 滴液
- portArgs.Distance = 20000;
- var res = DataCentre.GetClient.Factory(OpName).Write(portArgs);
- if (!res)
- {
- logger.LogInformation("写入失败,等待两秒后再次写入");
- Thread.Sleep(2000);
- continue;
- }
- _titrationCount += 1;
- task.Amount += _amountValue;
- #endregion
- #region 摄像头采集信号
- if (_titrationCount.Equals(currSignals.Count - 7))
- {
- currSignals[currSignals.Count - 1] = _graber.GrabSignal(_signalTimeLen);
- }
- else
- {
- currSignals.Add(_graber.GrabSignal(_signalTimeLen));
- }
- #endregion
- #region 颜色信号判断
- if (currSignals.Count >= 7) // 信号判断
- {
- var currpt = currSignals.Count - 7; // 计算起点
- var subB = (currSignals[currpt + 6].GetBSV() - (currSignals[currpt + 0].GetBSV() +
- currSignals[currpt + 1].GetBSV()) / 2) * 100 / currSignals[currpt + 6].GetBSV();
- logger.LogInformation($"当前第{_titrationCount:D3}滴,体积为:{ task.Amount:F3},滴定阈值获取为{subB:F3}");
- Dictionary<string, double> dropValueArg = new()
- {
- { "Count", _titrationCount },
- { "Amount", task.Amount },
- { "BlueValue", subB }
- };
- Messager.Send("DropValue", dropValueArg);
- if (subB <= balanceVal)
- {
- jumpCount++;
- var swten = new Stopwatch();
- swten.Start();
- var retreatCount = 1; //后退次数
- while (true) // 继续采集信号,监测是否褪色
- {
- currSignals[currpt + 6] = _graber.GrabSignal(_signalTimeLen);
- subB = (currSignals[currpt + 6].GetBSV() -
- (currSignals[currpt + 0].GetBSV() + currSignals[currpt + 1].GetBSV()) / 2) *
- 100 / currSignals[currpt + 6].GetBSV();
- logger.LogInformation($"检测已到达设定阈值,观察是否褪色,观察阈值为{subB:F3}");
- if (subB <= balanceVal * 0.7)
- {
- retreatCount++;
- if (retreatCount > _balanceVals.AfterWaitTime)
- {
- break;
- }
- isRunning = false;
- Thread.Sleep(1000);
- continue; // 未褪色,继续监测
- }
- isRunning = true; //当检测到的信号值 大于阈值时,则滴定未结束,需要继续滴定
- if (retreatCount > 3)
- {
- slowSpeedCount = 10; //如果回退超过三次判定,则给定慢速10次
- }
- break;
- }
- swten.Stop();
- }
- else
- {
- jumpCount = jumpCount > 0 ? jumpCount - 1 : 0;
- slowSpeedCount = slowSpeedCount > 0 ? slowSpeedCount - 1 : slowSpeedCount;
- }
- }
- #endregion
- Thread.Sleep((jumpCount <= 1 && slowSpeedCount <= 1) ? 800 : 3000);
- }
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- }
- /// <summary>
- /// 获取液体滴定阈值
- /// </summary>
- private double GetBalanceVal(EquipmentTask task)
- {
- var balanceVal = task.SampleConcentration switch
- {
- "Low" => _balanceVals.LowValue * -1,
- "High" => _balanceVals.HighValue * -1,
- _ => throw new ArgumentNullException(task.SampleConcentration)
- };
- return balanceVal;
- }
- /// <summary>
- /// 摄像头调整
- /// </summary>
- private void AdjustCamera(string level)
- {
- _graber.IsNoFiredEvent = true; // 调节曝光参数
- if (TitrationSettings.SensorPara.UseAutoUpdateRoiPos)
- {
- _graber.UpdateRoiPos(writeFlag: false);
- }
- switch (level)
- {
- case "Low":
- _graber.PresetLightParam();
- break;
- case "High":
- _graber.WebCam.SetProperties(AForge.Video.DirectShow.CameraControlProperty.Exposure, -3, AForge.Video.DirectShow.CameraControlFlags.Manual);
- Thread.Sleep(2000);
- _graber.WebCam.GetProperties(AForge.Video.DirectShow.CameraControlProperty.Exposure, out var value, out var flags);
- logger.LogInformation($"高浓度设置了曝光值 ---> -2,当前曝光值为:{value}");
- break;
- }
- _graber.IsNoFiredEvent = false;
- }
- /// <summary>
- /// 切换高低浓度
- /// </summary>
- /// <param name="way"></param>
- private bool ConvertConcentration(WriteWay way)
- {
- PortArgs switchArg = new()
- {
- TypeName = OpName,
- WriteWay = way
- };
- return DataCentre.GetClient.Factory(OpName).Write(switchArg);
- }
- private static bool ConvertConcentrationM(WriteWay way)
- {
- PortArgs switchArg = new()
- {
- TypeName = OpName,
- WriteWay = way
- };
- return DataCentre.GetClient.Factory(OpName).Write(switchArg);
- }
- /// <summary>
- /// 计算结果
- /// </summary>
- private bool CalculateResult(EquipmentTask task)
- {
- try
- {
- task.Result = task.TaskType switch
- {
- "水样" => GetSampleResult(task),
- "空白" => 0,
- "标定" => 0,
- _ => throw new ArgumentNullException(task.TaskType),
- };
- task.Result = Math.Round(task.Result, 2);
- //这里是要在界面显示的样子
-
- task.Result= task.Result < 0 ? 0 : task.Result;
- task.Udf1 = task.SampleConcentration.Equals("Low") ? 0 < task.Result && task.Result < 4 ? "ND" : task.Result.ToString() : task.Result.ToString();
- //task.Udf1 = task.Result.ToString();
- task.Amount = Convert.ToDouble(Math.Round((decimal)task.Amount, 2));
- _dataManager.Update(task);
- var resultArg = new Dictionary<string, string>
- {
- {"LocalName", task.OriginLocalName},
- {"Volume", Math.Round((decimal)task.Amount, 2).ToString()},
- {"Result", task.Udf1}
- };
- //通知更新
- Messager.Send("SampleResult", resultArg);
- return true;
- }
- catch (Exception)
- {
- return false;
- }
- }
- /// <summary>
- /// 获取水样的结果
- /// </summary>
- /// <param name="task"></param>
- /// <returns></returns>
- /// 计算公式 :ρ=((V * ( V0 - V1 ) * 8000 )/ V2 )* f
- public double GetSampleResult(EquipmentTask task)
- {
- var blankTasks = _dataManager.GetTaskByWaveKey(task.WaveKey, task.SampleConcentration, "空白") ?? _dataManager.GetLastOtherTaskByWaveKey("空白", task.SampleConcentration);
- SampleCalculate.tempCount = 0;
- blankTasks.GeBlankTaskResult(_balanceVals.MaxVolume, out var noneValue);
- var bdTasks = _dataManager.GetTaskByWaveKey(task.WaveKey, task.SampleConcentration, "标定") ?? _dataManager.GetLastOtherTaskByWaveKey("标定", task.SampleConcentration);
- bdTasks.GetBDTaskResult(_balanceVals.MaxVolume, task.SampleConcentration, out var bdValue);
- //var bdValue = 0.0;
- var Taskvolumn = Math.Round(task.Amount, 2);
- //计算参数 C:硫酸亚铁铵浓度
- double avgValue = bdValue * (noneValue - Taskvolumn) * 8000 / 10 * task.GetSampleMultiple;
- return avgValue;
- }
- #if false
- /// <summary>
- /// 获取空白样的结果
- /// </summary>
- /// <param name="noneTasks"></param>
- /// <param name="noneValue"></param>
- private void GetNoneTaskResult(List<EquipmentTask> noneTasks, out double noneValue)
- {
- if (noneTasks?.Count > 1)
- {
- var noneMaxValue = noneTasks.Max(item => item.Amount);
- var noneMinValue = noneTasks.Min(item => item.Amount);
- if (noneMaxValue - noneMinValue <= 0.5)
- {
- noneValue = noneTasks.Average(item => item.Amount);
- return;
- }
- if (noneMaxValue >= _balanceVals.MaxVolume)
- {
- GetNoneTaskResult(noneTasks.Where(item => item.Amount != noneMaxValue).ToList(), out noneValue);
- }
- else
- {
- noneValue = noneMaxValue;
- }
- }
- else
- {
- var first = noneTasks?.FirstOrDefault();
- noneValue = first?.Amount ?? 0;
- }
- }
- #endif
- public void CheckCamera(string level,string final)
- {
- EquipmentTask task1 = new EquipmentTask();
- var data2 = task1.GetDataArgs();
- _graber = data2.LiquidDrop.Graber;
- _graber.IsNoFiredEvent = true; // 调节曝光参数
- if (TitrationSettings.SensorPara.UseAutoUpdateRoiPos)
- {
- _graber.UpdateRoiPos(writeFlag: false);
- }
- switch (level)
- {
- case "低":
- _graber.PresetLightParammanual(Convert.ToInt32(final));
- break;
- case "High":
- _graber.WebCam.SetProperties(AForge.Video.DirectShow.CameraControlProperty.Exposure, -3, AForge.Video.DirectShow.CameraControlFlags.Manual);
- Thread.Sleep(2000);
- _graber.WebCam.GetProperties(AForge.Video.DirectShow.CameraControlProperty.Exposure, out var value, out var flags);
- logger.LogInformation($"高浓度设置了曝光值 ---> -2,当前曝光值为:{value}");
- break;
- }
- _graber.IsNoFiredEvent = false;
- }
- }
- }
|