This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,434 @@
using DTS.Common;
using DTS.Common.Utilities;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.Serialization.IRIGCH10.Packets;
using System;
using System.Collections.Generic;
using System.IO;
namespace DTS.Serialization.IRIGCH10
{
/// <summary>
/// this class is used to simplify parsing out CH10 data from a binary stream
/// </summary>
public class Chapter10File
{
/// <summary>
/// used to hold transport stream headers as they are read
/// </summary>
private readonly List<ITransportStreamHeader> _transportHeaders = new List<ITransportStreamHeader>();
/// <summary>
/// returns all transport headers that were read, in order they were read
/// </summary>
/// <returns></returns>
public ITransportStreamHeader[] GetTransportHeaders() { return _transportHeaders.ToArray(); }
/// <summary>
/// holds a list of packet headers as they are read
/// </summary>
private readonly List<IPacketHeader> _packets = new List<IPacketHeader>();
/// <summary>
/// returns all packet headers that were read, in the order they were read in
/// </summary>
/// <returns></returns>
public IPacketHeader[] GetPacketHeaders() { return _packets.ToArray(); }
/// <summary>
/// holds any secondary time packets that were read
/// </summary>
private readonly List<ISecondaryTimeFormatHeader> _secondaryTimePackets = new List<ISecondaryTimeFormatHeader>();
/// <summary>
/// returns all secondary time headers in the order they were read in
/// </summary>
/// <returns></returns>
public ISecondaryTimeFormatHeader[] GetSecondaryTimeHeaders() { return _secondaryTimePackets.ToArray(); }
/// <summary>
/// lookup of a packet header that was read in as well as the start of that packet and end of that packet amongst
/// all bytes in the file
/// </summary>
private readonly Dictionary<IPacketHeader, Tuple<long, long>> _packetToByteStartStop = new Dictionary<IPacketHeader, Tuple<long, long>>();
private readonly byte[] _bytes = null;
/// <summary>
/// returns all bytes for a packet (as apposed to just the bytes for the packet header)
/// all bytes returned are in their own buffer, independent of bytes read in
/// </summary>
/// <param name="packet"></param>
/// <returns></returns>
public byte[] GetBytesForPacket(IPacketHeader packet)
{
if (!_packetToByteStartStop.ContainsKey(packet)) { return null; }
var tuple = _packetToByteStartStop[packet];
var length = tuple.Item2 - tuple.Item1;
var bytes = new byte[length];
Buffer.BlockCopy(_bytes, (int)tuple.Item1, bytes, 0, (int)length);
return bytes;
}
public int GoodPackets { get; private set; } = 0;
public int RejectedPackets { get; private set; } = 0;
/// <summary>
/// adds a time packet 1 packet to the byte stream
/// </summary>
private static void InsertTimePacket1(BinaryWriter bw, int seconds, int nanoseconds, ref byte timeSequenceNumber,
int startSeconds, int startNanoSeconds)
{
//time packet 1 must always start on a second boundary, so we need to calulate the nearest start second to our
//actual start time, and all further packets also need to be on that boundary
var time = PTP1588Timestamps.UnitTimeStampToDateTimeLocal((decimal)startSeconds, (decimal)startNanoSeconds).ToUniversalTime();
var currentTime = PTP1588Timestamps.UnitTimeStampToDateTimeLocal((decimal)seconds, (decimal)nanoseconds).ToUniversalTime();
var newTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, currentTime.Minute, currentTime.Second);
var tickDelta = time.Ticks - newTime.Ticks;
var newRTC = GetRTC(tickDelta);
var timePacket = new TimePacketFormat1(timeSequenceNumber, newTime, newRTC, nanoseconds, seconds);
timeSequenceNumber++;
bw.Write(timePacket.GetBytes());
}
/// <summary>
/// describes a function to get the next Int16 ADC sample from a binary file
/// </summary>
/// <param name="channelIdx">the index of the channel among channels in the test</param>
/// <returns></returns>
public delegate short GetNextSampleDelegate(int channelIdx);
/// <summary>
/// returns the number of samples for the channel
/// </summary>
/// <param name="channelIndex">the index of the channel among channels in the test</param>
/// <returns></returns>
public delegate long GetChannelLengthDelegate(int channelIndex);
/// <summary>
/// writes an output PCM export file
/// </summary>
public static void WriteFilePCM(string tmats, GetNextSampleDelegate getNextSample,
GetChannelLengthDelegate getChannelLength,
int totalChannels,
int nanoseconds, int seconds, double sampleRate,
bool includeSecondaryHeader,
string fileName,
TickEventHandler tickEventHandler,
object tickObject)
{
var startNanoSeconds = nanoseconds;
var startSeconds = seconds;
if (System.IO.File.Exists(fileName))
{
FileUtils.DeleteFileOrMove(fileName, APILogger.Log);
}
using (var ms = new FileStream(fileName, FileMode.OpenOrCreate))
{
using (var bw = new BinaryWriter(ms))
{
//simulate writing the transport bytes ... not needed for ch10 file though ...
//first packet should be tmats
var tmatsPacket = new TMATSPacket(nanoseconds, seconds, tmats, includeSecondaryHeader);
bw.Write(tmatsPacket.GetBytes());
var currentSample = 0L;
byte sequenceNumber = 0x01;
byte timeSequenceNumber = 0x01;
var lastSecondTransmitted = 0;
if (!includeSecondaryHeader)
{
//insert first time packet at time second 1
InsertTimePacket1(bw, seconds, nanoseconds, ref timeSequenceNumber, startSeconds, startNanoSeconds);
lastSecondTransmitted = seconds;
}
var channel0Length = getChannelLength(0);
while (currentSample < channel0Length)
{
var newRTC = GetRTC(currentSample, sampleRate);
if (includeSecondaryHeader)
{
var timePacket = new TimePacketFormat2(timeSequenceNumber, false, nanoseconds, seconds, newRTC,
includeSecondaryHeader);
var time = PTP1588Timestamps.UnitTimeStampToDateTimeLocal((decimal)seconds, (decimal)nanoseconds).ToUniversalTime();
timeSequenceNumber++;
bw.Write(timePacket.GetBytes());
}
else
{
if (seconds > lastSecondTransmitted)
{
lastSecondTransmitted = seconds;
InsertTimePacket1(bw, seconds, nanoseconds, ref timeSequenceNumber, startSeconds, startNanoSeconds);
}
}
var pcmPacket = GetPcmPacket(currentSample, getNextSample, channel0Length, totalChannels, nanoseconds, seconds, sampleRate, out var samplesProcessed,
sequenceNumber, includeSecondaryHeader);
bw.Write(pcmPacket.GetBytes());
currentSample += samplesProcessed;
sequenceNumber++;
var elapsedNanoSeconds = samplesProcessed / (decimal)sampleRate * Constants.NANOS_PER_SECOND;
var newNanos = nanoseconds + elapsedNanoSeconds;
if (newNanos > Constants.NANOS_PER_SECOND)
{
while (newNanos >= Constants.NANOS_PER_SECOND)
{
seconds++;
newNanos -= Constants.NANOS_PER_SECOND;
}
}
nanoseconds = Convert.ToInt32(Math.Truncate(newNanos));
tickEventHandler?.Invoke(tickObject, 50D + 50D * currentSample / channel0Length);
}
}
}
}
public static void WriteFileAnalog(string tmats, GetNextSampleDelegate getNextSample,
GetChannelLengthDelegate getChannelLength,
int totalChannels,
int nanoseconds, int seconds, double sampleRate,
bool includeSecondaryHeader,
string fileName,
TickEventHandler tickEventHandler,
object tickObject)
{
var startNanoSeconds = nanoseconds;
var startSeconds = seconds;
if (System.IO.File.Exists(fileName))
{
FileUtils.DeleteFileOrMove(fileName, APILogger.Log);
}
using (var ms = new FileStream(fileName, FileMode.OpenOrCreate))
{
using (var bw = new BinaryWriter(ms))
{
//simulate writing the transport bytes ... not needed for ch10 file though ...
//first packet should be tmats
var tmatsPacket = new TMATSPacket(nanoseconds, seconds, tmats, includeSecondaryHeader);
bw.Write(tmatsPacket.GetBytes());
var currentSample = 0L;
byte sequenceNumber = 0x01;
byte timeSequenceNumber = 0x01;
var lastSecondTransmitted = 0;
if (!includeSecondaryHeader)
{
//insert first time packet at time second 1
InsertTimePacket1(bw, seconds, nanoseconds, ref timeSequenceNumber, startSeconds, startNanoSeconds);
lastSecondTransmitted = seconds;
}
var channel0Length = getChannelLength(0);
while (currentSample < channel0Length)
{
var newRTC = GetRTC(currentSample, sampleRate);
if (includeSecondaryHeader)
{
var timePacket = new TimePacketFormat2(timeSequenceNumber, false, nanoseconds, seconds, newRTC,
includeSecondaryHeader);
var time = PTP1588Timestamps.UnitTimeStampToDateTimeLocal((decimal)seconds, (decimal)nanoseconds).ToUniversalTime();
var newTime = new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
timeSequenceNumber++;
bw.Write(timePacket.GetBytes());
}
else
{
if (seconds > lastSecondTransmitted)
{
lastSecondTransmitted = seconds;
InsertTimePacket1(bw, seconds, nanoseconds, ref timeSequenceNumber, startSeconds, startNanoSeconds);
}
}
var analogPacket = GetAnalogPacket(currentSample, getNextSample, channel0Length, totalChannels, nanoseconds, seconds, sampleRate, out var samplesProcessed,
sequenceNumber, includeSecondaryHeader);
bw.Write(analogPacket.GetBytes());
currentSample += samplesProcessed;
sequenceNumber++;
var elapsedNanoSeconds = samplesProcessed / (decimal)sampleRate * Constants.NANOS_PER_SECOND;
var newNanos = nanoseconds + elapsedNanoSeconds;
if (newNanos > Constants.NANOS_PER_SECOND)
{
while (newNanos >= Constants.NANOS_PER_SECOND)
{
seconds++;
newNanos -= Constants.NANOS_PER_SECOND;
}
}
nanoseconds = Convert.ToInt32(Math.Truncate(newNanos));
tickEventHandler?.Invoke(tickObject, 50D + 50D * currentSample / channel0Length);
}
}
}
}
/// <summary>
/// returns a PCM data packet with the next samples (targetting 100ms of data)
/// </summary>
private static PCMDataPacket GetPcmPacket(long currentSample, GetNextSampleDelegate getNextSample,
long channelLength, int totalChannels, int nanoseconds,
int seconds, double sampleRate, out long samplesProcessed, byte sequenceNumber, bool includeSecondaryHeader)
{
var newRTC = GetRTC(currentSample, sampleRate);
var numSamples = channelLength;
numSamples -= currentSample;
//we should target 100ms of data per packet, sample rate is in seconds
//so divide by 10 to get number of samples per 100ms
var numSamplesPerPacket = sampleRate / 10;
//if we want more samples than are available, just truncate down to max available
if (numSamples > numSamplesPerPacket)
{
numSamples = Convert.ToInt64(numSamplesPerPacket);
}
var pcmPacket = new PCMDataPacket(nanoseconds, seconds,
getNextSample, totalChannels, channelLength, newRTC, numSamples, currentSample, sequenceNumber, 3,
includeSecondaryHeader);
samplesProcessed = numSamples;
return pcmPacket;
}
private static AnalogDataFormat1Packet GetAnalogPacket(long currentSample, GetNextSampleDelegate getNextSample,
long channelLength, int totalChannels, int nanoseconds,
int seconds, double sampleRate, out long samplesProcessed, byte sequenceNumber, bool includeSecondaryHeader)
{
var newRTC = GetRTC(currentSample, sampleRate);
var numSamples = channelLength;
numSamples -= currentSample;
//we should target 100ms of data per packet
var numSamplesPerPacket = Math.Floor(sampleRate / 10);
if (numSamples > numSamplesPerPacket)
{
numSamples = Convert.ToInt64(numSamplesPerPacket);
}
var analogPacket = new AnalogDataFormat1Packet(nanoseconds, seconds,
getNextSample, totalChannels, channelLength, newRTC, numSamples, currentSample, sequenceNumber, 3,
includeSecondaryHeader);
samplesProcessed = numSamples;
return analogPacket;
}
//for convenience just store relative time counter 10MHZ conversion factor
private const int RTC_PER_SECOND = 10000000;
private static long GetRTC(long currentSample, double sampleRate)
{
var secondsPassed = currentSample / sampleRate;
return AbstractDataPacket.BASE_RTC + Convert.ToInt64(secondsPassed * RTC_PER_SECOND);
}
private static long GetRTC(long tickDelta)
{
var seconds = (double)tickDelta / TimeSpan.TicksPerSecond;
return AbstractDataPacket.BASE_RTC - Convert.ToInt64(seconds * RTC_PER_SECOND);
}
/// <summary>
/// parses out all packets from array of bytes
/// </summary>
/// <param name="bytes"></param>
public Chapter10File(byte[] bytes)
{
_bytes = new byte[bytes.Length];
Buffer.BlockCopy(bytes, 0, _bytes, 0, bytes.Length);
var currentByteIndex = 0L;
var badPackets = 0;
var goodPackets = 0;
while (currentByteIndex < (bytes.Length - PacketHeader.PACKET_HEADER_LENGTH))
{
try
{
currentByteIndex = ReadTransportHeader(bytes, currentByteIndex, out var transportHeader);
var startOfChapter10Packet = currentByteIndex;
currentByteIndex = ReadChapter10PacketHeader(bytes, currentByteIndex, out var packetHeader);
if (packetHeader.PacketSyncPattern != PacketHeader.EXPECTED_SYNC_PATTERN || packetHeader.CheckSum != packetHeader.ComputeCheckSum())
{
badPackets++;
//this packet is invalid, so we need to skip ahead
//skip until we see the next sync pattern, then backstep to the start of the transport bytes, then continue on
currentByteIndex = GetIndexOfNextPacket(bytes, startOfChapter10Packet);
continue;
}
_transportHeaders.Add(transportHeader);
if (packetHeader.SecondaryHeaderPresent)
{
ReadChapter10SecondHeaderTimeFormat(bytes, startOfChapter10Packet + PacketHeader.PACKET_HEADER_LENGTH, out var secondaryTimeHeader);
_secondaryTimePackets.Add(secondaryTimeHeader);
}
_packets.Add(packetHeader);
_packetToByteStartStop[packetHeader] = new Tuple<long, long>(startOfChapter10Packet, currentByteIndex);
goodPackets++;
}
catch (Exception ex)
{
throw new Exception($"Hit exception processing file at byte: {currentByteIndex}, {ex.Message}", ex);
}
}
GoodPackets = goodPackets;
RejectedPackets = badPackets;
}
/// <summary>
/// determines the next valid packet starting location after the provided starting spot
/// this is used to skip over bad data to the next good packet
/// </summary>
/// <param name="bytes"></param>
/// <param name="startIndex"></param>
/// <returns></returns>
public static long GetIndexOfNextPacket(byte[] bytes, long startIndex)
{
for (var i = startIndex; i < bytes.Length - 1; i++)
{
if (BitConverter.ToUInt16(bytes, (int)i) == PacketHeader.EXPECTED_SYNC_PATTERN)
{
return i;
}
}
//if we got here there are no more valid packets, you are done.
return bytes.Length;
}
/// <summary>
/// reads a secondary time header from provided bytes and starting spot
/// </summary>
/// <param name="bytes"></param>
/// <param name="start"></param>
/// <param name="secondaryTimeFormat"></param>
private void ReadChapter10SecondHeaderTimeFormat(byte[] bytes, long start, out ISecondaryTimeFormatHeader secondaryTimeFormat)
{
var headerBytes = new byte[SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH];
Array.Copy(bytes, start, headerBytes, 0, SecondaryTimeFormatHeader.SECONDARY_TIME_HEADER_LENGTH);
secondaryTimeFormat = new SecondaryTimeFormatHeader(headerBytes);
}
/// <summary>
/// reads a transport header from provided bytes and starting spot
/// </summary>
/// <param name="bytes"></param>
/// <param name="startIndex"></param>
/// <param name="transportHeader"></param>
/// <returns></returns>
private long ReadTransportHeader(byte[] bytes, long startIndex, out TransportStreamHeader transportHeader)
{
var transportHeaderBytes = new byte[4];
Array.Copy(bytes, startIndex, transportHeaderBytes, 0, 4);
transportHeader = new TransportStreamHeader(transportHeaderBytes);
return startIndex + 4L;
}
/// <summary>
/// reads a Packet from stream of bytes at given starting spot
/// </summary>
/// <param name="bytes"></param>
/// <param name="startIndex"></param>
/// <param name="packetHeader"></param>
/// <returns></returns>
public static long ReadChapter10PacketHeader(byte[] bytes, long startIndex, out IPacketHeader packetHeader)
{
var headerBytes = new byte[PacketHeader.PACKET_HEADER_LENGTH];
Array.Copy(bytes, startIndex, headerBytes, 0, PacketHeader.PACKET_HEADER_LENGTH);
packetHeader = new PacketHeader(headerBytes);
return startIndex + packetHeader.PacketLength;
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Test.Module.IConvertable.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
namespace DTS.Serialization
{
// *** see Test.cs ***
public partial class Test
{
// *** see Test.Module.cs ***
public partial class Module
{
/// <summary>
/// An object that expresses this interface can convert itself to and from a
/// <see cref="DTS.Serialization.Test.Module"/> object.
/// </summary>
///
public interface IConvertable
{
/// <summary>
/// Convert this object to a <see cref="DTS.Serialization.Test.Module"/>.
/// </summary>
///
/// <param name="parentTest">
/// The <see cref="DTS.Serialization.ParentTest"/> that contains the afixed object.
/// </param>
///
/// <returns>
/// The <see cref="DTS.Serialization.Test.Module"/> equivalent of this object.
/// </returns>
///
Module ToDtsSerializationTestModule(Test parentTest);
/// <summary>
/// Initialize this object using the specified <see cref="DTS.Serialization.Test.Module"/>.
/// </summary>
///
/// <param name="test">
/// The <see cref="DTS.Serialization.Test.Module"/> with which this object will be initialized from.
/// </param>
///
void FromDtsSerializationTestModule(Module testModule, ReportErrors reportErrors);
}
}
}
}

View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AAFilterCutoffDescription_Description" xml:space="preserve">
<value>What freuqncy content the user can expect; Include notes of AAfilters applied and any applicable reasoning</value>
</data>
<data name="AAFilterCutoffDescription_Title" xml:space="preserve">
<value>AA Filter Cutoff description</value>
</data>
<data name="BitResolution_Description" xml:space="preserve">
<value>The resolution settings for the test in engineering units per bit</value>
</data>
<data name="BitResolution_Title" xml:space="preserve">
<value>Bit Resolution(Units per bit)</value>
</data>
<data name="ChannelErrors_Description" xml:space="preserve">
<value>Yes or No depending if channel errors are noted in the data</value>
</data>
<data name="ChannelErrors_Title" xml:space="preserve">
<value>Channel Errors (Y or N)</value>
</data>
<data name="DataType_Description" xml:space="preserve">
<value>The type of data milestone this file supports</value>
</data>
<data name="DataType_Title" xml:space="preserve">
<value>Data Type (Raw, Converted, or Processed)</value>
</data>
<data name="DigitalFilterType_Description" xml:space="preserve">
<value>The digital filter applied and the cutoff in Hz</value>
</data>
<data name="DigitalFilterType_Title" xml:space="preserve">
<value>Digital Filter Type/Cutoff (Hz)</value>
</data>
<data name="EngineeringUnits_Description" xml:space="preserve">
<value>Engineering units depicted in Converted and Processed Data sets; Voltages for Raw data</value>
</data>
<data name="EngineeringUnits_Title" xml:space="preserve">
<value>Engineering Units</value>
</data>
<data name="LabName_Description" xml:space="preserve">
<value>Include the name of the University, Institution, and/or Lab that conducted the test</value>
</data>
<data name="LabName_Title" xml:space="preserve">
<value>Lab Name</value>
</data>
<data name="Notes_Description" xml:space="preserve">
<value>Any notes or descriptions useful in supporting data file analysis</value>
</data>
<data name="Notes_Title" xml:space="preserve">
<value>Notes</value>
</data>
<data name="POCName_Description" xml:space="preserve">
<value>Include the name of the test Point of Contact</value>
</data>
<data name="POCName_Title" xml:space="preserve">
<value>POC Name</value>
</data>
<data name="POCPhoneAndEmail_Description" xml:space="preserve">
<value>Include applicable lab phone number, email, etc. for contacting the POC</value>
</data>
<data name="POCPhoneAndEmail_Title" xml:space="preserve">
<value>POC phone and email</value>
</data>
<data name="SamplingRate_Description" xml:space="preserve">
<value>The data sampling rate in Hz</value>
</data>
<data name="SamplingRate_Title" xml:space="preserve">
<value>Sampling Rate (Hz)</value>
</data>
<data name="SensorAxis_Description" xml:space="preserve">
<value>The direction of the sensor axis; include whether direction is global or local</value>
</data>
<data name="SensorAxis_Title" xml:space="preserve">
<value>Sensor Axis (direction)</value>
</data>
<data name="SensorLocation_Description" xml:space="preserve">
<value>Location of the sensor, using body region codes</value>
</data>
<data name="SensorLocation_Title" xml:space="preserve">
<value>Sensor Location</value>
</data>
<data name="SensorMakeModelSerial_Description" xml:space="preserve">
<value>The brand name of the sensor used with the model name and serial number</value>
</data>
<data name="SensorMakeModelSerial_Title" xml:space="preserve">
<value>Sensor Make Model Serial</value>
</data>
<data name="SensorMountType_Description" xml:space="preserve">
<value>If Applicable include the type of sensor mount: LOFFI, BOBKAT, glued, fixed, other</value>
</data>
<data name="SensorMountType_Title" xml:space="preserve">
<value>Sensor Mount Type</value>
</data>
<data name="TestDate_Description" xml:space="preserve">
<value>Date the test was conducted</value>
</data>
<data name="TestDate_Title" xml:space="preserve">
<value>Test Date</value>
</data>
<data name="TestNumber_Description" xml:space="preserve">
<value>Test Number that correlates with filename and README file test numbers. This is a lab generated test number that sequences the series of tests for a specific surrogate (PHMS or HIII)</value>
</data>
<data name="TestNumber_Title" xml:space="preserve">
<value>Test Number</value>
</data>
<data name="TestObject_Description" xml:space="preserve">
<value>Description of the objects being tested. PHMS with specimen ID, type of HIII, combination, or other</value>
</data>
<data name="TestObject_Title" xml:space="preserve">
<value>Test Object (HIII, PMHS, combo, etc.)</value>
</data>
<data name="TestTime_Description" xml:space="preserve">
<value>Local lab time when the test was conducted</value>
</data>
<data name="TestTime_Title" xml:space="preserve">
<value>Test Time</value>
</data>
<data name="TestType_Description" xml:space="preserve">
<value>Short text description of the type of test conducted</value>
</data>
<data name="TestType_Title" xml:space="preserve">
<value>Test Type (sled, blast, drop, etc.)</value>
</data>
</root>