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,175 @@
<base:BaseView x:Class="DTS.Viewer.AddCalculatedChannel.AddCalculatedChannelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:root="clr-namespace:DTS.Viewer.AddCalculatedChannel"
xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<base:BaseView.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource PageContentTextBoxStyle}" />
<Style TargetType="TextBlock" BasedOn="{StaticResource PageContentTextStyle}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource PageContentPasswordBoxStyle}" />
<Style TargetType="Button" BasedOn="{StaticResource FlatButton}"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<Style TargetType="toolkit:DoubleUpDown" BasedOn="{StaticResource PageContentXCDoubleUpDown}">
<Setter Property="Width" Value="150"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="FormatString" Value="N0"/>
<Setter Property="Increment" Value="1"/>
</Style>
<sys:Double x:Key="HIC_LENGTH_MIN">1</sys:Double>
<sys:Double x:Key="HIC_LENGTH_MAX">100</sys:Double>
</base:BaseView.Resources>
<Grid Background="{StaticResource Brush_ApplicationContentBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Page Title -->
<TextBlock Style="{StaticResource BaselineTextStyle4}" Text="{root:TranslateExtension AddCalculatedChannel}" Grid.Row="0"/>
<!-- Content-->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" MinWidth="480"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Channel Name-->
<TextBlock Grid.Column="0" Grid.Row="0" Text="{root:TranslateExtension ChannelName}"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding ChannelName, Mode=TwoWay, FallbackValue=Integration}" x:Name="tbChannelName" MaxLength="100" />
<!-- Channel Description-->
<TextBlock Grid.Column="0" Grid.Row="1" Text="{root:TranslateExtension Description}" Visibility="Collapsed"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding ChannelDescription, Mode=TwoWay}" IsEnabled="False" x:Name="tbChannelDescription" Visibility="Collapsed"/>
<!-- ISO Code-->
<TextBlock Grid.Column="0" Grid.Row="2" Text="{root:TranslateExtension ISOCode}"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding IsoCode, Mode=TwoWay, FallbackValue=????????????????}" MaxLength="25"/>
<!-- Calculation Type -->
<TextBlock Grid.Column="0" Grid.Row="3" Text="{root:TranslateExtension Calculation}"/>
<ComboBox Grid.Column="1" Grid.Row="3" ItemsSource="{Binding CalculationList}" SelectedItem="{Binding SelectedCalculation}" /><!--SelectionChanged="cbCalculationList_SelectionChanged" x:Name="cbCalculationList"/>-->
<!--multiple channel selector-->
<TextBlock Grid.Column="0" Grid.Row="4" Visibility="{Binding MultipleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visible}" Text="{root:TranslateExtension InputChannels}" VerticalAlignment="Top"/>
<!-- Single Channel Selector -->
<TextBlock Grid.Column="0" Grid.Row="4" Text="{root:TranslateExtension CalculationInputChannel}" Visibility="{Binding SingleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"/>
<ComboBox Grid.Column="1" Grid.Row="4" ItemsSource="{Binding ChannelList}" SelectedItem="{Binding SourceChannel}" Visibility="{Binding SingleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
<!--multiple channel selector-->
<ListView ItemsSource="{Binding ChannelListObjects}" Grid.Row="4" Grid.Column="1" Visibility="{Binding MultipleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visible}"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header=" " Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsThreeState="False" IsChecked="{Binding Path=IsIncluded}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{root:TranslateExtension Channel}" DisplayMemberBinding="{Binding Path=DisplayName}" />
</GridView>
</ListView.View>
</ListView>
<!--ThreeDIRTRACC-->
<Grid Grid.Row="4" Grid.Column="0" Visibility="{Binding ThreeDIRTRACCVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visibility.Collapsed}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Text="{root:TranslateExtension InputChannels}" />
</Grid>
<Grid Grid.Row="4" Grid.Column="1" Visibility="{Binding ThreeDIRTRACCVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{root:TranslateExtension ThreeD_IRTracc}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{root:TranslateExtension ThreeD_RotPot1}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBlock Grid.Column="0" Grid.Row="2" Text="{root:TranslateExtension ThreeD_RotPot2}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<ComboBox Grid.Row="0" ItemsSource="{Binding IRTraccChannelList}" SelectedItem="{Binding IRTraccChannel}" Grid.Column="1" DisplayMemberPath="DisplayName"/>
<ComboBox Grid.Row="1" ItemsSource="{Binding Pot1ChannelList}" SelectedItem="{Binding Pot1Channel}" Grid.Column="1" DisplayMemberPath="DisplayName" />
<ComboBox Grid.Row="2" ItemsSource="{Binding Pot2ChannelList}" SelectedItem="{Binding Pot2Channel}" Grid.Column="1" DisplayMemberPath="DisplayName" />
</Grid>
<!--HIC-->
<StackPanel Grid.Row="4" Grid.Column="0" Orientation="Vertical" Visibility="{Binding HICChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visibility.Collapsed}">
<TextBlock Grid.Row="0" Text="{root:TranslateExtension ClipLengthMS}" />
<TextBlock Grid.Row="1" Text="{root:TranslateExtension HICAccelerationX}" />
<TextBlock Grid.Row="2" Text="{root:TranslateExtension HICAccelerationY}" />
<TextBlock Grid.Row="3" Text="{root:TranslateExtension HICAccelerationZ}" />
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="1" Visibility="{Binding HICChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}">
<toolkit:DoubleUpDown Grid.Column="0" Grid.Row="0"
Minimum="{StaticResource HIC_LENGTH_MIN}" Maximum="{StaticResource HIC_LENGTH_MAX}"
Value="{Binding HICLength}" />
<ComboBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName"
AutomationProperties.AutomationId="HICAccelerationXComboBox"
SelectedItem="{Binding HICAccelerationX}" />
<ComboBox Grid.Column="0" Grid.Row="2" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName" AutomationProperties.AutomationId="HICAccelerationYComboBox"
SelectedItem="{Binding HICAccelerationY}" />
<ComboBox Grid.Column="0" Grid.Row="3" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName" AutomationProperties.AutomationId="HICAccelerationZComboBox"
SelectedItem="{Binding HICAccelerationZ}" />
</StackPanel>
</Grid>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,387 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DTS.Viewer.AddCalculatedChannel.Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class StringResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal StringResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DTS.Viewer.AddCalculatedChannel.Resources.StringResources", typeof(StringResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Add Calculated Channel.
/// </summary>
internal static string AddCalculatedChannel {
get {
return ResourceManager.GetString("AddCalculatedChannel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Average.
/// </summary>
internal static string CalculatedChannel_Average {
get {
return ResourceManager.GetString("CalculatedChannel_Average", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (upper thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_Abdomen {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_Abdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_LowerThorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_LowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_Thorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_Thorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CalculatedChannel_IRTRACC3DAbdomen {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3DAbdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3DLowerThorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3DLowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sum.
/// </summary>
internal static string CalculatedChannel_Sum {
get {
return ResourceManager.GetString("CalculatedChannel_Sum", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation.
/// </summary>
internal static string Calculation {
get {
return ResourceManager.GetString("Calculation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cosine.
/// </summary>
internal static string CALCULATION_Cos {
get {
return ResourceManager.GetString("CALCULATION_Cos", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Derivative.
/// </summary>
internal static string CALCULATION_Derivative {
get {
return ResourceManager.GetString("CALCULATION_Derivative", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Double integral.
/// </summary>
internal static string CALCULATION_DoubleIntegral {
get {
return ResourceManager.GetString("CALCULATION_DoubleIntegral", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Integral.
/// </summary>
internal static string CALCULATION_Integral {
get {
return ResourceManager.GetString("CALCULATION_Integral", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sine.
/// </summary>
internal static string CALCULATION_Sin {
get {
return ResourceManager.GetString("CALCULATION_Sin", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (upper thorax).
/// </summary>
internal static string CALCULATION_ThreeDIRTracc {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTracc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CALCULATION_ThreeDIRTraccAbdomen {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTraccAbdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CALCULATION_ThreeDIRTraccLowerThorax {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTraccLowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation Input Channel.
/// </summary>
internal static string CalculationInputChannel {
get {
return ResourceManager.GetString("CalculationInputChannel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Channel.
/// </summary>
internal static string Channel {
get {
return ResourceManager.GetString("Channel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Channel Name.
/// </summary>
internal static string ChannelName {
get {
return ResourceManager.GetString("ChannelName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Clip length (ms).
/// </summary>
internal static string ClipLengthMS {
get {
return ResourceManager.GetString("ClipLengthMS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Description.
/// </summary>
internal static string Description {
get {
return ResourceManager.GetString("Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Acceleration X.
/// </summary>
internal static string HICAccelerationX {
get {
return ResourceManager.GetString("HICAccelerationX", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Acceleration Y.
/// </summary>
internal static string HICAccelerationY {
get {
return ResourceManager.GetString("HICAccelerationY", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to AccelerationZ.
/// </summary>
internal static string HICAccelerationZ {
get {
return ResourceManager.GetString("HICAccelerationZ", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Head injury criterion requires 3 channels.
/// </summary>
internal static string HICRequires3Channels {
get {
return ResourceManager.GetString("HICRequires3Channels", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Input channels.
/// </summary>
internal static string InputChannels {
get {
return ResourceManager.GetString("InputChannels", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ISO Code.
/// </summary>
internal static string ISOCode {
get {
return ResourceManager.GetString("ISOCode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: No channels included.
/// </summary>
internal static string NoChannelsIncluded {
get {
return ResourceManager.GetString("NoChannelsIncluded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Units don&apos;t match for all input channels.
/// </summary>
internal static string ResultantUnitsDontMatch {
get {
return ResourceManager.GetString("ResultantUnitsDontMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Sample rates don&apos;t match for all input channels.
/// </summary>
internal static string SampleRatesDontMatch {
get {
return ResourceManager.GetString("SampleRatesDontMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation contains multiple sample rates. Input will be resampled to the highest sample rate using linear interpolation..
/// </summary>
internal static string SuperSamplingWarning {
get {
return ResourceManager.GetString("SuperSamplingWarning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to IR-TRACC.
/// </summary>
internal static string ThreeD_IRTracc {
get {
return ResourceManager.GetString("ThreeD_IRTracc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to R. Pot Y.
/// </summary>
internal static string ThreeD_RotPot1 {
get {
return ResourceManager.GetString("ThreeD_RotPot1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to R. Pot Z.
/// </summary>
internal static string ThreeD_RotPot2 {
get {
return ResourceManager.GetString("ThreeD_RotPot2", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,228 @@
<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AddCalculatedChannel" xml:space="preserve">
<value>Add Calculated Channel</value>
</data>
<data name="Calculation" xml:space="preserve">
<value>Calculation</value>
</data>
<data name="CalculationInputChannel" xml:space="preserve">
<value>Calculation Input Channel</value>
</data>
<data name="Channel" xml:space="preserve">
<value>Channel</value>
</data>
<data name="ChannelName" xml:space="preserve">
<value>Channel Name</value>
</data>
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="InputChannels" xml:space="preserve">
<value>Input channels</value>
</data>
<data name="ISOCode" xml:space="preserve">
<value>ISO Code</value>
</data>
<data name="CalculatedChannel_Average" xml:space="preserve">
<value>Average</value>
</data>
<data name="CalculatedChannel_IRTRACC3D" xml:space="preserve">
<value>3D IR-TRACC (upper thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3DAbdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CalculatedChannel_IRTRACC3DLowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_Abdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_LowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_Thorax" xml:space="preserve">
<value>3D IR-TRACC (thorax)</value>
</data>
<data name="CalculatedChannel_Sum" xml:space="preserve">
<value>Sum</value>
</data>
<data name="CALCULATION_Cos" xml:space="preserve">
<value>Cosine</value>
</data>
<data name="CALCULATION_Derivative" xml:space="preserve">
<value>Derivative</value>
</data>
<data name="CALCULATION_DoubleIntegral" xml:space="preserve">
<value>Double integral</value>
</data>
<data name="CALCULATION_Integral" xml:space="preserve">
<value>Integral</value>
</data>
<data name="CALCULATION_Sin" xml:space="preserve">
<value>Sine</value>
</data>
<data name="CALCULATION_ThreeDIRTracc" xml:space="preserve">
<value>3D IR-TRACC (upper thorax)</value>
</data>
<data name="CALCULATION_ThreeDIRTraccAbdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CALCULATION_ThreeDIRTraccLowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="ThreeD_IRTracc" xml:space="preserve">
<value>IR-TRACC</value>
</data>
<data name="ThreeD_RotPot1" xml:space="preserve">
<value>R. Pot Y</value>
</data>
<data name="ThreeD_RotPot2" xml:space="preserve">
<value>R. Pot Z</value>
</data>
<data name="SuperSamplingWarning" xml:space="preserve">
<value>Calculation contains multiple sample rates. Input will be resampled to the highest sample rate using linear interpolation.</value>
</data>
<data name="ClipLengthMS" xml:space="preserve">
<value>Clip length (ms)</value>
</data>
<data name="HICAccelerationX" xml:space="preserve">
<value>Acceleration X</value>
</data>
<data name="HICAccelerationY" xml:space="preserve">
<value>Acceleration Y</value>
</data>
<data name="HICAccelerationZ" xml:space="preserve">
<value>AccelerationZ</value>
</data>
<data name="HICRequires3Channels" xml:space="preserve">
<value>Error: Head injury criterion requires 3 channels</value>
</data>
<data name="NoChannelsIncluded" xml:space="preserve">
<value>Error: No channels included</value>
</data>
<data name="ResultantUnitsDontMatch" xml:space="preserve">
<value>Error: Units don't match for all input channels</value>
</data>
<data name="SampleRatesDontMatch" xml:space="preserve">
<value>Error: Sample rates don't match for all input channels</value>
</data>
</root>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DTS.Viewer.AddCalculatedChannel")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DTS.Viewer.AddCalculatedChannel")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6451f3ed-934e-47e3-a1ca-33c223a6507a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,21 @@
using System;
using System.Windows.Markup;
using DTS.Viewer.AddCalculatedChannel.Resources;
namespace DTS.Viewer.AddCalculatedChannel
{
[MarkupExtensionReturnType(typeof(string))]
public class TranslateExtension : MarkupExtension
{
private readonly string _key;
public TranslateExtension(string key) { _key = key; }
private const string NotFound = "#stringnotfound#";
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (string.IsNullOrEmpty(_key)) { return NotFound; }
return StringResources.ResourceManager.GetString(_key) ?? NotFound + " " + _key;
}
}
}

View File

@@ -0,0 +1,969 @@
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.Serialization;
using DTS.Slice.Control;
using DTS.Common;
using DTS.Common.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static DTS.Viewer.AddCalculatedChannel.AddCalculatedChannelViewModel;
using Prism.Ioc;
using DTS.Common.Calculations;
using DTS.Common.Utilities;
using Prism.Events;
namespace DTS.Viewer.AddCalculatedChannel.Model
{
public class CalculatedChannelCreator
{
private static readonly int ChannelNumberCalculationChannelIndicator = 100000;
public static Test.Module.CalculatedChannel[] CreateChannels(string testId,
string folder,
Calculation calculation,
List<Test.Module.Channel> inputChannels,
string channelName,
int startingNumber,
List<Test.Module.Channel> allChannels,
int clipLength,
out List<string> errorList,
int defaultEncoding)
{
Test.Module.CalculatedChannel[] calculatedChannels = null;
errorList = new List<string>();
switch (calculation)
{
case Calculation.ThreeDIRTracc: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.Thorax, startingNumber, defaultEncoding); break;
case Calculation.ThreeDIRTraccLowerThorax: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.LowerThorax, startingNumber, defaultEncoding); break;
case Calculation.ThreeDIRTraccAbdomen: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.Abdomen, startingNumber, defaultEncoding); break;
case Calculation.SUM:
case Calculation.AVE:
case Calculation.Resultant:
case Calculation.HIC:
calculatedChannels = CreateChannelsAggregateOperation(testId, folder, calculation, inputChannels, channelName, startingNumber, clipLength);
break;
default: calculatedChannels = CreateChannelsBinaryOperation(testId, folder, calculation, inputChannels, channelName, startingNumber); break;
}
if (null == calculatedChannels) return null;
for (var i = 0; i < calculatedChannels.Length; i++)
{
calculatedChannels[i].AbsoluteDisplayOrder = startingNumber + i;
}
if (ValidateChannelName(channelName, inputChannels, allChannels, out errorList)) return calculatedChannels;
//ReportErrors(errorList);
return null;
}
private static Serialization.SliceRaw.File.PersistentChannel CreatePersistentInformationObject(Test.Module.CalculatedChannel channel, string filepath)
{
var channelHeader = new Serialization.SliceRaw.File.BinaryChannelHeader
{
NumberOfTriggers = (ushort)(channel.ParentModule.TriggerSampleNumbers.Count)
};
channelHeader.TriggerSampleNumbers = new ulong[channelHeader.NumberOfTriggers];
// Do trigger sample information.
for (var i = 0; i < channelHeader.NumberOfTriggers; i++)
{
channelHeader.TriggerSampleNumbers[i] = channel.ParentModule.TriggerSampleNumbers[i];
}
// Do EU information.
if (channel is Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware)
{ //
// Persistent object property accessors already pad out EU so data will be word-aligned,
// so we'll want to make sure we do the same thing here.
//
var eu = (channel as Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware).EngineeringUnits;
var paddedEu = (1 == eu.Length % 2) ? (eu.Clone() as string).PadRight(eu.Length + 1, ' ') : eu;
channelHeader.EuFieldLengthWithTerminator = (ushort)(paddedEu.Length + 1);
channelHeader.EngineeringUnit = new char[channelHeader.EuFieldLengthWithTerminator - 1];
for (var j = 0; j < channelHeader.EuFieldLengthWithTerminator - 1; j++)
{
channelHeader.EngineeringUnit[j] = paddedEu[j];
}
}
else
{
channelHeader.EuFieldLengthWithTerminator = 1;
channelHeader.EngineeringUnit = new char[0];
}
// Do ISO code information.
channelHeader.IsoCode = new char[16];
// Make sure memory-mapped file does NOT exist (persistent channel object will overwrite header but append data
// after old file data... don't want that!)
if (System.IO.File.Exists(filepath))
{
GC.Collect();
FileUtils.DeleteFileOrMove(filepath, APILogger.Log);
////Rename existing channel file and kick off thread that will deleted it some time later. This needs to
////happen in this case as the test tree still contains references to the original file and it can't be deleted
////here. After a new channel is added, the old one is removed. The worker thread should wait long enough for that
////to happen (or better, check to see when it does) and then delete the file. This should eliminate the File.IO
////Exception that was being thrown.
//string tmpfilepath = filepath + ".bak";
//APILogger.Log("Renaming: " + filepath + " to " + tmpfilepath + " and deferring deletion.");
//System.IO.Path.ChangeExtension(filepath, Guid.NewGuid().ToString());
//System.Threading.ThreadPool.QueueUserWorkItem(DeleteChannelFile, tmpfilepath);
}
// Create the persistent channel object and return it.
return new Serialization.SliceRaw.File.PersistentChannel(filepath, channelHeader, true);
}
/// <summary>
/// this function takes a calculation and a list of input channels and returns
/// a list of doubles that is the output of doing that calculation
/// </summary>
/// <param name="calculation"></param>
/// <param name="channels"></param>
/// <returns></returns>
private static IList<double> PerformCalculationsAggregate(Calculation calculation,
List<Test.Module.Channel> channels)
{
var maxSampleRate = channels.Select(ch => ch.ParentModule.SampleRateHz).Max();
//this will hold the unfiltered input data for all the input channels
var unfilteredDataEU = new List<List<double>>();
//this will hold the output data
var dOutput = new List<double>();
//this will hold the emc channel data for the input channels (the input channels already have this data
//but keeping a local reference here removes some repeated casting that we'd have to do
var emcChannels = new List<Event.Module.Channel>();
//we may have different start times and the sample indices may not align, if we pick the first channel as a reference
//channel, then we can keep track of the delta for each channels start and the reference channel start in terms of samples
foreach (var ch in channels)
{
var emc = ch.emc as Event.Module.Channel;
emcChannels.Add(emc);
var data = emc.GetUnfilteredDataEu();
unfilteredDataEU.Add(data);
var start = GetTimeOfFirstSample(emc);
}
//any aggregate channels (SUM/AVE) just keep a single double and update it as needed while processing samples
var dAggregateValue = 0D;
var bAdd = true;
var currentChannelSampleIndex = 0;
//to properly aggregate, we need to put both datasets to the right sample rate
//using interpolation
//we need to calculate the min/max time across all channels and then
//the specific min of each channel, this tells us how to align data
var minStart = channels.Select(ch => ((double)ch.ParentModule.TriggerSampleNumbers[0] - ch.ParentModule.StartRecordSampleNumber) / ch.ParentModule.SampleRateHz).Min();
var minEnd = double.MaxValue;
var channelOffsetStarts = new List<int>();
var rates = new List<double>();
for (int i = 0; i < channels.Count; i++)
{
var ch = channels[i];
var chStart = ((double)ch.ParentModule.TriggerSampleNumbers[0] - ch.ParentModule.StartRecordSampleNumber) / ch.ParentModule.SampleRateHz;
var channelOffsetStart = (int)((chStart - minStart) * ch.ParentModule.SampleRateHz);
channelOffsetStarts.Add(channelOffsetStart);
var chEnd = ch.ParentModule.NumberOfSamples - chStart * ch.ParentModule.SampleRateHz;
minEnd = Math.Min(minEnd, chEnd / ch.ParentModule.SampleRateHz);
var rate = maxSampleRate / ch.ParentModule.SampleRateHz;
rates.Add(rate);
}
minStart = -1D * Math.Truncate(1000D * minStart) / 1000D;
minEnd = Math.Truncate(1000D * minEnd) / 1000D;
var totalSamples = Convert.ToInt32(Math.Floor((minEnd - minStart) * maxSampleRate));
for (var iSampleIDX = 0; iSampleIDX < totalSamples; iSampleIDX++)
{
var timeAtIndex =
dAggregateValue = 0;
bAdd = true;
var dSumSquares = 0D;
for (var iChannel = 0; iChannel < emcChannels.Count; iChannel++)
{
var rate = rates[iChannel];
var indexAtCurrentTime = (iSampleIDX - channelOffsetStarts[iChannel]) / rate;
var thisChannelsIndexAtCurrentTime = Convert.ToInt32(Math.Floor(indexAtCurrentTime));
var step = Convert.ToInt32(Math.Ceiling(indexAtCurrentTime) - thisChannelsIndexAtCurrentTime);
if (currentChannelSampleIndex < 0 || currentChannelSampleIndex >= unfilteredDataEU[iChannel].Count)
{
bAdd = false;
break;
}
var dataAtPoint = unfilteredDataEU[iChannel][thisChannelsIndexAtCurrentTime];
var increment = 0D;
if ((1 + thisChannelsIndexAtCurrentTime) < unfilteredDataEU[iChannel].Count)
{
increment = (unfilteredDataEU[iChannel][1 + thisChannelsIndexAtCurrentTime] - dataAtPoint) / rate;
}
else
{
increment = (dataAtPoint - unfilteredDataEU[iChannel][thisChannelsIndexAtCurrentTime - 1]) / rate;
}
dataAtPoint += (increment * step);
dAggregateValue += dataAtPoint;
//HIC must be in g's
if (calculation == Calculation.HIC)
{
if (((Event.Module.AnalogInputChannel)emcChannels[iChannel]).EngineeringUnits.ToLower().Trim() != "g")
{
//convert from m/sec^2 to g
dataAtPoint *= 9.80665D;
}
}
dSumSquares += Math.Pow(dataAtPoint, 2);
}
if (!bAdd) continue;
switch (calculation)
{
case Calculation.AVE: dOutput.Add(dAggregateValue / channels.Count); break;
case Calculation.SUM: dOutput.Add(dAggregateValue); break;
case Calculation.Resultant:
case Calculation.HIC:
dOutput.Add(Math.Sqrt(dSumSquares));
break;
}
}
return dOutput;
}
/// <summary>
/// performs calculations for a binary calculation channel (integrate/differentiate/FFT, etc)
/// </summary>
/// <param name="calculation"></param>
/// <param name="channel"></param>
/// <returns></returns>
private static IList<double> PerformCalculationBinary(Calculation calculation, Event.Module.Channel channel)
{
var data = channel.GetUnfilteredDataEu();
var sampleRate = Convert.ToInt32(channel.ParentModule.SampleRateHz);
switch (calculation)
{
case Calculation.Integral:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var integral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
return integral.Range;
}
case Calculation.DoubleIntegral:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var integral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
db = new ClonableDoubles();
db.AddRange(integral.Range);
var doubleIntegral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
return doubleIntegral.Range;
}
case Calculation.Derivative:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var derivative = new Common.Utilities.Math.Nhtsa.Differentiation(db, sampleRate);
return derivative.Range;
}
case Calculation.Sin:
{
return channel.DataEu.Select(euSample => Math.Sin(euSample)).ToList();
}
case Calculation.Cos:
{
return channel.DataEu.Select(euSample => Math.Cos(euSample)).ToList();
}
}
return new List<double>();
}
private static Test.Module.CalculatedChannel CreateCalculatedChannelsIRTRACC(Calculation calculation, Test.Module.Channel[] inputChannels)
{
switch (calculation)
{
case Calculation.ThreeDIRTracc:
case Calculation.ThreeDIRTraccAbdomen:
case Calculation.ThreeDIRTraccLowerThorax:
return Test.Module.CalculatedChannel.CreateInstance(new[]
{
inputChannels[0],
inputChannels[1],
inputChannels[2]
});
default:
return Test.Module.CalculatedChannel.CreateInstance(inputChannels[0]);
}
}
//private Event.Module.Channel GetSourceEMC()
//{
// switch (_calculation)
// {
// case Calculation.ThreeDIRTracc:
// case Calculation.ThreeDIRTraccAbdomen:
// case Calculation.ThreeDIRTraccLowerThorax:
// return
// (cbIRTracc.SelectedItem as ChannelHelper).MyChannel.emc as Event.Module.Channel;
// default:
// return _sourceChannel.emc as Event.Module.Channel;
// }
//}
//private static void DeleteChannelFile(object filepath)
//{
// FileUtils.DeleteFileOrMove((string)filepath, APILogger.Log);
//}
/// <summary>
/// performs the IR-Tracc 3D calculation
/// based on issue
/// 7489 Implement 2D/3D IRTRACC support
/// </summary>
/// <param name="dAX"></param>
/// <param name="dAY"></param>
/// <param name="dAZ"></param>
/// <param name="dOut"></param>
private static void PerformCalculation(out IList<double> dAX, out IList<double> dAY, out IList<double> dAZ, out IList<double> dOut,
Test.Module.Channel irTraccChannel, Test.Module.Channel rPot1Channel, Test.Module.Channel rPot2Channel, ThreeDIRTraccType irtraccType)
{
var maxRate = Math.Max(rPot1Channel.ParentModule.SampleRateHz, rPot2Channel.ParentModule.SampleRateHz);
maxRate = Math.Max(maxRate, irTraccChannel.ParentModule.SampleRateHz);
var irtraccEMC = irTraccChannel.emc as Event.Module.Channel;
var rPot1EMC = rPot1Channel.emc as Event.Module.Channel;
var rPot2EMC = rPot2Channel.emc as Event.Module.Channel;
if (0 != maxRate % rPot1Channel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {rPot1Channel.ParentModule.SampleRateHz}"); }
if (0 != maxRate % rPot2Channel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {rPot2Channel.ParentModule.SampleRateHz}"); }
if (0 != maxRate % irTraccChannel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {irTraccChannel.ParentModule.SampleRateHz}"); }
//this is the EU data for each channel NOTE - ALL CHANNELS MUST NOT BE USING ZEROING!!! (we handle zeroing already below)
var irTraccEUData = irtraccEMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref irTraccEUData, "DISPLEU.txt");
//var irTraccmVData = irtraccEMC.GetUnfilteredDataMV();
var rPot1EUData = rPot1EMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref rPot1EUData, "YPOTEU.txt");
var rPot2EUData = rPot2EMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref rPot2EUData, "ZPOTEU.txt");
//this calculates start time for each channel
var startIRTracc = (double)(irTraccChannel.ParentModule.TriggerSampleNumbers[0] - irTraccChannel.ParentModule.StartRecordSampleNumber) / irTraccChannel.ParentModule.SampleRateHz;
startIRTracc = -1D * Math.Truncate(startIRTracc * 1000D) / 1000D;
var startRPot1 = (double)(rPot1Channel.ParentModule.TriggerSampleNumbers[0] - rPot1Channel.ParentModule.StartRecordSampleNumber) / rPot1Channel.ParentModule.SampleRateHz;
startRPot1 = -1D * Math.Truncate(startRPot1 * 1000D) / 1000D;
var startRPot2 = (double)(rPot2Channel.ParentModule.TriggerSampleNumbers[0] - rPot2Channel.ParentModule.StartRecordSampleNumber) / rPot2Channel.ParentModule.SampleRateHz;
startRPot2 = -1D * Math.Truncate(startRPot2 * 1000D) / 1000D;
//this calculates the end for each channel
var endIRTracc = (irTraccChannel.ParentModule.NumberOfSamples + startIRTracc * irTraccChannel.ParentModule.SampleRateHz) / irTraccChannel.ParentModule.SampleRateHz;
endIRTracc = Math.Truncate(endIRTracc * 1000D) / 1000D;
var endRPot1 = (rPot1Channel.ParentModule.NumberOfSamples + startRPot1 * rPot1Channel.ParentModule.SampleRateHz) / rPot1Channel.ParentModule.SampleRateHz;
endRPot1 = Math.Truncate(endRPot1 * 1000D) / 1000D;
var endRPot2 = (rPot2Channel.ParentModule.NumberOfSamples + startRPot2 * rPot2Channel.ParentModule.SampleRateHz) / rPot2Channel.ParentModule.SampleRateHz;
endRPot2 = Math.Truncate(endRPot2 * 1000D) / 1000D;
//here we select the latest start between channels
var start = Math.Max(startIRTracc, startRPot1);
start = Math.Max(start, startRPot2);
//here we find the earliest end between the channels
var end = Math.Min(endIRTracc, endRPot1);
end = Math.Min(end, endRPot2);
// we will super sample to the highest sample rate, and use a common start/stop between all channels.
var length = Convert.ToInt32(Math.Floor((end - start) * maxRate));
//these are the containers for our output data
dAX = new List<double>(length);
dAY = new List<double>(length);
dAZ = new List<double>(length);
dOut = new List<double>(length);
var aicIRTRACC = irTraccChannel as Test.Module.AnalogInputChannel;
var aicRPot1 = rPot1Channel as Test.Module.AnalogInputChannel;
var aicRPOT2 = rPot2Channel as Test.Module.AnalogInputChannel;
//calculates the rate of each channel relative to the highest rate of any of the channels
var rateIRTracc = Convert.ToInt32(Math.Ceiling(maxRate / irTraccChannel.ParentModule.SampleRateHz));
var rateRPot1 = Convert.ToInt32(Math.Ceiling(maxRate / rPot1Channel.ParentModule.SampleRateHz));
var rateRPot2 = Convert.ToInt32(Math.Ceiling(maxRate / rPot2Channel.ParentModule.SampleRateHz));
var R0 = aicIRTRACC.LinearizationFormula.CalibrationFactor * Math.Pow(aicIRTRACC.ZeroPoint, aicIRTRACC.LinearizationFormula.LinearizationExponent);
//we are converting to volt as sensitivity is in mV/V and our original calculation is in deg/V/V
var θy0 = aicRPot1.InitialEu; //((1000D/aicRPot1.Sensitivity)/aicRPot1.FactoryExcitationVoltage)*aicRPot1.ZeroPoint;
var θz0 = aicRPOT2.InitialEu; //((1000D/aicRPOT2.Sensitivity)/aicRPOT2.FactoryExcitationVoltage)*aicRPOT2.ZeroPoint;
//all the formulas use the first data point to zero the output channel data, these variables will hold that zero data for out output channels
//this is columns V through Y
var xa1_0 = double.NaN;
var ya1_0 = double.NaN;
var za1_0 = double.NaN;
var dOut_0 = double.NaN;
//your delta and D0 are dependent on your 3D-IRTRACC type, we get the constant for each type from the config file
var δ = 0D;
var D0 = 0D;
switch (irtraccType)
{
case ThreeDIRTraccType.Abdomen:
δ = SensorConstants.δAbdomen;
D0 = SensorConstants.D0Abdomen;
break;
case ThreeDIRTraccType.Thorax:
δ = SensorConstants.δThorax;
D0 = SensorConstants.D0Thorax;
break;
case ThreeDIRTraccType.LowerThorax:
δ = SensorConstants.δThoraxLower;
D0 = SensorConstants.D0ThoraxLower;
break;
default:
throw new NotSupportedException("unsupported irtracc type: " + irtraccType.ToString());
}
//calculates the offset in samples for each channels start relative to the
//latest common start time between channels
var irTraccOffsetStart = (int)(startIRTracc - start) * irTraccChannel.ParentModule.SampleRateHz;
var rPot1OffsetStart = (int)(startRPot1 - start) * rPot1Channel.ParentModule.SampleRateHz;
var rPot2OffsetStart = (int)(startRPot2 - start) * rPot2Channel.ParentModule.SampleRateHz;
//go through all samples in the output, calculate the index for each channel and do some calcs
for (var i = 0; i < length; i++)
{
//this is the index for the given time, this index could be theoretical
//and doesn't exist (ie 1.5)
var indexAtCurrentTimeIRTracc = (i - irTraccOffsetStart) / rateIRTracc;
//this is the actual index that physically exists (1 for 1.5 for instance)
var actualIndexAtCurrentTimeIRTracc = Convert.ToInt32(Math.Floor(indexAtCurrentTimeIRTracc));
//this is the linear interpolation "step" between this sample and the next
//sample
var stepIRTracc = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeIRTracc) - actualIndexAtCurrentTimeIRTracc);
var indexAtCurrentTimeRPot1 = (i - rPot1OffsetStart) / rateRPot1;
var actualIndexAtCurrentTimeRPot1 = Convert.ToInt32(Math.Floor(indexAtCurrentTimeRPot1));
var stepRPot1 = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeIRTracc) - actualIndexAtCurrentTimeIRTracc);
var indexAtCurrentTimeRPot2 = (i - rPot2OffsetStart) / rateRPot2;
var actualIndexAtCurrentTimeRPot2 = Convert.ToInt32(Math.Floor(indexAtCurrentTimeRPot2));
var stepRPot2 = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeRPot2) - actualIndexAtCurrentTimeRPot2);
var incrementIRTracc = 0D;
var valueIRTraccAtPoint = irTraccEUData[actualIndexAtCurrentTimeIRTracc];
var incrementRPot1 = 0D;
var valueRPot1AtPoint = rPot1EUData[actualIndexAtCurrentTimeRPot1];
var incrementRPot2 = 0D;
var valueRPot2AtPoint = rPot2EUData[actualIndexAtCurrentTimeRPot2];
//calculate the interpolation value per step for channel
//for instance for 10k and 20k sps for sample 2 of the 10k
//increment would be (data[2]-data[1])/2
if ((1 + actualIndexAtCurrentTimeIRTracc) < irTraccEUData.Count)
{
incrementIRTracc = (irTraccEUData[1 + actualIndexAtCurrentTimeIRTracc] - valueIRTraccAtPoint) / rateIRTracc;
}
else
{
incrementIRTracc = (valueIRTraccAtPoint - irTraccEUData[actualIndexAtCurrentTimeIRTracc - 1]) / rateIRTracc;
}
if ((1 + actualIndexAtCurrentTimeRPot1) < rPot1EUData.Count)
{
incrementRPot1 = (rPot1EUData[1 + actualIndexAtCurrentTimeRPot1] - valueRPot1AtPoint) / rateRPot1;
}
else
{
incrementRPot1 = (valueRPot1AtPoint - rPot1EUData[actualIndexAtCurrentTimeRPot1 - 1]) / rateRPot1;
}
if ((1 + actualIndexAtCurrentTimeRPot2) < rPot2EUData.Count)
{
incrementRPot2 = (rPot2EUData[1 + actualIndexAtCurrentTimeRPot2] - valueRPot2AtPoint) / rateRPot2;
}
else
{
incrementRPot2 = (valueRPot2AtPoint = rPot2EUData[actualIndexAtCurrentTimeRPot2 - 1]) / rateRPot2;
}
//math magic from excel
//double b = D0 + System.Math.Abs(irTraccEUData[i] - calFactorInterceptRemoval) - R0;
//double R = aicIRTRACC.LinearizationFormula.CalibrationFactor*
// System.Math.Pow(irTraccmVData[i]/1000D, aicIRTRACC.LinearizationFormula.LinearizationExponent);
//D0+(R-R0) this is column N
//double r = D0 + (R - R0);
var r = valueIRTraccAtPoint + incrementIRTracc * stepIRTracc;
//θy'=θy-θy0 this is column O
var θyprime = valueRPot1AtPoint + incrementRPot1 * stepRPot1 - θy0;
//θz'=θz-θz0 this is column p
var θzprime = valueRPot2AtPoint + incrementRPot2 * stepRPot2 - θz0;
//this is column r
var xa1 = -1D * δ * Math.Sin(θyprime * Math.PI / 180) + r * Math.Cos(θzprime * Math.PI / 180) * Math.Cos(θyprime * Math.PI / 180);
//this is column s
var ya1 = r * Math.Sin(θzprime * Math.PI / 180);
//this is column t
var za1 = -1D * δ * Math.Cos(θyprime * Math.PI / 180D) - r * Math.Cos(θzprime * Math.PI / 180D) * Math.Sin(θyprime * Math.PI / 180D);
//assign the output channel zero points if needed
if (double.IsNaN(xa1_0)) { xa1_0 = xa1; }
if (double.IsNaN(ya1_0)) { ya1_0 = ya1; }
if (double.IsNaN(za1_0)) { za1_0 = za1; }
//add in our data to the output channels
dAX.Add(xa1 - xa1_0);
dAY.Add(ya1 - ya1_0);
dAZ.Add(za1 - za1_0);
//this is column Z
var temp = Math.Sqrt(Math.Pow(r, 2) + Math.Pow(δ, 2));
if (double.IsNaN(dOut_0)) { dOut_0 = temp; }
dOut.Add(temp - dOut_0);
}
}
private static double GetTimeOfFirstSample(Event.Module.Channel channel)
{
return ((double)channel.ParentModule.TriggerSampleNumbers[0] -
channel.ParentModule.StartRecordSampleNumber) / channel.ParentModule.SampleRateHz;
}
private static Test.Module.CalculatedChannel[] Create3DIRTraccChannels(string testId, string folder,
List<Test.Module.Channel> inputChannels, string channelName, ThreeDIRTraccType irTraccType, int offset, int defaultEncoding)
{
System.Diagnostics.Trace.Assert(3 == inputChannels.Count, "3D IR-TRACC requires 3 channels");
var maxRate = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Max();
var distinctRates = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Distinct().ToArray();
foreach (var rate in distinctRates)
{
if (0 != maxRate % rate)
{
throw new NotSupportedException($"Sample rate: {maxRate} is not a multiple of sample rate: {rate}");
}
}
if (distinctRates.Length > 1)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { Resources.StringResources.SuperSamplingWarning }, null));
}
var irtraccEMC = inputChannels[0].emc as Event.Module.Channel;
var rPot1EMC = inputChannels[1].emc as Event.Module.Channel;
var rPot2EMC = inputChannels[2].emc as Event.Module.Channel;
var calc = Calculation.ThreeDIRTracc;
switch (irTraccType)
{
case ThreeDIRTraccType.Abdomen: calc = Calculation.ThreeDIRTraccAbdomen; break;
case ThreeDIRTraccType.Thorax: calc = Calculation.ThreeDIRTracc; break;
case ThreeDIRTraccType.LowerThorax: calc = Calculation.ThreeDIRTraccLowerThorax; break;
}
var ccDeltaAX = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAX.ChannelDescriptionString = channelName + " (dAX)";
var ccDeltaAY = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAY.ChannelDescriptionString = channelName + " (dAY)";
var ccDeltaAZ = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAZ.ChannelDescriptionString = channelName + " (dAZ)";
var ccDistanceDelta = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDistanceDelta.ChannelDescriptionString = channelName;
var outputChannels = new Test.Module.CalculatedChannel[] { ccDeltaAX, ccDeltaAY, ccDeltaAZ, ccDistanceDelta };
foreach (var cc in outputChannels)
{
cc.Calculation = calc.ToString();
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + irtraccEMC.AbsoluteDisplayOrder + offset;
cc.Number = ChannelNumberCalculationChannelIndicator + offset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = 1;
cc.Data.UnitConversion = 1;
cc.Data.UserOffsetEU = 0;
cc.ExcitationVoltage = 0;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = irtraccEMC.ChannelId + "_" + (cc.Number + offset);
cc.ChannelGroupName = irtraccEMC.ChannelGroupName;
cc.IsInverted = false;
cc.PreTestZeroLevelAdc = 0;
cc.SerialNumber = cc.ChannelDescriptionString;
var emc = new Event.Module.AnalogInputChannel(cc, irtraccEMC.ParentModule, cc.Number);
cc.emc = emc;
offset++;
}
ccDeltaAX.EngineeringUnits = "mm";
ccDeltaAY.EngineeringUnits = "mm";
ccDeltaAZ.EngineeringUnits = "mm";
ccDistanceDelta.EngineeringUnits = "mm";
PerformCalculation(out IList<double> dax, out IList<double> day, out IList<double> daz, out IList<double> dDistance, inputChannels[0], inputChannels[1], inputChannels[2], irTraccType);
irtraccEMC = null;
rPot1EMC = null;
rPot2EMC = null;
var datas = new[] { dax, day, daz, dDistance };
for (var i = 0; i < datas.Length && i < outputChannels.Length; i++)
{
var data = datas[i];
var scaleFactor = 0D;
var adcData = ScaleEuData(ref data, out scaleFactor);
outputChannels[i].Sensitivity = scaleFactor;
outputChannels[i].DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
//adjust the output channel with the max rate we super sampled to
//and update the number of samples...
outputChannels[i].SampleRateHz = maxRate;
outputChannels[i].ParentModule.NumberOfSamples = Convert.ToUInt64(data.Count);
((Event.Module.AnalogInputChannel)outputChannels[i].emc).ParentModule.SampleRateHz = maxRate;
((Event.Module.AnalogInputChannel)outputChannels[i].emc).ParentModule.NumberOfSamples = Convert.ToUInt64(data.Count);
var f = new Serialization.SliceRaw.File { DefaultEncoding = defaultEncoding };
var fileName = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, outputChannels[i].Number);
var filepath = System.IO.Path.Combine(folder, fileName);
outputChannels[i].Data.ScaleFactorMv = 1 / scaleFactor;
outputChannels[i].Data.ScaleFactorEU = 1 / scaleFactor;
outputChannels[i].LinearizationFormula.MarkValid(false);
outputChannels[i].PersistentChannelInfo = CreatePersistentInformationObject(outputChannels[i], filepath);
outputChannels[i].PersistentChannelInfo.BeginAppendSession();
outputChannels[i].PersistentChannelInfo.AppendSessionData(adcData.ToArray());
outputChannels[i].PersistentChannelInfo.EndAppendSession();
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer?.CreatePersistentChannel(outputChannels[i], outputChannels[i].ParentModule.NumberOfSamples, outputChannels[i].ParentModule.SampleRateHz, null, null, 0, 0);
var bypass = false;
var reader = f.Importer as Serialization.SliceRaw.File.Reader;
reader?.ReadChannel(outputChannels[i], outputChannels[i].ParentModule, filepath, ref bypass);
(outputChannels[i].emc as Event.Module.Channel).UnfilteredData = outputChannels[i].PersistentChannelInfo;
(outputChannels[i].emc as Event.Module.Channel).Scaler.SetScaleFactorMv(1D / scaleFactor);
}
return outputChannels.ToArray();
}
private static Test.Module.CalculatedChannel[] CreateChannelsAggregateOperation(string testId, string folder,
Calculation calculation, List<Test.Module.Channel> inputChannels, string channelName, int channelOffset, int clipLength)
{
System.Diagnostics.Trace.Assert(1 < inputChannels.Count,
calculation.ToString() + " requires at least 1 channel");
var sourceEmc = inputChannels[0].emc as Event.Module.Channel;
var sourceChannel = inputChannels[0];
var maxSampleRate = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Max();
var distinctRates = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Distinct().ToArray();
foreach (var rate in distinctRates)
{
if (maxSampleRate % rate != 0)
{
throw new NotSupportedException($"Sample rate: {maxSampleRate} is not a multiple of {rate}");
}
}
if (distinctRates.Length > 1)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { Resources.StringResources.SuperSamplingWarning }, null));
}
//Create new test channel
var cc = CreateCalculatedChannelsIRTRACC(calculation, new[] { sourceChannel });
cc.SampleRateHz = maxSampleRate;
cc.Calculation = calculation.ToString();
cc.ChannelDescriptionString = channelName;
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.Number = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = sourceEmc.Multiplier;
cc.Data.UnitConversion = sourceEmc.UnitConversion;
cc.Data.UserOffsetEU = sourceEmc.UserOffsetEU;
cc.ExcitationVoltage = 0;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = sourceChannel.ChannelId + "_" + cc.Number;
cc.ChannelGroupName = sourceChannel.ChannelGroupName;
cc.IsInverted = false;
var emc = new Event.Module.AnalogInputChannel(cc, sourceEmc.ParentModule, sourceEmc.AbsoluteNumber);
cc.emc = emc;
//Do the maths. Use source channel as source for data as it's properly set up.
var euData = PerformCalculationsAggregate(calculation, inputChannels);
cc.ParentModule.NumberOfSamples = Convert.ToUInt64(euData.Count);
emc.ParentModule.NumberOfSamples = Convert.ToUInt64(euData.Count);
//Don't use the source channel emc anymore.
sourceEmc = null;
//Scale the data
var adcData = ScaleEuData(ref euData, out double scaleFactor);
cc.Sensitivity = scaleFactor;
//Test by writing source channel data. Readback should be identical
var f = new Serialization.SliceRaw.File();
f.DefaultEncoding = Encoding.Unicode.CodePage;
//Create file with from source channel. At this point it's not complete -- it still needs number of
//samples, etc.
var filename = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, cc.Number);
var filepath = System.IO.Path.Combine(folder, filename);
cc.Data.ScaleFactorMv = 1 / scaleFactor;
cc.Data.ScaleFactorEU = 1 / scaleFactor;
switch (calculation)
{
default:
cc.DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
if (sourceChannel is Test.Module.AnalogInputChannel analogInputChannel) { cc.EngineeringUnits = analogInputChannel.EngineeringUnits; }
else { cc.EngineeringUnits = "NOT DEFINED"; }
break;
case Calculation.Sin:
case Calculation.Cos:
cc.DesiredRange = 1.1;
cc.EngineeringUnits = "rads";
break;
}
//All done with channel. Create persistent object with what's in the channel object
cc.PersistentChannelInfo = CreatePersistentInformationObject(cc, filepath);
//Write out the data to the memory-mapped file
cc.PersistentChannelInfo.BeginAppendSession();
cc.PersistentChannelInfo.AppendSessionData(adcData.ToArray());
cc.PersistentChannelInfo.EndAppendSession();
//Use the export writer to update the binary channel fields with everything that's missing. This will also
//Update the CRC.
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer.CreatePersistentChannel(cc, cc.ParentModule.NumberOfSamples, cc.ParentModule.SampleRateHz, null, null, 0, 0);
//At this point the PersistentChannel is blown away. Read it back in and hook it up.
var bypass = false;
(f.Importer as Serialization.SliceRaw.File.Reader).ReadChannel(cc, cc.ParentModule, filepath, ref bypass);
emc.UnfilteredData = cc.PersistentChannelInfo;
if (calculation == Calculation.HIC)
{
var channelData = new ChannelData("g");
channelData.FilteredEU = euData.ToArray();
var hic = HeadInjuryCriterion.GetHeadInjuryCriterion(channelData, cc.SampleRateHz, clipLength);
cc.T1 = Convert.ToUInt64(hic.StartSample);
cc.T2 = Convert.ToUInt64(hic.EndSample);
cc.HIC = hic.HIC;
}
return new[] { cc };
}
/// <summary>
/// creates a calculated channel for binary operations (sine/cosine/integral/ffs)
/// </summary>
/// <param name="testId"></param>
/// <param name="folder"></param>
/// <param name="calculation"></param>
/// <param name="inputChannels"></param>
/// <param name="channelName"></param>
/// <param name="channelOffset"></param>
/// <returns></returns>
private static Test.Module.CalculatedChannel[] CreateChannelsBinaryOperation(string testId, string folder,
Calculation calculation, List<Test.Module.Channel> inputChannels, string channelName, int channelOffset)
{
var sourceEmc = inputChannels[0].emc as Event.Module.Channel;
var sourceChannel = inputChannels[0];
//Create new test channel
var cc = CreateCalculatedChannelsIRTRACC(calculation, new[] { sourceChannel });
cc.Calculation = calculation.ToString();
cc.ChannelDescriptionString = channelName;
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.Number = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = sourceEmc.Multiplier;
cc.Data.UnitConversion = sourceEmc.UnitConversion;
cc.Data.UserOffsetEU = sourceEmc.UserOffsetEU;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = sourceChannel.ChannelId + "_" + cc.Number;
cc.ChannelGroupName = sourceChannel.ChannelGroupName;
cc.IsInverted = false;
var emc = new Event.Module.AnalogInputChannel(cc, sourceEmc.ParentModule, sourceEmc.AbsoluteNumber);
cc.emc = emc;
//Do the maths. Use source channel as source for data as it's properly set up.
var euData = PerformCalculationBinary(calculation, sourceEmc);
//Don't use the source channel emc anymore.
sourceEmc = null;
//Scale the data
var adcData = ScaleEuData(ref euData, out var scaleFactor);
cc.Sensitivity = scaleFactor;
//Test by writing source channel data. Readback should be identical
var f = new Serialization.SliceRaw.File { DefaultEncoding = Encoding.Unicode.CodePage };
//Create file with from source channel. At this point it's not complete -- it still needs number of
//samples, etc.
var filename = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, cc.Number);
var filepath = System.IO.Path.Combine(folder, filename);
cc.Data.ScaleFactorMv = 1 / scaleFactor;
cc.Data.ScaleFactorEU = 1 / scaleFactor;
switch (calculation)
{
default:
cc.DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
if (sourceChannel is Test.Module.AnalogInputChannel analogInputChannel) { cc.EngineeringUnits = analogInputChannel.EngineeringUnits; }
else { cc.EngineeringUnits = "NOT DEFINED"; }
break;
case Calculation.Sin:
case Calculation.Cos:
cc.DesiredRange = 1.1;
cc.EngineeringUnits = "rads";
break;
}
//All done with channel. Create persistent object with what's in the channel object
cc.PersistentChannelInfo = CreatePersistentInformationObject(cc, filepath);
//Write out the data to the memory-mapped file
cc.PersistentChannelInfo.BeginAppendSession();
cc.PersistentChannelInfo.AppendSessionData(adcData.ToArray());
cc.PersistentChannelInfo.EndAppendSession();
//Use the export writer to update the binary channel fields with everything that's missing. This will also
//Update the CRC.
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer.CreatePersistentChannel(cc, cc.ParentModule.NumberOfSamples, cc.ParentModule.SampleRateHz, null, null, 0, 0);
//At this point the PersistentChannel is blown away. Read it back in and hook it up.
var bypass = false;
(f.Importer as Serialization.SliceRaw.File.Reader).ReadChannel(cc, cc.ParentModule, filepath,
ref bypass);
emc.UnfilteredData = cc.PersistentChannelInfo;
return new[] { cc };
}
public enum ThreeDIRTraccType
{
Thorax,
Abdomen,
LowerThorax
}
private static short[] ScaleEuData(ref IList<double> euData, out double scaleFactor)
{
scaleFactor = 1.0;
var max = (from d in euData select Math.Abs(d)).Max();
if (0 == max)
{
max = 1;
}
//we used ABS above, so we need to consider that the signal could be bipolar and be peak to peak of 2*max
max *= 2;
if (short.MaxValue > max)
{
scaleFactor = short.MaxValue / max;
}
else
{
scaleFactor = max / short.MaxValue;
}
//Scale the data
var data = new List<short>();
foreach (var euSample in euData)
{
data.Add((short)(euSample * scaleFactor));
}
return data.ToArray();
}
/// <summary>
/// Validate name of the new calculated channel
/// </summary>
/// <param name="channelName">name of the new calculated channel</param>
/// <param name="inputChannels">existing channels</param>
/// <param name="allChannels">If null - calling form MakeCalculatedChannels() in Download.xaml.cs</param>
/// <param name="errorList">list of errors</param>
/// <returns>if anyy errors - returns false</returns>
public static bool ValidateChannelName(string channelName, List<Test.Module.Channel> inputChannels, List<Test.Module.Channel> allChannels, out List<string> errorList)
{
errorList = new List<string>();
if (allChannels == null) return errorList.Count == 0;
if (string.IsNullOrEmpty(channelName)) { errorList.Add("Channel name cannot be empty."); }
if (inputChannels.Exists(ch => ch.ChannelDescriptionString == channelName))
{ errorList.Add("Channel name is not unique. [input channels]"); }
if (allChannels.Exists(ch => ch.ChannelDescriptionString == channelName))
{ errorList.Add("Channel name is not unique. [all channels]"); }
return errorList.Count == 0;
}
#region helper classes
private sealed class ClonableDoubles : List<double>, ICloneable
{
object ICloneable.Clone()
{
var l = new List<double>();
l.AddRange(ToArray());
return l;
}
}
#endregion
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.Windows.Media.Imaging;
using DTS.Common;
using DTS.Common.Interface;
using DTS.Viewer.AddCalculatedChannel;
using Prism.Ioc;
using Prism.Modularity;
using Unity;
// ReSharper disable RedundantAttributeUsageProperty
// ReSharper disable UnusedParameter.Local
[assembly: AddCalculatedChannelModuleName()]
[assembly: AddCalculatedChannelModuleImageAttribute()]
namespace DTS.Viewer.AddCalculatedChannel
{
[Module(ModuleName = "AddCalculatedChannel")]
public class AddCalculatedChannelModule : IModule
{
/// <summary>
/// Injected unity container
/// </summary>
private readonly IUnityContainer _unityContainer;
/// <summary>
/// Initializes a new instance of the <see cref="AddCalculatedChannelModule"/> class.
/// </summary>
/// <param name="unityContainer">Obtained reference of the unity container by using dependency injection.</param>
public AddCalculatedChannelModule(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public void Initialize()
{
// Register View & View-Model with Unity dependency injection container as a singleton.
_unityContainer.RegisterType<IAddCalculatedChannelView, AddCalculatedChannelView>();
_unityContainer.RegisterType<IAddCalculatedChannelViewModel, AddCalculatedChannelViewModel>();
}
public void OnInitialized(IContainerProvider containerProvider)
{
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
Initialize();
}
}
/// <summary>
/// Attribute class contains assembly name
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class AddCalculatedChannelModuleNameAttribute : TextAttribute
{
public AddCalculatedChannelModuleNameAttribute() : this(null) { }
public AddCalculatedChannelModuleNameAttribute(string s)
{
AssemblyName = AssemblyNames.AddCalculatedChannel.ToString();
}
public override string AssemblyName { get; }
public override Type GetAttributeType()
{
return typeof(TextAttribute);
}
public override string GetAssemblyName()
{
return AssemblyName;
}
}
/// <summary>
/// Attribute class contains assembly image and name - used on the Main screen to display available components
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class AddCalculatedChannelModuleImageAttribute : ImageAttribute
{
private BitmapImage _img;
public AddCalculatedChannelModuleImageAttribute() : this(null) { }
public override BitmapImage AssemblyImage
{
get { _img = AssemblyInfo.GetImage(AssemblyNames.AddCalculatedChannel.ToString()); return _img; }
}
public AddCalculatedChannelModuleImageAttribute(string s)
{
_img = AssemblyInfo.GetImage(AssemblyNames.AddCalculatedChannel.ToString());
}
public override Type GetAttributeType()
{
return typeof(ImageAttribute);
}
public override BitmapImage GetAssemblyImage()
{
return AssemblyImage;
}
private string _name;
public override string AssemblyName
{
get { _name = AssemblyNames.AddCalculatedChannel.ToString(); return _name; }
}
public override string GetAssemblyName()
{
return AssemblyName;
}
private string _group;
public override string AssemblyGroup
{
get { _group = eAssemblyGroups.Viewer.ToString(); return _group; }
}
public override string GetAssemblyGroup()
{
return AssemblyGroup;
}
private eAssemblyRegion _region;
public override eAssemblyRegion AssemblyRegion
{
get { _region = eAssemblyRegion.AddCalculatedChannelRegion; return _region; }
}
public override eAssemblyRegion GetAssemblyRegion()
{
return AssemblyRegion;
}
}
}

View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6451F3ED-934E-47E3-A1CA-33C223A6507A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DTS.Viewer.AddCalculatedChannel</RootNamespace>
<AssemblyName>DTS.Viewer.AddCalculatedChannel</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xaml.Behaviors">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Prism">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.dll</HintPath>
</Reference>
<Reference Include="Prism.Unity.Wpf">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Unity.Wpf.dll</HintPath>
</Reference>
<Reference Include="Prism.Wpf">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.Abstractions">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Unity.Container">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Container.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="Xceed.Wpf.Toolkit">
<HintPath>..\..\..\Common\DTS.Common\lib\Xceed.Wpf.Toolkit\Xceed.Wpf.Toolkit.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Model\CalculatedChannelCreator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AddCalculatedChannelModule.cs" />
<Compile Include="Resources\StringResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>StringResources.resx</DependentUpon>
</Compile>
<Compile Include="Resources\TranslateExtension.cs" />
<Compile Include="ViewModel\AddCalculatedChannelViewModel.cs" />
<Compile Include="View\AddCalculatedChannelView.xaml.cs">
<DependentUpon>AddCalculatedChannelView.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="View\AddCalculatedChannelView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Common\DTS.Common.Calculations\DTS.Common.Calculations.csproj">
<Project>{5ce6f27b-1c5b-4101-88de-58a30b1e5f37}</Project>
<Name>DTS.Common.Calculations</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Core\DTS.Common.Core.csproj">
<Project>{fab1f470-1574-4301-b56e-d3364aa93679}</Project>
<Name>DTS.Common.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.DAS.Concepts\DTS.Common.DAS.Concepts.csproj">
<Project>{AE3987F7-C4C6-40FB-A353-1A2DADEF7A9A}</Project>
<Name>DTS.Common.DAS.Concepts</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.SerializationPlus\DTS.Common.SerializationPlus.csproj">
<Project>{b9d1ac5b-7a6f-4b14-9ff8-3a1fc03519e2}</Project>
<Name>DTS.Common.SerializationPlus</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Serialization\DTS.Common.Serialization.csproj">
<Project>{0679d014-59c2-4327-b288-0e3bd1374710}</Project>
<Name>DTS.Common.Serialization</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{D6DA1B74-C711-43C2-91B1-1908A8D04DBF}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common\DTS.Common.csproj">
<Project>{114edc77-f3b5-4576-a91b-40818d503b55}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\DataPRO\IService\IService.csproj">
<Project>{C9C45B72-05A3-4962-BC13-A78B1F4B1925}</Project>
<Name>IService</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\StringResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>StringResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,17 @@
using DTS.Common.Interface;
// ReSharper disable CheckNamespace
namespace DTS.Viewer.AddCalculatedChannel
{
/// <summary>
/// Interaction logic for AddCalculatedChannelView.xaml
/// </summary>
public partial class AddCalculatedChannelView : IAddCalculatedChannelView
{
public AddCalculatedChannelView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.Windows.Media.Imaging;
using DTS.Common;
using DTS.Common.Interface;
using DTS.Viewer.AddCalculatedChannel;
using Prism.Ioc;
using Prism.Modularity;
using Unity;
// ReSharper disable RedundantAttributeUsageProperty
// ReSharper disable UnusedParameter.Local
[assembly: AddCalculatedChannelModuleName()]
[assembly: AddCalculatedChannelModuleImageAttribute()]
namespace DTS.Viewer.AddCalculatedChannel
{
[Module(ModuleName = "AddCalculatedChannel")]
public class AddCalculatedChannelModule : IModule
{
/// <summary>
/// Injected unity container
/// </summary>
private readonly IUnityContainer _unityContainer;
/// <summary>
/// Initializes a new instance of the <see cref="AddCalculatedChannelModule"/> class.
/// </summary>
/// <param name="unityContainer">Obtained reference of the unity container by using dependency injection.</param>
public AddCalculatedChannelModule(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public void Initialize()
{
// Register View & View-Model with Unity dependency injection container as a singleton.
_unityContainer.RegisterType<IAddCalculatedChannelView, AddCalculatedChannelView>();
_unityContainer.RegisterType<IAddCalculatedChannelViewModel, AddCalculatedChannelViewModel>();
}
public void OnInitialized(IContainerProvider containerProvider)
{
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
Initialize();
}
}
/// <summary>
/// Attribute class contains assembly name
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class AddCalculatedChannelModuleNameAttribute : TextAttribute
{
public AddCalculatedChannelModuleNameAttribute() : this(null) { }
public AddCalculatedChannelModuleNameAttribute(string s)
{
AssemblyName = AssemblyNames.AddCalculatedChannel.ToString();
}
public override string AssemblyName { get; }
public override Type GetAttributeType()
{
return typeof(TextAttribute);
}
public override string GetAssemblyName()
{
return AssemblyName;
}
}
/// <summary>
/// Attribute class contains assembly image and name - used on the Main screen to display available components
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
public class AddCalculatedChannelModuleImageAttribute : ImageAttribute
{
private BitmapImage _img;
public AddCalculatedChannelModuleImageAttribute() : this(null) { }
public override BitmapImage AssemblyImage
{
get { _img = AssemblyInfo.GetImage(AssemblyNames.AddCalculatedChannel.ToString()); return _img; }
}
public AddCalculatedChannelModuleImageAttribute(string s)
{
_img = AssemblyInfo.GetImage(AssemblyNames.AddCalculatedChannel.ToString());
}
public override Type GetAttributeType()
{
return typeof(ImageAttribute);
}
public override BitmapImage GetAssemblyImage()
{
return AssemblyImage;
}
private string _name;
public override string AssemblyName
{
get { _name = AssemblyNames.AddCalculatedChannel.ToString(); return _name; }
}
public override string GetAssemblyName()
{
return AssemblyName;
}
private string _group;
public override string AssemblyGroup
{
get { _group = eAssemblyGroups.Viewer.ToString(); return _group; }
}
public override string GetAssemblyGroup()
{
return AssemblyGroup;
}
private eAssemblyRegion _region;
public override eAssemblyRegion AssemblyRegion
{
get { _region = eAssemblyRegion.AddCalculatedChannelRegion; return _region; }
}
public override eAssemblyRegion GetAssemblyRegion()
{
return AssemblyRegion;
}
}
}

View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6451F3ED-934E-47E3-A1CA-33C223A6507A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DTS.Viewer.AddCalculatedChannel</RootNamespace>
<AssemblyName>DTS.Viewer.AddCalculatedChannel</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xaml.Behaviors">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Prism">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.dll</HintPath>
</Reference>
<Reference Include="Prism.Unity.Wpf">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Unity.Wpf.dll</HintPath>
</Reference>
<Reference Include="Prism.Wpf">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Prism.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.Abstractions">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Unity.Container">
<HintPath>..\..\..\Common\DTS.Common\lib\PrismLibrary\Unity.Container.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="Xceed.Wpf.Toolkit">
<HintPath>..\..\..\Common\DTS.Common\lib\Xceed.Wpf.Toolkit\Xceed.Wpf.Toolkit.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Model\CalculatedChannelCreator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AddCalculatedChannelModule.cs" />
<Compile Include="Resources\StringResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>StringResources.resx</DependentUpon>
</Compile>
<Compile Include="Resources\TranslateExtension.cs" />
<Compile Include="ViewModel\AddCalculatedChannelViewModel.cs" />
<Compile Include="View\AddCalculatedChannelView.xaml.cs">
<DependentUpon>AddCalculatedChannelView.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="View\AddCalculatedChannelView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Common\DTS.Common.Calculations\DTS.Common.Calculations.csproj">
<Project>{5ce6f27b-1c5b-4101-88de-58a30b1e5f37}</Project>
<Name>DTS.Common.Calculations</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Core\DTS.Common.Core.csproj">
<Project>{fab1f470-1574-4301-b56e-d3364aa93679}</Project>
<Name>DTS.Common.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.DAS.Concepts\DTS.Common.DAS.Concepts.csproj">
<Project>{AE3987F7-C4C6-40FB-A353-1A2DADEF7A9A}</Project>
<Name>DTS.Common.DAS.Concepts</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.SerializationPlus\DTS.Common.SerializationPlus.csproj">
<Project>{b9d1ac5b-7a6f-4b14-9ff8-3a1fc03519e2}</Project>
<Name>DTS.Common.SerializationPlus</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Serialization\DTS.Common.Serialization.csproj">
<Project>{0679d014-59c2-4327-b288-0e3bd1374710}</Project>
<Name>DTS.Common.Serialization</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{D6DA1B74-C711-43C2-91B1-1908A8D04DBF}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Common\DTS.Common\DTS.Common.csproj">
<Project>{114edc77-f3b5-4576-a91b-40818d503b55}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\DataPRO\IService\IService.csproj">
<Project>{C9C45B72-05A3-4962-BC13-A78B1F4B1925}</Project>
<Name>IService</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\StringResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>StringResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,969 @@
using DTS.Common.Enums.Sensors;
using DTS.Common.Utilities.Logging;
using DTS.Common.Utils;
using DTS.Serialization;
using DTS.Slice.Control;
using DTS.Common;
using DTS.Common.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static DTS.Viewer.AddCalculatedChannel.AddCalculatedChannelViewModel;
using Prism.Ioc;
using DTS.Common.Calculations;
using DTS.Common.Utilities;
using Prism.Events;
namespace DTS.Viewer.AddCalculatedChannel.Model
{
public class CalculatedChannelCreator
{
private static readonly int ChannelNumberCalculationChannelIndicator = 100000;
public static Test.Module.CalculatedChannel[] CreateChannels(string testId,
string folder,
Calculation calculation,
List<Test.Module.Channel> inputChannels,
string channelName,
int startingNumber,
List<Test.Module.Channel> allChannels,
int clipLength,
out List<string> errorList,
int defaultEncoding)
{
Test.Module.CalculatedChannel[] calculatedChannels = null;
errorList = new List<string>();
switch (calculation)
{
case Calculation.ThreeDIRTracc: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.Thorax, startingNumber, defaultEncoding); break;
case Calculation.ThreeDIRTraccLowerThorax: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.LowerThorax, startingNumber, defaultEncoding); break;
case Calculation.ThreeDIRTraccAbdomen: calculatedChannels = Create3DIRTraccChannels(testId, folder, inputChannels, channelName, ThreeDIRTraccType.Abdomen, startingNumber, defaultEncoding); break;
case Calculation.SUM:
case Calculation.AVE:
case Calculation.Resultant:
case Calculation.HIC:
calculatedChannels = CreateChannelsAggregateOperation(testId, folder, calculation, inputChannels, channelName, startingNumber, clipLength);
break;
default: calculatedChannels = CreateChannelsBinaryOperation(testId, folder, calculation, inputChannels, channelName, startingNumber); break;
}
if (null == calculatedChannels) return null;
for (var i = 0; i < calculatedChannels.Length; i++)
{
calculatedChannels[i].AbsoluteDisplayOrder = startingNumber + i;
}
if (ValidateChannelName(channelName, inputChannels, allChannels, out errorList)) return calculatedChannels;
//ReportErrors(errorList);
return null;
}
private static Serialization.SliceRaw.File.PersistentChannel CreatePersistentInformationObject(Test.Module.CalculatedChannel channel, string filepath)
{
var channelHeader = new Serialization.SliceRaw.File.BinaryChannelHeader
{
NumberOfTriggers = (ushort)(channel.ParentModule.TriggerSampleNumbers.Count)
};
channelHeader.TriggerSampleNumbers = new ulong[channelHeader.NumberOfTriggers];
// Do trigger sample information.
for (var i = 0; i < channelHeader.NumberOfTriggers; i++)
{
channelHeader.TriggerSampleNumbers[i] = channel.ParentModule.TriggerSampleNumbers[i];
}
// Do EU information.
if (channel is Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware)
{ //
// Persistent object property accessors already pad out EU so data will be word-aligned,
// so we'll want to make sure we do the same thing here.
//
var eu = (channel as Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware).EngineeringUnits;
var paddedEu = (1 == eu.Length % 2) ? (eu.Clone() as string).PadRight(eu.Length + 1, ' ') : eu;
channelHeader.EuFieldLengthWithTerminator = (ushort)(paddedEu.Length + 1);
channelHeader.EngineeringUnit = new char[channelHeader.EuFieldLengthWithTerminator - 1];
for (var j = 0; j < channelHeader.EuFieldLengthWithTerminator - 1; j++)
{
channelHeader.EngineeringUnit[j] = paddedEu[j];
}
}
else
{
channelHeader.EuFieldLengthWithTerminator = 1;
channelHeader.EngineeringUnit = new char[0];
}
// Do ISO code information.
channelHeader.IsoCode = new char[16];
// Make sure memory-mapped file does NOT exist (persistent channel object will overwrite header but append data
// after old file data... don't want that!)
if (System.IO.File.Exists(filepath))
{
GC.Collect();
FileUtils.DeleteFileOrMove(filepath, APILogger.Log);
////Rename existing channel file and kick off thread that will deleted it some time later. This needs to
////happen in this case as the test tree still contains references to the original file and it can't be deleted
////here. After a new channel is added, the old one is removed. The worker thread should wait long enough for that
////to happen (or better, check to see when it does) and then delete the file. This should eliminate the File.IO
////Exception that was being thrown.
//string tmpfilepath = filepath + ".bak";
//APILogger.Log("Renaming: " + filepath + " to " + tmpfilepath + " and deferring deletion.");
//System.IO.Path.ChangeExtension(filepath, Guid.NewGuid().ToString());
//System.Threading.ThreadPool.QueueUserWorkItem(DeleteChannelFile, tmpfilepath);
}
// Create the persistent channel object and return it.
return new Serialization.SliceRaw.File.PersistentChannel(filepath, channelHeader, true);
}
/// <summary>
/// this function takes a calculation and a list of input channels and returns
/// a list of doubles that is the output of doing that calculation
/// </summary>
/// <param name="calculation"></param>
/// <param name="channels"></param>
/// <returns></returns>
private static IList<double> PerformCalculationsAggregate(Calculation calculation,
List<Test.Module.Channel> channels)
{
var maxSampleRate = channels.Select(ch => ch.ParentModule.SampleRateHz).Max();
//this will hold the unfiltered input data for all the input channels
var unfilteredDataEU = new List<List<double>>();
//this will hold the output data
var dOutput = new List<double>();
//this will hold the emc channel data for the input channels (the input channels already have this data
//but keeping a local reference here removes some repeated casting that we'd have to do
var emcChannels = new List<Event.Module.Channel>();
//we may have different start times and the sample indices may not align, if we pick the first channel as a reference
//channel, then we can keep track of the delta for each channels start and the reference channel start in terms of samples
foreach (var ch in channels)
{
var emc = ch.emc as Event.Module.Channel;
emcChannels.Add(emc);
var data = emc.GetUnfilteredDataEu();
unfilteredDataEU.Add(data);
var start = GetTimeOfFirstSample(emc);
}
//any aggregate channels (SUM/AVE) just keep a single double and update it as needed while processing samples
var dAggregateValue = 0D;
var bAdd = true;
var currentChannelSampleIndex = 0;
//to properly aggregate, we need to put both datasets to the right sample rate
//using interpolation
//we need to calculate the min/max time across all channels and then
//the specific min of each channel, this tells us how to align data
var minStart = channels.Select(ch => ((double)ch.ParentModule.TriggerSampleNumbers[0] - ch.ParentModule.StartRecordSampleNumber) / ch.ParentModule.SampleRateHz).Min();
var minEnd = double.MaxValue;
var channelOffsetStarts = new List<int>();
var rates = new List<double>();
for (int i = 0; i < channels.Count; i++)
{
var ch = channels[i];
var chStart = ((double)ch.ParentModule.TriggerSampleNumbers[0] - ch.ParentModule.StartRecordSampleNumber) / ch.ParentModule.SampleRateHz;
var channelOffsetStart = (int)((chStart - minStart) * ch.ParentModule.SampleRateHz);
channelOffsetStarts.Add(channelOffsetStart);
var chEnd = ch.ParentModule.NumberOfSamples - chStart * ch.ParentModule.SampleRateHz;
minEnd = Math.Min(minEnd, chEnd / ch.ParentModule.SampleRateHz);
var rate = maxSampleRate / ch.ParentModule.SampleRateHz;
rates.Add(rate);
}
minStart = -1D * Math.Truncate(1000D * minStart) / 1000D;
minEnd = Math.Truncate(1000D * minEnd) / 1000D;
var totalSamples = Convert.ToInt32(Math.Floor((minEnd - minStart) * maxSampleRate));
for (var iSampleIDX = 0; iSampleIDX < totalSamples; iSampleIDX++)
{
var timeAtIndex =
dAggregateValue = 0;
bAdd = true;
var dSumSquares = 0D;
for (var iChannel = 0; iChannel < emcChannels.Count; iChannel++)
{
var rate = rates[iChannel];
var indexAtCurrentTime = (iSampleIDX - channelOffsetStarts[iChannel]) / rate;
var thisChannelsIndexAtCurrentTime = Convert.ToInt32(Math.Floor(indexAtCurrentTime));
var step = Convert.ToInt32(Math.Ceiling(indexAtCurrentTime) - thisChannelsIndexAtCurrentTime);
if (currentChannelSampleIndex < 0 || currentChannelSampleIndex >= unfilteredDataEU[iChannel].Count)
{
bAdd = false;
break;
}
var dataAtPoint = unfilteredDataEU[iChannel][thisChannelsIndexAtCurrentTime];
var increment = 0D;
if ((1 + thisChannelsIndexAtCurrentTime) < unfilteredDataEU[iChannel].Count)
{
increment = (unfilteredDataEU[iChannel][1 + thisChannelsIndexAtCurrentTime] - dataAtPoint) / rate;
}
else
{
increment = (dataAtPoint - unfilteredDataEU[iChannel][thisChannelsIndexAtCurrentTime - 1]) / rate;
}
dataAtPoint += (increment * step);
dAggregateValue += dataAtPoint;
//HIC must be in g's
if (calculation == Calculation.HIC)
{
if (((Event.Module.AnalogInputChannel)emcChannels[iChannel]).EngineeringUnits.ToLower().Trim() != "g")
{
//convert from m/sec^2 to g
dataAtPoint *= 9.80665D;
}
}
dSumSquares += Math.Pow(dataAtPoint, 2);
}
if (!bAdd) continue;
switch (calculation)
{
case Calculation.AVE: dOutput.Add(dAggregateValue / channels.Count); break;
case Calculation.SUM: dOutput.Add(dAggregateValue); break;
case Calculation.Resultant:
case Calculation.HIC:
dOutput.Add(Math.Sqrt(dSumSquares));
break;
}
}
return dOutput;
}
/// <summary>
/// performs calculations for a binary calculation channel (integrate/differentiate/FFT, etc)
/// </summary>
/// <param name="calculation"></param>
/// <param name="channel"></param>
/// <returns></returns>
private static IList<double> PerformCalculationBinary(Calculation calculation, Event.Module.Channel channel)
{
var data = channel.GetUnfilteredDataEu();
var sampleRate = Convert.ToInt32(channel.ParentModule.SampleRateHz);
switch (calculation)
{
case Calculation.Integral:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var integral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
return integral.Range;
}
case Calculation.DoubleIntegral:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var integral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
db = new ClonableDoubles();
db.AddRange(integral.Range);
var doubleIntegral = new Common.Utilities.Math.Nhtsa.Integration(db, sampleRate);
return doubleIntegral.Range;
}
case Calculation.Derivative:
{
var db = new ClonableDoubles();
db.AddRange(data.ToArray());
var derivative = new Common.Utilities.Math.Nhtsa.Differentiation(db, sampleRate);
return derivative.Range;
}
case Calculation.Sin:
{
return channel.DataEu.Select(euSample => Math.Sin(euSample)).ToList();
}
case Calculation.Cos:
{
return channel.DataEu.Select(euSample => Math.Cos(euSample)).ToList();
}
}
return new List<double>();
}
private static Test.Module.CalculatedChannel CreateCalculatedChannelsIRTRACC(Calculation calculation, Test.Module.Channel[] inputChannels)
{
switch (calculation)
{
case Calculation.ThreeDIRTracc:
case Calculation.ThreeDIRTraccAbdomen:
case Calculation.ThreeDIRTraccLowerThorax:
return Test.Module.CalculatedChannel.CreateInstance(new[]
{
inputChannels[0],
inputChannels[1],
inputChannels[2]
});
default:
return Test.Module.CalculatedChannel.CreateInstance(inputChannels[0]);
}
}
//private Event.Module.Channel GetSourceEMC()
//{
// switch (_calculation)
// {
// case Calculation.ThreeDIRTracc:
// case Calculation.ThreeDIRTraccAbdomen:
// case Calculation.ThreeDIRTraccLowerThorax:
// return
// (cbIRTracc.SelectedItem as ChannelHelper).MyChannel.emc as Event.Module.Channel;
// default:
// return _sourceChannel.emc as Event.Module.Channel;
// }
//}
//private static void DeleteChannelFile(object filepath)
//{
// FileUtils.DeleteFileOrMove((string)filepath, APILogger.Log);
//}
/// <summary>
/// performs the IR-Tracc 3D calculation
/// based on issue
/// 7489 Implement 2D/3D IRTRACC support
/// </summary>
/// <param name="dAX"></param>
/// <param name="dAY"></param>
/// <param name="dAZ"></param>
/// <param name="dOut"></param>
private static void PerformCalculation(out IList<double> dAX, out IList<double> dAY, out IList<double> dAZ, out IList<double> dOut,
Test.Module.Channel irTraccChannel, Test.Module.Channel rPot1Channel, Test.Module.Channel rPot2Channel, ThreeDIRTraccType irtraccType)
{
var maxRate = Math.Max(rPot1Channel.ParentModule.SampleRateHz, rPot2Channel.ParentModule.SampleRateHz);
maxRate = Math.Max(maxRate, irTraccChannel.ParentModule.SampleRateHz);
var irtraccEMC = irTraccChannel.emc as Event.Module.Channel;
var rPot1EMC = rPot1Channel.emc as Event.Module.Channel;
var rPot2EMC = rPot2Channel.emc as Event.Module.Channel;
if (0 != maxRate % rPot1Channel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {rPot1Channel.ParentModule.SampleRateHz}"); }
if (0 != maxRate % rPot2Channel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {rPot2Channel.ParentModule.SampleRateHz}"); }
if (0 != maxRate % irTraccChannel.ParentModule.SampleRateHz) { throw new InvalidOperationException($"Sample rate: {maxRate} is not a multiple of sample rate: {irTraccChannel.ParentModule.SampleRateHz}"); }
//this is the EU data for each channel NOTE - ALL CHANNELS MUST NOT BE USING ZEROING!!! (we handle zeroing already below)
var irTraccEUData = irtraccEMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref irTraccEUData, "DISPLEU.txt");
//var irTraccmVData = irtraccEMC.GetUnfilteredDataMV();
var rPot1EUData = rPot1EMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref rPot1EUData, "YPOTEU.txt");
var rPot2EUData = rPot2EMC.GetUnfilteredDataEu();
DiskUtility.ReplaceDataIfNeeded(ref rPot2EUData, "ZPOTEU.txt");
//this calculates start time for each channel
var startIRTracc = (double)(irTraccChannel.ParentModule.TriggerSampleNumbers[0] - irTraccChannel.ParentModule.StartRecordSampleNumber) / irTraccChannel.ParentModule.SampleRateHz;
startIRTracc = -1D * Math.Truncate(startIRTracc * 1000D) / 1000D;
var startRPot1 = (double)(rPot1Channel.ParentModule.TriggerSampleNumbers[0] - rPot1Channel.ParentModule.StartRecordSampleNumber) / rPot1Channel.ParentModule.SampleRateHz;
startRPot1 = -1D * Math.Truncate(startRPot1 * 1000D) / 1000D;
var startRPot2 = (double)(rPot2Channel.ParentModule.TriggerSampleNumbers[0] - rPot2Channel.ParentModule.StartRecordSampleNumber) / rPot2Channel.ParentModule.SampleRateHz;
startRPot2 = -1D * Math.Truncate(startRPot2 * 1000D) / 1000D;
//this calculates the end for each channel
var endIRTracc = (irTraccChannel.ParentModule.NumberOfSamples + startIRTracc * irTraccChannel.ParentModule.SampleRateHz) / irTraccChannel.ParentModule.SampleRateHz;
endIRTracc = Math.Truncate(endIRTracc * 1000D) / 1000D;
var endRPot1 = (rPot1Channel.ParentModule.NumberOfSamples + startRPot1 * rPot1Channel.ParentModule.SampleRateHz) / rPot1Channel.ParentModule.SampleRateHz;
endRPot1 = Math.Truncate(endRPot1 * 1000D) / 1000D;
var endRPot2 = (rPot2Channel.ParentModule.NumberOfSamples + startRPot2 * rPot2Channel.ParentModule.SampleRateHz) / rPot2Channel.ParentModule.SampleRateHz;
endRPot2 = Math.Truncate(endRPot2 * 1000D) / 1000D;
//here we select the latest start between channels
var start = Math.Max(startIRTracc, startRPot1);
start = Math.Max(start, startRPot2);
//here we find the earliest end between the channels
var end = Math.Min(endIRTracc, endRPot1);
end = Math.Min(end, endRPot2);
// we will super sample to the highest sample rate, and use a common start/stop between all channels.
var length = Convert.ToInt32(Math.Floor((end - start) * maxRate));
//these are the containers for our output data
dAX = new List<double>(length);
dAY = new List<double>(length);
dAZ = new List<double>(length);
dOut = new List<double>(length);
var aicIRTRACC = irTraccChannel as Test.Module.AnalogInputChannel;
var aicRPot1 = rPot1Channel as Test.Module.AnalogInputChannel;
var aicRPOT2 = rPot2Channel as Test.Module.AnalogInputChannel;
//calculates the rate of each channel relative to the highest rate of any of the channels
var rateIRTracc = Convert.ToInt32(Math.Ceiling(maxRate / irTraccChannel.ParentModule.SampleRateHz));
var rateRPot1 = Convert.ToInt32(Math.Ceiling(maxRate / rPot1Channel.ParentModule.SampleRateHz));
var rateRPot2 = Convert.ToInt32(Math.Ceiling(maxRate / rPot2Channel.ParentModule.SampleRateHz));
var R0 = aicIRTRACC.LinearizationFormula.CalibrationFactor * Math.Pow(aicIRTRACC.ZeroPoint, aicIRTRACC.LinearizationFormula.LinearizationExponent);
//we are converting to volt as sensitivity is in mV/V and our original calculation is in deg/V/V
var θy0 = aicRPot1.InitialEu; //((1000D/aicRPot1.Sensitivity)/aicRPot1.FactoryExcitationVoltage)*aicRPot1.ZeroPoint;
var θz0 = aicRPOT2.InitialEu; //((1000D/aicRPOT2.Sensitivity)/aicRPOT2.FactoryExcitationVoltage)*aicRPOT2.ZeroPoint;
//all the formulas use the first data point to zero the output channel data, these variables will hold that zero data for out output channels
//this is columns V through Y
var xa1_0 = double.NaN;
var ya1_0 = double.NaN;
var za1_0 = double.NaN;
var dOut_0 = double.NaN;
//your delta and D0 are dependent on your 3D-IRTRACC type, we get the constant for each type from the config file
var δ = 0D;
var D0 = 0D;
switch (irtraccType)
{
case ThreeDIRTraccType.Abdomen:
δ = SensorConstants.δAbdomen;
D0 = SensorConstants.D0Abdomen;
break;
case ThreeDIRTraccType.Thorax:
δ = SensorConstants.δThorax;
D0 = SensorConstants.D0Thorax;
break;
case ThreeDIRTraccType.LowerThorax:
δ = SensorConstants.δThoraxLower;
D0 = SensorConstants.D0ThoraxLower;
break;
default:
throw new NotSupportedException("unsupported irtracc type: " + irtraccType.ToString());
}
//calculates the offset in samples for each channels start relative to the
//latest common start time between channels
var irTraccOffsetStart = (int)(startIRTracc - start) * irTraccChannel.ParentModule.SampleRateHz;
var rPot1OffsetStart = (int)(startRPot1 - start) * rPot1Channel.ParentModule.SampleRateHz;
var rPot2OffsetStart = (int)(startRPot2 - start) * rPot2Channel.ParentModule.SampleRateHz;
//go through all samples in the output, calculate the index for each channel and do some calcs
for (var i = 0; i < length; i++)
{
//this is the index for the given time, this index could be theoretical
//and doesn't exist (ie 1.5)
var indexAtCurrentTimeIRTracc = (i - irTraccOffsetStart) / rateIRTracc;
//this is the actual index that physically exists (1 for 1.5 for instance)
var actualIndexAtCurrentTimeIRTracc = Convert.ToInt32(Math.Floor(indexAtCurrentTimeIRTracc));
//this is the linear interpolation "step" between this sample and the next
//sample
var stepIRTracc = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeIRTracc) - actualIndexAtCurrentTimeIRTracc);
var indexAtCurrentTimeRPot1 = (i - rPot1OffsetStart) / rateRPot1;
var actualIndexAtCurrentTimeRPot1 = Convert.ToInt32(Math.Floor(indexAtCurrentTimeRPot1));
var stepRPot1 = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeIRTracc) - actualIndexAtCurrentTimeIRTracc);
var indexAtCurrentTimeRPot2 = (i - rPot2OffsetStart) / rateRPot2;
var actualIndexAtCurrentTimeRPot2 = Convert.ToInt32(Math.Floor(indexAtCurrentTimeRPot2));
var stepRPot2 = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeRPot2) - actualIndexAtCurrentTimeRPot2);
var incrementIRTracc = 0D;
var valueIRTraccAtPoint = irTraccEUData[actualIndexAtCurrentTimeIRTracc];
var incrementRPot1 = 0D;
var valueRPot1AtPoint = rPot1EUData[actualIndexAtCurrentTimeRPot1];
var incrementRPot2 = 0D;
var valueRPot2AtPoint = rPot2EUData[actualIndexAtCurrentTimeRPot2];
//calculate the interpolation value per step for channel
//for instance for 10k and 20k sps for sample 2 of the 10k
//increment would be (data[2]-data[1])/2
if ((1 + actualIndexAtCurrentTimeIRTracc) < irTraccEUData.Count)
{
incrementIRTracc = (irTraccEUData[1 + actualIndexAtCurrentTimeIRTracc] - valueIRTraccAtPoint) / rateIRTracc;
}
else
{
incrementIRTracc = (valueIRTraccAtPoint - irTraccEUData[actualIndexAtCurrentTimeIRTracc - 1]) / rateIRTracc;
}
if ((1 + actualIndexAtCurrentTimeRPot1) < rPot1EUData.Count)
{
incrementRPot1 = (rPot1EUData[1 + actualIndexAtCurrentTimeRPot1] - valueRPot1AtPoint) / rateRPot1;
}
else
{
incrementRPot1 = (valueRPot1AtPoint - rPot1EUData[actualIndexAtCurrentTimeRPot1 - 1]) / rateRPot1;
}
if ((1 + actualIndexAtCurrentTimeRPot2) < rPot2EUData.Count)
{
incrementRPot2 = (rPot2EUData[1 + actualIndexAtCurrentTimeRPot2] - valueRPot2AtPoint) / rateRPot2;
}
else
{
incrementRPot2 = (valueRPot2AtPoint = rPot2EUData[actualIndexAtCurrentTimeRPot2 - 1]) / rateRPot2;
}
//math magic from excel
//double b = D0 + System.Math.Abs(irTraccEUData[i] - calFactorInterceptRemoval) - R0;
//double R = aicIRTRACC.LinearizationFormula.CalibrationFactor*
// System.Math.Pow(irTraccmVData[i]/1000D, aicIRTRACC.LinearizationFormula.LinearizationExponent);
//D0+(R-R0) this is column N
//double r = D0 + (R - R0);
var r = valueIRTraccAtPoint + incrementIRTracc * stepIRTracc;
//θy'=θy-θy0 this is column O
var θyprime = valueRPot1AtPoint + incrementRPot1 * stepRPot1 - θy0;
//θz'=θz-θz0 this is column p
var θzprime = valueRPot2AtPoint + incrementRPot2 * stepRPot2 - θz0;
//this is column r
var xa1 = -1D * δ * Math.Sin(θyprime * Math.PI / 180) + r * Math.Cos(θzprime * Math.PI / 180) * Math.Cos(θyprime * Math.PI / 180);
//this is column s
var ya1 = r * Math.Sin(θzprime * Math.PI / 180);
//this is column t
var za1 = -1D * δ * Math.Cos(θyprime * Math.PI / 180D) - r * Math.Cos(θzprime * Math.PI / 180D) * Math.Sin(θyprime * Math.PI / 180D);
//assign the output channel zero points if needed
if (double.IsNaN(xa1_0)) { xa1_0 = xa1; }
if (double.IsNaN(ya1_0)) { ya1_0 = ya1; }
if (double.IsNaN(za1_0)) { za1_0 = za1; }
//add in our data to the output channels
dAX.Add(xa1 - xa1_0);
dAY.Add(ya1 - ya1_0);
dAZ.Add(za1 - za1_0);
//this is column Z
var temp = Math.Sqrt(Math.Pow(r, 2) + Math.Pow(δ, 2));
if (double.IsNaN(dOut_0)) { dOut_0 = temp; }
dOut.Add(temp - dOut_0);
}
}
private static double GetTimeOfFirstSample(Event.Module.Channel channel)
{
return ((double)channel.ParentModule.TriggerSampleNumbers[0] -
channel.ParentModule.StartRecordSampleNumber) / channel.ParentModule.SampleRateHz;
}
private static Test.Module.CalculatedChannel[] Create3DIRTraccChannels(string testId, string folder,
List<Test.Module.Channel> inputChannels, string channelName, ThreeDIRTraccType irTraccType, int offset, int defaultEncoding)
{
System.Diagnostics.Trace.Assert(3 == inputChannels.Count, "3D IR-TRACC requires 3 channels");
var maxRate = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Max();
var distinctRates = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Distinct().ToArray();
foreach (var rate in distinctRates)
{
if (0 != maxRate % rate)
{
throw new NotSupportedException($"Sample rate: {maxRate} is not a multiple of sample rate: {rate}");
}
}
if (distinctRates.Length > 1)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { Resources.StringResources.SuperSamplingWarning }, null));
}
var irtraccEMC = inputChannels[0].emc as Event.Module.Channel;
var rPot1EMC = inputChannels[1].emc as Event.Module.Channel;
var rPot2EMC = inputChannels[2].emc as Event.Module.Channel;
var calc = Calculation.ThreeDIRTracc;
switch (irTraccType)
{
case ThreeDIRTraccType.Abdomen: calc = Calculation.ThreeDIRTraccAbdomen; break;
case ThreeDIRTraccType.Thorax: calc = Calculation.ThreeDIRTracc; break;
case ThreeDIRTraccType.LowerThorax: calc = Calculation.ThreeDIRTraccLowerThorax; break;
}
var ccDeltaAX = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAX.ChannelDescriptionString = channelName + " (dAX)";
var ccDeltaAY = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAY.ChannelDescriptionString = channelName + " (dAY)";
var ccDeltaAZ = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDeltaAZ.ChannelDescriptionString = channelName + " (dAZ)";
var ccDistanceDelta = CreateCalculatedChannelsIRTRACC(calc, new[] { inputChannels[0], inputChannels[1], inputChannels[2] });
ccDistanceDelta.ChannelDescriptionString = channelName;
var outputChannels = new Test.Module.CalculatedChannel[] { ccDeltaAX, ccDeltaAY, ccDeltaAZ, ccDistanceDelta };
foreach (var cc in outputChannels)
{
cc.Calculation = calc.ToString();
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + irtraccEMC.AbsoluteDisplayOrder + offset;
cc.Number = ChannelNumberCalculationChannelIndicator + offset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = 1;
cc.Data.UnitConversion = 1;
cc.Data.UserOffsetEU = 0;
cc.ExcitationVoltage = 0;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = irtraccEMC.ChannelId + "_" + (cc.Number + offset);
cc.ChannelGroupName = irtraccEMC.ChannelGroupName;
cc.IsInverted = false;
cc.PreTestZeroLevelAdc = 0;
cc.SerialNumber = cc.ChannelDescriptionString;
var emc = new Event.Module.AnalogInputChannel(cc, irtraccEMC.ParentModule, cc.Number);
cc.emc = emc;
offset++;
}
ccDeltaAX.EngineeringUnits = "mm";
ccDeltaAY.EngineeringUnits = "mm";
ccDeltaAZ.EngineeringUnits = "mm";
ccDistanceDelta.EngineeringUnits = "mm";
PerformCalculation(out IList<double> dax, out IList<double> day, out IList<double> daz, out IList<double> dDistance, inputChannels[0], inputChannels[1], inputChannels[2], irTraccType);
irtraccEMC = null;
rPot1EMC = null;
rPot2EMC = null;
var datas = new[] { dax, day, daz, dDistance };
for (var i = 0; i < datas.Length && i < outputChannels.Length; i++)
{
var data = datas[i];
var scaleFactor = 0D;
var adcData = ScaleEuData(ref data, out scaleFactor);
outputChannels[i].Sensitivity = scaleFactor;
outputChannels[i].DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
//adjust the output channel with the max rate we super sampled to
//and update the number of samples...
outputChannels[i].SampleRateHz = maxRate;
outputChannels[i].ParentModule.NumberOfSamples = Convert.ToUInt64(data.Count);
((Event.Module.AnalogInputChannel)outputChannels[i].emc).ParentModule.SampleRateHz = maxRate;
((Event.Module.AnalogInputChannel)outputChannels[i].emc).ParentModule.NumberOfSamples = Convert.ToUInt64(data.Count);
var f = new Serialization.SliceRaw.File { DefaultEncoding = defaultEncoding };
var fileName = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, outputChannels[i].Number);
var filepath = System.IO.Path.Combine(folder, fileName);
outputChannels[i].Data.ScaleFactorMv = 1 / scaleFactor;
outputChannels[i].Data.ScaleFactorEU = 1 / scaleFactor;
outputChannels[i].LinearizationFormula.MarkValid(false);
outputChannels[i].PersistentChannelInfo = CreatePersistentInformationObject(outputChannels[i], filepath);
outputChannels[i].PersistentChannelInfo.BeginAppendSession();
outputChannels[i].PersistentChannelInfo.AppendSessionData(adcData.ToArray());
outputChannels[i].PersistentChannelInfo.EndAppendSession();
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer?.CreatePersistentChannel(outputChannels[i], outputChannels[i].ParentModule.NumberOfSamples, outputChannels[i].ParentModule.SampleRateHz, null, null, 0, 0);
var bypass = false;
var reader = f.Importer as Serialization.SliceRaw.File.Reader;
reader?.ReadChannel(outputChannels[i], outputChannels[i].ParentModule, filepath, ref bypass);
(outputChannels[i].emc as Event.Module.Channel).UnfilteredData = outputChannels[i].PersistentChannelInfo;
(outputChannels[i].emc as Event.Module.Channel).Scaler.SetScaleFactorMv(1D / scaleFactor);
}
return outputChannels.ToArray();
}
private static Test.Module.CalculatedChannel[] CreateChannelsAggregateOperation(string testId, string folder,
Calculation calculation, List<Test.Module.Channel> inputChannels, string channelName, int channelOffset, int clipLength)
{
System.Diagnostics.Trace.Assert(1 < inputChannels.Count,
calculation.ToString() + " requires at least 1 channel");
var sourceEmc = inputChannels[0].emc as Event.Module.Channel;
var sourceChannel = inputChannels[0];
var maxSampleRate = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Max();
var distinctRates = inputChannels.Select(ch => ch.ParentModule.SampleRateHz).Distinct().ToArray();
foreach (var rate in distinctRates)
{
if (maxSampleRate % rate != 0)
{
throw new NotSupportedException($"Sample rate: {maxSampleRate} is not a multiple of {rate}");
}
}
if (distinctRates.Length > 1)
{
var eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { Resources.StringResources.SuperSamplingWarning }, null));
}
//Create new test channel
var cc = CreateCalculatedChannelsIRTRACC(calculation, new[] { sourceChannel });
cc.SampleRateHz = maxSampleRate;
cc.Calculation = calculation.ToString();
cc.ChannelDescriptionString = channelName;
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.Number = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = sourceEmc.Multiplier;
cc.Data.UnitConversion = sourceEmc.UnitConversion;
cc.Data.UserOffsetEU = sourceEmc.UserOffsetEU;
cc.ExcitationVoltage = 0;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = sourceChannel.ChannelId + "_" + cc.Number;
cc.ChannelGroupName = sourceChannel.ChannelGroupName;
cc.IsInverted = false;
var emc = new Event.Module.AnalogInputChannel(cc, sourceEmc.ParentModule, sourceEmc.AbsoluteNumber);
cc.emc = emc;
//Do the maths. Use source channel as source for data as it's properly set up.
var euData = PerformCalculationsAggregate(calculation, inputChannels);
cc.ParentModule.NumberOfSamples = Convert.ToUInt64(euData.Count);
emc.ParentModule.NumberOfSamples = Convert.ToUInt64(euData.Count);
//Don't use the source channel emc anymore.
sourceEmc = null;
//Scale the data
var adcData = ScaleEuData(ref euData, out double scaleFactor);
cc.Sensitivity = scaleFactor;
//Test by writing source channel data. Readback should be identical
var f = new Serialization.SliceRaw.File();
f.DefaultEncoding = Encoding.Unicode.CodePage;
//Create file with from source channel. At this point it's not complete -- it still needs number of
//samples, etc.
var filename = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, cc.Number);
var filepath = System.IO.Path.Combine(folder, filename);
cc.Data.ScaleFactorMv = 1 / scaleFactor;
cc.Data.ScaleFactorEU = 1 / scaleFactor;
switch (calculation)
{
default:
cc.DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
if (sourceChannel is Test.Module.AnalogInputChannel analogInputChannel) { cc.EngineeringUnits = analogInputChannel.EngineeringUnits; }
else { cc.EngineeringUnits = "NOT DEFINED"; }
break;
case Calculation.Sin:
case Calculation.Cos:
cc.DesiredRange = 1.1;
cc.EngineeringUnits = "rads";
break;
}
//All done with channel. Create persistent object with what's in the channel object
cc.PersistentChannelInfo = CreatePersistentInformationObject(cc, filepath);
//Write out the data to the memory-mapped file
cc.PersistentChannelInfo.BeginAppendSession();
cc.PersistentChannelInfo.AppendSessionData(adcData.ToArray());
cc.PersistentChannelInfo.EndAppendSession();
//Use the export writer to update the binary channel fields with everything that's missing. This will also
//Update the CRC.
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer.CreatePersistentChannel(cc, cc.ParentModule.NumberOfSamples, cc.ParentModule.SampleRateHz, null, null, 0, 0);
//At this point the PersistentChannel is blown away. Read it back in and hook it up.
var bypass = false;
(f.Importer as Serialization.SliceRaw.File.Reader).ReadChannel(cc, cc.ParentModule, filepath, ref bypass);
emc.UnfilteredData = cc.PersistentChannelInfo;
if (calculation == Calculation.HIC)
{
var channelData = new ChannelData("g");
channelData.FilteredEU = euData.ToArray();
var hic = HeadInjuryCriterion.GetHeadInjuryCriterion(channelData, cc.SampleRateHz, clipLength);
cc.T1 = Convert.ToUInt64(hic.StartSample);
cc.T2 = Convert.ToUInt64(hic.EndSample);
cc.HIC = hic.HIC;
}
return new[] { cc };
}
/// <summary>
/// creates a calculated channel for binary operations (sine/cosine/integral/ffs)
/// </summary>
/// <param name="testId"></param>
/// <param name="folder"></param>
/// <param name="calculation"></param>
/// <param name="inputChannels"></param>
/// <param name="channelName"></param>
/// <param name="channelOffset"></param>
/// <returns></returns>
private static Test.Module.CalculatedChannel[] CreateChannelsBinaryOperation(string testId, string folder,
Calculation calculation, List<Test.Module.Channel> inputChannels, string channelName, int channelOffset)
{
var sourceEmc = inputChannels[0].emc as Event.Module.Channel;
var sourceChannel = inputChannels[0];
//Create new test channel
var cc = CreateCalculatedChannelsIRTRACC(calculation, new[] { sourceChannel });
cc.Calculation = calculation.ToString();
cc.ChannelDescriptionString = channelName;
cc.AbsoluteDisplayOrder = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.Number = ChannelNumberCalculationChannelIndicator + channelOffset;
cc.ProportionalToExcitation = false;
cc.ZeroMvInADC = 0;
cc.OriginalOffsetADC = 0;
cc.Data.MvPerEu = 1;
cc.Data.Multiplier = sourceEmc.Multiplier;
cc.Data.UnitConversion = sourceEmc.UnitConversion;
cc.Data.UserOffsetEU = sourceEmc.UserOffsetEU;
cc.Excitation = 0;
cc.ZeroMethod = ZeroMethodType.None;
cc.RemoveOffset = false;
cc.ChannelId = sourceChannel.ChannelId + "_" + cc.Number;
cc.ChannelGroupName = sourceChannel.ChannelGroupName;
cc.IsInverted = false;
var emc = new Event.Module.AnalogInputChannel(cc, sourceEmc.ParentModule, sourceEmc.AbsoluteNumber);
cc.emc = emc;
//Do the maths. Use source channel as source for data as it's properly set up.
var euData = PerformCalculationBinary(calculation, sourceEmc);
//Don't use the source channel emc anymore.
sourceEmc = null;
//Scale the data
var adcData = ScaleEuData(ref euData, out var scaleFactor);
cc.Sensitivity = scaleFactor;
//Test by writing source channel data. Readback should be identical
var f = new Serialization.SliceRaw.File { DefaultEncoding = Encoding.Unicode.CodePage };
//Create file with from source channel. At this point it's not complete -- it still needs number of
//samples, etc.
var filename = new Serialization.SliceRaw.File().GetCalculatedChannelFileNameFromTestNameAndChannelNumber(testId, cc.Number);
var filepath = System.IO.Path.Combine(folder, filename);
cc.Data.ScaleFactorMv = 1 / scaleFactor;
cc.Data.ScaleFactorEU = 1 / scaleFactor;
switch (calculation)
{
default:
cc.DesiredRange = Constants.ADC_MIDPOINT / scaleFactor;
if (sourceChannel is Test.Module.AnalogInputChannel analogInputChannel) { cc.EngineeringUnits = analogInputChannel.EngineeringUnits; }
else { cc.EngineeringUnits = "NOT DEFINED"; }
break;
case Calculation.Sin:
case Calculation.Cos:
cc.DesiredRange = 1.1;
cc.EngineeringUnits = "rads";
break;
}
//All done with channel. Create persistent object with what's in the channel object
cc.PersistentChannelInfo = CreatePersistentInformationObject(cc, filepath);
//Write out the data to the memory-mapped file
cc.PersistentChannelInfo.BeginAppendSession();
cc.PersistentChannelInfo.AppendSessionData(adcData.ToArray());
cc.PersistentChannelInfo.EndAppendSession();
//Use the export writer to update the binary channel fields with everything that's missing. This will also
//Update the CRC.
var writer = (f.Exporter as Serialization.SliceRaw.File.Writer);
writer.CreatePersistentChannel(cc, cc.ParentModule.NumberOfSamples, cc.ParentModule.SampleRateHz, null, null, 0, 0);
//At this point the PersistentChannel is blown away. Read it back in and hook it up.
var bypass = false;
(f.Importer as Serialization.SliceRaw.File.Reader).ReadChannel(cc, cc.ParentModule, filepath,
ref bypass);
emc.UnfilteredData = cc.PersistentChannelInfo;
return new[] { cc };
}
public enum ThreeDIRTraccType
{
Thorax,
Abdomen,
LowerThorax
}
private static short[] ScaleEuData(ref IList<double> euData, out double scaleFactor)
{
scaleFactor = 1.0;
var max = (from d in euData select Math.Abs(d)).Max();
if (0 == max)
{
max = 1;
}
//we used ABS above, so we need to consider that the signal could be bipolar and be peak to peak of 2*max
max *= 2;
if (short.MaxValue > max)
{
scaleFactor = short.MaxValue / max;
}
else
{
scaleFactor = max / short.MaxValue;
}
//Scale the data
var data = new List<short>();
foreach (var euSample in euData)
{
data.Add((short)(euSample * scaleFactor));
}
return data.ToArray();
}
/// <summary>
/// Validate name of the new calculated channel
/// </summary>
/// <param name="channelName">name of the new calculated channel</param>
/// <param name="inputChannels">existing channels</param>
/// <param name="allChannels">If null - calling form MakeCalculatedChannels() in Download.xaml.cs</param>
/// <param name="errorList">list of errors</param>
/// <returns>if anyy errors - returns false</returns>
public static bool ValidateChannelName(string channelName, List<Test.Module.Channel> inputChannels, List<Test.Module.Channel> allChannels, out List<string> errorList)
{
errorList = new List<string>();
if (allChannels == null) return errorList.Count == 0;
if (string.IsNullOrEmpty(channelName)) { errorList.Add("Channel name cannot be empty."); }
if (inputChannels.Exists(ch => ch.ChannelDescriptionString == channelName))
{ errorList.Add("Channel name is not unique. [input channels]"); }
if (allChannels.Exists(ch => ch.ChannelDescriptionString == channelName))
{ errorList.Add("Channel name is not unique. [all channels]"); }
return errorList.Count == 0;
}
#region helper classes
private sealed class ClonableDoubles : List<double>, ICloneable
{
object ICloneable.Clone()
{
var l = new List<double>();
l.AddRange(ToArray());
return l;
}
}
#endregion
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DTS.Viewer.AddCalculatedChannel")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DTS.Viewer.AddCalculatedChannel")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6451f3ed-934e-47e3-a1ca-33c223a6507a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,387 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DTS.Viewer.AddCalculatedChannel.Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class StringResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal StringResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DTS.Viewer.AddCalculatedChannel.Resources.StringResources", typeof(StringResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Add Calculated Channel.
/// </summary>
internal static string AddCalculatedChannel {
get {
return ResourceManager.GetString("AddCalculatedChannel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Average.
/// </summary>
internal static string CalculatedChannel_Average {
get {
return ResourceManager.GetString("CalculatedChannel_Average", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (upper thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_Abdomen {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_Abdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_LowerThorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_LowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3D_Thorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3D_Thorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CalculatedChannel_IRTRACC3DAbdomen {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3DAbdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CalculatedChannel_IRTRACC3DLowerThorax {
get {
return ResourceManager.GetString("CalculatedChannel_IRTRACC3DLowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sum.
/// </summary>
internal static string CalculatedChannel_Sum {
get {
return ResourceManager.GetString("CalculatedChannel_Sum", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation.
/// </summary>
internal static string Calculation {
get {
return ResourceManager.GetString("Calculation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cosine.
/// </summary>
internal static string CALCULATION_Cos {
get {
return ResourceManager.GetString("CALCULATION_Cos", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Derivative.
/// </summary>
internal static string CALCULATION_Derivative {
get {
return ResourceManager.GetString("CALCULATION_Derivative", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Double integral.
/// </summary>
internal static string CALCULATION_DoubleIntegral {
get {
return ResourceManager.GetString("CALCULATION_DoubleIntegral", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Integral.
/// </summary>
internal static string CALCULATION_Integral {
get {
return ResourceManager.GetString("CALCULATION_Integral", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sine.
/// </summary>
internal static string CALCULATION_Sin {
get {
return ResourceManager.GetString("CALCULATION_Sin", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (upper thorax).
/// </summary>
internal static string CALCULATION_ThreeDIRTracc {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTracc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (abdomen).
/// </summary>
internal static string CALCULATION_ThreeDIRTraccAbdomen {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTraccAbdomen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 3D IR-TRACC (lower thorax).
/// </summary>
internal static string CALCULATION_ThreeDIRTraccLowerThorax {
get {
return ResourceManager.GetString("CALCULATION_ThreeDIRTraccLowerThorax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation Input Channel.
/// </summary>
internal static string CalculationInputChannel {
get {
return ResourceManager.GetString("CalculationInputChannel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Channel.
/// </summary>
internal static string Channel {
get {
return ResourceManager.GetString("Channel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Channel Name.
/// </summary>
internal static string ChannelName {
get {
return ResourceManager.GetString("ChannelName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Clip length (ms).
/// </summary>
internal static string ClipLengthMS {
get {
return ResourceManager.GetString("ClipLengthMS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Description.
/// </summary>
internal static string Description {
get {
return ResourceManager.GetString("Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Acceleration X.
/// </summary>
internal static string HICAccelerationX {
get {
return ResourceManager.GetString("HICAccelerationX", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Acceleration Y.
/// </summary>
internal static string HICAccelerationY {
get {
return ResourceManager.GetString("HICAccelerationY", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to AccelerationZ.
/// </summary>
internal static string HICAccelerationZ {
get {
return ResourceManager.GetString("HICAccelerationZ", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Head injury criterion requires 3 channels.
/// </summary>
internal static string HICRequires3Channels {
get {
return ResourceManager.GetString("HICRequires3Channels", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Input channels.
/// </summary>
internal static string InputChannels {
get {
return ResourceManager.GetString("InputChannels", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ISO Code.
/// </summary>
internal static string ISOCode {
get {
return ResourceManager.GetString("ISOCode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: No channels included.
/// </summary>
internal static string NoChannelsIncluded {
get {
return ResourceManager.GetString("NoChannelsIncluded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Units don&apos;t match for all input channels.
/// </summary>
internal static string ResultantUnitsDontMatch {
get {
return ResourceManager.GetString("ResultantUnitsDontMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error: Sample rates don&apos;t match for all input channels.
/// </summary>
internal static string SampleRatesDontMatch {
get {
return ResourceManager.GetString("SampleRatesDontMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Calculation contains multiple sample rates. Input will be resampled to the highest sample rate using linear interpolation..
/// </summary>
internal static string SuperSamplingWarning {
get {
return ResourceManager.GetString("SuperSamplingWarning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to IR-TRACC.
/// </summary>
internal static string ThreeD_IRTracc {
get {
return ResourceManager.GetString("ThreeD_IRTracc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to R. Pot Y.
/// </summary>
internal static string ThreeD_RotPot1 {
get {
return ResourceManager.GetString("ThreeD_RotPot1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to R. Pot Z.
/// </summary>
internal static string ThreeD_RotPot2 {
get {
return ResourceManager.GetString("ThreeD_RotPot2", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,228 @@
<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AddCalculatedChannel" xml:space="preserve">
<value>Add Calculated Channel</value>
</data>
<data name="Calculation" xml:space="preserve">
<value>Calculation</value>
</data>
<data name="CalculationInputChannel" xml:space="preserve">
<value>Calculation Input Channel</value>
</data>
<data name="Channel" xml:space="preserve">
<value>Channel</value>
</data>
<data name="ChannelName" xml:space="preserve">
<value>Channel Name</value>
</data>
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="InputChannels" xml:space="preserve">
<value>Input channels</value>
</data>
<data name="ISOCode" xml:space="preserve">
<value>ISO Code</value>
</data>
<data name="CalculatedChannel_Average" xml:space="preserve">
<value>Average</value>
</data>
<data name="CalculatedChannel_IRTRACC3D" xml:space="preserve">
<value>3D IR-TRACC (upper thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3DAbdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CalculatedChannel_IRTRACC3DLowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_Abdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_LowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="CalculatedChannel_IRTRACC3D_Thorax" xml:space="preserve">
<value>3D IR-TRACC (thorax)</value>
</data>
<data name="CalculatedChannel_Sum" xml:space="preserve">
<value>Sum</value>
</data>
<data name="CALCULATION_Cos" xml:space="preserve">
<value>Cosine</value>
</data>
<data name="CALCULATION_Derivative" xml:space="preserve">
<value>Derivative</value>
</data>
<data name="CALCULATION_DoubleIntegral" xml:space="preserve">
<value>Double integral</value>
</data>
<data name="CALCULATION_Integral" xml:space="preserve">
<value>Integral</value>
</data>
<data name="CALCULATION_Sin" xml:space="preserve">
<value>Sine</value>
</data>
<data name="CALCULATION_ThreeDIRTracc" xml:space="preserve">
<value>3D IR-TRACC (upper thorax)</value>
</data>
<data name="CALCULATION_ThreeDIRTraccAbdomen" xml:space="preserve">
<value>3D IR-TRACC (abdomen)</value>
</data>
<data name="CALCULATION_ThreeDIRTraccLowerThorax" xml:space="preserve">
<value>3D IR-TRACC (lower thorax)</value>
</data>
<data name="ThreeD_IRTracc" xml:space="preserve">
<value>IR-TRACC</value>
</data>
<data name="ThreeD_RotPot1" xml:space="preserve">
<value>R. Pot Y</value>
</data>
<data name="ThreeD_RotPot2" xml:space="preserve">
<value>R. Pot Z</value>
</data>
<data name="SuperSamplingWarning" xml:space="preserve">
<value>Calculation contains multiple sample rates. Input will be resampled to the highest sample rate using linear interpolation.</value>
</data>
<data name="ClipLengthMS" xml:space="preserve">
<value>Clip length (ms)</value>
</data>
<data name="HICAccelerationX" xml:space="preserve">
<value>Acceleration X</value>
</data>
<data name="HICAccelerationY" xml:space="preserve">
<value>Acceleration Y</value>
</data>
<data name="HICAccelerationZ" xml:space="preserve">
<value>AccelerationZ</value>
</data>
<data name="HICRequires3Channels" xml:space="preserve">
<value>Error: Head injury criterion requires 3 channels</value>
</data>
<data name="NoChannelsIncluded" xml:space="preserve">
<value>Error: No channels included</value>
</data>
<data name="ResultantUnitsDontMatch" xml:space="preserve">
<value>Error: Units don't match for all input channels</value>
</data>
<data name="SampleRatesDontMatch" xml:space="preserve">
<value>Error: Sample rates don't match for all input channels</value>
</data>
</root>

View File

@@ -0,0 +1,21 @@
using System;
using System.Windows.Markup;
using DTS.Viewer.AddCalculatedChannel.Resources;
namespace DTS.Viewer.AddCalculatedChannel
{
[MarkupExtensionReturnType(typeof(string))]
public class TranslateExtension : MarkupExtension
{
private readonly string _key;
public TranslateExtension(string key) { _key = key; }
private const string NotFound = "#stringnotfound#";
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (string.IsNullOrEmpty(_key)) { return NotFound; }
return StringResources.ResourceManager.GetString(_key) ?? NotFound + " " + _key;
}
}
}

View File

@@ -0,0 +1,175 @@
<base:BaseView x:Class="DTS.Viewer.AddCalculatedChannel.AddCalculatedChannelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:DTS.Common.Base;assembly=DTS.Common"
xmlns:root="clr-namespace:DTS.Viewer.AddCalculatedChannel"
xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:converters="clr-namespace:DTS.Common.Converters;assembly=DTS.Common"
xmlns:controls="clr-namespace:DTS.Common.Controls;assembly=DTS.Common"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<base:BaseView.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource PageContentTextBoxStyle}" />
<Style TargetType="TextBlock" BasedOn="{StaticResource PageContentTextStyle}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource PageContentCheckBoxStyle}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource PageContentPasswordBoxStyle}" />
<Style TargetType="Button" BasedOn="{StaticResource FlatButton}"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<Style TargetType="toolkit:DoubleUpDown" BasedOn="{StaticResource PageContentXCDoubleUpDown}">
<Setter Property="Width" Value="150"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="FormatString" Value="N0"/>
<Setter Property="Increment" Value="1"/>
</Style>
<sys:Double x:Key="HIC_LENGTH_MIN">1</sys:Double>
<sys:Double x:Key="HIC_LENGTH_MAX">100</sys:Double>
</base:BaseView.Resources>
<Grid Background="{StaticResource Brush_ApplicationContentBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Page Title -->
<TextBlock Style="{StaticResource BaselineTextStyle4}" Text="{root:TranslateExtension AddCalculatedChannel}" Grid.Row="0"/>
<!-- Content-->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" MinWidth="480"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Channel Name-->
<TextBlock Grid.Column="0" Grid.Row="0" Text="{root:TranslateExtension ChannelName}"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding ChannelName, Mode=TwoWay, FallbackValue=Integration}" x:Name="tbChannelName" MaxLength="100" />
<!-- Channel Description-->
<TextBlock Grid.Column="0" Grid.Row="1" Text="{root:TranslateExtension Description}" Visibility="Collapsed"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding ChannelDescription, Mode=TwoWay}" IsEnabled="False" x:Name="tbChannelDescription" Visibility="Collapsed"/>
<!-- ISO Code-->
<TextBlock Grid.Column="0" Grid.Row="2" Text="{root:TranslateExtension ISOCode}"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding IsoCode, Mode=TwoWay, FallbackValue=????????????????}" MaxLength="25"/>
<!-- Calculation Type -->
<TextBlock Grid.Column="0" Grid.Row="3" Text="{root:TranslateExtension Calculation}"/>
<ComboBox Grid.Column="1" Grid.Row="3" ItemsSource="{Binding CalculationList}" SelectedItem="{Binding SelectedCalculation}" /><!--SelectionChanged="cbCalculationList_SelectionChanged" x:Name="cbCalculationList"/>-->
<!--multiple channel selector-->
<TextBlock Grid.Column="0" Grid.Row="4" Visibility="{Binding MultipleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visible}" Text="{root:TranslateExtension InputChannels}" VerticalAlignment="Top"/>
<!-- Single Channel Selector -->
<TextBlock Grid.Column="0" Grid.Row="4" Text="{root:TranslateExtension CalculationInputChannel}" Visibility="{Binding SingleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}"/>
<ComboBox Grid.Column="1" Grid.Row="4" ItemsSource="{Binding ChannelList}" SelectedItem="{Binding SourceChannel}" Visibility="{Binding SingleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
<!--multiple channel selector-->
<ListView ItemsSource="{Binding ChannelListObjects}" Grid.Row="4" Grid.Column="1" Visibility="{Binding MultipleChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visible}"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header=" " Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsThreeState="False" IsChecked="{Binding Path=IsIncluded}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{root:TranslateExtension Channel}" DisplayMemberBinding="{Binding Path=DisplayName}" />
</GridView>
</ListView.View>
</ListView>
<!--ThreeDIRTRACC-->
<Grid Grid.Row="4" Grid.Column="0" Visibility="{Binding ThreeDIRTRACCVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visibility.Collapsed}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Text="{root:TranslateExtension InputChannels}" />
</Grid>
<Grid Grid.Row="4" Grid.Column="1" Visibility="{Binding ThreeDIRTRACCVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{root:TranslateExtension ThreeD_IRTracc}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{root:TranslateExtension ThreeD_RotPot1}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBlock Grid.Column="0" Grid.Row="2" Text="{root:TranslateExtension ThreeD_RotPot2}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<ComboBox Grid.Row="0" ItemsSource="{Binding IRTraccChannelList}" SelectedItem="{Binding IRTraccChannel}" Grid.Column="1" DisplayMemberPath="DisplayName"/>
<ComboBox Grid.Row="1" ItemsSource="{Binding Pot1ChannelList}" SelectedItem="{Binding Pot1Channel}" Grid.Column="1" DisplayMemberPath="DisplayName" />
<ComboBox Grid.Row="2" ItemsSource="{Binding Pot2ChannelList}" SelectedItem="{Binding Pot2Channel}" Grid.Column="1" DisplayMemberPath="DisplayName" />
</Grid>
<!--HIC-->
<StackPanel Grid.Row="4" Grid.Column="0" Orientation="Vertical" Visibility="{Binding HICChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visibility.Collapsed}">
<TextBlock Grid.Row="0" Text="{root:TranslateExtension ClipLengthMS}" />
<TextBlock Grid.Row="1" Text="{root:TranslateExtension HICAccelerationX}" />
<TextBlock Grid.Row="2" Text="{root:TranslateExtension HICAccelerationY}" />
<TextBlock Grid.Row="3" Text="{root:TranslateExtension HICAccelerationZ}" />
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="1" Visibility="{Binding HICChannelSelectorVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}">
<toolkit:DoubleUpDown Grid.Column="0" Grid.Row="0"
Minimum="{StaticResource HIC_LENGTH_MIN}" Maximum="{StaticResource HIC_LENGTH_MAX}"
Value="{Binding HICLength}" />
<ComboBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName"
AutomationProperties.AutomationId="HICAccelerationXComboBox"
SelectedItem="{Binding HICAccelerationX}" />
<ComboBox Grid.Column="0" Grid.Row="2" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName" AutomationProperties.AutomationId="HICAccelerationYComboBox"
SelectedItem="{Binding HICAccelerationY}" />
<ComboBox Grid.Column="0" Grid.Row="3" ItemsSource="{Binding AvailableHICChannels}" DisplayMemberPath="DisplayName" AutomationProperties.AutomationId="HICAccelerationZComboBox"
SelectedItem="{Binding HICAccelerationZ}" />
</StackPanel>
</Grid>
</Grid>
</base:BaseView>

View File

@@ -0,0 +1,17 @@
using DTS.Common.Interface;
// ReSharper disable CheckNamespace
namespace DTS.Viewer.AddCalculatedChannel
{
/// <summary>
/// Interaction logic for AddCalculatedChannelView.xaml
/// </summary>
public partial class AddCalculatedChannelView : IAddCalculatedChannelView
{
public AddCalculatedChannelView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]