using FLY.Thick.Blowing.IService; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FLY.Thick.Blowing.UI.Fix.Client { public class CalFilmLen : INotifyPropertyChanged { #region 状态 /// <summary> /// 信息 /// </summary> public string Msg { get; private set; } /// <summary> /// 下载中 /// </summary> public bool IsDownloading { get; private set; } /// <summary> /// 数据准备好了 /// </summary> public bool IsDataReady { get; private set; } /// <summary> /// 计算中 /// </summary> public bool IsCaling { get; private set; } /// <summary> /// 有足够的数据,可以下载 /// </summary> public bool IsCanDownload { get; private set; } /// <summary> /// 当前数据总分钟数 min /// </summary> public int DataMaxMinute { get; private set; } /// <summary> /// 必须获取的最少数据量 min /// </summary> public int DataMinMinute { get; private set; } /// <summary> /// 最佳获取数据量 min /// </summary> public int DataBestMinute { get; private set; } #endregion #region 参数 /// <summary> /// 第1牵引速度 /// </summary> public double Velocity1 { get; private set; } /// <summary> /// 速度滤波 单位s /// </summary> public int VelocityFilter { get; private set; } = 1; /// <summary> /// 膜距离 /// </summary> public double FilmLength { get; private set; } #endregion IBlowingFixService mCurrBlowing; IBlowingDetect mCurrRDetect; BlowingDetectCore mRDetectCore; List<ADCell> mADList = new List<ADCell>(); List<LimitCell> mLimitList = new List<LimitCell>(); List<RollCell> mRollList = new List<RollCell>(); #region 画图 public List<TimeValue> LimitValues { get; } = new List<TimeValue>(); public List<TimeValue> VelocityValues { get; } = new List<TimeValue>(); public List<TimeValue> ThicknessValues { get; } = new List<TimeValue>(); public List<TimeValue> FilmLength3DValues { get; } = new List<TimeValue>(); [PropertyChanged.DoNotCheckEquality] public List<double> CurrFilmLength3D { get; set; } = new List<double>(); [PropertyChanged.DoNotCheckEquality] public List<double> NewFilmLength3D { get; set; } = new List<double>(); public class Frame { /// <summary> /// 厚度 /// </summary> public double[] Thicks; /// <summary> /// 旋转方向 /// </summary> public Misc.DIRECTION Direction; /// <summary> /// 旋转次数 /// </summary> public int RotationCnt; /// <summary> /// 与上一幅图的相关性 /// </summary> public double R; /// <summary> /// 大于30%数据 非 NaN /// </summary> public bool IsVaild; } [PropertyChanged.DoNotCheckEquality] public List<Frame> Frames { get; set; } = new List<Frame>(); #endregion int NBolts; int OrgBoltNo; DateTime dataBegin; /// <summary> /// 最小旋转次数 /// </summary> const int minRotationCnt = 2; public CalFilmLen() { mRDetectCore = new BlowingDetectCore(); } public void Init(IBlowingFixService mRenZiJiaFix, IBlowingDetect mRDetect) { this.mCurrBlowing = mRenZiJiaFix; this.mCurrRDetect = mRDetect; this.FilmLength = mRDetect.FilmLength; Misc.BindingOperations.SetBinding(mCurrRDetect, "BufTotalTime", () => { DataMaxMinute = (int)(mCurrRDetect.BufTotalTime.TotalMinutes); }); Misc.BindingOperations.SetBinding(mCurrRDetect, "RotationCnt", () => { if (mRDetect.RotationCnt < minRotationCnt) { IsCanDownload = false; } else { IsCanDownload = true; } }); Misc.BindingOperations.SetBinding(mCurrRDetect, "RenZiJiaPeriod", () => { DataMinMinute = (int)(mRDetect.RenZiJiaPeriod.TotalMinutes * (minRotationCnt - 1)); DataBestMinute = (int)Math.Round((mRDetect.RenZiJiaPeriod.TotalMinutes * 3)); }); } public bool DownloadData(int getDataMinute) { //应该在界面 检测错误原因 if (IsDownloading) return false; if (IsCaling) return false; TimeSpan getBufTime = TimeSpan.FromMinutes(getDataMinute); if ( getBufTime > mCurrRDetect.BufTotalTime) return false; dataBegin = DateTime.Now - getBufTime; IsDownloading = true; IsDataReady = false; DownloadData_limit(); return true; } void DownloadData_limit() { Msg = $"下载 转向信号数据 [{dataBegin} - Now]...."; mCurrRDetect.GetLimitList(dataBegin, (object AsyncState, object retData) => { Action act = AsyncState as Action; var p = retData as GetLimitListReponse; if ((p.datas == null) || p.datas.Count() < 2) { Msg = $"数据下载异常, 转向信号数量<2"; IsDownloading = false; return; } mLimitList = p.datas; DownloadData_roll(); },null); } void DownloadData_roll() { Msg = $"下载 辊信号数据 [{dataBegin} - Now]...."; mCurrRDetect.GetRollList(dataBegin, (object AsyncState, object retData) => { var p = retData as GetRollListReponse; if ((p.datas == null) || p.datas.Count() < 10) { Msg = "数据下载异常, 辊信号数量 < 10"; IsDownloading = false; return; } mRollList = p.datas; DownloadData_ad(); }, null ); } void DownloadData_ad() { Msg = $"下载 厚度数据 [{dataBegin} - Now]...."; mCurrBlowing.GetADList(dataBegin, (object AsyncState, object retData) => { var p = retData as GetADListReponse; if ((p.datas == null) || p.datas.Count() < 10) { Msg = "数据下载异常, 厚度数据数量 < 10"; IsDownloading = false; return; } mADList = p.datas.Select( a => new ADCell() { Ad = a.thick, Time = a.dt } ).ToList(); if (mCurrRDetect.Is3D) DownloadData_CurrFilmLength3D(); else DownloadData_OK(); }, null); } void DownloadData_CurrFilmLength3D() { Msg = $"下载 膜距离增量数据 [{dataBegin} - Now]...."; mCurrRDetect.GetFilmLength3D( (object AsyncState, object retData) => { var p = retData as GetFilmLength3DReponse; CurrFilmLength3D = p.datas; DownloadData_OK(); }, null); } void DownloadData_OK() { NBolts = mCurrBlowing.NBolts; OrgBoltNo = mCurrBlowing.OrgBoltNo; if (OrgBoltNo < 1) OrgBoltNo = 1; mRDetectCore.Init( mCurrRDetect.RAngle, mCurrRDetect.RollPerimeter, mCurrRDetect.RenZiJiaPeriod, mCurrRDetect.FilmLength, mCurrRDetect.Is3D, mRollList, mLimitList, CurrFilmLength3D); UpdateLimitValues(); UpdateThicknessValues(); UpdateVelocityValues(VelocityFilter); UpdateADList(); UpdateFrames(); Msg = "数据下载完成"; IsDownloading = false; IsDataReady = true; } public void UpdateVelocityValues(int velocity_filter) { VelocityFilter = velocity_filter; var filter_half = TimeSpan.FromSeconds(VelocityFilter / 2); VelocityValues.Clear(); for (int i = 0; i < mRollList.Count(); i++) { var dt_min = mRollList[i].dt - filter_half; var dt_max = mRollList[i].dt + filter_half; int i_begin = 0; int i_end = mRollList.Count()-1; for (int j = i; j >= 0; j--) { if (mRollList[j].dt <= dt_min) { //找到了 i_begin = j; break; } } for (int j = i; j < mRollList.Count(); j++) { if (mRollList[j].dt >= dt_max) { //找到了 i_end = j; break; } } if (i_begin == i_end) { i_begin = i; i_end = i + 1; if (i_end >= mRollList.Count()) { i_begin = i - 1; i_end = i; } } TimeSpan ts = mRollList[i_end].dt - mRollList[i_begin].dt; double minute = 1.0 * ts.Ticks / TimeSpan.TicksPerMinute; double v = (i_end - i_begin)*mCurrRDetect.RollPerimeter / 1000 / minute; VelocityValues.Add( new TimeValue() { Time = mRollList[i].dt, Value = v }); } OnPropertyChanged("VelocityValues"); Velocity1 = VelocityValues.Average(tv => tv.Value); if (mCurrRDetect.Is3D) UpdateFilmLength3D(Velocity1); } public void UpdateFilmLength3D(double velocity1) { Velocity1 = velocity1; FilmLength3DValues.Clear(); double sum = 0; FilmLength3DValues.Add( new TimeValue() { Time = VelocityValues[0].Time, Value = sum }); for (int i = 1; i < VelocityValues.Count(); i++) { var ts = VelocityValues[i].Time - VelocityValues[i - 1].Time; double minute = 1.0* ts.Ticks / TimeSpan.TicksPerMinute; sum += ((VelocityValues[i].Value + VelocityValues[i - 1].Value) / 2 - Velocity1) * minute; FilmLength3DValues.Add( new TimeValue() { Time = VelocityValues[i].Time, Value = sum }); } double min_f = FilmLength3DValues.Min(tv => tv.Value); foreach (var tv in FilmLength3DValues) tv.Value -= min_f; OnPropertyChanged("FilmLength3DValues"); UpdateNewFilmLength3D(); } void UpdateThicknessValues() { ThicknessValues.Clear(); foreach (var adcell in mADList) { ThicknessValues.Add( new TimeValue() { Time = adcell.Time, Value = Misc.MyBase.ISVALIDATA(adcell.Ad)? adcell.Ad / 100.0:double.NaN }); } OnPropertyChanged("ThicknessValues"); } void UpdateLimitValues() { LimitValues.Clear(); foreach (var limit in mLimitList) { DateTime dt = limit.dt_begin; if (dt == DateTime.MinValue) dt = limit.dt_end; LimitValues.Add(new TimeValue() { Time = dt, Value = limit.no }); } OnPropertyChanged("LimitValues"); } void UpdateADList() { for (int i = 0; i < mADList.Count(); i++) { ADCell c = mADList[i]; if(i==143) { } int ret = mRDetectCore.GetFilmInfo( out BlowingDetectCore.FilmInfo filminfo, mADList[i].Time); if (ret > 0 )//发生在辊信号的未来,把数据删除!!!! { //异常 mADList.RemoveRange(i, mADList.Count() - i); return; } if (filminfo.rotationCnt == 1) { } else if (filminfo.rotationCnt != 1) { } if (filminfo.inCV) { } //计算相关性,只使用 膜边=0mm 模式 c.Direction = filminfo.direction; c.Angles.Clear(); c.Angles.Add(filminfo.angle); c.RotationCnt = filminfo.rotationCnt; c.Velocity = filminfo.filmVelocity; c.InCV = filminfo.inCV; } } void UpdateNewFilmLength3D() { int n = 100; List< IEnumerable<double>> fs = new List<IEnumerable<double>>(); for (int i = 0; i < mLimitList.Count()-1; i++) { int no = mLimitList[i].no; DateTime begin_dt = mLimitList[i].dt_end; DateTime end_dt = mLimitList[i+1].dt_begin; if ((begin_dt == DateTime.MinValue) || (end_dt == DateTime.MinValue)) { //异常 continue; } var filmlength3d = FilmLength3DValues.Where(tv => tv.Time >= begin_dt && tv.Time <= end_dt); double[] f = new double[n]; int k = 0; for (int j = 0; j < f.Count(); j++) { DateTime dt = begin_dt + TimeSpan.FromTicks(j * (end_dt - begin_dt).Ticks / f.Count()); bool hadFind = false; for (; k < filmlength3d.Count(); k++) { if (filmlength3d.ElementAt(k).Time >= dt) { //找到了 f[j] = filmlength3d.ElementAt(k).Value; hadFind = true; break; } } if (!hadFind)//找不到 { if (j > 0) f[j] = f[j - 1]; } } if (no == 0) fs.Add(f); else fs.Add(f.Reverse()); } //求均值 List<double> newfilmlength3d = new List<double>(); for (int i = 0; i < fs.First().Count(); i++) { double sum = 0; for (int j = 0; j < fs.Count(); j++) { sum += fs[j].ElementAt(i); } newfilmlength3d.Add(sum / fs.Count()); } NewFilmLength3D = newfilmlength3d; } public void SetFilmLength3D() { CurrFilmLength3D = NewFilmLength3D; mRDetectCore.mFilmLength3D = CurrFilmLength3D; if (mRDetectCore.Is3D) { UpdateFrames(); } mCurrRDetect.SetFilmLength3D(NewFilmLength3D); FLY.ControlLibrary.Window_Tip.Show( "应用成功", $"立体式旋转 膜距离增量设置成功", TimeSpan.FromSeconds(2)); } public void SetFilmLength(double filmLength) { FilmLength = filmLength; mRDetectCore.FilmLength = filmLength; UpdateADList(); UpdateFrames(); } void UpdateFrames() { Frames = GetFrames(); } List<Frame> GetFrames() { List<Frame> frames = new List<Frame>(); int boltIndex = -1; List<int> datas = new List<int>(); int roationCnt = -1; Frame frame = null; foreach (ADCell c in mADList) { int bi = (int)(NBolts * c.Angles[0] / 360); if (bi < 0) bi = 0; else if (bi >= NBolts) bi = NBolts - 1; int boltno = bi + OrgBoltNo; if (boltno > NBolts) boltno -= NBolts; //添加到 if ((c.InCV == true) && ((roationCnt == -1) || (roationCnt != c.RotationCnt)) ) { roationCnt = c.RotationCnt; frame = new Frame(); frame.RotationCnt = roationCnt; frame.Direction = c.Direction; frame.Thicks = new double[NBolts]; for (int j = 0; j < frame.Thicks.Count(); j++) frame.Thicks[j] = double.NaN; frames.Add(frame); boltIndex = -1; } if ((boltIndex == -1) || (boltIndex != boltno - 1)) { datas.Clear(); } datas.Add(c.Ad); boltIndex = boltno - 1; int avg = Misc.MyMath.Avg(datas); if (Misc.MyBase.ISVALIDATA(avg)) frame.Thicks[boltIndex] = avg / 100.0; } for (int i = 1; i < frames.Count; i++) { frames[i].IsVaild = 1.0 * frames[i].Thicks.Count(t => !double.IsNaN(t)) / frames[i].Thicks.Count() > 0.3; if (frames[i].IsVaild) { //计算相关性 frames[i].R = Misc.MyMath.Correl(frames[i].Thicks, frames[i - 1].Thicks); } } return frames; } bool TestFilmLength(double filmlength, ref double max_r, ref double best_filmlength, out double r) { bool ret = false; mRDetectCore.FilmLength = filmlength; UpdateADList(); var frames = GetFrames(); r = frames.Max(f => f.R); if (r > max_r) { max_r = r; best_filmlength = mRDetectCore.FilmLength; ret = true; } return ret; } public async void Cal(double begin_filmlength, double end_filmlength) { if (mRDetectCore.RotationCnt < 3) { Msg = "---警告--- 没法自动计算,旋转次数少于3次"; return; } if (begin_filmlength < 3) begin_filmlength = 3; if (end_filmlength > 50) end_filmlength = 50; IsCaling = true; double max_r=0; double best_filmlength=FilmLength; await Task.Factory.StartNew(() => { for (double i = begin_filmlength; i < end_filmlength; i+=0.1) { TestFilmLength(i, ref max_r, ref best_filmlength, out double r); int progress = (int)((i - begin_filmlength) / (end_filmlength - begin_filmlength) * 100); Msg = $"{progress:000}/100 {i:F1}m R={r:F3} 最合理[{best_filmlength:F1}m MaxR={max_r:F3}]"; } }); SetFilmLength(best_filmlength); Msg = $"最合理[{best_filmlength:F1}m MaxR={max_r:F3}]"; IsCaling = false; } //public void Start() //{ // if (step == 0) // { // step = 1; // dt_onpoll = DateTime.MinValue; // RotationCnt = 3; // TimeOfMin = DateTime.MinValue; // TimeOfMax = DateTime.MinValue; // mADList.Clear(); // OnPoll(); // } //} //bool Poll() //{ // switch (step) // { // case 1: // { // if (Step01()) // { // step = 2; // return true; // } // } // break; // case 2: // { // if (Step02()) // { // step = 3; // return true; // } // } // break; // case 3: // { // if (Step03())//已经成功获取了时间 // { // step = 4; // return true; // } // else // { // if (TimeOfMin == DateTime.MinValue) // { // step = 2; // } // } // } // break; // case 4: // { // Step04(); // step = 5; // } // break; // } // return false; //} //DateTime dt_onpoll = DateTime.MinValue; public event PropertyChangedEventHandler PropertyChanged; ///// <summary> ///// 每次获取完所有angle,执行,每20秒触发一次 ///// </summary> //public void OnPoll() //{ // DateTime now = DateTime.Now; // if ((dt_onpoll != DateTime.MinValue) && ((now - dt_onpoll) < TimeSpan.FromSeconds(30))) // return; // dt_onpoll = now; // while (Poll()) ; //} //bool Step01() //{ // //下载数据 // if (mCurrRDetect.RotationCnt < 3) // { // RotationCnt = 3; // State = "RotationCnt=3 Wait"; // return true; // } // RotationCnt = mCurrBlowing.mPDetect.RotationCnt; // return true; //} ///// <summary> ///// 确保三个rotationcnt 都存在 ///// </summary> ///// <returns></returns> //bool Step02() //{ // if (RotationCnt > mCurrBlowing.mPDetect.RotationCnt) // { // State = "RotationCnt=" + // RotationCnt.ToString() + ">" + mCurrBlowing.mPDetect.RotationCnt.ToString() + " Wait"; // return false; // } // DateTime min_time; // DateTime max_time; // double min_fl = MinFilmLength; // double max_fl = MaxFilmLength; // BlowingDetect.GetLimitTimeResult r1 = // mCurrBlowing.mPDetect.GetLimitTime( // RotationCnt - 2, // min_fl, // out min_time); // BlowingDetect.GetLimitTimeResult r2 = // mCurrBlowing.mPDetect.GetLimitTime( // RotationCnt, // max_fl, // out max_time); // string state = "[min_fl=" + min_fl.ToString() + "m (" + min_time.ToLongTimeString() + ") " + r1.ToString() + "]," + // "[max_fl=" + max_fl.ToString() + "m (" + max_time.ToLongTimeString() + ") " + r2.ToString() + "] "; // if ((r1 == BlowingDetect.GetLimitTimeResult.NOEXIST) || // (r2 == BlowingDetect.GetLimitTimeResult.NOEXIST)) // { // //不可能存在的错误 // RotationCnt++; // state += "Wait 不可能存在的错误 NOEXIST, RotationCnt=" + RotationCnt.ToString(); // State = state; // return false; // } // else if ((r1 == BlowingDetect.GetLimitTimeResult.ISFURTURE) || // (r2 == BlowingDetect.GetLimitTimeResult.ISFURTURE)) // { // //就是它,等!!!! // state += "Wait ,it is the one!!!!"; // State = state; // return false; // } // else if ((r1 != BlowingDetect.GetLimitTimeResult.OK) || // (r2 != BlowingDetect.GetLimitTimeResult.OK)) // { // //不可能存在的错误 // RotationCnt++; // state += "Wait 不可能存在的错误 ?????, RotationCnt=" + RotationCnt.ToString(); // State = state; // return false; // } // TimeOfMin = min_time; // TimeOfMax = max_time; // return true; //} //bool Step03() //{ // int copy_index_b = -1; // int copy_index_e = -1; // int ret = mCurrBlowing.ADListFastSearchIndex(TimeOfMin, out copy_index_b); // string state; // state = "TimeOfMin(" + TimeOfMin.ToLongTimeString() + ") (" + copy_index_b.ToString() + ") "; // if (ret == -1)//发生在过去 // { // state += " PAST"; // State = state; // RotationCnt++; // TimeOfMin = DateTime.MinValue; // TimeOfMax = DateTime.MinValue; // return false; // } // else if (ret == 1)//发生在未来 // { // state += " FUTURE"; // State = state; // return false; // } // ret = mCurrBlowing.ADListFastSearchIndex(TimeOfMax, out copy_index_e); // state += " TimeOfMax(" + TimeOfMax.ToLongTimeString() + ") (" + copy_index_e.ToString() + ")"; // if (ret == -1)//发生在过去 // { // //异常出错 // throw new ArgumentOutOfRangeException("min_time 在列表中, 但max_time在列表前"); // } // else if (ret == 1)//发生在未来 // { // state += " FUTURE"; // return false; // } // //复制所有scaninfolist // for (int i = copy_index_b; i <= copy_index_e; i++) // { // mADList.Add(mCurrBlowing.mADList[i].Clone()); // } // //复制 旋转架检测器 // mCurrRDetect = mCurrBlowing.mPDetect.Clone(); // //数据足够了 // state += " READY"; // State = state; // return true; //} //void Step04() //{ // //立刻计算 // Thread t = new Thread(Cal) // { // Priority = ThreadPriority.Lowest, // IsBackground = true // }; // t.Start(); //} //void Cal() //{ // //限位时间点,肯定在缓存区的中间!!!!! // //1.找到限位时间点所在的数据幅 // //2.以该点作为对称点,上下3幅计算thicks,再求相似度 // double min_fl = MinFilmLength; // double max_fl = MaxFilmLength; // double maxr = -1; // double maxr_fl = -1; // string state; // double curr_r = CalR(FilmLength); // for (double i = min_fl; i <= max_fl; i += 0.1) // { // double r = CalR(i); // if (r > maxr) // { // maxr = r; // maxr_fl = i; // } // state = "Cal"; // state += " (" + ((i - min_fl) / (max_fl - min_fl) * 100).ToString("F0") + "/100)"; // state += " [" + r.ToString("F3") + "," + i.ToString("N1") + "m]"; // state += " MaxR=[" + maxr.ToString("F3") + "," + maxr_fl.ToString("N1") + "m]"; // state += " CurrR=[" + curr_r.ToString("F3") + "," + FilmLength.ToString("N1") + "m]"; // State = state; // } // MaxR = maxr; // MaxRFilmLength = maxr_fl; // State = "Cal OK"; // step = 0; //} //double CalR(double filmLength) //{ // mCurrRDetect.FilmLength = filmLength; // for (int i = 0; i < mADList.Count(); i++) // { // ADCell c = mADList[i]; // BlowingDetect.FilmInfo filminfo; // int ret = mCurrRDetect.GetFilmInfo(out filminfo, mADList[i].dt, 2.3, 0); // if (ret != 0) // { // //异常 // return 0; // } // //计算相关性,只使用 膜边=0mm 模式 // c.direction = filminfo.direction; // c.angles.Add(filminfo.angle1); // c.angles.Add(filminfo.angle2); // c.rotationCnt = filminfo.rotationCnt; // c.velocity = filminfo.filmVelocity; // c.inCV = filminfo.inCV; // } // //找到 rotationCnt 为 RotationCnt-2, 与 RotationCnt-1 的数据,进行相似度计算 // //直接使用角度划分数据, 360° // //360个数据太多,使用120个数据 // int[] thicks1 = new int[120]; // int[] thicks2 = new int[120]; // for (int i = 0; i < 120; i++) // { // thicks1[i] = Misc.MyBase.NULL_VALUE; // thicks2[i] = Misc.MyBase.NULL_VALUE; // } // int sum = 0; // int cnt = 0; // //int angle = -1; // int angle_3 = -1; // int rotationcnt = 0; // for (int i = 0; i < mADList.Count(); i++) // { // ADCell c = mADList[i]; // if (cnt == 0) // { // if (Misc.MyBase.ISVALIDATA(c.ad)) // { // sum += c.ad; // cnt++; // } // angle_3 = (int)(c.angles.First() / 3); // rotationcnt = c.rotationCnt; // } // else // { // bool change = false; // if ((rotationcnt != c.rotationCnt) || // (angle_3 != (int)(c.angles.First() / 3))) // { // change = true; // } // if (!change) // { // if (Misc.MyBase.ISVALIDATA(c.ad)) // { // sum += c.ad; // cnt++; // } // } // else // { // int[] thicks = null; // if (rotationcnt == RotationCnt - 2) // thicks = thicks1; // else if (rotationcnt == RotationCnt - 1) // thicks = thicks2; // if (thicks != null) // { // int index = angle_3; // if (index >= 120) // index = 119; // else if (index < 0) // index = 0; // if (cnt > 0) // thicks[index] = sum / cnt; // else // thicks[index] = Misc.MyBase.NULL_VALUE; // } // sum = 0; // cnt = 0; // if (Misc.MyBase.ISVALIDATA(c.ad)) // { // sum += c.ad; // cnt++; // } // rotationcnt = c.rotationCnt; // angle_3 = (int)(c.angles.First() / 3); // } // } // } // //计算相似性 // return Misc.MyMath.Correl(thicks1, thicks2); //} protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } //string file_path = "bulkdb.json"; public void Save(string file_path) { try { CalFilmLenJsonDB param = new CalFilmLenJsonDB() { RAngle = mRDetectCore.RAngle, RollPerimeter = mRDetectCore.RollPerimeter, RenZiJiaPeriod = mRDetectCore.RenZiJiaPeriod, FilmLength = mRDetectCore.FilmLength, Is3D = mRDetectCore.Is3D, mRollList = mRDetectCore.mRollList, mLimitList = mRDetectCore.mLimitList, mFilmLength3D = mRDetectCore.mFilmLength3D, NBolts = NBolts, OrgBoltNo = OrgBoltNo, mADList = mADList.Select(a => new ADSingle() { dt = a.Time, thick = a.Ad }).ToList() }; File.WriteAllText(file_path, JsonConvert.SerializeObject(param, Formatting.Indented)); } catch { //异常,没有json 编码失败 } } public void Load(string file_path) { try { if (File.Exists(file_path)) { string json = File.ReadAllText(file_path); var param = JsonConvert.DeserializeObject<CalFilmLenJsonDB>(json); Load(param); } } catch { //异常,没有json 解码失败 } } void Load(CalFilmLenJsonDB param) { mRDetectCore.Init( param.RAngle, param.RollPerimeter, param.RenZiJiaPeriod, param.FilmLength, param.Is3D, param.mRollList, param.mLimitList, param.mFilmLength3D); NBolts = param.NBolts; OrgBoltNo = param.OrgBoltNo; if (OrgBoltNo < 1) OrgBoltNo = 1; FilmLength = param.FilmLength; mLimitList = param.mLimitList; mRollList = param.mRollList; mADList = param.mADList.Select( a => new ADCell() { Ad = a.thick, Time = a.dt } ).ToList(); UpdateLimitValues(); UpdateThicknessValues(); UpdateVelocityValues(VelocityFilter); UpdateADList(); UpdateFrames(); IsDataReady = true; } public void Test() { CalFilmLenJsonDB param = new CalFilmLenJsonDB() { NBolts = 96, RAngle = 350, RollPerimeter = 314, FilmLength = 24, Is3D = false, mFilmLength3D = null, RenZiJiaPeriod = TimeSpan.FromMinutes(6.1), mADList = new List<ADSingle>(), mLimitList = new List<LimitCell>(), mRollList = new List<RollCell>() }; #region 虚拟数据 int[] thicks = new int[]{ 3518 , 3484 , 3634 , 3620 , 3579 , 3625 , 3635 , 3638 , 3635 , 3606 , 3611 , 3603 , 3590 , 3631 , 3646 , 3647 , 3710 , 3705 , 3607 , 3720 , 3680 , 3637 , 3659 , 3703 , 3860 , 3720 , 3615 , 3810 , 3772 , 3666 , 3614 , 3627 , 3618 , 3502 , 3575 , 3583 , 3615 , 3680 , 3730 , 3840 , 3927 , 3946 , 3923 , 3841 , 3797 , 3865 , 3810 , 3711 , 3754 , 3705 , 3723 , 3699 , 3723 , 3801 , 3786 , 3798 , 3907 , 3945 , 3828 , 3860 , 3846 , 3903 , 3871 , 3844 , 3759 , 3816 , 3886 , 3815 , 3789 , 3876 , 3942 , 3854 , 3842 , 3921 , 3846 , 3835 , 3886 , 3881 , 3820 , 3787 , 3730 , 3617 , 3650 , 3610 , 3536 , 3545 , 3564 , 3584 , 3580 , 3572 , 3571 , 3579 , 3620 , 3634 , 3484 , 3518 , }; //线速度 m/min double FilmVelocity = 20; TimeSpan Cool = TimeSpan.FromSeconds(2.3); //速度震荡周期 m double FV_Range = 2; TimeSpan DataLen = TimeSpan.FromMinutes(30); DateTime dt_begin = DateTime.Now; DateTime dt_end = dt_begin + DataLen; for (TimeSpan ts = TimeSpan.Zero; ts < DataLen; ts += TimeSpan.FromSeconds(1)) { DateTime dt = dt_begin + ts; double min = ts.TotalMinutes; //速度以1/2旋转周期变化 double v = FilmVelocity + Math.Sin(Math.PI * 2 * min / (param.RenZiJiaPeriod.TotalMinutes / 2)) * FV_Range; if (param.mRollList.Count() == 0) { param.mRollList.Add(new RollCell() { dt = dt }); } else { while ((dt - param.mRollList.Last().dt).TotalMinutes * v > (param.RollPerimeter / 1000)) { param.mRollList.Add(new RollCell() { dt = param.mRollList.Last().dt + TimeSpan.FromMinutes((param.RollPerimeter / 1000) / v) }); } } int n = ((int)(min / param.RenZiJiaPeriod.TotalMinutes)) % 2; double min2 = min - param.FilmLength / v + param.RenZiJiaPeriod.TotalMinutes * 2; int n2 = ((int)(min2 / param.RenZiJiaPeriod.TotalMinutes)) % 2; double m = min2 % param.RenZiJiaPeriod.TotalMinutes; int idx = (int)(thicks.Count() * m / param.RenZiJiaPeriod.TotalMinutes); if (idx < 0) idx = 0; else if (idx > thicks.Count()) idx = thicks.Count() - 1; int thick; if (n2 == 0) thick = thicks[idx]; else thick = thicks[thicks.Count() - 1 - idx]; param.mADList.Add(new ADSingle { dt = dt, thick = thick }); if (param.mLimitList.Count() == 0) { if (dt >= dt_begin + param.RenZiJiaPeriod) { param.mLimitList.Add(new LimitCell() { dt_begin = dt_begin + param.RenZiJiaPeriod, dt_end = dt_begin + param.RenZiJiaPeriod + Cool, no = n }); } } else if (dt >= param.mLimitList.Last().dt_end + param.RenZiJiaPeriod) { param.mLimitList.Add(new LimitCell() { dt_begin = param.mLimitList.Last().dt_end + param.RenZiJiaPeriod, dt_end = param.mLimitList.Last().dt_end + param.RenZiJiaPeriod + Cool, no = n }); } } #endregion Load(param); } } public class CalFilmLenJsonDB { /// <summary> /// 离开限位 到 撞下一个限位 的 旋转架转动总角度 单位° /// </summary> public double RAngle; /// <summary> /// 辊周长,单位mm /// </summary> public double RollPerimeter; /// <summary> /// 离开限位 到 撞下一个限位 的 旋转架转动时间, 需要初始值,以后测量出来的 /// </summary> public TimeSpan RenZiJiaPeriod; /// <summary> /// 人字架到测厚仪膜长 单位m /// </summary> public double FilmLength; /// <summary> /// 旋转架为立式,测厚仪安装在二牵引前面,膜距离 与 旋转角度 一起变化, 旋转角度越大 膜距离越大 /// </summary> public bool Is3D; /// <summary> /// 辊信号列表 /// </summary> public List<RollCell> mRollList; /// <summary> /// 转向信号列表 /// </summary> public List<LimitCell> mLimitList; /// <summary> /// 当为 立式旋转架时,膜距离与旋转角度有关系 /// 列表的长度为 200, 列表的头为信号0离开, 尾为信号1进入 /// </summary> public List<double> mFilmLength3D; public List<ADSingle> mADList; public int NBolts; public int OrgBoltNo=1; } }