横河wvf型数据,分别保存在hdr(数据信息文件)和wvf(数据文件)两个文件中。
其中HDR文件格式及参数可以参考: http://www.yokogawa.com/jp-ymi/tm/TI/TIdoc/TI700021.pdf
1.保存hdr中数据信息的结构体
//.hdr文件的wvf文件信息struct public struct WVFInfo { public string FileName; public string FormatVersion; public string Model; public WVFEndianType Endian; public string DataFormat; public int GroupNumber; public int TraceTotalNumber; public int DataOffset; public List<WVFGroup> Groups; } //wvf group struct public struct WVFGroup { public int TraceNumber; public int BlockNumber; //Traces public List<string> TraceName; public List<int> BlockSize; public List<double> VResolution; public List<double> VOffset; public List<WVFByteFormatType> VDataTypeByteFormat; public List<int> VDataTypeByteNumber; public List<string> VUnit; public List<string> VPlusOverData; public List<string> VMinusOverData; public List<double> VIllegalData; public List<double> VMaxData; public List<double> VMinData; public List<double> HResolution; public List<double> HOffset; public List<string> HUnit; //currently only support 1 block public List<string> Date; public List<string> Time; public List<List<double>> TValues; public List<List<double>> YValues; } //wvf文件的数据格式struct public enum WVFByteFormatType { IS = 0, //int IU = 1, //unsigned int FS = 2, //float } //wvf文件的数据大小端struct public enum WVFEndianType { Big = 0, //Big Endian Little = 1 //Little Endian }
2.读取hdr时会用到的字符串操作函数
string fileparse(string keyword, string text) { string value = ""; int indexStart = text.IndexOf(keyword); if (indexStart < 0) { Console.WriteLine("Could not find " + keyword + " entry in the file"); } else { int indexEnd = text.Substring(indexStart).IndexOf("\r\n"); string line = text.Substring(indexStart, indexEnd).Trim(); value = line.Replace(keyword, " ").Trim(); } return value; } List<string> stringparse(string str) { string[] args = str.Trim().Split(' '); List<string> list = new List<string>(); foreach (string arg in args) { if (arg.Trim().Length != 0) { list.Add(arg); } } return list; }
3. 读取hdr文件的函数
//read header .hdr file void ReadHDR(string path) { string content = File.ReadAllText(path); info.FileName = path.Substring(0, path.LastIndexOf('.')); info.FormatVersion = fileparse("FormatVersion", content); info.Model = fileparse("Model", content); info.DataFormat = fileparse("DataFormat", content); info.GroupNumber = Convert.ToInt32(fileparse("GroupNumber", content)); info.TraceTotalNumber = Convert.ToInt32(fileparse("TraceTotalNumber", content)); info.DataOffset = Convert.ToInt32(fileparse("DataOffset", content)); info.Endian = (fileparse("Endian", content) == "Big") ? WVFEndianType.Big : WVFEndianType.Little; info.Groups = new List<WVFGroup>(); for (int i = 0; i < Info.GroupNumber; i++) { //Group WVFGroup group = new WVFGroup(); int groupIndex = content.IndexOf("$Group" + (i+1).ToString()); string groupContent = content.Substring(groupIndex); group.TraceNumber = Convert.ToInt32(fileparse("TraceNumber", groupContent)); group.BlockNumber = Convert.ToInt32(fileparse("BlockNumber", groupContent)); //Traces group.TraceName = stringparse(fileparse("TraceName", groupContent)); group.BlockSize = stringparse(fileparse("BlockSize", groupContent)).ConvertAll<int>(x => Convert.ToInt32(x)); group.VResolution = stringparse(fileparse("VResolution", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.VOffset = stringparse(fileparse("VOffset", groupContent)).ConvertAll<double>(x=>Convert.ToDouble(x)); List<string> vDataType = stringparse(fileparse("VDataType", groupContent)); group.VDataTypeByteFormat = new List<WVFByteFormatType>(); group.VDataTypeByteNumber = new List<int>(); /* % VDataType % ISn : n-byte signed integer % IUn : n-byte unsigned integer % FSn : n-byte signed real % FUn : n-byte unsigned real % Bm : m-byte logical data */ foreach (string dt in vDataType) { int num = 0; switch (dt[0]) { case 'I': //integer numbers switch (dt[1]) { case 'S': group.VDataTypeByteNumber.Add(Convert.ToInt32(dt.Substring(2))); group.VDataTypeByteFormat.Add(WVFByteFormatType.IS); break; case 'U': group.VDataTypeByteNumber.Add(Convert.ToInt32(dt.Substring(2))); group.VDataTypeByteFormat.Add(WVFByteFormatType.IU); break; default: group.VDataTypeByteNumber.Add(0); group.VDataTypeByteFormat.Add(WVFByteFormatType.IS); break; } break; case 'F': //real numbers switch (dt[1]) { case 'S': group.VDataTypeByteNumber.Add(Convert.ToInt32(dt.Substring(2))); group.VDataTypeByteFormat.Add(WVFByteFormatType.FS); break; default: group.VDataTypeByteNumber.Add(0); group.VDataTypeByteFormat.Add(WVFByteFormatType.FS); break; } break; default: group.VDataTypeByteNumber.Add(0); group.VDataTypeByteFormat.Add(WVFByteFormatType.IS); break; } } group.VUnit = stringparse(fileparse("VUnit", groupContent)); group.VPlusOverData = stringparse(fileparse("VPlusOverData", groupContent)); group.VMinusOverData = stringparse(fileparse("VMinusOverData", groupContent)); group.VIllegalData = stringparse(fileparse("VIllegalData", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.VMaxData = stringparse(fileparse("VMaxData", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.VMinData = stringparse(fileparse("VMinData", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.HResolution = stringparse(fileparse("HResolution", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.HOffset = stringparse(fileparse("HOffset", groupContent)).ConvertAll<double>(x => Convert.ToDouble(x)); group.HUnit = stringparse(fileparse("HUnit", groupContent)); group.Date = stringparse(fileparse("Date", groupContent)); group.Time = stringparse(fileparse("Time", groupContent)); group.TValues = new List<List<double>>(); group.YValues = new List<List<double>>(); Info.Groups.Add(group); } }
4. 读取wvf文件的函数
//read data .wvf file void ReadWVF(int groupIndex = 0, int traceIndex = 0, int blockIndex = 0) { // Offset at beginning of binary file int offset = Info.DataOffset; // first for all groups before the selected group for (int i = 0; i < groupIndex; i++) { // for all traces and blocks in these groups... for (int j = 0; j < Info.Groups[i].TraceNumber; j++) { // add the offsets of all traces... offset += Info.Groups[i].BlockSize[j] * Info.Groups[i].BlockNumber * Info.Groups[i].VDataTypeByteNumber[j]; } } // File Format Trace or Block saves traces and blocks in different // sequences: // Trace : Group1,Trace1,Block1, Group1,Trace1,Block2, ..., Group1,Trace1,BlockN, ..., Group1,Trace2,Block1, ..., Group2,Trace1,Block1, ..., GroupN,TraceN,BlockN (each block for a specific waveform) // Block : Group1,Trace1,Block1, Group1,Trace2,Block1, ..., Group1,TraceN,Block1, ..., Group1,Trace1,Block2, ..., Group2,Trace1,Block1, ..., GroupN,TraceN,BlockN (each block for a specific time interval). if (Info.DataFormat == "Trace") { //trace format: //%... add offsets of the traces before the selected trace in the selected group for (int i = 0; i < traceIndex; i++) { offset += Info.Groups[groupIndex].BlockSize[i] * Info.Groups[groupIndex].BlockNumber * Info.Groups[groupIndex].VDataTypeByteNumber[i]; } //... and finally add offsets of the blocks in the selected trace in the selected group before the selected block offset += Info.Groups[groupIndex].BlockSize[traceIndex] * blockIndex * Info.Groups[groupIndex].VDataTypeByteNumber[traceIndex]; ; } else { //block format: //%... add offsets of the blocks before the selected block in the selected group for (int i = 0; i < blockIndex; i++) { for (int j = 0; j < Info.Groups[groupIndex].TraceNumber; j++) { offset += Info.Groups[groupIndex].BlockSize[j] * Info.Groups[groupIndex].VDataTypeByteNumber[j]; } } //... and finally add offsets of the traces in the selected block in the selected group before the selected trace for (int i = 0; i < traceIndex; i++) { offset += Info.Groups[groupIndex].BlockSize[i] * Info.Groups[groupIndex].VDataTypeByteNumber[i]; } } fs.Seek(offset, SeekOrigin.Begin); //number of data points stored in the selected trace in the file int nop = Info.Groups[groupIndex].BlockSize[traceIndex]; WVFByteFormatType byteFormat = Info.Groups[groupIndex].VDataTypeByteFormat[traceIndex]; int byteNum = Info.Groups[groupIndex].VDataTypeByteNumber[traceIndex]; List<double> listY = new List<double>(); List<double> listT = new List<double>(); //read data values for (int i = 0; i < nop; i++) { byte[] bVal = reader.ReadBytes(byteNum); double dVal = 0; switch (byteFormat) { case WVFByteFormatType.IS: switch (byteNum) { case 2: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToInt16(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToInt16(bVal, 0); break; } break; case 4: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToInt32(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToInt32(bVal, 0); break; } break; case 8: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToInt64(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToInt64(bVal, 0); break; } break; default: break; } break; case WVFByteFormatType.IU: switch (byteNum) { case 2: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToUInt16(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToUInt16(bVal, 0); break; } break; case 4: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToUInt32(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToUInt32(bVal, 0); break; } break; case 8: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToUInt64(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToUInt64(bVal, 0); break; } break; default: break; } break; case WVFByteFormatType.FS: switch (byteNum) { case 4: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToSingle(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToSingle(bVal, 0); break; } break; case 8: switch (Info.Endian) { case WVFEndianType.Big: dVal = BitConverter.ToDouble(bVal.Reverse().ToArray(), 0); break; default: dVal = BitConverter.ToDouble(bVal, 0); break; } break; default: break; } break; default: break; } listY.Add(Info.Groups[groupIndex].VOffset[traceIndex] + Info.Groups[groupIndex].VResolution[traceIndex] * dVal); listT.Add(Info.Groups[groupIndex].HOffset[traceIndex] + Info.Groups[groupIndex].HResolution[traceIndex] * (1 + i)); } Info.Groups[groupIndex].TValues.Add(listT); Info.Groups[groupIndex].YValues.Add(listY); }
5. 读取wvf的类
public class WVFFile { WVFInfo info = new WVFInfo(); FileStream fs; BinaryReader reader; public WVFInfo Info { get { return info; } set { info = value; } } public WVFFile(string header, string file) { Info = new WVFInfo(); ReadHDR(header); fs = new FileStream(file, FileMode.Open, FileAccess.Read); reader = new BinaryReader(fs); for(int i = 0; i < Info.GroupNumber; i++) { for (int j = 0; j < Info.Groups[i].TraceNumber; j++) { ReadWVF(i, j); } } reader.Close(); fs.Close(); } }