586 lines
28 KiB
C#
586 lines
28 KiB
C#
|
|
/*
|
|||
|
|
* ToyotaCsv.File.Writer.cs
|
|||
|
|
*
|
|||
|
|
* Copyright © 2009
|
|||
|
|
* Diversified Technical Systems, Inc.
|
|||
|
|
* All Rights Reserved
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Text;
|
|||
|
|
using DTS.Common.DAS.Concepts;
|
|||
|
|
using DTS.Common.Utilities.DotNetProgrammingConstructs;
|
|||
|
|
using DTS.Common.Enums.Sensors;
|
|||
|
|
using DTS.Common.Utilities.Logging;
|
|||
|
|
|
|||
|
|
namespace DTS.Serialization.ToyotaCsv
|
|||
|
|
{
|
|||
|
|
// *** see ToyotaCsv.File.cs ***
|
|||
|
|
public partial class File
|
|||
|
|
{ ///
|
|||
|
|
/// <summary>
|
|||
|
|
/// Utility object for serializing <see cref="DTS.Serialization.Test"/>s to disk
|
|||
|
|
/// in the Toyota CSV format.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
public class Writer : Writer<File>, IWriter<Test>
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Initialize an instance of the ToyotaCsv.File.Writer class.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
/// <param name="fileType">
|
|||
|
|
/// The associated <see cref="DTS.SErialization.ToyotaCsv.File"/> object.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
internal Writer(File fileType, int encoding)
|
|||
|
|
: base(fileType, encoding)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private const string NUMBER_FORMAT = "F8";
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The different export modes that should theoretically be supported by this format.
|
|||
|
|
/// </summary>
|
|||
|
|
public enum ExportMode
|
|||
|
|
{
|
|||
|
|
FtssExcel,
|
|||
|
|
Ttc,
|
|||
|
|
Standard,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the current CSV export format.
|
|||
|
|
/// </summary>
|
|||
|
|
public ExportMode CurrentExportMode
|
|||
|
|
{
|
|||
|
|
get => _CurrentExportMode.Value;
|
|||
|
|
set => _CurrentExportMode.Value = value;
|
|||
|
|
}
|
|||
|
|
private readonly Property<ExportMode> _CurrentExportMode
|
|||
|
|
= new Property<ExportMode>(
|
|||
|
|
typeof(Writer).Namespace + ".File.Writer.CurrentExportMode",
|
|||
|
|
ExportMode.FtssExcel,
|
|||
|
|
true
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Notify <see cref="DTS.Serialization.BeginEventHandler"/> subscribers that the write
|
|||
|
|
/// is starting.
|
|||
|
|
/// </summary>
|
|||
|
|
public event BeginEventHandler OnBegin;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Notify <see cref="DTS.Serialization.EndEventHandler"/> subscribers that the write
|
|||
|
|
/// is finished.
|
|||
|
|
/// </summary>
|
|||
|
|
public event EndEventHandler OnEnd;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Notify <see cref="DTS.Serialization.TickEventHandler"/> subscribers that we are one
|
|||
|
|
/// tick closer to write completion.
|
|||
|
|
/// </summary>
|
|||
|
|
public event TickEventHandler OnTick;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// notify subscribers that writing is cancelling
|
|||
|
|
/// </summary>
|
|||
|
|
public event CancelEventHandler OnCancel;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// notify subscribers that writer encountered fatal error
|
|||
|
|
/// </summary>
|
|||
|
|
public event ErrorEventHandler OnError;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The number of data samples that need to be written for a "tick" to be dispatched.
|
|||
|
|
/// </summary>
|
|||
|
|
private int DataSamplesPerTick => 1000;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Return the number of data to be written per "tick".
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="channel"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private uint GetChannelTicks(Test.Module.Channel channel)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{ //
|
|||
|
|
// Most of our wait time will be spent writing data, so we need to give
|
|||
|
|
// the process a little finer granularity.
|
|||
|
|
//
|
|||
|
|
return (uint)(channel.PersistentChannelInfo.Length / DataSamplesPerTick);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
throw new Exception("encountered problem determining number of status ticks for channel " + (null != channel ? "\"" + channel.Number.ToString() + "\"" : "<NULL>"), ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Write the specified test to the specified pathname.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
/// <param name="pathname">
|
|||
|
|
/// The <see cref="string"/> pathname to which the specified test should be serialized.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="test">
|
|||
|
|
/// The <see cref="DTS.Serialization.Test"/> to be written out.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
Write(pathname, id, null, test, bFiltering, includeGroupNameInISOExport, null, null, 0, null, null, null, null, null, null, minStartTime, dataCollectionLength);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
throw new Exception("encountered problem non-event notified writing test", ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the filtered channel data. If this list is supplied, the corresponding test
|
|||
|
|
/// channel data values will be supplied from this list.
|
|||
|
|
/// </summary>
|
|||
|
|
public List<double[]> FilteredChannelData
|
|||
|
|
{
|
|||
|
|
get => _FilteredChannelData.Value;
|
|||
|
|
set => _FilteredChannelData.Value = value;
|
|||
|
|
}
|
|||
|
|
private readonly Property<List<double[]>> _FilteredChannelData
|
|||
|
|
= new Property<List<double[]>>(
|
|||
|
|
typeof(Writer).FullName + ".FilteredChannelData",
|
|||
|
|
new List<double[]>(),
|
|||
|
|
true
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Write the representation file/files of the specified DTS.Serialization.Test
|
|||
|
|
/// at the given pathname.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
/// <param name="targetPathname">
|
|||
|
|
/// The <see cref="string"/> pathname of the specified object's resulting file
|
|||
|
|
/// representation.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
public void Write(string pathname,
|
|||
|
|
string id,
|
|||
|
|
string dataFolder,
|
|||
|
|
Test test,
|
|||
|
|
bool bFiltering,
|
|||
|
|
bool includeGroupNameInISOExport,
|
|||
|
|
FilteredData fd,
|
|||
|
|
Test.Module.Channel tmChannel,
|
|||
|
|
int channelNumber,
|
|||
|
|
BeginEventHandler beginEventHandler,
|
|||
|
|
CancelEventHandler cancelEventHandler,
|
|||
|
|
EndEventHandler endEventHandler,
|
|||
|
|
TickEventHandler tickEventHandler,
|
|||
|
|
ErrorEventHandler errorEventHandler,
|
|||
|
|
CancelRequested cancelRequested,
|
|||
|
|
double minStartTime,
|
|||
|
|
int dataCollectionLength)
|
|||
|
|
{
|
|||
|
|
System.Exception exception = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
OnBegin += beginEventHandler;
|
|||
|
|
OnEnd += endEventHandler;
|
|||
|
|
OnTick += tickEventHandler;
|
|||
|
|
OnCancel += cancelEventHandler;
|
|||
|
|
OnError += errorEventHandler;
|
|||
|
|
|
|||
|
|
// Compute the total number of write ticks that will be dispatched during this
|
|||
|
|
// write, and let the caller know that we're underway.
|
|||
|
|
uint totalWriteTicksNeeded = 0;
|
|||
|
|
uint totalWriteTicksDispatched = 0;
|
|||
|
|
if (test.Channels.Count > 0)
|
|||
|
|
totalWriteTicksNeeded = GetChannelTicks(test.Channels[0]);
|
|||
|
|
OnBegin?.Invoke(this, totalWriteTicksNeeded);
|
|||
|
|
|
|||
|
|
var fs = new FileStream(pathname, FileMode.Create);
|
|||
|
|
|
|||
|
|
|
|||
|
|
using (var fileWriter = new StreamWriter(fs, Encoding.Unicode))
|
|||
|
|
{
|
|||
|
|
var exportChannels = test.Channels;
|
|||
|
|
|
|||
|
|
switch (CurrentExportMode)
|
|||
|
|
{
|
|||
|
|
case ExportMode.FtssExcel:
|
|||
|
|
case ExportMode.Ttc:
|
|||
|
|
WriteChannelInfo(fileWriter,
|
|||
|
|
test,
|
|||
|
|
FilteredChannelData,
|
|||
|
|
tickEventHandler,
|
|||
|
|
totalWriteTicksNeeded,
|
|||
|
|
ref totalWriteTicksDispatched,
|
|||
|
|
cancelRequested);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
throw new NotSupportedException("ToyotaCSV::File::Writer export mode not supported: " + CurrentExportMode.ToString());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
exception = new Exception("encountered problem writing TTS test files", ex);
|
|||
|
|
APILogger.Log("encountered problem writing TTS test files", ex);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
finally
|
|||
|
|
{
|
|||
|
|
OnEnd?.Invoke(this);
|
|||
|
|
if (null != cancelRequested && cancelRequested())
|
|||
|
|
{
|
|||
|
|
OnCancel?.Invoke(this);
|
|||
|
|
}
|
|||
|
|
if (null != exception && null != errorEventHandler)
|
|||
|
|
{
|
|||
|
|
errorEventHandler(this, exception);
|
|||
|
|
}
|
|||
|
|
else if (null != exception)
|
|||
|
|
{
|
|||
|
|
throw exception;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Initialize(string pathname,
|
|||
|
|
string id,
|
|||
|
|
string dataFolder,
|
|||
|
|
Test test,
|
|||
|
|
bool bFiltering,
|
|||
|
|
bool includeGroupNameInISOExport,
|
|||
|
|
FilteredData fd,
|
|||
|
|
Test.Module.Channel tmChannel,
|
|||
|
|
int channelNumber,
|
|||
|
|
BeginEventHandler beginEventHandler,
|
|||
|
|
CancelEventHandler cancelEventHandler,
|
|||
|
|
EndEventHandler endEventHandler,
|
|||
|
|
TickEventHandler tickEventHandler,
|
|||
|
|
ErrorEventHandler errorEventHandler,
|
|||
|
|
CancelRequested cancelRequested)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// A collection of a channel and associated metadata that will all be needed together when
|
|||
|
|
/// this file format starts laying down bytes.
|
|||
|
|
/// </summary>
|
|||
|
|
private sealed class ChannelWithMeta
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the <see cref="DTS.Serialization.Test.Module.Channel"/> to be serialized.
|
|||
|
|
/// </summary>
|
|||
|
|
public Test.Module.Channel Channel { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the <see cref="DataScaler"/> associated with the
|
|||
|
|
/// specified channel.
|
|||
|
|
/// </summary>
|
|||
|
|
public DataScaler Scaler { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the <see cref="double"/> sample rate associated with the specified channel.
|
|||
|
|
/// </summary>
|
|||
|
|
public double SampleRate { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get/set the <see cref="double"/> start time associated with the specified channel.
|
|||
|
|
/// </summary>
|
|||
|
|
public double StartTime { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Initialize an instance of the ChannelWithMeta class.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
/// <param name="channel">
|
|||
|
|
/// A <see cref="DTS.Serialization.Test.Module.Channel"/> to be serialized.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="scaler">
|
|||
|
|
/// The <see cref="DataScaler"/> containing scaling information for
|
|||
|
|
/// the specified channel.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="samplerate">
|
|||
|
|
/// The <see cref="double"/> sample rate of the associated channel.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="starttime">
|
|||
|
|
/// The <see cref="double"/> start time of the associated channel.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
public ChannelWithMeta(Test.Module.Channel channel, DataScaler scaler, double samplerate, double starttime)
|
|||
|
|
{
|
|||
|
|
Channel = channel;
|
|||
|
|
Scaler = scaler;
|
|||
|
|
SampleRate = samplerate;
|
|||
|
|
StartTime = starttime;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Write the specified test to the specified stream.
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
/// <param name="fileWriter">
|
|||
|
|
/// The <see cref="System.IO.StreamWriter"/> to which the specified test should be serialized.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="test">
|
|||
|
|
/// The <see cref="DTS.Serialization.Test"/> to be serialized.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
/// <param name="writeEvent">
|
|||
|
|
/// The <see cref="ToyotaCsv.File.Writer.EventHandler"/> that should handle write-progress
|
|||
|
|
/// reporting; null if none is to be used.
|
|||
|
|
/// </param>
|
|||
|
|
///
|
|||
|
|
protected void WriteChannelInfo
|
|||
|
|
(
|
|||
|
|
StreamWriter fileWriter,
|
|||
|
|
Test test,
|
|||
|
|
List<double[]> filteredData,
|
|||
|
|
TickEventHandler tickEventHandler,
|
|||
|
|
uint totalWriteTicksNeeded,
|
|||
|
|
ref uint totalWriteTicksDispatched,
|
|||
|
|
CancelRequested cancelRequested
|
|||
|
|
)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// Row 1: Test number
|
|||
|
|
fileWriter.WriteLine(test.Id);
|
|||
|
|
|
|||
|
|
// Row 2:
|
|||
|
|
fileWriter.WriteLine(test.Id);
|
|||
|
|
|
|||
|
|
// Row 3: Test Date
|
|||
|
|
fileWriter.WriteLine($"{test.InceptionDate.Year - 2000}-{test.InceptionDate.Month}-{test.InceptionDate.Day}");
|
|||
|
|
|
|||
|
|
// Row 4: Impact Speed
|
|||
|
|
fileWriter.WriteLine("");
|
|||
|
|
|
|||
|
|
// Row 5, 6:
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
|
|||
|
|
// Row 7:
|
|||
|
|
fileWriter.WriteLine(test.Description);
|
|||
|
|
|
|||
|
|
// Row 8: Sampling Rate
|
|||
|
|
fileWriter.WriteLine(test.Modules.Count > 0 ? test.Modules[0].SampleRateHz.ToString() : "NO MODULES");
|
|||
|
|
|
|||
|
|
// Row 9, 10, 11, 12:
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
|
|||
|
|
// Row 13:
|
|||
|
|
//fprintf(fpExport, "%s,\n", TestPtr->VehicleList[0].Description);
|
|||
|
|
|
|||
|
|
// Row 14: Dummies
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
//for(iIndex = 0; iIndex < MAX_DEVICE_DISPLAY; iIndex++)
|
|||
|
|
//{
|
|||
|
|
// if(strlen(TestPtr->DeviceList[iIndex].DeviceID) > 0)
|
|||
|
|
// {
|
|||
|
|
// fprintf(fpExport, "%s,", TestPtr->DeviceList[iIndex].DeviceID);
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//fprintf(fpExport, "\n");
|
|||
|
|
|
|||
|
|
// Row 15, 16, 17, 18, 19, 20:
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
|
|||
|
|
// Row 21: Header: Time and codes
|
|||
|
|
fileWriter.Write("TIME,");
|
|||
|
|
|
|||
|
|
foreach (var channel in test.Channels)
|
|||
|
|
fileWriter.Write(channel.ChannelDescriptionString + ",");
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
|
|||
|
|
//for(iIndex = 0; iIndex < iChannelListCount; iIndex++)
|
|||
|
|
//{
|
|||
|
|
// RackIndex = ChannelList[iIndex].iRack;
|
|||
|
|
// ModuleIndex = ChannelList[iIndex].iModule;
|
|||
|
|
// ChannelIndex = ChannelList[iIndex].iChannel;
|
|||
|
|
// ChannelPtr = &SystemPtr->HWRack[RackIndex].HWModuleList[ModuleIndex].HWChannelList[ChannelIndex];
|
|||
|
|
// if(IsChannelValid(ChannelPtr))
|
|||
|
|
// {
|
|||
|
|
// if(strlen(ChannelPtr->SensorUserChannelDescription) > 0)
|
|||
|
|
// {
|
|||
|
|
// fprintf(fpExport, "%s,", ChannelPtr->SensorUserChannelDescription);
|
|||
|
|
// }
|
|||
|
|
// else if(ChannelPtr->UserPointerValid[0])
|
|||
|
|
// {
|
|||
|
|
// fprintf(fpExport, "%s,", ((SensorDBItem *)(ChannelPtr->UserPointer[0]))->Code);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
//fprintf(fpExport, "\n");
|
|||
|
|
|
|||
|
|
// Row 22, 23, 24:
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
|
|||
|
|
var channelsWithMeta = new List<ChannelWithMeta>();
|
|||
|
|
var filteredDataIndex = 0;
|
|||
|
|
|
|||
|
|
foreach (var channel in test.Channels)
|
|||
|
|
{ //
|
|||
|
|
// Bundle data and associated scaling information for in preparation for
|
|||
|
|
// upcoming write.
|
|||
|
|
//
|
|||
|
|
var scaler = new DataScaler();
|
|||
|
|
scaler.IsInverted = channel is Common.DAS.Concepts.DAS.Channel.IInversionAware ? (channel as Common.DAS.Concepts.DAS.Channel.IInversionAware).IsInverted : false;
|
|||
|
|
scaler.SetScaleFactorMv(channel.Data.ScaleFactorMv);
|
|||
|
|
scaler.SetScaleFactorEU(channel.Data.ScaleFactorEU);
|
|||
|
|
scaler.SetUseEUScaleFactors(channel.Data.UseEUScaleFactors);
|
|||
|
|
scaler.UnitConversion = (channel as Test.Module.AnalogInputChannel).UnitConversion;
|
|||
|
|
scaler.BasedOnOutputAtCapacity = (channel as Test.Module.AnalogInputChannel).AtCapacity;
|
|||
|
|
scaler.CapacityOutputIsBasedOn = (channel as Test.Module.AnalogInputChannel).CapacityOutputIsBasedOn;
|
|||
|
|
scaler.SensitivityUnits = (channel as Test.Module.AnalogInputChannel).SensitivityUnits;
|
|||
|
|
if (channel is Test.Module.AnalogInputChannel)
|
|||
|
|
{
|
|||
|
|
scaler.IEPE = (channel as Test.Module.AnalogInputChannel).Bridge == SensorConstants.BridgeType.IEPE;
|
|||
|
|
scaler.Digital = (channel as Test.Module.AnalogInputChannel).Bridge == SensorConstants.BridgeType.DigitalInput;
|
|||
|
|
scaler.SetDigitalMultiplier((channel as Test.Module.AnalogInputChannel).DigitalMultiplier);
|
|||
|
|
scaler.DigitalMode = (channel as Test.Module.AnalogInputChannel).DigitalMode;
|
|||
|
|
}
|
|||
|
|
if ((channel as Common.DAS.Concepts.DAS.Channel.ILinearized).LinearizationFormula.IsValid())
|
|||
|
|
{
|
|||
|
|
scaler.SetLinearizationFormula((channel as Common.DAS.Concepts.DAS.Channel.ILinearized).LinearizationFormula);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
scaler.SetLinearizationFormula(null);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
scaler.SetRemovedADC(channel.RemovedADC);
|
|||
|
|
scaler.SetRemovedInternalADC(channel.RemovedInternalADC);
|
|||
|
|
scaler.SetDataZeroLevelADC(channel.DataZeroLevelAdc);
|
|||
|
|
scaler.SetZeroMvInADC(channel.ZeroMvInADC);
|
|||
|
|
try { scaler.SetWindowAverageADC(channel.WindowAverageADC); }
|
|||
|
|
catch (System.Exception) { }
|
|||
|
|
//try { scaler.SetIRTraccZeros(Convert.ToDouble(channel.DataZeroLevelAdc), Convert.ToDouble(channel.PreTestZeroLevelAdc)); }
|
|||
|
|
//catch (System.Exception) { }
|
|||
|
|
//initialEU
|
|||
|
|
}
|
|||
|
|
catch (System.Exception) { }
|
|||
|
|
|
|||
|
|
scaler.SetMvPerEu(channel.Data.MvPerEu);
|
|||
|
|
|
|||
|
|
if (channel is Test.Module.AnalogInputChannel)
|
|||
|
|
{
|
|||
|
|
//
|
|||
|
|
// Maybe these should be replaced by DTS.DAS.Concepts versions for casting? Would need to
|
|||
|
|
// add excitation voltage as a concept, and proportional to excitation.
|
|||
|
|
//
|
|||
|
|
var analogChannel = channel as Test.Module.AnalogInputChannel;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
scaler.SetInitialOffset(analogChannel.InitialOffset);
|
|||
|
|
}
|
|||
|
|
catch (System.Exception) { }
|
|||
|
|
scaler.ZeroMethodType = analogChannel.ZeroMethod;
|
|||
|
|
scaler.NominalExcitationVoltage = analogChannel.ExcitationVoltage;
|
|||
|
|
try { scaler.FactoryExcitationVoltage = analogChannel.FactoryExcitationVoltage; }
|
|||
|
|
catch { };
|
|||
|
|
try { scaler.MeasuredExcitationVoltage = analogChannel.MeasuredExcitationVoltage; }
|
|||
|
|
catch { };
|
|||
|
|
scaler.ProportionalToExcitation = analogChannel.ProportionalToExcitation;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
channelsWithMeta.Add(
|
|||
|
|
new ChannelWithMeta(
|
|||
|
|
channel,
|
|||
|
|
scaler,
|
|||
|
|
channel.ParentModule.SampleRateHz,
|
|||
|
|
channel.ParentModule.TriggerSampleNumbers.Count > 0 ? channel.ParentModule.TriggerSampleNumbers[0] / channel.ParentModule.SampleRateHz * -1.0 : 0
|
|||
|
|
)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var minStartTime = channelsWithMeta.Min(cwm => cwm.StartTime);
|
|||
|
|
var maxStartTime = channelsWithMeta.Max(cwm => cwm.StartTime);
|
|||
|
|
// LINQ statement will sometimes hand back float-rounding error numbers (4.999999999999995 v 5.0), use same rounding we use for time.
|
|||
|
|
var minStopTime = double.Parse(channelsWithMeta.Min(cwm => cwm.StartTime + (cwm.Channel.PersistentChannelInfo.Length - 1) * 1.0 / cwm.SampleRate).ToString(NUMBER_FORMAT));
|
|||
|
|
var maxStopTime = double.Parse(channelsWithMeta.Max(cwm => cwm.StartTime + (cwm.Channel.PersistentChannelInfo.Length - 1) * 1.0 / cwm.SampleRate).ToString(NUMBER_FORMAT));
|
|||
|
|
|
|||
|
|
var minSampleRate = channelsWithMeta.Min(cwm => cwm.SampleRate);
|
|||
|
|
var maxSampleRate = channelsWithMeta.Max(cwm => cwm.SampleRate);
|
|||
|
|
if (minSampleRate != maxSampleRate)
|
|||
|
|
throw new UserException("Lowest sample rate (" + minSampleRate.ToString() + ") does not match highest sample rate (" + maxSampleRate.ToString() + ").\nThey must be identical.");
|
|||
|
|
var sampleRate = minSampleRate;
|
|||
|
|
|
|||
|
|
var dataCollectionLength = (int)((maxStopTime - minStartTime) * sampleRate); //maxDataLengthInAllChannels;
|
|||
|
|
|
|||
|
|
for (var i = 0; i < dataCollectionLength; i++)
|
|||
|
|
{
|
|||
|
|
if (null != cancelRequested && cancelRequested()) { break; }
|
|||
|
|
double time;
|
|||
|
|
fileWriter.Write((time = minStartTime + i * 1.0 / sampleRate).ToString("F6") + ",");
|
|||
|
|
foreach (var channelWithMeta in channelsWithMeta)
|
|||
|
|
{
|
|||
|
|
if (null != cancelRequested && cancelRequested()) { break; }
|
|||
|
|
//
|
|||
|
|
// If this channel's data is valid at the current time/index then go ahead and send it out
|
|||
|
|
// to the file; otherwise write out a blank space.
|
|||
|
|
//14513 double rounding error causing data to be offset by one sample incorrectly
|
|||
|
|
// note that using decimals will fix the imprecision issue, but will use more time ...
|
|||
|
|
var delta = Convert.ToDecimal(channelWithMeta.StartTime) - Convert.ToDecimal(minStartTime);
|
|||
|
|
var thisChannelsIndexAtCurrentTime = i - Convert.ToInt32(delta * Convert.ToDecimal(channelWithMeta.SampleRate));
|
|||
|
|
if (null != filteredData && filteredData.Count > 0)
|
|||
|
|
fileWriter.Write((thisChannelsIndexAtCurrentTime >= 0 && thisChannelsIndexAtCurrentTime < filteredData[filteredDataIndex].Length
|
|||
|
|
? (filteredData[filteredDataIndex][thisChannelsIndexAtCurrentTime]).ToString("F6")
|
|||
|
|
: "") + ",");
|
|||
|
|
else
|
|||
|
|
fileWriter.Write((thisChannelsIndexAtCurrentTime >= 0 && thisChannelsIndexAtCurrentTime < channelWithMeta.Channel.PersistentChannelInfo.Length
|
|||
|
|
? channelWithMeta.Scaler.GetEU(channelWithMeta.Channel.PersistentChannelInfo[thisChannelsIndexAtCurrentTime]).ToString("F6")
|
|||
|
|
: "") + ",");
|
|||
|
|
filteredDataIndex++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (0 == i % DataSamplesPerTick)
|
|||
|
|
{
|
|||
|
|
OnTick?.Invoke(this, ((double)totalWriteTicksDispatched++) / totalWriteTicksNeeded * 100);
|
|||
|
|
System.Windows.Forms.Application.DoEvents();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fileWriter.WriteLine();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
throw new Exception("encountered problem writing FTSS/Excel channel headers", ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|