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); } } } } } } } }