Files

119 lines
6.4 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
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<Test.Module.Channel> inputChannels,
string channelName,
int startingNumber,
List<Test.Module.Channel> allChannels,
int clipLength,
out List<string> 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<Test.Module.Channel> inputChannels,
List<Test.Module.Channel> allChannels,
out List<string> 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.