Files
2026-04-17 14:55:32 -04:00

209 lines
11 KiB
C#

using System;
using DTS.Common.Constant;
using DTS.Common.Enums;
using DTS.Common.Enums.Sensors;
namespace DTS.Serialization.TDAS
{
public class TLFBin
{
public double AcquisitionRate { get; set; }
public int PreTriggerDataPoints { get; set; }
public int PostTriggerDataPoints { get; set; }
public int PreZeroLevel { get; set; }
public int PreCalLevel { get; set; }
public double SignalToNoiseRatio { get; set; }
public int PostZeroLevel { get; set; }
public int PostCalLevel { get; set; }
public double SuperSampleRate { get; set; }
public TLFBin(Test.Module.Channel channel, double superSampleRate)
{
SuperSampleRate = superSampleRate;
var aic = channel as Test.Module.AnalogInputChannel;
AcquisitionRate = aic.ParentModule.SampleRateHz;
var rate = Convert.ToInt32(Math.Ceiling(superSampleRate / AcquisitionRate));
PreTriggerDataPoints = Convert.ToInt32(rate * ((long)aic.ParentModule.TriggerSampleNumbers[0] - (long)aic.ParentModule.StartRecordSampleNumber));
PostTriggerDataPoints = Convert.ToInt32(rate * ((long)aic.ParentModule.NumberOfSamples - ((long)aic.ParentModule.TriggerSampleNumbers[0] - (long)aic.ParentModule.StartRecordSampleNumber)));
PreZeroLevel = Convert.ToInt32(aic.PreTestZeroLevelAdc);
PreCalLevel = Convert.ToInt32(.7D * short.MaxValue);//we could put in a constant value, but
//this makes it clear where the value is coming from
// Noise as a % of full scale is actually std dev noise as percent of full scale?
// so by dividing by the full scale (which is in ADC to avoid confusion) we should
// have std dev noise back, we don't infact have a precal value in slice, so
// maybe using 80% of the full range will give us something reasonable
// I used the min value since the equation producing noise as a percent of full scale
// is using 32768, which is actually - short.min;
var stddev = aic.NoiseAsPercentageOfFullScale / (-1D) * short.MinValue;
stddev /= 100D;
if (0 == stddev) { SignalToNoiseRatio = 0D; }
else
{
SignalToNoiseRatio = 20D * Math.Log10(-.8D * short.MinValue / stddev);
}
//@TODO - this information isn't currently available
//PostZeroLevel = Convert.ToInt32(aic.PreTestZeroLevelAdc);
PostZeroLevel = 0;
PostCalLevel = 0;
var excitationVoltage = 5D;
if ((!aic.IsSquibChannel) && (aic.Bridge != SensorConstants.BridgeType.DigitalInput))
{
try
{
excitationVoltage = aic.FactoryExcitationVoltage;
}
catch (Exception) { excitationVoltage = aic.MeasuredExcitationVoltage; }
}
//14251 - TDC export does not respect viewer data modifications for multiply
//ScaleFactorEU *= aic.Data.Multiplier;
}
public void Serialize(System.IO.BinaryWriter bw, Test.Module.Channel channel)
{
var aic = (Test.Module.AnalogInputChannel)channel;
var scaler = SliceRaw.File.Reader.GetDataScaler(aic);
//147662,112211
var rate = Convert.ToInt32(Math.Ceiling(SuperSampleRate / AcquisitionRate));
bw.Write(BitConverter.GetBytes(SuperSampleRate), 0, 8);
bw.Write(BitConverter.GetBytes(PreTriggerDataPoints), 0, 4);
bw.Write(BitConverter.GetBytes(PostTriggerDataPoints), 0, 4);
bw.Write(BitConverter.GetBytes(PreZeroLevel), 0, 4);
bw.Write(BitConverter.GetBytes(PreCalLevel), 0, 4);
bw.Write(BitConverter.GetBytes(SignalToNoiseRatio), 0, 8);
bw.Write(BitConverter.GetBytes(PostZeroLevel), 0, 4);
bw.Write(BitConverter.GetBytes(PostCalLevel), 0, 4);
bw.Write(BitConverter.GetBytes(Convert.ToInt32(scaler.GetDataZeroLevelADC())), 0, 4);
bw.Write(BitConverter.GetBytes(scaler.GetScaleFactorMv()), 0, 8);
if (!aic.LinearizationFormula.IsValid())
{
bw.Write(BitConverter.GetBytes(scaler.GetAdcToEuScalingFactor()), 0, 8);
}
else
{
bw.Write(BitConverter.GetBytes(aic.SensorCapacity / (ushort.MaxValue / 2.0)), 0, 8);
}
if (((Test.Module.AnalogInputChannel)channel).Bridge == SensorConstants.BridgeType.DigitalInput)
{
double breakPoint = DigitalInputs.ConstantCurrentBreakPoint;
if (aic.DigitalMode == DigitalInputModes.THL || aic.DigitalMode == DigitalInputModes.TLH)
{
breakPoint = DigitalInputs.VoltageInputBreakPoint;
}
for (ulong i = 0; i < channel.PersistentChannelInfo.NumberOfSamples; i++)
{
for (var step = 0; step < rate; step++)
{
var adc = channel.PersistentChannelInfo[i];
var increment = 0D;
if ((i + 1) < channel.PersistentChannelInfo.NumberOfSamples)
{
increment = (channel.PersistentChannelInfo[i + 1] - adc) / rate;
}
else
{
increment = (adc - channel.PersistentChannelInfo[i - 1]) / rate;
}
if ((adc + increment * step) > breakPoint)
{
switch (aic.DigitalMode)
{
case DigitalInputModes.CCNC:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.ActiveValue), 0, 2);
break;
case DigitalInputModes.CCNO:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.DefaultValue), 0, 2);
break;
case DigitalInputModes.THL:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.ActiveValue), 0, 2);
break;
case DigitalInputModes.TLH:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.DefaultValue), 0, 2);
break;
default:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.ActiveValue), 0, 2);
break;
}
}
else
{
switch (aic.DigitalMode)
{
case DigitalInputModes.CCNC:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.DefaultValue), 0, 2);
break;
case DigitalInputModes.CCNO:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.ActiveValue), 0, 2);
break;
case DigitalInputModes.THL:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.DefaultValue), 0, 2);
break;
case DigitalInputModes.TLH:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.ActiveValue), 0, 2);
break;
default:
bw.Write(BitConverter.GetBytes((short)aic.DigitalMultiplier.DefaultValue), 0, 2);
break;
}
}
}
}
}
else
{
for (ulong i = 0; i < channel.PersistentChannelInfo.NumberOfSamples; i++)
{
var adc = channel.PersistentChannelInfo[i];
for (int step = 0; step < rate; step++)
{
var increment = 0D;
if ((i + 1) < channel.PersistentChannelInfo.NumberOfSamples)
{
increment = (channel.PersistentChannelInfo[i + 1] - adc) / rate;
}
else
{
increment = (adc - channel.PersistentChannelInfo[i - 1]) / rate;
}
//Use correct calculation for linear and non linear
//http://fogbugz/fogbugz/default.asp?10172
if (!aic.LinearizationFormula.IsValid())
{
bw.Write(BitConverter.GetBytes(Convert.ToInt16(adc + increment * step)), 0, 2);
}
else
{
//14496 TDAS export ALL failed
//newADC was underflowing in the below code that was causing an exception in 14496
//the sensor capacity was about 80mm, however there were some datapoints that were out of normal range
//(-250 or so EU), this appeared to be from a sig-gen ramp that went out of range for the IR-TRACC equation
//per CPB we now constrain newADC to short min/max and so the ADC rails in those spots.
var adcperEU = (ushort.MaxValue / 2.0) / aic.SensorCapacity;
var newADC = scaler.GetEU(adc) * adcperEU;
newADC += increment * step;
if (newADC < short.MinValue)
{
bw.Write(BitConverter.GetBytes(short.MinValue), 0, 2);
}
else if (newADC > short.MaxValue)
{
bw.Write(BitConverter.GetBytes(short.MaxValue), 0, 2);
}
else
{
bw.Write(BitConverter.GetBytes(Convert.ToInt16(newADC)), 0, 2);
}
}
}
}
}
}
}
}