using Misc; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlyADBase { /// <summary> /// 高级timegrid助手 /// 使用说明: /// ADPool 只能储存 1min数据, 其它XXXPool 保存1.5min数据 /// /// /// 获取最后一次运行动作的开始与结束时间 /// bool ret = mTimeGridAdvHelper.GetLastRunningTime(out DateTime beginTime, out DateTime endTime, out int marker, out DRIVE_MAN_ORDER order); /// /// 获取 指定时间范围的 timegrid 数据 /// var adList = mTimeGridAdvHelper.GetAD(beginTime, endTime, out DateTime reponse_endTime); /// /// 获取 指定时间范围的 pos 数据 /// var posList = mTimeGridAdvHelper.GetPos(reponse_endTime,adList.Count()); /// /// 获取 指定时间范围的 pos2 数据 /// var pos2List = mTimeGridAdvHelper.GetPos2(reponse_endTime,adList.Count()); /// /// 获取 指定时间范围的 输入口 数据 /// var istatusList = mTimeGridAdvHelper.GetIStatus(reponse_endTime,adList.Count()); /// /// 转为 grid 数据 /// int posLen = 8900; /// var grid = ToGrid(adList, posList, posOfGrid = 10, gridLen = posLen/10); /// /// </summary> public class TimeGridAdvHelper { NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); #region 一分钟数据缓存池, 目标每个AD数据(1.28ms) 都有对应的其它数据 /// <summary> /// AD数据池时间间隔为1.28ms, 肯定最少有一个数据 /// 每个数据包(200个数据)理论间隔是200*1.28ms, 但实际上不是。 /// 数据输出时,输出的每个数据必须是1ms, 需要通过数据包的systick线性填充数据 /// </summary> public List<DateTimeUnit3> ADPool = new List<DateTimeUnit3>(); /// <summary> /// pos 数据池, 肯定最少有一个数据 /// </summary> public List<DateTimeUnit> PosPool = new List<DateTimeUnit>(); /// <summary> /// 输入端口 数据池, 肯定最少有一个数据 /// </summary> public List<DateTimeUnit2> IStatusPool = new List<DateTimeUnit2>(); /// <summary> /// pos2 数据池, 肯定最少有一个数据 /// </summary> public List<DateTimeUnit> Pos2Pool = new List<DateTimeUnit>(); /// <summary> /// DriveStatus 数据池, 肯定最少有一个数据 /// </summary> public List<DateTimeUnit4> DriveStatusPool = new List<DateTimeUnit4>(); #endregion public DateTime NewestTime; /// <summary> /// /// </summary> public void Init() { Clear(); } /// <summary> /// 添加ad数据,且判断数据量是否够触发事件, 时间间隔为1.28ms /// </summary> /// <param name="end_dt"></param> /// <param name="adArray"></param> public void AddAD(DateTime end_dt, int[] adArray) { if (adArray.Count() == 0) return; //------------------------------------------------------------------------------------------ //AD数据添加 //DateTime dt = DateTime.MinValue; ADPool.Add(new DateTimeUnit3() { dt = end_dt, datas = adArray}); //long ticks = (long)((ts_ms * adArray.Count()) * TimeSpan.TicksPerMillisecond); NewestTime = end_dt; LimitPool(); } void LimitPool() { LimitSimplePool(ADPool); //LimitSimplePool_PosPool(); LimitSimplePool(PosPool,1.5); LimitSimplePool(Pos2Pool, 1.5); LimitSimplePool(DriveStatusPool, 1.5); LimitSimplePool(IStatusPool, 1.5); } /// <summary> /// /// </summary> /// <typeparam name="T">IDateTimeUnit</typeparam> /// <param name="pool">缓存区</param> /// <param name="cap_min">缓存区容量单位min</param> void LimitSimplePool<T>(List<T> pool, double cap_min = 1) where T : IDateTimeUnit { if (NewestTime == DateTime.MinValue) return; //限制的时间 var limitTime = NewestTime - TimeSpan.FromMinutes(cap_min); //删除Pos 数据池 int removeCnt = 0; for (int i = 0; i < pool.Count(); i++) { var cell = pool[i]; if (cell.dt < limitTime) { //需要删除 removeCnt = i + 1; } else { break; } } if (removeCnt > 0) { //不能全部数据删除完,必须留一个 if (removeCnt == pool.Count()) { removeCnt--; if (removeCnt <= 0) return;//不用删除了 } pool.RemoveRange(0, removeCnt); } } /// <summary> /// 添加脉冲 /// </summary> /// <param name="pos"></param> /// <param name="time"></param> public void AddPos(DateTime time, int pos) { AddSimpleData(PosPool, time, pos); } /// <summary> /// 添加驱动状态 /// </summary> /// <param name="time"></param> /// <param name="order"></param> /// <param name="driveStatus"></param> /// <param name="marker"></param> public void AddDriveStatus(DateTime time,DRIVE_MAN_ORDER order, DRIVE_MAN_STATUS driveStatus, int marker) { var pool = DriveStatusPool; if (pool.Count > 0) { if (pool.Last().dt > time) { //异常,把之前的数据删除 pool.Clear(); } else if (pool.Last().dt == time) { //删除之前那个 pool.RemoveAt(pool.Count() - 1); } } pool.Add(new DateTimeUnit4() { dt = time, order = order, driveStatus = driveStatus, marker = marker }); } void AddSimpleData(List<DateTimeUnit> pool, DateTime time, int data) { if (pool.Count > 0) { if (pool.Last().dt > time) { //异常,把之前的数据删除 //TODO, AD盒有bug, IO 推送, 的systick 比 pos 的systick 要慢, //正常的操作,全删除 //pool.Clear(); //数据插入就算了 for (int i = 1; i < pool.Count(); i++) { int index = pool.Count() - 1 - i; if (time > pool[index].dt) { //找到了 pool.Insert(index, new DateTimeUnit() { dt = time, data = data }); } else if (time == pool[index].dt) { //什么都不干 return; } } //找完了,不插了 } else if (pool.Last().dt == time) { //删除之前那个 //pool.RemoveAt(pool.Count() - 1); return; } } pool.Add(new DateTimeUnit() { dt = time, data = data }); } /// <summary> /// 添加脉冲 /// </summary> /// <param name="pos2"></param> /// <param name="time"></param> public void AddPos2(DateTime time, int pos2) { AddSimpleData(Pos2Pool, time, pos2); } /// <summary> /// 添加输入口状态 /// </summary> /// <param name="time"></param> /// <param name="istatus"></param> /// <param name="pos"></param> /// <param name="pos2"></param> public void AddIStatus(DateTime time, UInt16 istatus, int pos, int pos2) { var pool = IStatusPool; if (pool.Count > 0) { if (pool.Last().dt >= time) { //异常,把之前的数据删除 pool.Clear(); } } IStatusPool.Add(new DateTimeUnit2() { dt = time, istatus = istatus, isPosValid = true, pos = pos, pos2 = pos2 }); AddPos(time, pos); AddPos2(time, pos2); } /// <summary> /// 添加开始位置 /// </summary> /// <param name="pos"></param> /// <param name="time"></param> public void AddPos_Default(DateTime time, int pos) { if (PosPool.Count() == 0) { AddPos(time,pos); } } /// <summary> /// 添加开始位置 /// </summary> /// <param name="pos"></param> /// <param name="time"></param> public void AddPos2_Default(DateTime time, int pos) { if (Pos2Pool.Count() == 0) { AddPos2(time,pos); } } /// <summary> /// 添加开始驱动状态 /// </summary> /// <param name="time"></param> /// <param name="order"></param> /// <param name="dirveStatus"></param> /// <param name="marker"></param> public void AddDriveStatus_Default(DateTime time, DRIVE_MAN_ORDER order, DRIVE_MAN_STATUS dirveStatus, int marker) { if (IStatusPool.Count() == 0) { AddDriveStatus(time, order, dirveStatus, marker); } } /// <summary> /// 添加开始状态 /// </summary> /// <param name="istatus"></param> /// <param name="time"></param> public void AddIStatus_Default(DateTime time, UInt16 istatus) { if (IStatusPool.Count() == 0) { IStatusPool.Add(new DateTimeUnit2() { dt = time, istatus = istatus}); } } /// <summary> /// /// </summary> public void Clear() { PosPool.Clear(); ADPool.Clear(); IStatusPool.Clear(); Pos2Pool.Clear(); DriveStatusPool.Clear(); } /// <summary> /// 获取最后一次运行的时间段 /// </summary> /// <param name="begin"></param> /// <param name="end"></param> /// <param name="marker"></param> /// <param name="order"></param> /// <returns></returns> public bool GetLastRunningTime(out DateTime begin, out DateTime end, out int marker, out DRIVE_MAN_ORDER order) { begin = DateTime.MinValue; end = DateTime.MinValue; marker = 0; order = DRIVE_MAN_ORDER.IDLE; //1. 找 最后一个 driveStatus!=running的 int idxOfStop = -1; for (int i = DriveStatusPool.Count() - 1; i >= 0; i--) { var cell = DriveStatusPool[i]; if (cell.driveStatus != DRIVE_MAN_STATUS.RUNNING) { //对!!它是。但继续向前找找看 idxOfStop = i; } else { if (idxOfStop != -1) { //之前已经找到了, break; } } } if (idxOfStop == -1) { //一直在running,还没停下来 return false; } //2. 最向前找running的 int idxOfRunning = -1; for (int i = idxOfStop - 1; i >= 0; i--) { var cell = DriveStatusPool[i]; if (cell.driveStatus == DRIVE_MAN_STATUS.RUNNING) { //对!!它是。但继续向前找找看 idxOfRunning = i; } else { //没了 break; } } if (idxOfRunning == -1) { //一直停着,没有运行过 return false; } begin = DriveStatusPool[idxOfRunning].dt; end = DriveStatusPool[idxOfStop].dt; order = DriveStatusPool[idxOfStop].order; marker = DriveStatusPool[idxOfStop].marker; return true; } /// <summary> /// 获取最后一次运行中的timegrid; /// 找到最后一个 driveStatus!=running的, 最向前找running的 /// </summary> /// <param name="begin">开始时间</param> /// <param name="end">结束时间</param> /// <param name="reponse_endTime">返回数据的最后一个数据的时间,数据间隔为1.28ms</param> /// <returns></returns> public List<int> GetAD(DateTime begin, DateTime end, out DateTime reponse_endTime) { return TimeGridAdvHelperExt.GetAD(ADPool, begin, end, out reponse_endTime); } public List<int> GetAD(DateTime begin) { return TimeGridAdvHelperExt.GetAD(ADPool, begin ); } public List<int> GetPos(DateTime end_dt, int cnt) { return TimeGridAdvHelperExt.GetPos(PosPool, end_dt, cnt); } public List<int> GetPos2(DateTime end_dt, int cnt) { return TimeGridAdvHelperExt.GetPos(Pos2Pool, end_dt, cnt); } public List<UInt16> GetIStatus(DateTime end_dt, int cnt) { return TimeGridAdvHelperExt.GetIStatus(IStatusPool, end_dt, cnt); } public void GetIStatusRange( int istatusIndex, DateTime beginTime, DateTime endTime, out List<Range> data0, out List<Range> data1) { TimeGridAdvHelperExt.GetIStatusRange(IStatusPool, PosPool, true, istatusIndex, beginTime, endTime, out data0, out data1); } } public interface IDateTimeUnit { DateTime dt { get; set; } } public struct DateTimeUnit: IDateTimeUnit { public int data; public DateTime dt { get; set; } public override string ToString() { return $"{dt.Ticks} | {data}"; } } public struct DateTimeUnit4 : IDateTimeUnit { public DateTime dt { get; set; } public DRIVE_MAN_ORDER order; public DRIVE_MAN_STATUS driveStatus; public int marker; public override string ToString() { return $"{dt.Ticks} | {order} | {driveStatus} | {marker}"; } } public struct DateTimeUnit3 : IDateTimeUnit { /// <summary> /// 数据结束点 /// </summary> public DateTime dt { get; set; } /// <summary> /// 数据列 /// </summary> public int[] datas; public override string ToString() { return $"{dt.Ticks} | cnt={datas.Count()}"; } } public struct DateTimeUnit2: IDateTimeUnit { public DateTime dt { get; set; } public UInt16 istatus; public bool isPosValid; public int pos; public int pos2; public override string ToString() { if(isPosValid) return $"{dt.Ticks} | ({istatus:X2}) | 1={pos} | 2={pos2}"; else return $"{dt.Ticks} | ({istatus:X2})"; } } public static class TimeGridAdvHelperExt { /// <summary> /// 每个ad数据的时间间隔 1ms//1.28ms /// </summary> public const double ad_ts_ms = 1.28; public static TimeSpan ad_ts => TimeSpan.FromTicks((long)(ad_ts_ms * TimeSpan.TicksPerMillisecond)); public static List<int> GetAD(List<DateTimeUnit3> adPool, DateTime begin, DateTime end, out DateTime reponse_endTime) { reponse_endTime = DateTime.MinValue; var reponse2 = GetAD2(adPool, begin, end); if (reponse2.Count() == 0) return new List<int>(); DateTime lastTime = reponse2.Last().dt; reponse_endTime = lastTime; return GetAD(reponse2); } public static List<int> GetAD(List<DateTimeUnit3> adPool) { return GetAD(adPool, DateTime.MinValue); } public static List<int> GetAD(List<DateTimeUnit3> adPool, DateTime begin) { List<int> reponse = new List<int>(); //导出数据的时间 DateTime idealTime = adPool.Last().dt; //每个ad包的每个数据不是准确的1.28ms,肯定比1.28ms大,每次需要准 for (int i = 0; i < adPool.Count(); i++) { int idx = adPool.Count() - 1 - i; //当前缓存区包,数据的时间间隔 TimeSpan curr_ad_ts; //计算这个包每个数据的时间间隔 DateTime end_dt = adPool[idx].dt; if (idx > 0) { var begin_dt = adPool[idx - 1].dt; double total_ms = (end_dt - begin_dt).Ticks / TimeSpan.TicksPerMillisecond; var curr_ad_ts_ms = total_ms / adPool[idx].datas.Count(); curr_ad_ts = TimeSpan.FromTicks((long)(curr_ad_ts_ms * TimeSpan.TicksPerMillisecond)); } else if (adPool.Count() > 1) { var begin_dt = adPool[idx].dt - (adPool[idx + 1].dt - adPool[idx].dt); double total_ms = (end_dt - begin_dt).Ticks / TimeSpan.TicksPerMillisecond; var curr_ad_ts_ms = total_ms / adPool[idx].datas.Count(); curr_ad_ts = TimeSpan.FromTicks((long)(curr_ad_ts_ms * TimeSpan.TicksPerMillisecond)); } else { curr_ad_ts = ad_ts; } DateTime actTime = adPool[idx].dt;//从缓存区获取数据的时间 for (int j = 0; j < adPool[idx].datas.Count(); j++) { int idx2 = adPool[idx].datas.Count() - 1 - j; int ad = adPool[idx].datas[idx2]; actTime -= curr_ad_ts; while (idealTime > actTime) { reponse.Add(ad);//导出数据 idealTime -= ad_ts;//导出数据时间累加 } } if (idealTime < begin) goto _end;//完成 } _end: //反转 reponse.Reverse(); return reponse; } /// <summary> /// 获取 时间在 begin~end 的 AD数据包 /// </summary> /// <param name="adPool"></param> /// <param name="begin"></param> /// <param name="end"></param> /// <returns></returns> static List<DateTimeUnit3> GetAD2(List<DateTimeUnit3> adPool, DateTime begin, DateTime end) { //ad 包的总数量不可能多,从头找也没所谓 List<DateTimeUnit3> reponse = new List<DateTimeUnit3>(); for (int i = 0; i < adPool.Count(); i++) { var cell = adPool[i]; if (cell.dt < begin) continue; else if (cell.dt <= end) reponse.Add(cell); else break; } return reponse; } /// <summary> /// 获取平均速度, 单位 脉冲/min /// </summary> /// <param name="posPool"></param> /// <param name="begin"></param> /// <param name="end"></param> /// <returns></returns> public static double GetSpeed(List<DateTimeUnit> posPool, DateTime begin, DateTime end) { int searchIdx = posPool.Count() - 1; int end_pos = GetPos(posPool, end, ref searchIdx); int begin_pos = GetPos(posPool, begin, ref searchIdx); return (end_pos - begin_pos) / (end - begin).TotalMinutes; } /// <summary> /// 输出以 ad_ts_ms 为间隔脉冲列表 /// </summary> /// <param name="posPool"></param> /// <param name="end_dt"></param> /// <param name="cnt"></param> /// <returns></returns> public static List<int> GetPos(List<DateTimeUnit> posPool, DateTime end_dt, int cnt) { //从后面开始找 int searchIdx = posPool.Count() - 1; List<int> reponse = new List<int>(); DateTime lastTime = end_dt; for (int i = 0; i < cnt; i++) { reponse.Add(GetPos(posPool, lastTime, ref searchIdx)); lastTime -= ad_ts; } //反转 reponse.Reverse(); return reponse; } /// <summary> /// 获取时间对应的 位置点 /// </summary> /// <param name="dt"></param> /// <param name="posPool">脉冲缓存池</param> /// <param name="searchIdx">查询开始序号</param> /// <returns></returns> public static int GetPos(List<DateTimeUnit> posPool, DateTime dt, ref int searchIdx) { //找到 时间落在 [idx,idx+1] 之间的 序号 int index = searchIndex(posPool, dt, searchIdx); searchIdx = index; if (index == posPool.Count() - 1) { //发生在未来,返回最后一个脉冲,不进行线性预测 return posPool[index].data; } else if (index < 0) { //发生在过去,返回第一个脉冲,不进行线性预测 return posPool[0].data; } return GetPosLinear(posPool, dt, index); } /// <summary> /// 线性插值算 pos; /// 以 [idx,idx+1] 的比例, 给出 time 计算 pos /// </summary> /// <param name="posPool"></param> /// <param name="time"></param> /// <param name="idx"></param> /// <returns></returns> static int GetPosLinear(List<DateTimeUnit> posPool, DateTime time, int idx) { if (posPool.Count() <= 0)//不应该存在 { throw new Exception("没数据,还没准备好,不能获取"); } if (posPool.Count() == 1) return posPool.First().data; if (idx < 0) idx = 0; if (idx >= posPool.Count() - 1) idx = posPool.Count() - 2; var cell0 = posPool[idx]; var cell1 = posPool[idx + 1]; double d_pos = cell0.data - cell1.data; if (d_pos == 0) return cell0.data; TimeSpan ts = cell0.dt - cell1.dt; double p = d_pos * (time - cell1.dt).Ticks / ts.Ticks; return (int)(p + cell1.data); } enum SearchState { ContinueLastTime, Back, ForwToCheck } /// <summary> /// 找到 时间 dt 落在 [idx,idx+1] 之间的 idx; /// 返回 -1,证明dt 在列表在前面, 或列表数据量为=0, /// 当dt 大于 列表最后一个数, 返回最后一个数据的id /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list">列表</param> /// <param name="dt"></param> /// <param name="searchStartIdx">从列表的某个位置开始向前查找</param> /// <returns></returns> public static int searchIndex<T>(List<T> list, DateTime dt, int searchStartIdx) where T : IDateTimeUnit { if (list.Count() == 0) return -1; int max_index = list.Count() - 1; if (dt >= list[max_index].dt) return max_index; if (dt < list[0].dt) return -1; int index = searchStartIdx; SearchState state = SearchState.ContinueLastTime; if ((index < 0) || (index >= max_index))//重新开始 { index = max_index; state = SearchState.Back; } else if (state == SearchState.ContinueLastTime) { if (list[index].dt <= dt) { //可能找到了 //再向正方向看看 state = SearchState.ForwToCheck; } else { state = SearchState.Back; } } if (state == SearchState.ForwToCheck) { while (true) { DateTime time = list[index].dt; if (time > dt) { //就是之前那个 index--; return index; } else { index++; } if (index > max_index) { //最后一个就是了 throw new Exception("之前没有判断出 时间点在列表后,异常!!"); //return max_index; } } } else//SearchState.Back { while (true) { DateTime time = list[index].dt; if (time <= dt) { //就是它 return index; } index--; if (index < 0) { //不可能发生 throw new Exception("之前没有判断出 时间点在列表前,异常!!"); } } } } public static List<UInt16> GetIStatus(List<DateTimeUnit2> iStatusPool, DateTime end_dt, int cnt) { int searchIdx = iStatusPool.Count() - 1; List<UInt16> reponse = new List<UInt16>(); DateTime lastTime = end_dt; for (int i = 0; i < cnt; i++) { reponse.Add(GetIStatus(iStatusPool, lastTime, ref searchIdx)); lastTime -= ad_ts; } //反转 reponse.Reverse(); return reponse; } /// <summary> /// 根据时间点,获取输入口状态; /// 时间 dt 落在 [searchIdx,searchIdx+1] /// </summary> /// <param name="iStatusPool"></param> /// <param name="dt"></param> /// <param name="searchIdx"></param> /// <returns></returns> public static UInt16 GetIStatus(List<DateTimeUnit2> iStatusPool, DateTime dt, ref int searchIdx) { int index = searchIndex(iStatusPool, dt, searchIdx); if (index < 0) index = 0; searchIdx = index; return (UInt16)iStatusPool[index].istatus; } /// <summary> /// data0 的 输入口=false 脉冲范围;data1 的 输入口=true 脉冲范围; /// </summary> /// <param name="iStatusPool">输入口池</param> /// <param name="posPool">脉冲池</param> /// <param name="isPos1">是pos1?</param> /// <param name="istatusIndex">输入口序号</param> /// <param name="beginTime">开始时间</param> /// <param name="endTime">结束时间</param> /// <param name="data0">false脉冲范围</param> /// <param name="data1">true脉冲范围</param> public static void GetIStatusRange( List<DateTimeUnit2> iStatusPool, List<DateTimeUnit> posPool, bool isPos1, int istatusIndex, DateTime beginTime, DateTime endTime, out List<Range> data0, out List<Range> data1) { int istatus_search_idx = iStatusPool.Count - 1; int pos_search_idx = posPool.Count - 1; data0 = new List<Range>(); data1 = new List<Range>(); UInt16 istatus = GetIStatus(iStatusPool, beginTime, ref istatus_search_idx); int beginPos = GetPos(posPool, beginTime, ref pos_search_idx); int endPos = GetPos(posPool, endTime, ref pos_search_idx); DIRECTION direction = endPos > beginPos ? DIRECTION.FORWARD : DIRECTION.BACKWARD; bool istatus_no_b = Misc.MyBase.CHECKBIT(istatus, istatusIndex); Range r = new Range(); r.Begin = beginPos; for (int i = istatus_search_idx + 1; i < iStatusPool.Count(); i++) { istatus = iStatusPool[i].istatus; int pos; if (isPos1) pos = iStatusPool[i].pos; else pos = iStatusPool[i].pos2; bool b = Misc.MyBase.CHECKBIT(istatus, istatusIndex); if (iStatusPool[i].dt >= endTime) { //结束,这是最后!!! break; } else { if (b != istatus_no_b) { r.End = pos; if (istatus_no_b) data1.Add(r); else data0.Add(r); istatus_no_b = b; r = new Range(); r.Begin = pos; } } } r.End = beginPos; if (istatus_no_b) data1.Add(r); else data0.Add(r); if (direction == DIRECTION.FORWARD) { for (int i = 0; i < data0.Count(); i++) { data0[i].End -= 1; } for (int i = 0; i < data1.Count(); i++) { data1[i].End -= 1; } } else { for (int i = 0; i < data0.Count(); i++) { data0[i].End += 1; int t = data0[i].End; data0[i].End = data0[i].Begin; data0[i].Begin = t; } data0.Reverse(); for (int i = 0; i < data1.Count(); i++) { data1[i].End += 1; int t = data1[i].End; data1[i].End = data1[i].Begin; data1[i].Begin = t; } data1.Reverse(); } } /// <summary> /// data0 的 输入口=false 序号范围;data1 的 输入口=true 序号范围; /// timeOffset 为时间偏移,用于多AD盒情况,iStatusPool内的全部时间都会+timeOffset /// </summary> /// <param name="iStatusPool">输入口池</param> /// <param name="istatusIndex">输入口序号</param> /// <param name="beginTime">开始时间</param> /// <param name="endTime">结束时间</param> /// <param name="data0">false脉冲范围</param> /// <param name="data1">true脉冲范围</param> public static void GetIStatusRange( List<DateTimeUnit2> iStatusPool, int istatusIndex, DateTime beginTime, DateTime endTime, out List<Range_DateTime> data0, out List<Range_DateTime> data1) { int istatus_search_idx = iStatusPool.Count - 1; data0 = new List<Range_DateTime>(); data1 = new List<Range_DateTime>(); UInt16 istatus = GetIStatus(iStatusPool, beginTime, ref istatus_search_idx); bool istatus_no_b = Misc.MyBase.CHECKBIT(istatus, istatusIndex); Range_DateTime r = new Range_DateTime(); r.Begin = beginTime; int i = istatus_search_idx + 1; while (i < iStatusPool.Count()) { istatus = iStatusPool[i].istatus; bool b = Misc.MyBase.CHECKBIT(istatus, istatusIndex); if (iStatusPool[i].dt >= endTime) { //结束,这是最后!!! break; } else { if (b != istatus_no_b) { r.End = iStatusPool[i].dt; if (istatus_no_b) data1.Add(r); else data0.Add(r); istatus_no_b = b; r = new Range_DateTime(); r.Begin = iStatusPool[i].dt; } } i++; } r.End = endTime; if (istatus_no_b) data1.Add(r); else data0.Add(r); } static void toGrid_step1(int[] grids_sum, int[] grids_cnt, int gridLen, int grid_idx, int ad) { if ((grid_idx < 0) || (grid_idx >= gridLen)) { return; } if (!Misc.MyBase.ISVALIDATA(ad)) return; grids_cnt[grid_idx]++; grids_sum[grid_idx] += ad; } /// <summary> /// 输出 grid图。 adList[x-adLag] 对应 posList[x] /// </summary> /// <param name="adList"></param> /// <param name="posList"></param> /// <param name="posOfGrid"></param> /// <param name="gridLen"></param> /// <param name="adLag"></param> /// <returns></returns> public static int[] ToGrid(List<int> adList, List<int> posList, int posOfGrid, int gridLen, int adLag=0) { int[] grids_sum = new int[gridLen]; int[] grids_cnt = new int[gridLen]; int grid_idx_last = -1; //grid_idx 应该要连续变化,不是,那就插值 for (int j = 0; j < adList.Count() && j < posList.Count(); j++) { int index = j - adLag; if (index < 0 || index >= adList.Count()) continue; int ad = adList[index]; int pos = posList[j]; int grid_idx = pos / posOfGrid; if (grid_idx_last != -1 && (Math.Abs(grid_idx_last - grid_idx) > 1)) { //步子太大,需要插值 if (grid_idx_last < grid_idx) { for (int i = grid_idx_last; i < grid_idx; i++) { toGrid_step1(grids_sum, grids_cnt, gridLen, i, ad); } } else { for (int i = grid_idx_last; i > grid_idx; i--) { toGrid_step1(grids_sum, grids_cnt, gridLen, i, ad); } } } toGrid_step1(grids_sum, grids_cnt, gridLen, grid_idx, ad); grid_idx_last = grid_idx; } for (int i = 0; i < gridLen; i++) { if (grids_cnt[i] == 0) grids_sum[i] = Misc.MyBase.NULL_VALUE; else grids_sum[i] = (int)(grids_sum[i] / grids_cnt[i]); } return grids_sum; } } public class Range_DateTime { public DateTime Begin; public DateTime End; } }