using FLY.Thick.Blowing.IService; using FObjBase; using FObjBase.Reflect; using Misc; using SQLite; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FLY.Thick.Blowing.Server.Model { /// /// 提供接口,让别人获取 整理好的 当前生产,或之前生产的数据。 /// 从LocalDb 获取数据, 或从 直接从数据获取数据 /// /// 与HistoryDb,成对。 /// HistoryDb 是写 /// BulkDb 是读 /// public class BulkDb : IBulkDbService { /// /// 本地数据库 /// LocalDb localDb; DbModel dbModel; IShareDbService shareDb; /// /// 最后一条扫描数据Id /// public long LastScanDataId { get; private set; } = -1; /// /// 最后一条产品Id /// public long LastProfileId { get; private set; } = -1; /// /// 数据库最后一次被修改时间 /// public DateTime LastTimestamp { get; private set; } /// /// 开始产生数据时间 /// public DateTime StartTime { get; private set; } /// /// 最后产生数据时间 /// public DateTime EndTime { get; private set; } /// /// 当前生产,已经结束,已经下辊了 /// public bool IsFinished { get; private set; } /// /// 混合数据,时间范围 /// 大于 TimeSpan.Zero 起作用 /// public TimeSpan MixDataTimeRange { get; set; } = TimeSpan.FromMinutes(5); /// /// 混合数据,均值波动范围 /// 大于 0 起作用 /// public double MixDataAvgRange { get; set; } = 5; /// /// /// public event PropertyChangedEventHandler PropertyChanged; /// /// 临时数据改变 /// [Push(typeof(BulkDbTempFrameChangedEventArgs))] public event EventHandler TempFrameChanged; public Func GetTempFrameAction; /// /// /// public BulkDb() { } /// /// 写入动态数据 /// /// /// public void SetTempFrame(DateTime time, DateTime endTime, int startIndex, double[] D) { TempFrameChanged?.Invoke(this, new BulkDbTempFrameChangedEventArgs() { Time = time, EndTime = endTime, StartIndex = startIndex, D = D }); } /// /// 获取临时数据 /// /// /// /// [Call(typeof(BulkDbTempFrameChangedEventArgs))] public void GetTempFrame( AsyncCBHandler asyncDelegate, object asyncContext) { BulkDbTempFrameChangedEventArgs e; if (GetTempFrameAction != null) e = GetTempFrameAction(); else e = new BulkDbTempFrameChangedEventArgs(); asyncDelegate?.Invoke(asyncContext, e); } /// /// /// /// /// /// public void Init(IShareDbService shareDb, LocalDb localDb, DbModel dbModel) { this.localDb = localDb; this.dbModel = dbModel; this.shareDb = shareDb; LocalDBLoad(); Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileStartTime), this, nameof(StartTime)); Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileEndTime), this, nameof(EndTime)); Misc.BindingOperations.SetBinding(localDb, nameof(localDb.IsProfileFinished), this, nameof(IsFinished)); this.shareDb.ProfileChanged += ShareDB_ProfileChanged; this.shareDb.ScanDataAdded += ShareDB_ScanDataAdded; } private void ShareDB_ProfileChanged(object sender, EventArgs _e) { ProfileChangedEventArgs e = (ProfileChangedEventArgs)_e; var profile = e.profile; //清除本地缓存 localDb.CurrProfile = profile; localDb.ProfileStartTime = profile.StartTime; localDb.ProfileEndTime = profile.EndTime; localDb.IsProfileFinished = profile.IsFinished; LastProfileId = profile.ID; LastTimestamp = DateTime.Now; } private void ShareDB_ScanDataAdded(object sender, EventArgs _e) { ScanDataAddedEventArgs e = (ScanDataAddedEventArgs)_e; LastScanDataId = e.scandata.ID; LastTimestamp = DateTime.Now; } /// /// 加载数据库中最后1次订单数据到 本地 /// void LocalDBLoad() { var reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_Profile.ID)}) FROM {dbModel.TbProfile.TableName}"); if (reponse is DBNull) { localDb.ProfileStartTime = DateTime.MinValue; localDb.ProfileEndTime = DateTime.MinValue; localDb.IsProfileFinished = true; return; } long maxid = System.Convert.ToInt64(reponse); var profile = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {maxid}").First(); reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_ScanData.ID)}) FROM {dbModel.TbScanData.TableName}"); if (!(reponse is DBNull)) { maxid = System.Convert.ToInt64(reponse); LastScanDataId = maxid; } localDb.CurrProfile = profile; localDb.ProfileStartTime = profile.StartTime; localDb.ProfileEndTime = profile.EndTime; localDb.IsProfileFinished = profile.IsFinished; LastProfileId = profile.ID; } /// /// 获取profile /// /// /// /// [Call(typeof(Pack_GetProfileReponse))] public async void GetProfile( Pack_GetProfileRequest request, AsyncCBHandler asyncDelegate, object asyncContext) { Pack_GetProfileReponse reponse = new Pack_GetProfileReponse(); reponse.Request = request; await Task.Factory.StartNew(() => { List db_profiles = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {request.Id}"); if (db_profiles.Count() == 0) return; reponse.profile = db_profiles.First(); }); asyncDelegate(asyncContext, reponse); } /// /// 获取N幅数据,需要异步 /// /// /// /// public async void GetFrame(Pack_GetFrameRequest request, AsyncCBHandler asyncDelegate, object asyncContext) { Pack_GetFrameReponse reponse = new Pack_GetFrameReponse(); reponse.Request = request; if (request.Mix > 10)//数量限制,避免死机 request.Mix = 10; else if (request.Mix < 1) request.Mix = 1; await Task.Factory.StartNew(() => { List db_scandatas; if (request.Id <= 0) db_scandatas = dbModel.TbScanData.Find( $"ORDER BY {nameof(Db_ScanData.ID)} DESC" + $" LIMIT {request.Mix} OFFSET {-request.Id}"); else db_scandatas = dbModel.TbScanData.Find( $"WHERE {nameof(Db_ScanData.ID)} <= {request.Id}" + $" ORDER BY ID DESC LIMIT {request.Mix}"); if (db_scandatas.Count() == 0) return; var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map, List>(db_scandatas); var lc_scanData = lc_scanDatas.First(); if (lc_scanDatas.Count() > 1) { //求均值 lc_scanData.Thicks = GetMixScanData(lc_scanDatas); } reponse.scanData = lc_scanData; //找profile var db_profiles = dbModel.TbProfile.Find( $"WHERE {nameof(Db_Profile.StartTime)}<={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" + $" AND {nameof(Db_Profile.EndTime)}>={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" + $" ORDER BY {nameof(Db_Profile.ID)} DESC"); if (db_profiles.Count() > 0) { reponse.profile = db_profiles.First(); } }); asyncDelegate(asyncContext, reponse); } /// /// 获取纵向趋势图 /// /// /// /// public async void GetTrend(Pack_GetTrendRequest request, AsyncCBHandler asyncDelegate, object asyncContext) { Pack_GetTrendReponse reponse = new Pack_GetTrendReponse(); reponse.Request = request; if (request.Count > 200)//数量限制,避免死机 request.Count = 200; else if (request.Count < 1) request.Count = 1; if (request.Mix > 10)//数量限制,避免死机 request.Mix = 10; else if (request.Mix < 1) request.Mix = 1; if (request.Interval < 1)//避免 /0 request.Interval = 1; await Task.Factory.StartNew(() => { List db_scandatas = null; if (request.Interval <= request.Mix) { //间隔<=混合,全部数据连续获取 int cnt = request.Count * request.Interval + request.Mix - 1; if (!request.IsSearchByTime) { if (request.Id <= 0) db_scandatas = dbModel.TbScanData.Find( $" ORDER BY ID DESC" + $" LIMIT {cnt} OFFSET {-request.Id}"); else db_scandatas = dbModel.TbScanData.Find( $"WHERE (ID <= {request.Id})" + $" ORDER BY ID DESC" + $" LIMIT {cnt}"); } else { db_scandatas = dbModel.TbScanData.Find( $"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" + $" ORDER BY ID DESC" + $" LIMIT {cnt}"); } } else { //间隔>混合 隔段获取 int cnt = request.Count * request.Mix; if (!request.IsSearchByTime) { if (request.Id <= 0) db_scandatas = dbModel.TbScanData.Find( $"WHERE ID % {request.Interval} < {request.Mix}" + $" ORDER BY ID DESC" + $" LIMIT {cnt} OFFSET {-request.Id}"); else db_scandatas = dbModel.TbScanData.Find( $"WHERE (ID <= {request.Id})" + $" AND ( ID % {request.Interval} < {request.Mix})" + $" ORDER BY ID DESC" + $" LIMIT {cnt}"); } else { db_scandatas = dbModel.TbScanData.Find( $"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" + $" AND ( ID % {request.Interval} < {request.Mix})" + $" ORDER BY ID DESC" + $" LIMIT {cnt}"); } } if (db_scandatas.Count() == 0) return; //从尾向前排的!!!! var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map, List>(db_scandatas); reponse.Values = ToTrend2(lc_scanDatas, request.Count, request.Mix, request.Interval); var lc_scanData = lc_scanDatas.First(); reponse.ScanDataId = lc_scanData.ID; }); asyncDelegate(asyncContext, reponse); } double[] GetMixScanData(List lc_scanDatas) { var lc_scanData = lc_scanDatas[0]; //求均值 double[] thks = new double[lc_scanData.Thicks.Count()]; int[] cnt = new int[thks.Count()]; for (int j = 0; j < lc_scanDatas.Count(); j++) { int index = j; if (lc_scanDatas[index].Thicks.Count() != thks.Count()) { //结束,异常 break; } for (int i = 0; i < thks.Count(); i++) { var v = lc_scanDatas[index].Thicks[i]; if (!double.IsNaN(v)) { thks[i] += v; cnt[i]++; } } } for (int i = 0; i < thks.Count(); i++) { if (cnt[i] > 0) thks[i] /= cnt[i]; else thks[i] = double.NaN; } return thks; } double[] GetMixScanData(List lc_scanDatas, int offset, int mix, out int realMix) { //lc_scanDatas[0] 是最新的数据!! List lc_scanDatas2 = new List(); for (int i = 0; i < mix; i++) { int index = offset + i; if (index >= lc_scanDatas.Count()) break; lc_scanDatas2.Add(lc_scanDatas[offset + i]); } //连续两幅图时间间隔 大于 MixDataTimeRange 删除 if (MixDataTimeRange > TimeSpan.Zero) { for (int i = 1; i < lc_scanDatas2.Count(); i++) { var scanData0 = lc_scanDatas2[i - 1]; var scanData1 = lc_scanDatas2[i]; if (scanData0.Time - scanData1.Time > MixDataTimeRange) { lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i); break; } } } //把 均值与 最新的一幅图 的均值 偏差 大于 MixDataAvgRange 删除 if (MixDataAvgRange > 0) { var newest_scanData = lc_scanDatas2[0]; //注意数据是没有剔除的, 计算平均值时,要明确范围 var newest_avg = Misc.MyMath.Avg(newest_scanData.Thicks); if (!double.IsNaN(newest_avg)) { for (int i = 1; i < lc_scanDatas2.Count(); i++) { var scanData = lc_scanDatas2[i]; var avg = Misc.MyMath.Avg(scanData.Thicks); if (double.IsNaN(avg))//一幅数据异常,全部删除 { lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i); break; } //变化太大 if (Math.Abs(newest_avg - avg) > MixDataAvgRange) { lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i); break; } } } else { lc_scanDatas2.RemoveRange(1, lc_scanDatas2.Count() - 1); } } realMix = lc_scanDatas2.Count(); if (lc_scanDatas2.Count() > 1) { //求均值 return GetMixScanData(lc_scanDatas2); } else { return lc_scanDatas2.First().Thicks.ToArray(); } } List ToTrend2(List lc_scanDatas, int count, int mix, int interval) { // lc_scanDatas.First() 是ID最大的数据 //if (mix == 1) //{ // return lc_scanDatas.Select(sd => // { // double avg = sd.Thicks.AverageNoNull(); // double sigma = sd.Thicks.Sigma(); // return new TrendValue() // { // ScanDataID = sd.ID, // ProfileID = sd.ProfileID, // Sigma = sigma, // Value = avg, // Time = sd.Time // }; // }).ToList(); //} List trendValues = new List(); for (int i = 0; i < lc_scanDatas.Count(); i++) { var sd = lc_scanDatas[i]; if (sd.ID % interval == 0) { //它是数据点 double[] thks = GetMixScanData(lc_scanDatas, i, mix, out int _m); //求均值 double avg = thks.AverageNoNull(); double sigma = thks.Sigma(); trendValues.Add(new TrendValue() { ScanDataID = sd.ID, Sigma = sigma, Value = avg, Time = lc_scanDatas[i].Time }); if (trendValues.Count() >= count) break;//完成 } } return trendValues; } /// /// 完成 /// public void Finish() { shareDb.FinishProfile(); } } }