using CommonLib.DataStruct; using CommonLib.IO; using CommonLib.IO.File; using CommonLib.LOG; using CommonLib.WavFile; using DataCollectionSystem; using DataCollectionSystem.CommonLib.Data; using InfluxDB.Client.Writes; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock; namespace CommonLib.DAQ { public class DAQCard : VK70xNMC { public Object lockObj = new Object(); public static Boolean bOffline = true; const int RingSize = 10; public List ListWavFile { get; private set; } = new List(2); public List ListFIFOFile { get; private set; } = new List(2); private List ListRingArray = new List(4); public EventHandler EventscanAndConnect; //private List> ListRingOrgArray = new List>(4); /// /// 系统中运行的板卡 /// public static List ListRunCard { get; private set; } = new List(); /// /// 枚举系统所有的板卡 /// public static Dictionary dictCard { get; private set; } = new Dictionary(); public DAQCard() { // base.EventVoltage += DoEventVoltage; //base.EventReconnectAll += DoReconnectAll; } public static DAQCard GetCard(string HostName) { var card = dictCard.AsEnumerable().Where(keypair => keypair.Value.HostName == HostName).FirstOrDefault().Value; return card; } public new bool Enable { get { return base.Enable; } set { if (value == true) { InitFiles(VK70xNMC.MAX_CH_NUM); if(bOffline==false) base.Enable = value;//真机运行 else { RunGenFakeData();// 假数据 base.Enable = true; } } else { base.Enable = false; CloseFiles(); } } } public double[][] Threashold { get; internal set; } //public double[][] Threashold { get; internal set; } public void RunGenFakeData() { Task.Run(() => { Thread thread = Thread.CurrentThread; thread.Name = $" {this.HostName} GenFakeData"; GenFakeData(); }); } public static string[] HostNames = new string[100]; public static int ScanDevice() { int err = 0; int devTotalCount = 0; if (bOffline == false) { err = VK70xNMC.ScanListDevice(ref HostNames, ref devTotalCount); // 扫描设备 if (err == 0) { dictCard.Clear(); AllCardCount = 0; for (int i = 0; i < devTotalCount; i++) { DAQCard card = new DAQCard(); card.HostName = HostNames[i]; dictCard.Add(card.CardNO, card); } } } else { dictCard.Clear(); AllCardCount = 0; HostNames = new string[]{ "192.168.1.200", }; for (int i = 0; i < HostNames.Count(); i++) { DAQCard card = new DAQCard(); card.HostName = HostNames[i]; dictCard.Add(card.CardNO, card); } } return err; } public static void CloseAllDevices() { foreach(var cardpair in dictCard) { cardpair.Value.Enable= false; } dictCard.Clear(); VK70xNMC.CloseAllDevices(); } // public override void DoReConnectAll() { //断开连接,发出定时请求,到时候自动重新扫描并重连 //断开所有板卡 //断开TCP server //延时一段时间 //重新扫描 //连接 EventscanAndConnect.Invoke(this, new EventArgs()); } public override void DoEventVoltage() { SaveVoltageData(); //输出电压值 } #region SaveVoltageData int channels = VK70xNMC.MAX_CH_NUM; byte[][] WriteFileBuffers = null; /// /// 原始数据流 /// double[][] chDatas = null; /// /// 初始化合并后数据流的缓冲区 /// private void InitdataMemory() { if (WriteFileBuffers == null) WriteFileBuffers = new byte[channels/2][]; //保存原始数据 if (chDatas == null) { chDatas = new double[channels][]; //电压波形 //4组电压缓冲区 int DATA_COUNT_PERCH = VK70xNMC.DATA_COUNT_PERCH; ; for (int i = 0; i < channels; i++) { chDatas[i] = new double[DATA_COUNT_PERCH]; } for (int i = 0; i < channels/2; i++) { WriteFileBuffers[i] = new byte[chDatas[i].Length * 8]; } } } double[] fakedata = null; private void GenFakeData() { int remain = 0; int len = 0; int pos = 0; InitdataMemory(); EventKill.Reset(); try { if (fakedata == null) { //fakedata = FakeData.LoadDataFromTxt(@"Datasrc\N_Metal_N.csv"); fakedata = FakeData.LoadDataFromTxt(@"Datasrc\N_Metal_N_Resonance_N.csv"); } Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < channels; i++) { ListDP[i] = new DataProcess(); } //100 虚拟数据输出速率 10ms while (EventKill.WaitOne(20) == false) { //求剩下的长度 remain = fakedata.Count() - pos; //如果剩余长度大于chdatas长度 ,直接 len = (remain > chDatas[0].Count()) ? chDatas[0].Count() : remain; if (len < chDatas[0].Count()) { pos = 0; continue; //break; } for (int i = 0; i < channels; i++) { Array.Copy(fakedata, pos, chDatas[i],0, len); } DoEventVoltage(); pos += len; //UpdateChart(); } watch.Stop(); double t = watch.ElapsedMilliseconds; LogStorage.Logs.Add(LogLevel.Trace, $"消耗时间{t.ToString("F4")} ms \n "); } catch(Exception ex) { LogStorage.Logs.Add(LogLevel.Error, $"{ ex.Message } { ex.StackTrace } "); } } /// /// 1z张卡有4个通道,有两个合并块 /// AutoRange[] autoRanges = new AutoRange[2] { new AutoRange(1), new AutoRange(1) }; /// /// 切换通道 /// /// /// double[][] GetAutoRangeVoltage(double[][] chDatas) { double[][] voltages = new double[2][]; //1.2通道合并 autoRanges[0].AddData(0, chDatas[0]); autoRanges[0].AddData(1, chDatas[1]); voltages[0] = autoRanges[0].GetOutPutData(); //3.4通道合并 autoRanges[1].AddData(0, chDatas[2]); autoRanges[1].AddData(1, chDatas[3]); voltages[1] = autoRanges[1].GetOutPutData(); return voltages; } /// /// 自动量程 0 是衰减挡位 1是放大挡位 /// 根据幅度切换 /// 但是发现有交越失真,废弃 /// /// /// /* double[][] GetAutoRangeVoltage(double[][] chDatas) { double gain02f = 0.2f; double gain100f = 100.0f; double threshold = 0.0316f; double[][] voltages = new double[2][]; int len0 = chDatas.GetLength(0); int len1 = chDatas[0].GetLength(0); //初始化接收内存 for (int i = 0; i < 2; i++) { voltages[i] = new double[len1]; } //还原到原始值 for (int i = 0; i < len0; i++) { double Gain = i % 2 == 0 ? gain02f : gain100f; for (int j = 0; j < len1; j++) { chDatas[i][j] = chDatas[i][j] *100/ Gain; } } ////将所有通道电压转换为绝对值 double[][] AbschDatas = new double[len0][]; for (int i = 0; i < len0; i++) { AbschDatas[i] = new double[len1]; for (int j = 0; j < len1; j++) { AbschDatas[i][j] = Math.Abs(chDatas[i][j]); } } // 2通道放大,所以用2通道判断 // 小于 31.6 用 2通道 ,大于 31.6 用1通道挡位 //根据绝对值判断采用哪个通道 //自适应通道 for (int i = 0;i< len1;i++) { voltages[0][i] = AbschDatas[1][i] > threshold ? chDatas[0][i] : chDatas[1][i]; voltages[1][i] = AbschDatas[3][i] > threshold ? chDatas[2][i] : chDatas[3][i]; } // 强信号通道 //for (int i = 0; i < len1; i++) // { // voltages[0][i] = chDatas[1][i]; // voltages[1][i] = chDatas[3][i]; // } return voltages; } */ void SaveVoltageData() { try { //锁定 lock (lockObj) { InitdataMemory(); //将电压分拆到缓冲区中 if (bOffline==false) { for (int i = 0; i < VK70xNMC.MAX_CH_NUM; i++) { chDatas[i] = new double[VK70xNMC.DATA_COUNT_PERCH]; for (int j = 0; j < VK70xNMC.DATA_COUNT_PERCH; j++) { chDatas[i][j] = readData[i, j]; } } } double[][] chDatas2 = GetAutoRangeVoltage(chDatas); for (int i = 0; i < 2; i++) { Buffer.BlockCopy(chDatas2[i], 0, WriteFileBuffers[i], 0, WriteFileBuffers[i].GetLength(0) * Marshal.SizeOf(WriteFileBuffers[i][0])); int no = i; ListFIFOFile[no].Write_FIFO_Data(WriteFileBuffers[no]); //TODO:要增加一个线程停止的关闭文件机制 /* ThreadPool.QueueUserWorkItem(new WaitCallback((object stateInfo) => { })); */ ListWavFile[i].FillBuffer(chDatas2[i]); } Stopwatch stopwatch= new Stopwatch(); stopwatch.Start(); UpdateChart(chDatas2); double t = stopwatch.ElapsedMilliseconds; Console.WriteLine("UpdateChart 消耗时间:{0}ms", t.ToString()); //TODO:判断时间,超过时间就写下一个文件 TimeSpan timespan = DateTime.Now - ListFIFOFile[0].StartTime; if (timespan >= MainForm.configValue.spitTime) { reInitFIFOFiles(); } } } catch (Exception ex) { LogStorage.Logs.Add(LogLevel.Error, $"{ ex.Message } { ex.StackTrace } "); } } public void reInitFIFOFiles() { lock (lockObj) { CloseFiFoFiles(); //关闭文件 InitFiFOFiles();//打开新文件保存 } } public void reInitWaveFiles() { lock (lockObj) { CloseWaveFiles(); //关闭文件 InitWaveFiles(2); } } /// /// 求复数complex数组的模modul数组 /// /// 复数数组 /// 模数组 public double[] Cmp2Mdl(alglib.complex[] input) { ///有输入数组的长度确定输出数组的长度 double[] output = new double[input.Length]; ///对所有输入复数求模 for (int i = 0; i < input.Length; i++) { output[i] = ToModul(input[i].x, input[i].y) / 2000; } ///返回模数组 return output; } /// /// 求复数的模 /// /// public double ToModul(double real, double image) { return Math.Sqrt(real * real + image * image); } List ListDP = new List() { new DataProcess(), new DataProcess(), new DataProcess(), new DataProcess() }; void UpdateChart(double[][] chDatas2) { string ident = string.Empty; int id = this.CardNO; //TODO: BUG 报的是错误的,此处需要修复 ident = MainForm.monitorDevices.listMonitorDevices[0].devices[CardNO].Name; int channelcnt = chDatas2.GetLength(0); for (int i = 0; i < channelcnt; i++) { DisplayPointArray inertData = new DisplayPointArray(); alglib.complex[] f; Stopwatch watch = new Stopwatch(); watch.Start(); alglib.fftr1d(chDatas2[i], out f); double[] data_result = Cmp2Mdl(f); watch.Stop(); double t = watch.ElapsedMilliseconds; Console.WriteLine("Cmp2Mdl 消耗时间:{0}ms", t.ToString()); inertData.Line1Display = chDatas2[i]; inertData.Line1FFTDisplay = data_result; //将原始数据转为double[] 数组?? 拷贝到另外一个数组 //原始特征 int srcLen = chDatas2[i].Length; double[] orgdata = new Double[srcLen]; Array.Copy(chDatas2[i], orgdata, srcLen); //FFTRingArray.checkError(orgdata); //DataProcess dp = new DataProcess(); Boolean anomaly = false; int anomalyInt = 0; ListDP[i].checkError(ident ,orgdata,ref anomaly,ref anomalyInt); //将FFT数据放入环形缓冲区 int halfLen = data_result.Length / 2; double[] half_FFT = new double[halfLen]; Array.Copy(data_result, half_FFT, halfLen); watch.Start(); if(bOffline==false) { WriteFluxDB(inertData,HostName,i.ToString(), anomaly, anomalyInt); } watch.Stop(); t = watch.ElapsedMilliseconds; Console.WriteLine("WriteFluxDB 消耗时间:{0}ms", t.ToString()); //将data_result送入队列 double[] magicValue = ListRingArray[i].AddData(half_FFT); // 判断选中的列 if ((CardNO == MainForm.SelectCardID) && (i == MainForm.SelectCardChannel)) { lock (MainForm.FFT_Amp) { MainForm.FFT_Amp = half_FFT[70]; } /* double[] barChartPoints = magicValue; MainForm.drawBarChartdataQueue.Enqueue(barChartPoints); //多点 */ MainForm.PowerQueues[0].Enqueue(ListDP[i].Mel1); MainForm.PowerQueues[1].Enqueue(ListDP[i].Mel2); MainForm.PowerQueues[2].Enqueue(ListDP[i].Time1); MainForm.PowerQueues[3].Enqueue(ListDP[i].Time2); MainForm.PowerQueues[4].Enqueue(ListDP[i].spectral1); MainForm.PowerQueues[5].Enqueue(ListDP[i].spectral2); MainForm.drawLinedataQueue.Enqueue(inertData); } //此处写入数据库 } } private double GetAmptitude(DisplayPointArray innertData) { double spl = 0; double p0 = 2e-5; double amptitude = 0; Double[] points = innertData.Line1Display; int count = points.Count(); double sum = 0; for(int i = 0; i < count;i++) { sum += points[i] * points[i]; } sum /= count; amptitude = Math.Sqrt(sum); spl = 20 * Math.Log10(amptitude / p0); /* Leng = len(x) pa = np.sqrt(np.sum(np.power(x, 2)) / Leng) p0 = 2e-5 spl = 20 * np.log10(pa / p0) return spl */ return amptitude; } private void FillDict(WriteFluxDB fluxDB, Double[] FFTpoints) { //foreach(var dic in fluxDB.dictFFT) var list = fluxDB.dictFFT.ToList(); for (int i=0;i dic = list[i]; int index = dic.Key; Double value = FFTpoints[index]; fluxDB.dictFFT[index] =(float) value; } } private void WriteFluxDB(DisplayPointArray innertData,string Device,string channel, Boolean anomaly, int anomalyInt ) { Double[] points = innertData.Line1Display; Double[] FFTpoints = innertData.Line1FFTDisplay; double peak = points.Max(); double RMS = AutoRange.GetRMS (points); // try { WriteFluxDB fluxDB = MainForm.fluxDB; FillDict(fluxDB, FFTpoints); double dc = FFTpoints[0]; fluxDB.Write_features(anomaly, anomalyInt, (float)dc, (float)peak, (float)RMS, Device, channel); if(anomaly) { fluxDB.spike_events( (float)RMS, Device, channel); } fluxDB.Write_spectrogram(Device, channel); // fluxDB.Wirte_spike_events(Device, channel, 12.3f); float Amptitude = (float)GetAmptitude(innertData); fluxDB.Wirte_waveform(Device, channel, Amptitude); } catch(Exception ex) { LogStorage.Logs.Add(LogLevel.Error, ex.Message + "\n" + ex.StackTrace); } } #endregion private void InitFiles(int m_chlCnt) { InitFiFOFiles(); InitRingArray(m_chlCnt); InitWaveFiles(m_chlCnt); } private void InitRingArray(int m_chlCnt) { //初始化缓冲队列 ListRingArray = new List(m_chlCnt); for (int i = 0; i < m_chlCnt; i++) { FFTRingArray ringArray = new FFTRingArray(RingSize); ringArray.Threshold = Threashold[i];////从配置文件中获取过来的 ringArray.Tag = i; ringArray.ErrorNotify += ErrorNotifyHandler; ListRingArray.Add(ringArray); } } private void InitWaveFiles(int m_chlCnt) { ListWavFile = new List(2); ///初始化通道 for (int i = 0; i < 2; i++) { WaveFile wavfile = new WaveFile(1000, 32000); wavfile.Init_Write_Stream(CardNO, ListWavFile.Count); int SavePointCnt = MainForm.configValue.SaveSampleTimeSecond* SAMPLING_RATE; int MaxSavePointCnt = MainForm.configValue.PerSampleTimeSecond * SAMPLING_RATE; //设置缓冲区大小 wavfile.SetPointCnt(SavePointCnt, MaxSavePointCnt); ListWavFile.Add(wavfile); //wavfile.EventCloseFile += doEventClose; } } void InitFiFOFiles() { ListFIFOFile = new List(2); ///初始化通道 for (int i = 0; i < 2; i++) { FIFO_IO_FILE fifo_file = new FIFO_IO_FILE(); fifo_file.Init_Write_Stream(CardNO, ListFIFOFile.Count); ListFIFOFile.Add(fifo_file); fifo_file.EventCloseFile += doEventClose; } } /// /// 关闭文件的时候检查目录里旧文件是否可以删除 /// /// /// private void doEventClose(object sender, EventArgs e) { } private void CloseFiFoFiles() { for (int i = 0; i < ListFIFOFile.Count; i++) { ListFIFOFile[i].CloseFile(); ListRingArray[i].Clear(); } } //InitWaveFiles private void CloseWaveFiles() { for (int i = 0; i < ListWavFile.Count; i++) { ListWavFile[i].CloseFile(); } } private void CloseFiles() { CloseFiFoFiles(); CloseWaveFiles(); } private void ErrorNotifyHandler(object sender, EventArgs e) { FFTRingArray array = sender as FFTRingArray; Object tag = array.Tag; int channel = (int)tag; string[] CardNotify = { "2#主变", "灯泡头", "灯泡体", "排水环" }; ErrorArgs e1 = e as ErrorArgs; //string Info = string.Format("{0}处振动通道1出现本体敲击故障!", CardNotify[CardNO]); //string Info = string.Format("2#主变处噪声通道2出现高压漏电故障!"); string Info = string.Format("{0}#采集卡{1}通道出现故障!", CardNO + 1, channel + 1); LogStorage.Logs.Add(LogLevel.MOTOR_Error, Info); } } }