Files
2026-04-17 14:55:32 -04:00

302 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/DataValues.cs
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/ReviewableAttribute.NotApplicableException.cs
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/Filter.cs
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/ChannelDefaultSaeJ211Filter.cs
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs
- Common/DTS.Common.Serialization/Control/Event/Module/Channel/SaeJ211Filter.cs
generated_at: "2026-04-16T03:42:34.925173+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "2400faf1f9897d63"
---
# Documentation: `DTS.Slice.Control.Event.Module.Channel` Subsystem
## 1. Purpose
This module provides core data structures and abstractions for representing and manipulating channel data within event recordings in the DTS Slice Control system. It defines the foundational types for physical channels, calculated channels, filters (including SAE J211compliant filters), and data storage mechanisms (in-memory vs. memory-mapped). The subsystem enables filtering, unit conversion, and serialization of channel data, supporting both raw sensor inputs (ADC) and derived quantities (EU, mV), as well as computed channels (e.g., integrals, derivatives, FFTs). It serves as the data model layer for event analysis and review workflows.
## 2. Public Interface
### `DataValues` class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/DataValues.cs`*
- **`DataValues()`**
Initializes a `DataValues` instance using in-memory storage (i.e., `UseMemoryMappedFile = false`).
- **`DataValues(bool useMemoryMappedFile)`**
Initializes a `DataValues` instance. If `useMemoryMappedFile` is `true`, the instance is configured to use memory-mapped files for data storage (intended for large datasets exceeding process memory limits).
- **`UseMemoryMappedFile: bool`**
Property controlling whether the instance uses memory-mapped files (`true`) or in-memory storage (`false`). Implemented via a `Property<bool>` wrapper.
---
### `Filter` abstract class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/Filter.cs`*
- **`Name: string` (abstract)**
Returns a descriptive name for the filter (e.g., `"6G"` for a 6g filter, or `"123.45Hz"` for ad hoc).
- **`IsCfc: bool` (abstract)**
Returns `true` if the filter corresponds to a defined CFC (Channel Filter Classification) value; `false` for `Unfiltered` or `AdHoc`.
- **`Type: ChannelFilter` (abstract)**
Returns the canonical `ChannelFilter` enum value representing the filter (e.g., `ChannelFilter.SixG`, `ChannelFilter.AdHoc`).
- **`CutoffFrequencyHz: double` (abstract)**
Returns the filters cutoff frequency in hertz.
- **`Apply(Channel input, DataDisplayUnits displayUnits, bool bUseLegacyTDCSoftwareFilterAdjustment): double[]` (abstract)**
Applies the filter to the unfiltered data of the specified `input` channel, returning filtered data in the requested `displayUnits` (ADC, EU, or mV). The `bUseLegacyTDCSoftwareFilterAdjustment` flag controls whether a one-sample phase shift is applied to match legacy TDC behavior (see issue #8747).
- **`Apply(double[] data, double sampleRate, bool bUseLegacyTDCSoftwareFilterAdjustment): double[]` (abstract)**
Applies the filter to a raw data array with known `sampleRate`, returning filtered data. Used when channel context is unavailable.
- **`ToBaseString(): string` (abstract)**
Returns the filters base name (e.g., `"6G"`), without any decorative prefix (e.g., `"Default (6G)"`). Distinct from `ToString()`.
---
### `SaeJ211Filter` class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/SaeJ211Filter.cs`*
- **`SaeJ211Filter(ChannelFilter originalType)`**
Initializes a filter for a CFC-compliant type (e.g., `ChannelFilter.SixG`). Throws `Exception` if `originalType == ChannelFilter.AdHoc`.
- **`SaeJ211Filter(double cutoffFrequencyHz)`**
Initializes an ad hoc filter with the specified cutoff frequency.
- **`SaeJ211Filter(SaeJ211Filter originalFilter)`**
Copy constructor.
- **`OriginalType: ChannelFilter`**
Stores the original filter type passed at construction (e.g., `AdHoc` for ad hoc filters). Not modifiable after construction.
- **`Type: ChannelFilter` (override)**
Returns the *effective* filter type: if `OriginalType == AdHoc`, resolves to the nearest matching CFC (or `AdHoc` if no match); otherwise returns `OriginalType`.
- **`IsCfc: bool` (override)**
Returns `true` if `Type` is neither `Unfiltered` nor `AdHoc`.
- **`CutoffFrequencyHz: double` (override)**
Returns the cutoff frequency in Hz (derived from `OriginalType` or explicitly set for ad hoc filters).
- **`IsoDescription: char`**
Returns the first character of the ISO description for `OriginalType` (e.g., `'G'` for `SixG`).
- **`Name: string` (override)**
Returns a human-readable name:
- For `AdHoc`: `"123.45Hz"`
- For CFC types: description from `DescriptionAttributeCoder<ChannelFilter>` (e.g., `"6G"`).
- **`Apply(...)` (override)**
Implements filtering using `FilterUtility`. Supports filtering from `UnfilteredData`, `UnfilteredDataEu`, or `UnfilteredDataMv` depending on `displayUnits`. Logs warnings for invalid data via `APILogger`.
- **`Parse(string serialization): Filter` (static)**
Parses a serialized filter string (e.g., `"6G"`, `"123.45Hz"`) into a `Filter` instance. Falls back to `Unfiltered` on parse failure.
- **`Equals(object obj): bool` (override)**
Case-insensitive comparison of filter names.
- **`GetHashCode(): int` (override)**
Hash code based on lowercase filter name.
- **`ToString(): string` (override)**
Returns `Name`.
- **`ToBaseString(): string` (override)**
Returns `Name`.
---
### `DefaultSaeJ211Filter` class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/ChannelDefaultSaeJ211Filter.cs`*
- **`DefaultSaeJ211Filter(SaeJ211Filter filter)`**
Copy constructor.
- **`DefaultSaeJ211Filter(ChannelFilter filterType)`**
Initializes with a CFC filter type.
- **`DefaultSaeJ211Filter(double adHocFrequency)`**
Initializes with an ad hoc frequency.
- **`Name: string` (override)**
Returns `"Default (" + base.Name + ")"` (e.g., `"Default (6G)"`).
- **`ToBaseString(): string` (override)**
Returns `base.Name` (e.g., `"6G"`).
- **`ToString(): string` (override)**
Returns `Name`.
---
### `CalculatedChannel` abstract class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs`*
- **`Operation` enum**
Defines supported calculations: `Integral`, `Derivative`, `HeadInjuryCriteria`, `FFT`, `ImportedCSV`, `Resultant`, `TSR`, `Scale`, `Offset`, `Sine`, `Cosine`.
- **`CalculationType: Operation`**
Returns the operation performed by this channel.
- **`X: double[]`, `Y: double[]`**
Read-only arrays of x-axis and y-axis data points.
- **`XAxis: XUnits`**
X-axis unit type (`msec`, `sec`, `Hz`, `samples`).
- **`XUnitsString: string`**
Human-readable unit string (e.g., `"ms"`, `"Hz"`).
- **`EngineeringUnits: string`**
Y-axis engineering units (e.g., `"g"`, `"m/s"`).
- **`SupportsADC: bool` (override)**
Always `false` for calculated channels.
- **`SupportsEU: bool` (override)**
Always `true`.
- **`SupportsmV: bool` (override)**
Always `false`.
- **`ActualMaxRangeEu`, `ActualMinRangeEu`, `DataMaxEu`, `DataMinEu`, `DataRangeEu`, `DataHalfRangeValueEu` (overrides)**
Computed from `Y` data (e.g., `DataMaxEu = _y.Max()`).
- **`IsConfigured: bool` (override)**
Always `true`; setting throws `NotSupportedException`.
- **`GetUnfilteredDataEu(): List<double>` (override)**
Returns a copy of `Y`.
- **Constructors**
- `CalculatedChannel(string name, XUnits xAxis, string yAxis, double[] xValues, double[] yValues, Operation calcType, int number, Module parentModule)`
Initializes with data, axis labels, and calculation type. Sets `CurrentFilter` to `DefaultSaeJ211Filter(ChannelFilter.Unfiltered)`.
- **`ToString(): string` (override)**
Returns `ChannelDescriptionString` or `"N/A"`.
---
### Derived `CalculatedChannel` classes
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/CalculatedChannel.cs`*
- **`FFTCalculatedChannel`**
- **`PeakFrequency: double`**
Returns the peak frequency from the FFT.
- **`IntegralCalculatedChannel`, `DerivativeCalculatedChannel`, `ScaleCalculatedChannel`, `OffsetCalculatedChannel`, `ResultantCalculatedChannel`, `AdditiveVectorCalculatedChannel`, `SineCalculatedChannel`, `CosineCalculatedChannel`**
All inherit from `CalculatedChannel` with no additional public members.
> **Note**: `HICCalculatedChannel` is commented out in source and not documented.
---
### `ReviewableAttribute.NotApplicableException` class
*Defined in: `Common/DTS.Common.Serialization/Control/Event/Module/Channel/ReviewableAttribute.NotApplicableException.cs`*
- **`NotApplicableException()`**
Default constructor.
- **`NotApplicableException(string msg)`**
Constructor with message.
- **`NotApplicableException(string msg, Exception innerEx)`**
Constructor with message and inner exception.
> Inherits from `ApplicationException`.
---
## 3. Invariants
- **`DataValues.UseMemoryMappedFile`**
Once set during construction, this flag determines the storage strategy for channel data. No runtime switching is exposed.
- **`SaeJ211Filter.OriginalType`**
Immutable after construction. `Type` may differ from `OriginalType` for ad hoc filters (resolved to nearest CFC or `AdHoc`).
- **`Filter.Type`**
For ad hoc filters (`OriginalType == AdHoc`), `Type` is computed dynamically based on `CutoffFrequencyHz` (via `ConvertFrequencyToChannelFilter`). If frequency matches a CFC enum value, `Type` becomes that CFC; otherwise remains `AdHoc`.
- **`CalculatedChannel` properties**
- `SupportsADC` and `SupportsmV` are always `false`; `SupportsEU` is always `true`.
- Range properties (`ActualMaxRangeEu`, etc.) are derived from `Y` data and may change if `Y` is modified (though `Y` is read-only via public API).
- **`Filter.Apply(...)`**
Filtering always uses `FilterUtility` with `Cfc = Type`, `AdHocFrequency = CutoffFrequencyHz`, and `SampleRate` from channel or parameter. Invalid data triggers logging and exception.
- **`Filter.Parse(...)`**
Returns `Unfiltered` filter on parse failure (not `null`).
---
## 4. Dependencies
### Internal Dependencies (from source)
- **`DTS.Common.Utilities`**
Used for `Property<T>`, logging (`APILogger`), and encoding utilities (`CfcValueAttributeCoder`, `DescriptionAttributeCoder`, `IsoDescriptionAttributeCoder`).
- **`DTS.Slice.Control.DAS.Channel`**
Referenced for `ChannelFilter` enum and `DataDisplayUnits` enum.
- **`DTS.Common.DAS.Concepts.DAS.Channel.IEngineeringUnitAware`**
Implemented by `CalculatedChannel`.
- **Serialization types**
`Serialization.SliceRaw.File.PersistentChannel`, `Serialization.TDAS.File.PersistentChannel`, `ILargeDataAware`, `Serialization.Test.Module.Channel`.
- **`DTS.Calculations.HeadInjuryCriterion.HICResult`**
Referenced in commented-out `HICCalculatedChannel` code.
- **`DTS.Common.Utilities.SaeJ211`**
Used for `FilterUtility` and related encoding.
### External Dependencies (inferred)
- **`System`**
Standard .NET types (`Exception`, `ApplicationException`, `CultureInfo`, `Enum`, etc.).
- **Windows Forms (commented)**
`System.Windows.Forms.MessageBox` appears in commented-out code (not active).
---
## 5. Gotchas
- **`DataValues` has no data storage logic**
The class only configures storage mode (`UseMemoryMappedFile`). Actual data handling is delegated to `Channel` (not shown in these files). `DataValues` is a configuration helper, not a data container.
- **`SaeJ211Filter.Type` may differ from `OriginalType`**
For ad hoc filters, `Type` resolves to the nearest CFC match. This can cause `IsCfc` to return `true` even if `OriginalType == AdHoc`.
- **`Filter.Parse(...)` silently falls back to `Unfiltered`**
On parse failure, returns `new SaeJ211Filter(ChannelFilter.Unfiltered)` instead of throwing. Callers must validate if needed.
- **`DefaultSaeJ211Filter.ToString()` vs `ToBaseString()`**
`ToString()` returns `"Default (X)"`, while `ToBaseString()` returns `"X"`. Confusing if not documented.
- **`CalculatedChannel` range properties assume non-empty `Y`**
`DataMaxEu`, `DataMinEu`, etc., use `_y.Max()`/`_y.Min()` without checking for empty data. Will throw `InvalidOperationException` if `Y` is empty.
- **`SupportsADC`/`SupportsmV` are hard-coded `false`**
Calculated channels never support raw ADC or mV; only engineering units (EU). Attempting to access `ActualMinRangeMv` throws `NotImplementedException`.
- **`CalculatedChannel` serialization methods throw `NotSupportedException`**
`FromDtsSerializationTestModuleChannel`, `ToDtsSerializationTestModuleChannel`, `SetPropertyValuesFrom(...)` all throw. Calculated channels are not serializable via these paths.
- **`Filter.Apply(...)` logs invalid data but throws**
`FilterUtility.InvalidDataDelegate` logs via `APILogger` but then throws an exception. No silent failure.
- **`ChannelFilter` enum values are used as frequencies**
CFC filters (e.g., `ChannelFilter.SixG`) are implicitly cast to `double` for frequency. This relies on enum underlying values matching CFC frequencies.
- **`IsoDescription` uses `OriginalType`**
The ISO description character is derived from `OriginalType`, not `Type`. For ad hoc filters, this may be `Unfiltered` (not meaningful).
- **`DataValues` constructor catches and rethrows as `Exception`**
Any exception during construction is wrapped in a generic `Exception` with a message like `"encountered problem constructing DTS.Slice.Control.Event.Module.Channel.DataValues"`. Original exception is preserved in `InnerException`.