using AutoMapper; using FLY.Thick.Base.Common; using FLY.Thick.Base.Server; using FLY.Thick.Blowing.Common; using FLY.Thick.Blowing.IService; using FLY.Thick.Blowing.Server.Model; using FlyADBase; using FObjBase; using FObjBase.Reflect; using MathNet.Numerics.LinearAlgebra.Double; using Misc; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; namespace FLY.Thick.Blowing.Server { /// /// /// public class GM_BlowingFix : GM_Base, IBlowingFixService { NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); const int MARKNO_PROFILE_ADD = 87; const int MARKNO_PROFILE_CHANGED = 88; //OrgHistoryDb orgHistoryDb; HistoryDb historyDb; BulkDb bulkDb; #region 延时操作,markno const int MARKNO_CALFRAME = 2; #endregion /// /// 人字架角度 & 膜走带位置检测 /// public BlowingDetect mPDetect; #region IRenZiJiaService #region 分区设定 /// /// 加热通道数 /// public int ChannelCnt { get; set; } = 88; /// /// 分区数/加热通道数 /// public int BPC { get; set; } = 1; /// /// 风环螺丝数 /// public int NBolts => ChannelCnt * BPC; /// /// 复位时,探头测量的位置对应分区号 /// public int OrgBoltNo { get; set; } = 1; /// /// 第1个螺丝号 /// public int BoltNo1st = 1; /// /// 使用分区表 /// public bool IsUsedMap { get; set; } bool IsNeedMap() { if (IsUsedMap && Map != null && Map.Count() > 0) return true; else return false; } private BoltMapCell[] map; /// /// 分区表,必须保证不能为null /// public BoltMapCell[] Map { get { return map; } set { //检测是否不一样 if (!IsEquals(map, value)) { if (!IsValid(value)) { IsUsedMap = false; map = null; } else { map = value; } } } } #endregion /// /// 测厚仪类型, 追边 or 扫描 /// public BlowingType BType { get; } = BlowingType.Fix; /// /// 测厚仪测量点位置方向:Left, Right (也就是三角形在左还是右) /// public bool IsProbeRight { get; set; } = true; /// /// 应用 /// public void Apply() { Save(); } [Push(typeof(RenZiJiaDataEventArgs))] public event EventHandler DataEvent; #endregion #region 吹膜定点解方程用 /// /// 测量模式, 决定是否解方程 /// public MeasureMode MMode { get; set; } = MeasureMode.Edge; /// /// 膜宽 单位 mm /// public int FilmWidth { get; set; } = 1500; /// /// 探头所在膜的横向位置 单位 mm /// public int FilmPosH { get; set; } = 70; #endregion DynArea mDynArea; BlowingFixProfileParam mProfileParam; /// /// 当前正在处理的 ADList 里面的数据.No /// int mADListToDoNo; /// /// 处理放入filminfo 的数据.No /// int mADListToDoNo_ToFilmInfo; /// /// 1s一个数据, /// RList mADList; /// /// 1条方程 /// class Formula { /// /// n元方程 /// public int n; /// /// 方程 xi前面的 ai /// public double[] ai; /// /// 方程 y 值 /// public double y; public Formula(int no_x) { int i; n = no_x; ai = new double[no_x]; for (i = 0; i < n; i++) ai[i] = 0; y = 0; } public bool AddData(IEnumerable idxs, double thk) { foreach (int idx in idxs) if ((idx < 0) || (idx >= n)) return false; foreach (int idx in idxs) ai[idx]++; y += thk; return true; } } class FRAME_INFO//一幅数据信息 { public DateTime StartTime;//开始时间 public DateTime EndTime;//结束时间 public int NoStartAD;//在AD列表 处理的数据开始点 public int NoEndAD;//在AD列表 处理的数据结束点 public DIRECTION direction;//当前幅数据,方向 public double velocity;//线速度 m/min public int rotationCnt;//人字架旋转次数 /// /// 对应数据库的 id /// public Int64? scandata_id = null; /// /// 分区数据 N*long /// public double[] frame; /// /// 经过分区表后的结果 /// public double[] frame_map; /// /// 推送出去的数据,也是数据库中的数据 /// public RenZiJiaDataEventArgs renZiJiaDataEventArgs; /// /// 推送出去的数据 被修改了 /// public bool renZiJiaDataEventArgsHasChanged = false; double frame_sum = 0; int frame_cnt = 0; static int virtual_nbolts = 88; static List virtual_formulas = new List(); static void UpdateVirtualFormulas() { virtual_formulas.Clear(); for (int i = 0; i < virtual_nbolts; i++) { int boltindex1 = i; int boltindex2 = i + 1; if (boltindex2 >= virtual_nbolts) boltindex2 = 0; Formula fm = new Formula(virtual_nbolts); fm.ai[boltindex1] = 1; fm.ai[boltindex2] = -1; virtual_formulas.Add(fm); } } static FRAME_INFO() { UpdateVirtualFormulas(); } public void SetNBolt(int nbolts) { frame = new double[nbolts]; appeared = new bool[nbolts]; for (int i = 0; i < nbolts; i++) { ClearFrameValue(i); } } void ClearFrameValue(int index) { frame[index] = double.NaN; appeared[index] = false; } public void Clear() { for (int i = 0; i < frame.Count(); i++) { ClearFrameValue(i); } IsValid = true; HasChanged = true; index_last = -1; frame_cnt = 0; frame_sum = 0; mFormulas.Clear(); last_solvedt = DateTime.MinValue; isTimeToSolve = false; canSolve = false; } public bool HasChanged = false;//数据被改变了!!!,是时候更新bulkdata public bool IsValid = true;//是合法数据 /// /// 提交,完成一次操作。清除状态 /// public void Submit() { HasChanged = false; } public void CheckForValid() { if (rotationCnt == 0)//旋转次数=0,肯定是不完整的数据 { HasChanged = true; IsValid = false; return; } //所有的数据都应该大于10 for (int i = 0; i < frame.Count(); i++) { if (!double.IsNaN(frame[i])) { if (frame[i] < 10.0) { HasChanged = true; IsValid = false; return; } } } } /// /// 上一次解方程的时间 /// DateTime last_solvedt = DateTime.MinValue; /// /// 是时候解方程 /// bool isTimeToSolve = false; /// /// 方程多了,能解方程 /// bool canSolve = false; /// /// 每个区号,是否有出现 /// bool[] appeared; /// /// 方程组 /// List mFormulas = new List(); public void SolveFormula() { if (!canSolve)//没有新方程,没法解 return; int nbolts = frame.Count(); if (virtual_nbolts != nbolts) { virtual_nbolts = nbolts; UpdateVirtualFormulas(); } //TODO 能否解得方程检查 int nrow = mFormulas.Count() + virtual_formulas.Count(); //if (nrow < NBolts) return; //Console.WriteLine("Total get {0} formular", nrow); //转换为 DenseMatrix 与 DenseVector DenseMatrix matrixA = new DenseMatrix(nrow, nbolts); DenseMatrix matrixAT = new DenseMatrix(nbolts, nrow); DenseVector vectorB = new DenseVector(nrow); int rowindex = 0; foreach (Formula fm in mFormulas) { matrixA.SetRow(rowindex, fm.ai); matrixAT.SetColumn(rowindex, fm.ai); vectorB[rowindex] = fm.y; rowindex++; } foreach (Formula fm in virtual_formulas) { matrixA.SetRow(rowindex, fm.ai); matrixAT.SetColumn(rowindex, fm.ai); vectorB[rowindex] = fm.y; rowindex++; } DenseMatrix ATA = (DenseMatrix)matrixA.TransposeThisAndMultiply(matrixA); DenseVector ATB = (DenseVector)matrixA.TransposeThisAndMultiply(vectorB); DenseVector X = (DenseVector)ATA.Solve(ATB); for (int i = 0; i < nbolts; i++) { double d = (appeared[i]) ? X[i] : double.NaN; frame[i] = d; } HasChanged = true; isTimeToSolve = false; canSolve = false; } /// /// 检查是否需要更新 /// public void CheckToSolveFormula() { if (isTimeToSolve) { SolveFormula(); } } int index_last = -1; public void SetFrameValue(int index, double value, DateTime dt) { int nbolts = frame.Count(); if (index >= nbolts) return;//异常 else if (index < 0) return;//异常 else if (double.IsNaN(value)) return;//异常 if (index_last != index) { index_last = index; HasChanged = true; frame_cnt = 0; frame_sum = 0; } frame_sum += value; frame_cnt++; frame[index] = frame_sum / frame_cnt; } /// /// 解方程方式更新 frame /// /// /// /// public void SetFrameValue(IEnumerable indexs, double value, DateTime dt) { int nbolts = frame.Count(); foreach (int index in indexs) { if (index >= nbolts) return;//异常 else if (index < 0) return;//异常 } if (double.IsNaN(value)) return;//异常 Formula fm = new Formula(nbolts); fm.AddData(indexs, value); mFormulas.Add(fm); foreach (int index in indexs) appeared[index] = true; canSolve = true; //5秒解一次方程 if ((index_last != indexs.First()) && ((dt - last_solvedt) >= TimeSpan.FromSeconds(5))) { index_last = indexs.First(); last_solvedt = dt; isTimeToSolve = true; } } } RList mFrameInfoList; AD2ThkHandler Ad2Thk; void checkParamErr() { if (ChannelCnt < 20 || ChannelCnt > 160) { ChannelCnt = 44; } if (BPC < 1 || BPC > 4) { BPC = 2; } if (OrgBoltNo < 1 || OrgBoltNo > NBolts) { OrgBoltNo = 1; } if (!IsValid(Map)) { IsUsedMap = false; Map = null; } } /// /// 检测通过,返回true /// /// bool IsValid(BoltMapCell[] mapCells) { bool map_err = false; bool g_o = false; bool g_n = false; if (mapCells == null) return true; //Map 检测 //OldNo,NewNo不能 <1 >NBolts //Map OldNo 必须从小到大环形排列 //Map NewNo 必须从小到大环形排列 for (int i = 0; i < mapCells.Count(); i++) { var mapCell = mapCells[i]; if (mapCell.NewNo < 1 || mapCell.NewNo > NBolts) { map_err = true; break; } if (mapCell.OldNo < 1 || mapCell.OldNo > NBolts) { map_err = true; break; } int i_next = i + 1; if (i_next >= mapCells.Count()) i_next = 0; var mapCell_next = mapCells[i_next]; if (mapCell.OldNo >= mapCell_next.OldNo) { if (!g_o) g_o = true; else { map_err = true; break; } } if (mapCell.NewNo >= mapCell_next.NewNo) { if (!g_n) g_n = true; else { map_err = true; break; } } } if (map_err) { return false; } else { return true; } } bool IsEquals(BoltMapCell c1, BoltMapCell c2) { if (c1 == c2) { return true; } if (c1 == null && c2 != null) return false; if (c1 != null && c2 == null) return false; if (c1.NewNo != c2.NewNo) return false; if (c1.OldNo != c2.OldNo) return false; return true; } bool IsEquals(BoltMapCell[] mapCells1, BoltMapCell[] mapCells2) { if (mapCells1 == mapCells2) return true; if (mapCells1 == null && mapCells2 != null) return false; if (mapCells1 != null && mapCells2 == null) return false; if (mapCells1.Count() != mapCells2.Count()) return false; //mapCells1 与 mapCells2 肯定都不是 null 且数量一样 for (int i = 0; i < mapCells1.Count(); i++) { var c1 = mapCells1[i]; var c2 = mapCells2[i]; if (!IsEquals(c1, c2)) return false; } return true; } /// /// /// /// public GM_BlowingFix(FlyAD7 flyad) : base(flyad) { GMState = CTRL_STATE.FIX; mPDetect = new BlowingDetect(); mPDetect.Load(); Load(); //检测参数 mPDetect.CheckParamErr(); checkParamErr(); InitList(); PropertyChanged += new PropertyChangedEventHandler(RenZiJiaFix_PropertyChanged); mPDetect.FilmInfoChangedEvent += new FilmInfoChangedEventHandler(mPDetect_FilmInfoChangedEvent); mPDetect.ClearEvent += new ClearEventHandler(mPDetect_ClearEvent); mFlyAD.TimeGridEvent += new FlyADBase.TimeGridEventHandler(flyad_TimeGridEvent); mPDetect.Init(flyad); } void mPDetect_ClearEvent(object sender) { //没信号,清空所有数据!!! Clear(); } /// /// 从1幅数据,获取头部,尾部,为于 ADList 的位置 /// /// /// /// /// false 数据不存在 bool GetFilmInfoADIndex(FRAME_INFO frameinfo, out int index_start, out int index_end) { index_start = mADList.No2Index(frameinfo.NoStartAD); index_end = mADList.No2Index(frameinfo.NoEndAD); if ((index_start < 0) || (index_end < 0) || (index_start >= mADList.Count) || (index_end >= mADList.Count)) { //数据已经不存在,删除 return false; } return true; } void mPDetect_FilmInfoChangedEvent(object sender, FilmInfoChangedEventArgs e) { var ret = ADListFastSearchIndex(e.Time, out int idx); switch (ret) { case ADListFastSearchIndexResult.Before://发送在过去 { mADListToDoNo = mADList.Index2No(0); mADListToDoNo_ToFilmInfo = mADListToDoNo; } break; case ADListFastSearchIndexResult.Now://发生在列表时间内 { mADListToDoNo = mADList.Index2No(idx); mADListToDoNo_ToFilmInfo = mADListToDoNo; } break; case ADListFastSearchIndexResult.Future: { //未来的,不处理 } break; } } void RenZiJiaFix_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(NBolts)) { //所有数据删除 mFrameInfoList.Clear(); } else if (e.PropertyName == nameof(OrgBoltNo)) { //TODO 只处理3幅图 int idx = mFrameInfoList.Count - 3; if (idx < 0) idx = 0; if (idx >= mFrameInfoList.Count) return; mADListToDoNo_ToFilmInfo = mFrameInfoList[idx].NoStartAD; } else if ((e.PropertyName == nameof(FilmWidth)) || (e.PropertyName == nameof(FilmPosH)) || (e.PropertyName == nameof(MMode))) { //重新计算当前幅数据 UpdateCurrFrame(); } } public void Init( AD2ThkHandler ad2thk, DynArea dynarea, BlowingFixProfileParam profileParam, HistoryDb historyDb, BulkDb bulkDb ) { Ad2Thk = ad2thk; mDynArea = dynarea; mProfileParam = profileParam; this.historyDb = historyDb; //this.orgHistoryDb = orgHistoryDb; this.bulkDb = bulkDb; this.bulkDb.GetTempFrameAction = GetTempFrame; Misc.BindingOperations.SetBinding(mPDetect, nameof(mPDetect.FilmVelocity), mDynArea, nameof(mDynArea.FilmVelocity)); Misc.BindingOperations.SetBinding(this, nameof(NBolts), () => { //TODO: 下面这些都没有用!!!!历史遗留问题 mDynArea.NBolts = NBolts; mDynArea.FirstBoltNo = 1; mDynArea.DataBoltNoBegin = 1; mDynArea.DataBoltNoEnd = NBolts; mDynArea.ScanBoltNoBegin = 1; mDynArea.ScanBoltNoEnd = NBolts; }); mProfileParam.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(mProfileParam.K)) { //重新计算当前幅数据 UpdateCurrFrame(); } }; mDynArea.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(mDynArea.SampleAD)) { //重新计算当前幅数据 UpdateCurrFrame(); } }; //记录调试数据 MarkDebugInit(); } BulkDbTempFrameChangedEventArgs GetTempFrame() { if (mFrameInfoList.Count() > 0) { var frameInfo = mFrameInfoList.Last(); var thicks = IsNeedMap() ? frameInfo.frame_map : frameInfo.frame; return new BulkDbTempFrameChangedEventArgs() { Time = frameInfo.StartTime, EndTime = frameInfo.EndTime, StartIndex = 0, D = thicks }; } else { return new BulkDbTempFrameChangedEventArgs(); } } #region 记录测试数据 DateTime markdebug_dt = DateTime.MinValue; void MarkDebugInit() { if (markdebug_dt == DateTime.MinValue) markdebug_dt = DateTime.Now; //启动1分钟定时器 FObjBase.PollModule.Current.Poll_Config( FObjBase.PollModule.POLL_CONFIG.ADD, () => { //mPDetect.GetSignList(markdebug_dt, (asyncContext, retData) => //{ // var reponse = retData as GetSignListReponse; // var cells = reponse.datas; // if (cells.Count > 0) // { // orgHistoryDb.AddSignData( // new Lc_Sign() // { // Time = cells.First().Time, // Signs = cells.ToArray() // }); // } //}, null); //mPDetect.GetRollList(markdebug_dt, (asyncContext, retData) => //{ // var reponse = retData as GetRollListReponse; // var cells = reponse.datas; // if (cells.Count > 0) // { // orgHistoryDb.AddRollData( // new Lc_Roll() // { // Time = cells.First().dt, // Signs = cells.ToArray() // }); // } //}, null); this.GetADList(markdebug_dt, (asyncContext, retData) => { var reponse = retData as GetADListReponse; var cells = reponse.datas; if (cells.Count > 0) { var thicks = cells.Select(c => c.thk).ToArray(); historyDb.AddTrendData( new Lc_TrendData() { Time = cells.First().dt, K = mProfileParam.K, Thicks = thicks }); } }, null); markdebug_dt = DateTime.Now; }, TimeSpan.FromMinutes(1)); } #endregion void UpdateCurrFrame() { FObjBase.PollModule.Current.Poll_JustOnce( new FObjBase.PollModule.PollHandler(delegate () { if (mFrameInfoList.Count > 0) { mADListToDoNo_ToFilmInfo = mFrameInfoList.Last().NoStartAD; } }), this, MARKNO_CALFRAME); } TimeSpan datOf1s_ts = TimeSpan.Zero; TimeSpan datOf1s_interval = TimeSpan.FromSeconds(1); List datOf1s = new List();//1秒数据缓存,用于求均值 void ClearDatOf1s() { datOf1s_ts = TimeSpan.Zero; datOf1s.Clear(); } void flyad_TimeGridEvent(object sender, FlyADBase.TimeGridEventArgs e) { bool issample = false; TimeSpan ts = e.Ts;//准确 //不使用AD盒的时间 //DateTime dt = e.Time;//准确 DateTime dt = DateTime.Now;//数据的尾 int[] data = e.Data; //这个数据包的总耗时 TimeSpan data_interval = TimeSpan.FromTicks((long)(ts.TotalMilliseconds * data.Count() * TimeSpan.TicksPerMillisecond)); //这个数据包开始的时间 DateTime data_begin_dt = dt - data_interval; //当前循环处理的数据 DateTime datOf100ms_dt = data_begin_dt - ts; for (int i = 0; i < data.Length; i++) { if (issample)//采样中,数据都是无效的 { datOf1s.Add(Misc.MyBase.NULL_VALUE); } else if (data[i] > UInt16.MaxValue) { datOf1s.Add(Misc.MyBase.NULL_VALUE); } else if (data[i] < 0) { datOf1s.Add(Misc.MyBase.NULL_VALUE); } else { datOf1s.Add(data[i]); } datOf1s_ts = datOf1s_ts + ts; datOf100ms_dt = datOf100ms_dt + ts; if (datOf1s_ts >= datOf1s_interval)//1s 一个数据 { int avgad = Misc.MyBase.NULL_VALUE; if (datOf1s.Count() > 0) { avgad = Misc.MyMath.Avg(datOf1s); } else if (mADList.Count() > 0) { avgad = mADList.Last().Ad; } mADList.RAdd( new ADCell() { Time = datOf100ms_dt, Ad = avgad }); ClearDatOf1s(); } } } private void InitList()//初始化列表 { if (mADList == null) { mADList = new RList(4000); mADListToDoNo = mADList.GetLastNo(); mADListToDoNo_ToFilmInfo = mADListToDoNo; } if (mFrameInfoList == null) mFrameInfoList = new RList(6); } //复位 void Clear() { if (mADList != null) mADList.Clear(); if (mFrameInfoList != null) { mFrameInfoList.Clear(); } ClearDatOf1s(); } int Angle2BoltIndex(double angle) { if (angle < 0) { angle += 360; } int boltindex = (int)(OrgBoltNo - BoltNo1st + angle * NBolts / 360); if (boltindex >= NBolts) { boltindex -= NBolts; } else if (boltindex < 0)//不应该发生,可能是 OrgBoltNo 出错了。 { boltindex += NBolts; } return boltindex; } enum ADListFastSearchIndexResult { /// /// 时间点在列表以前; /// Before = -1, /// /// 时间点在列表中; /// Now = 0, /// /// 时间点在列表的未来; /// Future = 1 } /// /// 找到在 dt 前最近的 ADList 序号; /// 当ADList 没有数据,返回 Future; /// 已知AD列表每个数据之间的时间差,快速推断结果; /// /// /// /// ADListFastSearchIndexResult ADListFastSearchIndex(DateTime dt, out int index) { index = 0; if (mADList.Count <= 0)//列表没有数据, 只能当它在未来 return ADListFastSearchIndexResult.Future; if (dt > mADList.Last().Time) return ADListFastSearchIndexResult.Future; else if (dt < mADList.First().Time) return ADListFastSearchIndexResult.Before; else { int offset = (int)((mADList.Last().Time - dt).TotalSeconds / datOf1s_interval.TotalSeconds); index = mADList.Count - offset - 1;//大约在这个位置附近 //安全限制 if (index >= mADList.Count) index = mADList.Count() - 1; else if (index < 0) index = 0; if (mADList[index].Time == dt) { //已经找到就是它!!!! } else if (mADList[index].Time > dt) { while (true) { index--; if (index <= 0) { index = 0;//最前面一个了 break; } if (mADList[index].Time <= dt) { //找到了 break; } } } else { while (true) { index++;//测试一下 if (index >= mADList.Count) { //到顶了,不找了 index--; break; } else if (mADList[index].Time == dt) { //找到了,就是它 break; } else if (mADList[index].Time > dt) { //上一个小于,现在大于,上一个就对了 index--; break; } } } return ADListFastSearchIndexResult.Now; } } void OnPoll_UpdateADList() { int adlist_index = mADList.No2Index(mADListToDoNo); if (adlist_index >= mADList.Count) return;//没有数据需要处理 if (adlist_index < 0) adlist_index = 0; for (int i = adlist_index; i < mADList.Count; i++) { mADListToDoNo = mADList.Index2No(i); //被测膜模式选择 switch (MMode) { case MeasureMode.Normal: { if (!OnPoll_UpdateADList_Normal(i)) return; } break; default: //case MeasureMode.Edge: { if (!OnPoll_UpdateADList_Edge(i)) return; } break; } } mADListToDoNo = mADList.Index2No(mADList.Count); } #region 不同测量模式的ADList数据更新 bool OnPoll_UpdateADList_Edge(int idx) { FilmInfo filminfo; int ret = mPDetect.GetFilmInfo(out filminfo, mADList[idx].Time, 2.3, 0); if (ret == 1)//发生在未来 { return false; } if (filminfo == null)//异常,FilmPosH 错误 { return false; } if (mADListToDoNo != mADList.Index2No(idx))//触发了事件 { return false; } ADCell adcell = mADList[idx]; adcell.Angles.Clear(); adcell.Angles.Add(filminfo.angle1); adcell.Direction = filminfo.direction; adcell.Velocity = filminfo.filmVelocity; adcell.RotationCnt = filminfo.rotationCnt; adcell.InCV = filminfo.inCV; return true; } bool OnPoll_UpdateADList_Normal(int idx) { FilmInfo filminfo; int ret = mPDetect.GetFilmInfo(out filminfo, mADList[idx].Time, FilmWidth, FilmPosH); if (ret == 1)//发生在未来 { return false; } if (filminfo == null)//异常,FilmPosH 错误 { return false; } if (mADListToDoNo != mADList.Index2No(idx))//触发了事件 { return false; } ADCell adcell = mADList[idx]; adcell.Angles.Clear(); adcell.Angles.Add(filminfo.angle1); adcell.Angles.Add(filminfo.angle2); adcell.Direction = filminfo.direction; adcell.Velocity = filminfo.filmVelocity; adcell.RotationCnt = filminfo.rotationCnt; adcell.InCV = filminfo.inCV; return true; } #endregion /// /// 状态不一样,人字架已经转了新一圈,需要增加新一幅数据 /// /// /// /// bool FrameInfoCheckToNew(ADCell adcell, FRAME_INFO frameinfo) { if ((adcell.Direction != frameinfo.direction) || (adcell.RotationCnt != frameinfo.rotationCnt)) //(Math.Abs(adcell.velocity - frameinfo.velocity) > 2)) { return true; } else { return false; } } /// /// 输出的数据都必须是稳定,可靠的。 生成一幅幅测厚仪数据!!!!!!!!!!!! /// void OnPoll_UpdateFrameInfo() { int adlist_index = mADList.No2Index(mADListToDoNo_ToFilmInfo);//当前在处理的 数据点 if (adlist_index >= mADList.Count) return;//没有数据需要处理 if (adlist_index < 0)//全部都要处理 adlist_index = 0; //当没有任何一幅数据时, frameinfo_index = mFrameInfoList.Count = 0 int frameinfo_index = Math.Max(mFrameInfoList.Count - 1, 0); //查找adlist_index 属于哪个frameinfo; //当找到,清空里面的.frame,一切重新开始!!! //当不能找到,说明只是接着上次的处理而已,不需要重新开始 for (int i = 0; i < mFrameInfoList.Count; i++) { int index_start; int index_end; FRAME_INFO frameinfo = mFrameInfoList[i]; if (!GetFilmInfoADIndex(frameinfo, out index_start, out index_end)) { //数据已经不存在,删除 mFrameInfoList.RemoveAt(i); i--; continue; } if (adlist_index <= index_end) { //要处理的数据点,位于 这幅数据 (frameinfo); 重新计算整幅数据 frameinfo_index = i; //adlist_index = mADList.No2Index(frameinfo.NoStartAD); break; } } int adlist_todo_index = mADList.No2Index(mADListToDoNo);//已经成功获取完位置信息的数据尽头 for (int i = adlist_index; (i < mADList.Count && i < adlist_todo_index); i++) { ADCell adcell = mADList[i]; //mADListToDoNo_ToFilmInfo = mADList.Index2No(i); FRAME_INFO frameinfo; //-------------------------------------------------------------------------------------------------------- //条件检测 if (frameinfo_index >= mFrameInfoList.Count)//根本没数据,新建 { frameinfo = new FRAME_INFO(); frameinfo.StartTime = adcell.Time; frameinfo.EndTime = adcell.Time; frameinfo.direction = adcell.Direction; frameinfo.velocity = adcell.Velocity; frameinfo.rotationCnt = adcell.RotationCnt; frameinfo.NoStartAD = mADList.Index2No(i); frameinfo.NoEndAD = mADList.Index2No(i); frameinfo.SetNBolt(NBolts); mFrameInfoList.RAdd(frameinfo); frameinfo_index = mFrameInfoList.Count - 1; } else { frameinfo = mFrameInfoList[frameinfo_index]; if (i <= mADList.No2Index(frameinfo.NoEndAD)) { //当为新数据, i应该>mADList.No2Index(frameinfo.NoEndAD) //能进这里,证明是要重新计算 //清空数据,重新来过 frameinfo.StartTime = adcell.Time; frameinfo.EndTime = adcell.Time; frameinfo.direction = adcell.Direction; frameinfo.velocity = adcell.Velocity; frameinfo.rotationCnt = adcell.RotationCnt; frameinfo.NoStartAD = mADList.Index2No(i); frameinfo.NoEndAD = mADList.Index2No(i); frameinfo.Clear(); } } //-------------------------------------------------------------------------------------------------------- if (FrameInfoCheckToNew(adcell, frameinfo)) { //一幅数据已经完成 switch (MMode) { case MeasureMode.Normal: { //最后检查一下是否需要解方程 frameinfo.SolveFormula(); } break; } //重新分区 if (IsNeedMap()) { //上面已经检查了 Map == null 的情况 Dictionary m = new Dictionary(); for (int j = 0; j < Map.Count(); j++) m.Add(Map[j].OldNo - 1, Map[j].NewNo - 1); frameinfo.frame_map = Misc.MyMath.Map(frameinfo.frame, m); } //更新数据库内容 { double[] frame; List map; if (IsNeedMap()) { //上面已经检查了 Map == null 的情况 frame = frameinfo.frame_map; map = new List(); foreach (var m in Map) map.Add(m.Clone()); } else { frame = frameinfo.frame; map = null; } //限制小数点 for (int j = 0; j < frame.Count(); j++) { if(!double.IsNaN(frame[j])) frame[j] = Math.Round(frame[j], 2); } frameinfo.renZiJiaDataEventArgs = new RenZiJiaDataEventArgs() { Time = frameinfo.StartTime, EndTime = frameinfo.EndTime, IsBackw = frameinfo.direction == DIRECTION.BACKWARD, RPeriod = mPDetect.RenZiJiaPeriod, RCnt = frameinfo.rotationCnt, OrgBoltNo = OrgBoltNo, RAngle = Math.Round(mPDetect.RAngle, 2), FilmLength = Math.Round(mPDetect.FilmLength, 2), FilmVelocity = Math.Round(mPDetect.FilmVelocity, 2), K = Math.Round(mProfileParam.K, 3), Thicks = frame, Boltmap = map }; frameinfo.renZiJiaDataEventArgsHasChanged = true; } //更新到下一个frameinfo frameinfo_index++; i--; continue; } double thk = Ad2Thk(adcell.Ad); switch (MMode) { case MeasureMode.Normal: { //解方程,更新frameinfo.frame var list = from a in adcell.Angles select Angle2BoltIndex(a); frameinfo.SetFrameValue(list, thk * 2, adcell.Time); } break; default: //case MeasureMode.Edge: { //均值,更新frameinfo.frame frameinfo.SetFrameValue(Angle2BoltIndex(adcell.Angles.First()), thk, adcell.Time); } break; } frameinfo.EndTime = adcell.Time; frameinfo.NoEndAD = mADList.Index2No(i); } mADListToDoNo_ToFilmInfo = mADListToDoNo; //检测数据更新情况,放入bulkdata for (int i = 0; i < mFrameInfoList.Count; i++) { FRAME_INFO frameinfo = mFrameInfoList[i]; switch (MMode) { case MeasureMode.Normal: { //最后检查一下是否需要解方程 frameinfo.SolveFormula(); } break; } if (frameinfo.HasChanged)//数据检测过,需要更新bulkdata里面的数据, 大部分发生在扫描过程中,还没结束一幅图 { //重新分区 if (IsNeedMap()) { //上面已经检查了 Map == null 的情况 Dictionary m = new Dictionary(); for (int j = 0; j < Map.Count(); j++) m.Add(Map[j].OldNo - 1, Map[j].NewNo - 1); frameinfo.frame_map = Misc.MyMath.Map(frameinfo.frame, m); } //TODO 更新即时图!!!! //var thicks = IsNeedMap() ? frameinfo.frame_map : frameinfo.frame; } } //检查数据是否被修改, 推送出去!!!!! if (mFrameInfoList.Count() > 0) { FRAME_INFO frameinfo = mFrameInfoList.Last(); if (frameinfo.HasChanged) { var thicks = IsNeedMap() ? frameinfo.frame_map : frameinfo.frame; //TODO, 推送的数据,可能太多了!!!! bulkDb.SetTempFrame(frameinfo.StartTime, frameinfo.EndTime, 0, thicks); } } foreach (var frameinfo in mFrameInfoList) { frameinfo.Submit(); } #region sqlite3 历史数据保存 if (mFrameInfoList.Any((frameinfo) => frameinfo.renZiJiaDataEventArgsHasChanged)) { //下辊检测 if (historyDb.localDb.IsProfileFinished) { AddProfile(); } } //检测数据更新情况,放入数据库, 数据不能被修改 RenZiJiaDataEventArgs renZiJiaDataEventArgs = null;//当数据被修改,推送事件!!!,当只有最后一幅图被推送 foreach (var frameinfo in mFrameInfoList) { if (frameinfo.renZiJiaDataEventArgsHasChanged) { frameinfo.renZiJiaDataEventArgsHasChanged = false; if (frameinfo.scandata_id == null) { if (frameinfo.renZiJiaDataEventArgs.FilmVelocity < 2) { //异常 continue; } //添加数据 var lc_scandata = Lc_AutoMapperProfile.Mapper.Map(frameinfo.renZiJiaDataEventArgs); historyDb.AddScanData(lc_scandata); frameinfo.scandata_id = lc_scandata.ID; renZiJiaDataEventArgs = frameinfo.renZiJiaDataEventArgs; } } } #endregion //当数据被修改,只推送最后一次的数据 if (renZiJiaDataEventArgs != null) DataEvent?.Invoke(this, renZiJiaDataEventArgs); } protected override void OnPoll() { OnPoll_UpdateADList(); OnPoll_UpdateFrameInfo(); } public override bool Start() { //以前的 Start() IsRunning = true; #region sqlite3 历史数据保存 CheckProfile(); mProfileParam.PropertyChanged += MProfileParam_PropertyChanged; #endregion FObjBase.PollModule.Current.Poll_Config( FObjBase.PollModule.POLL_CONFIG.ADD, onpoll_func, TimeSpan.FromSeconds(1)); return true; } #region sqlite3 历史数据保存 string[] profile_propertynames_add = new string[]{ "PName", "OrderNo", "Number" }; string[] profile_propertynames_update = new string[]{ "Target", "TolerancePercent" }; void CheckProfile() { if (historyDb.localDb.IsProfileFinished) { //复位 膜纵向位置 AddProfile(); } else { if (historyDb.localDb.CurrProfile != null) { Db_Profile dB_Profile = historyDb.localDb.CurrProfile; if ((dB_Profile.PName != mProfileParam.PName) || (dB_Profile.OrderNo != mProfileParam.OrderNo) || (dB_Profile.Number != mProfileParam.Number)) { AddProfile(); } else { //继续上一次生产!!!! UpdateProfile(); } } else { //异常 AddProfile(); } } } void AddProfile() { historyDb.AddProfile(new Db_Profile() { PName = mProfileParam.PName, OrderNo = mProfileParam.OrderNo, Number = mProfileParam.Number, Target = mProfileParam.Target, TolerancePercent = mProfileParam.TolerancePercent, StartTime = DateTime.Now, EndTime = DateTime.Now }); } void UpdateProfile() { historyDb.UpdateProfile(new Db_Profile() { PName = mProfileParam.PName, OrderNo = mProfileParam.OrderNo, Number = mProfileParam.Number, Target = mProfileParam.Target, TolerancePercent = mProfileParam.TolerancePercent, }); } private void MProfileParam_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (profile_propertynames_add.Contains(e.PropertyName)) { FObjBase.PollModule.Current.Poll_JustOnce( () => { if (!historyDb.localDb.IsProfileFinished) { historyDb.FinishProfile(); } AddProfile();//新 }, this, MARKNO_PROFILE_ADD); } else if (profile_propertynames_update.Contains(e.PropertyName)) { FObjBase.PollModule.Current.Poll_JustOnce( () => { UpdateProfile();//修改 }, this, MARKNO_PROFILE_CHANGED); } } #endregion string file_path = "renzijiafix.json"; bool Load() { if (File.Exists(file_path)) { try { string json = File.ReadAllText(file_path); var jsonDb = JsonConvert.DeserializeObject(json); BlowingFixJsonDb.Mapper.Map(jsonDb, this); return true; } catch { //异常,没有json 解码失败 } return false; } else//只是为了版本兼容,以后就会删除 { var jsonDb = FLY.Thick.Blowing.Server.Update.GM_BlowingFix.ToJsonDb(); if (jsonDb == null) return false; BlowingFixJsonDb.Mapper.Map(jsonDb, this); return true; } } void Save() { try { var jsonDb = BlowingFixJsonDb.Mapper.Map(this); string json = JsonConvert.SerializeObject(jsonDb, Formatting.Indented); File.WriteAllText(file_path, json); } catch { //异常,没有json 编码失败 } } /// /// 获取 厚度列表 /// /// 开始时间 /// /// [Call(typeof(GetADListReponse))] public void GetADList(DateTime begin, AsyncCBHandler asyncDelegate, object asyncContext) { var p = new GetADListReponse { datas = mADList.FindAll(a => a.Time > begin).Select(a => new ADSingle() { dt = a.Time, thk = Ad2Thk(a.Ad) }).ToList() }; asyncDelegate(asyncContext, p); } } public class BlowingFixJsonDb { public static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c => { c.CreateMap().ReverseMap(); })); public int ChannelCnt=88; public int BPC=1; public int OrgBoltNo=1; public bool IsUsedMap; public BoltMapCell[] Map; public bool IsProbeRight = true; } } namespace FLY.Thick.Blowing.Server.Update { public class GM_BlowingFix : ISaveToXml { /// /// 加热通道数 /// public int ChannelCnt { get; set; } = 88; /// /// 分区数/加热通道数 /// public int BPC { get; set; } = 1; /// /// 复位时,探头测量的位置对应分区号 /// public int OrgBoltNo { get; set; } = 1; /// /// 使用分区表 /// public bool IsUsedMap { get; set; } = false; /// /// 分区表,必须保证不能为null /// public List Map { get; } = new List(); static GM_BlowingFix() { Misc.SaveToXmlHepler.Regist(typeof(BoltMapCell)); } #region ISaveToXml public string[] GetSavePropertyNames() { return new string[]{ nameof(ChannelCnt), nameof(BPC), nameof(OrgBoltNo), nameof(IsUsedMap), nameof(Map) }; } #endregion public static BlowingFixJsonDb ToJsonDb() { if (File.Exists("renzijiafix.xml")) {//只是为了版本兼容,以后就会删除 FLY.Thick.Blowing.Server.Update.GM_BlowingFix blowingFix = new Update.GM_BlowingFix(); Misc.SaveToXmlHepler.Load("renzijiafix.xml", blowingFix); FLY.Thick.Blowing.Server.BlowingFixJsonDb jsonDb = new BlowingFixJsonDb(); jsonDb.ChannelCnt = blowingFix.ChannelCnt; jsonDb.BPC = blowingFix.BPC; jsonDb.OrgBoltNo = blowingFix.OrgBoltNo; jsonDb.IsUsedMap = blowingFix.IsUsedMap; jsonDb.Map = blowingFix.Map.ToArray(); return jsonDb ; } else return null; } } }