--- source_files: - DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.AddCalculatedChannel/Model/CalculatedChannelCreator.cs generated_at: "2026-04-16T13:59:32.414209+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "d05bf6b72e9c97be" --- # CalculatedChannelCreator Documentation ## 1. Purpose The `CalculatedChannelCreator` class is a factory responsible for creating derived data channels from existing sensor input channels. It supports three categories of calculations: 3D IR-Tracc displacement calculations (Thorax, Abdomen, LowerThorax variants), aggregate operations across multiple channels (SUM, AVE, Resultant, HIC), and single-channel binary operations (Integral, DoubleIntegral, Derivative, Sin, Cos). The class handles sample rate alignment via interpolation, creates persistent file-backed channel storage, and manages the full lifecycle of calculated channel creation including validation, computation, scaling, and serialization. ## 2. Public Interface ### `CreateChannels` ```csharp public static Test.Module.CalculatedChannel[] CreateChannels( string testId, string folder, Calculation calculation, List inputChannels, string channelName, int startingNumber, List allChannels, int clipLength, out List errorList, int defaultEncoding) ``` **Behavior:** Main entry point for creating calculated channels. Dispatches to appropriate private creation methods based on the `Calculation` enum value. Returns an array of `Test.Module.CalculatedChannel` objects or `null` on failure. Validates channel names before returning. Sets `AbsoluteDisplayOrder` on each created channel. ### `ValidateChannelName` ```csharp public static bool ValidateChannelName( string channelName, List inputChannels, List allChannels, out List errorList) ``` **Behavior:** Validates that the channel name is non-empty and unique across both input channels and all channels. Returns `true` if validation passes (empty error list). If `allChannels` is `null`, returns `true` immediately with empty error list (special case for calls from `MakeCalculatedChannels()` in Download.xaml.cs per source comments). ### `ThreeDIRTraccType` (enum) ```csharp public enum ThreeDIRTraccType { Thorax, Abdomen, LowerThorax } ``` **Behavior:** Defines the three anatomical positions for 3D IR-Tracc sensor calculations, each using different constants (`δ` and `D0`) from `SensorConstants`. ## 3. Invariants - **Channel Number Indicator:** All calculated channels use `ChannelNumberCalculationChannelIndicator` (100000) as a base offset for channel numbering. - **3D IR-Tracc Input Count:** Must have exactly 3 input channels (enforced by `Trace.Assert`). - **Aggregate Operation Input Count:** Must have at least 1 input channel (enforced by `Trace.Assert` for SUM/AVE/Resultant/HIC). - **Sample Rate Divisibility:** The maximum sample rate among input channels must be a multiple of all other input channel sample rates; otherwise `NotSupportedException` is thrown. - **Super-sampling Notification:** When input channels have different sample rates, a `PageErrorEvent` with `SuperSamplingWarning` is published via `IEventAggregator`. - **Data Scaling:** Output data is scaled to fit within `short.MaxValue` range for ADC representation. - **Engineering Units:** 3D IR-Tracc output channels use "mm" as engineering units; Sin/Cos use "rads". ## 4. Dependencies ### This Module Depends On: - `DTS.Common.Enums.Sensors` - `SensorConstants` for IR-Tracc physical constants - `DTS.Common.Utilities.Logging` - `APILogger` for file operation logging - `DTS.Common.Utils` - `FileUtils` for file deletion - `DTS.Serialization` - `Serialization.SliceRaw.File` and related types for persistent storage - `DTS.Slice.Control` - Unclear specific usage from source alone - `DTS.Common` - `Constants.ADC_MIDPOINT`, `ZeroMethodType` - `DTS.Common.Events` - `PageErrorEvent`, `PageErrorArg` - `DTS.Common.Calculations` - `HeadInjuryCriterion` for HIC calculations - `DTS.Common.Utilities.Math.Nhtsa` - `Integration`, `Differentiation` classes - `Prism.Ioc` - `ContainerLocator` for service location - `Prism.Events` - `IEventAggregator` for event publishing - `Test.Module` namespace - `Channel`, `CalculatedChannel`, `AnalogInputChannel` - `Event.Module` namespace - `Channel`, `AnalogInputChannel` (EMC layer) ### What Depends On This Module: - Unclear from source alone; callers are external to this file. ## 5. Gotchas ### Critical Bug in `CreateChannels` Return Logic Lines 54-57 contain inverted logic: ```csharp if (ValidateChannelName(channelName, inputChannels, allChannels, out errorList)) return calculatedChannels; //ReportErrors(errorList); return null; ``` The method returns `calculatedChannels` when validation **succeeds** but then immediately returns `null` afterward (unreachable code for the error path). The commented-out `ReportErrors` suggests incomplete error handling. The intent appears reversed—validation failure should likely return `null`. ### Copy-Paste Bug in `PerformCalculation` Line 388 calculates `stepRPot1` using the wrong index variable: ```csharp var stepRPot1 = Convert.ToInt32(Math.Ceiling(indexAtCurrentTimeIRTracc) - actualIndexAtCurrentTimeIRTracc); ``` This should likely use `indexAtCurrentTimeRPot1` instead of `indexAtCurrentTimeIRTracc`. ### Assignment in Conditional (Line 398) ```csharp incrementRPot2 = (valueRPot2AtPoint = rPot2EUData[actualIndexAtCurrentTimeRPot2 - 1]) / rateRPot2; ``` This assigns to `valueRPot2AtPoint` inside a conditional branch, which differs from the parallel IRTracc and RPot1 branches that only read the value. ### Explicit GC Collection `CreatePersistentInformationObject` calls `GC.Collect()` before file deletion to release memory-mapped file handles—a potential performance concern. ### Debug/Test Data Injection `PerformCalculation` calls `DiskUtility.ReplaceDataIfNeeded` with hardcoded filenames ("DISPLEU.txt", "YPOTEU.txt", "ZPOTEU.txt"), suggesting debug/override capability that may affect production behavior. ### HIC Unit Conversion `PerformCalculationsAggregate` converts m/s² to g's (multiplying by 9.80665) for HIC calculations when engineering units are not already "g", but this conversion is applied inconsistently—only to `dataAtPoint` for the `dSumSquares` calculation, not to `dAggregateValue`. ### Unused Variable Line 246 declares `var timeAtIndex =` with no assignment or usage.