using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Xml.Serialization;
using Misc;
using FObjBase;
using FlyADBase;
using FLY.Thick.Base.IService;
using PropertyChanged;
using Newtonsoft.Json;
using static Misc.ReverserInfo;
using FLY.Thick.Base.Common;
using AutoMapper;
namespace FLY.Thick.Base.Server
{
public class GSample : IGetSampleService
{
///
/// 报警测试
///
#region IGetSampleService 接口
///
/// 参数:使能
///
public bool Enable { get; set; } = true;
///
/// 参数:速度
///
public UInt32 Velocity { get; set; } = 500;
///
/// 参数:样品点范围 单位:脉冲
/// 样品点直径为 Range*2
///
public int SampleRange { get; set; } = 100;
///
/// 滤波窗口,单位 min
///
public int Window { get; set; }
///
/// 使用%方式检查异常
///
public bool IsCheckByPercent { get; set; } = true;
///
/// 异常比例 单位不是%
///
public double ErrPercent { get; set; } = 0.02;
///
/// 异常值
///
public int ErrValue { get; set; } = 200;
///
/// 当前 样品X_AD/样品0_AD 与 上一次比较 差异比例 单位不是%
///
public double CrossErrPercent { get; set; } = 0.02;
///
/// 样品
///
public SampleCell[] Samples { get; set; }
///
/// 参数:特征查找范围 单位:脉冲
/// 取样范围 会扩大为 -SearchRange ~ +SearchRange
///
public int SearchRange { get; set; } = 100;
///
/// 特征 相识度 0 正, 1 反
///
public SampleFeature[] Features { get; set; }
#endregion
TempFilter2[] tempFilters;
DIRECTION[] directions;
///
/// 采集状态
///
public SampleState[] states;
public enum SampleState
{
///
/// 准备采集
///
ReadyToCapture,
///
/// 采集成功
///
Ok,
///
/// 采集失败
///
IsFailure
}
IGageInfoService mGageInfo;
OBJComponents.Server.WarningSystem2 warningSystem;
IFlyADClientAdv flyad;
SampleData last_sampleData;
public event SampleChangedEventHandler SampleChangedEvent;
private string param_path;
public GSample():this("gsample.json")
{
}
public GSample(string param_path)
{
this.param_path = param_path;
Samples = new SampleCell[3];
Features = new SampleFeature[2];
tempFilters = new TempFilter2[Samples.Count()];
directions = new DIRECTION[Samples.Count()];
states = new SampleState[Samples.Count()];
for (int i = 0; i < Samples.Count(); i++)
tempFilters[i] = new TempFilter2();
Enable = true;
SampleRange = 100;//样品范围
Velocity = 200;//取样速度
Window = 3;//移动窗口
IsCheckByPercent = true;
ErrPercent = 2;
ErrValue = 200;
Samples[0] = new SampleCell()
{
Enable = true,
Position = 200,
OrgAD = 50300
};
directions[0] = DIRECTION.BACKWARD;
Samples[1] = new SampleCell()
{
Enable = false,
Position = 0,
OrgAD = 0
};
directions[1] = DIRECTION.FORWARD;
Samples[2] = new SampleCell()
{
Enable = false,
Position = 0,
OrgAD = 0
};
directions[2] = DIRECTION.FORWARD;
SearchRange = 100;
Features[0] = new SampleFeature() { StartPos = 0, EndPos = 0 };
Features[1] = new SampleFeature() { StartPos = 2000, EndPos = 2100 };
Load();
}
public virtual void Init(
IFlyADClientAdv flyad,
IGageInfoService gageInfo,
OBJComponents.Server.WarningSystem2 warningSystem)
{
this.flyad = flyad;
this.mGageInfo = gageInfo;
this.warningSystem = warningSystem;
}
public bool Load()
{
return GSampleJsonDb.Load(this, param_path);
}
///
/// 保存
///
public bool Save()
{
return GSampleJsonDb.Save(this, param_path);
}
///
/// 1.判断样品取样方向
/// 2.复位间隔计数
/// 3.复位所有样品取样状态
///
///
///
public virtual void Reset(int scanbegin, int scanend)
{
last_sampleData = null;
for (int i = 0; i < Samples.Count(); i++) {
SampleCell sample = Samples[i];
int pos = sample.Position;
directions[i] = (Math.Abs(pos - scanbegin) < Math.Abs(pos - scanend)) ? Misc.DIRECTION.BACKWARD : Misc.DIRECTION.FORWARD;
sample.AD = -1;
states[i] = SampleState.ReadyToCapture;
tempFilters[i].Reset();
}
}
///
/// 进入采集周期,设置全部采样点 为准备采集状态
///
public void ReadyToCapture()
{
for (int i = 0; i < Samples.Count(); i++)
{
states[i] = SampleState.ReadyToCapture;
}
}
///
/// 获取样品测量范围
///
///
/// 当没有样品,也没有特征,返回null
public Range GetSampleRange(Misc.DIRECTION direction)
{
int b, e;
if (GetSampleRange(direction, out b, out e))
{
return new Range() { Begin = b, End = e };
}
else
{
return new Range();
}
}
///
/// 获取样品测量范围
///
///
///
///
/// 当没有样品,也没有特征,返回False
public virtual bool GetSampleRange(Misc.DIRECTION direction, out int start,out int end)
{
start = 0;
end = 0;
bool valid = false;
int b=0, e=0;
int r_idx = (direction == Misc.DIRECTION.FORWARD) ? 0 : 1;
if (Features[r_idx].Enable)
{
b = Features[r_idx].StartPos;
e = Features[r_idx].EndPos;
valid = true;
}
for(int i=0;i< Samples.Count(); i++)
{
SampleCell sample = Samples[i];
if ((sample.Enable) && (directions[i] == direction))
{
int _b = sample.Position - SampleRange;
int _e = sample.Position + SampleRange;
if (!valid)
{
b = _b;
e = _e;
valid = true;
}
else
{
if (b > _b)
b = _b;
if (e < _e)
e = _e;
}
}
}
if (valid)
{
if (Features[r_idx].Enable)
{
b -= SearchRange;
e += SearchRange;
}
start = b;
end = e;
}
return valid;
}
///
/// 检测参数合法性
///
///
protected bool CheckParamIsValid()
{
//样品位置 要在 范围
foreach(SampleCell sample in Samples)
{
if (sample.Enable)
{
if(((sample.Position - SampleRange)<0) || ((sample.Position+SampleRange)>= flyad.PosLen))
return false;
}
}
foreach(SampleFeature feature in Features)
{
if (feature.Enable)
{
if(((feature.StartPos - SearchRange)<0) || ((feature.EndPos+SearchRange)>= flyad.PosLen))
return false;
}
}
return true;
}
///
/// 样品取样,推送给thickm, 参数一定合法,不用检测
///
///
public void Do(Misc.DIRECTION direction)
{
int[] dat;
flyad.GetGrid(direction,0, flyad.PosLen/flyad.PosOfGrid, out dat);
Do(direction, 0, dat);
}
bool CalGridOffset(SampleFeature psr, Misc.DIRECTION direction,int grid_start, int[] buf, out int grid_offset)
{
grid_offset = 0;
//检测机架数据,当为空时,不能作相识性计算
if (!mGageInfo.DataOK)
return true;
int pos1 = psr.StartPos;
int pos2 = psr.EndPos;
int posOfGrid = flyad.PosOfGrid;
int grid1 = pos1 / posOfGrid;
int grid2 = pos2 / posOfGrid;
int grid_searchtol = SearchRange / posOfGrid;
//获取相同方向的机架信息数据
int index = (direction == Misc.DIRECTION.FORWARD) ? 0 : 1;
int[] gagedata = null;
mGageInfo.GetGageInfo(index, (asyncContext, retData) =>
{
var reponse = retData as GetGageInfoResponse;
gagedata = reponse.Data;
}, this);
//合格,查找最大相识性的点
int grid_b = grid1 - grid_searchtol;
int grid_e = grid2 + grid_searchtol;
int grid_len = grid_e - grid_b + 1;
int[] scanData = new int[grid_len];//这个方向的需要 特征查找范围内的数据,不用考虑 buf 不够 grid_len
Array.Copy(buf, grid_b - grid_start, scanData, 0, grid_len);
double max_relvency = 0;
int max_grid_offset = 0;
for (int i = 0; i < grid_searchtol * 2; i++)
{
double r = Misc.MyMath.Correl(gagedata, grid1, scanData, i, grid2 - grid1 + 1);
if (r > max_relvency)
{
max_relvency = r;
max_grid_offset = i - grid_searchtol;
}
}
psr.MaxRelevancy = max_relvency;
psr.MaxOffset = max_grid_offset * posOfGrid;
if (max_relvency > 0.8) //相识度必须高于0.8
{
grid_offset = max_grid_offset;//位置修正
return true;
}
else
{
//相似性太低,取样失败!!!
return false;
}
}
///
/// 设置这个方向 全部样品为失败
///
///
void SetFailure(Misc.DIRECTION direction)
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
var tempre = tempFilters[i];
if ((directions[i] == direction) && (sample.Enable))
{
tempre.Reset();
states[i] = SampleState.IsFailure;
}
}
}
///
/// 设置全部样品为失败
///
void SetFailure()
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
var tempre = tempFilters[i];
if (sample.Enable)
{
tempre.Reset();
states[i] = SampleState.IsFailure;
}
}
}
public bool HasSampleAd()
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
if (sample.Enable)
{
if (sample.AD <= 0)
return false;
}
}
return true;
}
enum GetSampleAdResult
{
OK,
///
/// 没有采集数据
///
Invalid,
///
/// AD值为0
///
Zero,
///
/// 滤波 异常
///
FilterErr
}
GetSampleAdResult GetSampleAd(SampleCell sample, TempFilter2 tempre, int grid_start, int[] buf, int grid_offset, out int ad)
{
//获取grid 数据
int posOfGrid = flyad.PosOfGrid;
int grid = sample.Position / posOfGrid + grid_offset;
int grid_range = SampleRange / posOfGrid;
int grid1 = grid - grid_range;
int grid_len = grid_range * 2;
int grid_b = grid1 - grid_start;
int grid_e = grid_b + grid_len - 1;
//计算平均值
ad = Misc.MyMath.Avg(buf, grid_b, grid_e);
if (!Misc.MyBase.ISVALIDATA(ad))//AD无效。。。异常,复位
{
ad = -1;
return GetSampleAdResult.Invalid;
}
else
{
int orgAd = ad;
ad = tempre.CalSampleAD(orgAd, TimeSpan.FromMinutes(Window));//ad 滤波
double diff = Math.Abs(orgAd - ad);
if (IsCheckByPercent)
{
if (diff == 0)
{
}
else if (ad == 0)
{
ad = -1;
return GetSampleAdResult.Zero;
}
else if (diff / ad >= ErrPercent) //大于2% 异常
{
return GetSampleAdResult.FilterErr;
}
}
else
{
if (diff >= ErrValue)
{
return GetSampleAdResult.FilterErr;
}
}
}
return GetSampleAdResult.OK;
}
GetSampleAdResult SetSampleAds(Misc.DIRECTION direction, int grid_start, int[] buf, int grid_offset)
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
var tempre = tempFilters[i];
if ((directions[i] == direction) && (sample.Enable))
{
//获取滤波后的AD值
var ret = GetSampleAd(sample, tempre, grid_start, buf, grid_offset, out int ad);
if(ret == GetSampleAdResult.OK)
{
sample.AD = ad;
states[i] = SampleState.Ok;
}
else
{
return ret;
}
}
}
return GetSampleAdResult.OK;
}
///
/// 样品取样,推送给thickm, 参数一定合法,不用检测
///
/// 方向
/// 开始grid序号
/// grid数据
public virtual void Do(Misc.DIRECTION direction, int grid_start, int[] buf)
{
if (CheckParamIsValid() == false)
{
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:参数异常");
return;
}
int grid_offset = 0;//经过相识性计算后的偏移量
//数据在 gsample -> gagedata[0]
SampleFeature psr = Features[(direction == Misc.DIRECTION.FORWARD) ? 0 : 1];
//这个方向的特征查找使能了,位置修正!!!!!!
if (psr.Enable)
{
//通过特征 计算样品偏移,
//当没有机架信息,会返回 true
//成功 计算出偏移 返回 true
//相关性太低,返回 false
if (!CalGridOffset(psr, direction, grid_start, buf, out grid_offset))
{
//有问题,全部复位
SetFailure(direction);
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:特征查找失败");
goto _end;
}
}
//获取这个方向全部样品AD
var ret = SetSampleAds(direction, grid_start, buf, grid_offset);
switch (ret)
{
case GetSampleAdResult.Zero:
{
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:AD值为0");
}
break;
case GetSampleAdResult.Invalid:
{
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:没有采集数据");
}
break;
case GetSampleAdResult.FilterErr:
{
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:滤波数据与原始数据差异{ErrPercent:P0}");
}
break;
}
if (ret != GetSampleAdResult.OK)
{
//有问题,全部复位
SetFailure(direction);
}
if (OK())
{
//全部都采集完成
if (!IsErr())//没有异常
{
//备份
last_sampleData = new SampleData();
last_sampleData.Time = DateTime.Now;
last_sampleData.SampleADs = new int[Samples.Count()];
for (int i = 0; i < Samples.Count(); i++)
{
last_sampleData.SampleADs[i] = Samples[i].AD;
}
}
}
_end:
SampleChangedEvent?.Invoke(this);
}
bool IsErr()
{
if (last_sampleData == null)
return false;
if (IsPercentErr())
{
//历史比较有问题
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:样品AD与上次大于{ErrPercent:P0}变化");
//设置全部都是异常,重新测量
SetFailure();
last_sampleData = null;
return true;
}
if (IsCrossErr())
{
//交叉比较有问题
this.warningSystem.Update(
ERRNOs.Instance.SAMPLE_ERRNO_Failure.Code,
$"{ERRNOs.Instance.SAMPLE_ERRNO_Failure.Descrption}:样品比值与上次大于{CrossErrPercent:P0}变化");
//设置全部都是异常,重新测量
SetFailure();
last_sampleData = null;
return true;
}
return false;
}
///
/// 检测是否成功
///
///
public virtual bool OK()
{
return !IsFailure();
}
///
/// 刚才报警了,采样失败
///
///
public bool IsFailure()
{
if (Enable)
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
if (sample.Enable)
{
if (states[i] != SampleState.Ok)
return true;
}
}
}
return false;
}
///
/// 全部采集完成,与上次采集比较 大于2% 异常
///
///
bool IsPercentErr()
{
for (int i = 0; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
if (sample.Enable)
{
int ad = sample.AD;
if (ad <= 0)//写错程序
break;
int lastAd = last_sampleData.SampleADs[i];
double diff = Math.Abs(ad - lastAd);
if (diff / ad > ErrPercent) //大于2% 异常
{
return true;
}
}
}
return false;
}
///
/// 全部采集完成,再做 交叉比较
///
///
bool IsCrossErr()
{
//交叉比较
for (int i = 1; i < Samples.Count(); i++)
{
SampleCell sample = Samples[i];
if (sample.Enable)
{
double p = 1.0 * sample.AD / Samples[0].AD;
if (p <= 0)//写错程序
break;
int lastAdi = last_sampleData.SampleADs[i];
int lastAd0 = last_sampleData.SampleADs[0];
if (lastAd0 <= 0)//写错程序
break;
double last_p = 1.0 * lastAdi / lastAd0;
double diff = Math.Abs(last_p - p);
if (diff / p > CrossErrPercent) //大于2% 异常
{
return true;
}
}
}
return false;
}
///
/// 获取N秒的数据,
///
/// 序号
/// 数据
///
public void DoFix(int idx, int[] buf)
{
if (idx >= Samples.Count())
return;
else if (idx < 0)
return;
int avg = Misc.MyMath.Avg(buf);
SampleCell sample = Samples[idx];
sample.AD = avg;
SampleChangedEvent?.Invoke(this);
}
public event PropertyChangedEventHandler PropertyChanged;
public void Apply()
{
//通知上层
Save();
}
///
/// 返回 List(List(TempFilterData))
///
///
///
public void GetTempFilterDatas(AsyncCBHandler asyncDelegate, object asyncContext)
{
List> ret = new List>();
for (int i = 0; i < Samples.Count(); i++) {
SampleCell sample = Samples[i];
if (sample.Enable)
ret.Add(tempFilters[i].GetDatas());
}
asyncDelegate(asyncContext, ret);
}
}
public class SampleData : INotifyPropertyChanged
{
public DateTime Time { get; set; }
///
/// 样品采集AD值
///
public int[] SampleADs { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
public delegate void SampleChangedEventHandler(GSample gsample);
public class GSampleJsonDb
{
static Mapper Mapper { get; } = new AutoMapper.Mapper(new MapperConfiguration(c =>
{
c.CreateMap()
.ForMember(s => s.Samples, opt =>
{
opt.MapFrom(s => Map_SampleCell2SampleCellParam(s.Samples));
}).ForMember(s => s.Features, opt =>
{
opt.MapFrom(s => Map_SampleFeature2SampleFeatureParam(s.Features));
})
.ReverseMap()
.ForMember(s => s.Samples, opt =>
{
opt.MapFrom(s => Map_SampleCellParam2SampleCell(s.Samples));
})
.ForMember(s => s.Features, opt =>
{
opt.MapFrom(s => Map_SampleFeatureParam2SampleFeature(s.Features));
});
}));
static SampleCell[] Map_SampleCellParam2SampleCell(SampleCellParam[] sampleCellParams) {
string json = Newtonsoft.Json.JsonConvert.SerializeObject(sampleCellParams);
return Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
static SampleCellParam[] Map_SampleCell2SampleCellParam(SampleCell[] sampleCells)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(sampleCells);
return Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
static SampleFeature[] Map_SampleFeatureParam2SampleFeature(SampleFeatureParam[] sampleFeatureParams)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(sampleFeatureParams);
return Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
static SampleFeatureParam[] Map_SampleFeature2SampleFeatureParam(SampleFeature[] sampleFeatures)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(sampleFeatures);
return Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
public static bool Load(GSample src, string filePath)
{
try
{
if (File.Exists(filePath))
{
string json = File.ReadAllText(filePath);
var p = JsonConvert.DeserializeObject(json);
Mapper.Map(p, src);
return true;
}
}
catch
{
//异常,没有json 解码失败
}
return false;
}
public static bool Save(GSample src, string filePath)
{
var p = Mapper.Map(src);
try
{
File.WriteAllText(filePath, JsonConvert.SerializeObject(p, Formatting.Indented));
return true;
}
catch
{
//异常,没有json 编码失败
}
return false;
}
public bool Enable { get; set; } = true;
public int Window { get; set; }
public int SampleRange { get; set; } = 100;
public bool IsCheckByPercent { get; set; } = true;
public double ErrPercent { get; set; } = 2;
public int ErrValue { get; set; } = 200;
public double CrossErrPercent { get; set; } = 0.02;
public SampleCellParam[] Samples { get; set; }
public int SearchRange { get; set; } = 100;
public SampleFeatureParam[] Features { get; set; }
}
}