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
{
///
/// 开始滴定
///
/// 硫酸亚铁铵
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;
}
///
/// 润洗 && 清洗
///
///
///
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().Where(it => it.LiquidName.Equals(liquidname)).First();
liquid1.Total -= value; //硫酸亚铁铵(高)减去20体积
res = res && DataCentre._dataManager.Update(liquid1) > 0;
}
logger.LogInformation("润洗(清洗)流程完成");
return res;
}
///
/// 液体滴定
///
///
///
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().Where(it => it.LiquidName.Equals(liquidname)).First();
liquid1.Total -= data.Task.Amount; //硫酸亚铁铵(低)减去滴定体积
res = res && DataCentre._dataManager.Update(liquid1) > 0;
Messager.Send("DropEnd");
return res;
}
///
/// 液体滴定
///
///
///
public bool ManualSampleDropLiquid(Dictionary 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().Where(it => it.LiquidName.Equals("FAS")).First();
liquid1.Total -= data2.Task.Amount; //硫酸亚铁铵(低)减去滴定体积
res = res && DataCentre._dataManager.Update(liquid1) > 0;
Messager.Send("DropEnd");
Messager.Send("DropEndWindows");
return res;
}
///
/// 滴定开始
///
private void StartDropLiquid(ref EquipmentTask task)
{
try
{
var jumpCount = 0; //突跃次数
var slowSpeedCount = 0; //减速次数
var isRunning = true;
var balanceVal = GetBalanceVal(task);
var currSignals = new List(); // 信号队列
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 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);
}
}
///
/// 获取液体滴定阈值
///
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;
}
///
/// 摄像头调整
///
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;
}
///
/// 切换高低浓度
///
///
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);
}
///
/// 计算结果
///
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
{
{"LocalName", task.OriginLocalName},
{"Volume", Math.Round((decimal)task.Amount, 2).ToString()},
{"Result", task.Udf1}
};
//通知更新
Messager.Send("SampleResult", resultArg);
return true;
}
catch (Exception)
{
return false;
}
}
///
/// 获取水样的结果
///
///
///
/// 计算公式 :ρ=((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
///
/// 获取空白样的结果
///
///
///
private void GetNoneTaskResult(List 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;
}
}
}