220 lines
12 KiB
Markdown
220 lines
12 KiB
Markdown
---
|
|
source_files:
|
|
- DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.Graph/Model/TestDataSeries.cs
|
|
- DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.Graph/Model/TestDataSeriesModel.cs
|
|
generated_at: "2026-04-16T11:14:33.699820+00:00"
|
|
model: "zai-org/GLM-5-FP8"
|
|
schema_version: 1
|
|
sha256: "1630e6f30be700ba"
|
|
---
|
|
|
|
# Documentation: DTS.Viewer.Graph Module - Data Series Models
|
|
|
|
## 1. Purpose
|
|
|
|
This module provides the data models for representing and transforming test channel data into graphable series within the DTS Viewer application. `TestDataSeries` serves as the primary data transfer object holding X/Y values, metadata, and computed statistics for a single graphable channel. `TestDataSeriesModel` acts as a factory/processor that transforms raw `ITestChannel` data into `TestDataSeries` objects, handling time-series, FFT (Fast Fourier Transform), and PSD (Power Spectral Density) conversions with optional filtering and windowing. Together, they bridge the gap between raw binary sensor data and the visualization layer.
|
|
|
|
---
|
|
|
|
## 2. Public Interface
|
|
|
|
### TestDataSeries Class
|
|
|
|
**Namespace:** `DTS.Viewer.Graph.Model`
|
|
**Inherits:** `Common.Base.BasePropertyChanged`
|
|
**Implements:** `ITestDataSeries`
|
|
|
|
#### Properties
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `HIC` | `bool` | Indicates if Head Injury Criteria data is present. |
|
|
| `HICValue` | `string` | Formatted HIC value. |
|
|
| `T1Time`, `T2Time` | `string` | T1/T2 timestamp strings for HIC calculations. |
|
|
| `TestGroup` | `string` | Group identifier for the test. |
|
|
| `TestId` | `string` | Unique test identifier. |
|
|
| `TestSetupName` | `string` | Name of the test setup configuration. |
|
|
| `ChannelId` | `string` | Channel identifier. |
|
|
| `Xvalue` | `double[]` | Array of X-axis values (time or frequency). |
|
|
| `Yvalue` | `double[]` | Array of Y-axis values (amplitude, magnitude, or PSD). |
|
|
| `GraphColor` | `Brush` | WPF brush for graph rendering; getter creates new `SolidColorBrush` from internal `byte[]`. |
|
|
| `HardwareChannel` | `string` | Hardware channel name (auto-property). |
|
|
| `GroupName` | `string` | Channel group name (auto-property). |
|
|
| `SWAAF` | `string` | Software anti-aliasing filter setting (auto-property). |
|
|
| `Bridge` | `string` | Bridge type identifier (auto-property). |
|
|
| `HWAAF` | `string` | Hardware anti-aliasing filter rate (auto-property). |
|
|
| `SampleRate` | `string` | Sample rate in Hz (auto-property). |
|
|
| `ISOCode`, `ISOChannelName` | `string` | ISO-related identifiers (auto-properties). |
|
|
| `UserCode`, `UserChannelName` | `string` | User-defined identifiers (auto-properties). |
|
|
| `ChannelName`, `Description` | `string` | Channel naming and description (auto-properties). |
|
|
| `SensorSN` | `string` | Sensor serial number (auto-property). |
|
|
| `SensorSNDisplay` | `string` | Display-friendly serial number; returns `"N/A"` if test-specific embedded per `SensorConstants.IsTestSpecificEmbedded()`. |
|
|
| `EngineeringUnits` | `string` | Engineering units string (auto-property). |
|
|
| `Excitation` | `string` | Excitation voltage (auto-property). |
|
|
| `Polarity` | `string` | Sensor polarity (auto-property). |
|
|
| `MinY`, `MaxY`, `AvgY`, `StdDevY` | `string` | Statistical values; default to `Strings.Table_NA`. |
|
|
| `PeakMagnitude` | `double` | Peak magnitude for FFT data; default `0`. |
|
|
| `PeakFrequency` | `double` | Frequency of peak magnitude; default `0`. |
|
|
| `GRMS` | `double` | Root-mean-squared acceleration for PSD; default `0`. |
|
|
| `FFT` | `bool` | Indicates if series contains FFT/PSD data; default `false`. |
|
|
| `T0EUValue` | `string` | T0 value string; default empty. |
|
|
| `RecordingMode` | `string` | Recording mode description (auto-property). |
|
|
| `IsSaved` | `bool` | Read-only auto-property (getter only). |
|
|
|
|
#### Methods
|
|
|
|
```csharp
|
|
public void SetStatsFromYValues()
|
|
```
|
|
Sets `AvgY`, `StdDevY`, `MinY`, `MaxY`, `T0EUValue` from internal `Yvalue` array. Formats using `"G5"` format string.
|
|
|
|
```csharp
|
|
public void SetStatsFromYValues(double[] values)
|
|
```
|
|
Overload that accepts an external `double[]` array. Handles null/empty arrays by setting all stats to `NaN` (displayed as `Table_NA`).
|
|
|
|
```csharp
|
|
public void SetStatsFromChannel(ITestChannel channel)
|
|
```
|
|
Copies pre-calculated statistics from an `ITestChannel` instance using `channel.MinY`, `channel.MaxY`, `channel.AveY`, `channel.StdDevY`, `channel.T0Value`.
|
|
|
|
---
|
|
|
|
### TestDataSeriesModel Class
|
|
|
|
**Namespace:** `DTS.Viewer.Graph`
|
|
**Implements:** `IBaseModel`
|
|
|
|
#### Properties
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `Parent` | `IGraphViewModel` | Parent view model reference. |
|
|
| `_eventAggregator` | `IEventAggregator` | Prism event aggregator for publishing progress events. |
|
|
| `ErrorMessage` | `string` | Error message string with property change notification. |
|
|
| `IsSaved` | `bool` | Read-only auto-property. |
|
|
|
|
#### Methods
|
|
|
|
```csharp
|
|
public Task<ITestDataSeries> GetTestDataAsync(ITestChannel channel, IChartOptionsModel chartOptions, bool bVolts, IPSDReportSettingsModel psdSettings = null)
|
|
```
|
|
Async wrapper returning `GetTestData()`. **Warning:** Lacks `await` operators (runs synchronously per compiler warning suppression).
|
|
|
|
```csharp
|
|
public Task<List<ITestDataSeries>> GetTestDataAsync(List<ITestChannel> channels, IChartOptionsModel chartOptions, bool bVolts, IPSDReportSettingsModel psdSettings = null)
|
|
```
|
|
Async wrapper for batch channel processing. Catches `OutOfDataException` and re-throws with context. Optionally adds envelope channel if `psdSettings.ShowEnvelope` is true.
|
|
|
|
```csharp
|
|
public List<ITestDataSeries> GetTestData(List<ITestChannel> channels, IChartOptionsModel chartOptions, bool bVolts, IPSDReportSettingsModel psdSettings = null)
|
|
```
|
|
Synchronous batch processing. Maps each channel through `GetTestData()`. Handles `OutOfDataException` with sample index context.
|
|
|
|
```csharp
|
|
public ITestDataSeries GetTestData(ITestChannel channel, IChartOptionsModel chartOptions, bool bVolts, IPSDReportSettingsModel psdSettings = null)
|
|
```
|
|
Returns `AddTestChannelToChart()` result.
|
|
|
|
```csharp
|
|
public TestDataSeries AddTestChannelToChart(ITestChannel channel, IChartOptionsModel chartOptions, bool bVolts, IPSDReportSettingsModel psdSettings = null)
|
|
```
|
|
**Primary processing method.** Reads binary channel data via `Serialization.SliceRaw.File.Reader.ReadChannelsBinaryData()`, then branches based on `chartOptions.UnitType`:
|
|
- **FFT mode** (`ChartUnitTypeEnum.FFT` with `psdSettings == null`): Sets `FFT = true`, populates `PeakFrequency`, `PeakMagnitude`, calculates stats.
|
|
- **Regular time-series** (`psdSettings == null`): Handles HIC data if present, applies time unit multiplier, copies stats from channel.
|
|
- **PSD mode** (`psdSettings != null`): Trims data to selected range, applies optional low/high pass filters, computes PSD via `FftSharp.Transform.PSD_Welch()`, calculates GRMS.
|
|
|
|
Returns `null` if `channel.ErrorMessage` is not empty.
|
|
|
|
```csharp
|
|
private ITestDataSeries GetEnvelopeChannel(List<ITestDataSeries> data)
|
|
```
|
|
Creates a synthetic "envelope" series by taking the maximum Y-value at each frequency index across all input series. Sets `FFT = true`, color to black.
|
|
|
|
```csharp
|
|
private double CalculateGRMS(double[] freq, double[] psd)
|
|
```
|
|
Calculates Grms using numerical integration of PSD. Uses logarithmic interpolation formula; handles `N = -1` edge case separately. Returns `Math.Sqrt(aRMS.Sum())`.
|
|
|
|
---
|
|
|
|
## 3. Invariants
|
|
|
|
1. **Array Length Consistency**: `Xvalue` and `Yvalue` arrays should have matching lengths after processing by `TestDataSeriesModel`.
|
|
|
|
2. **FFT Flag Consistency**: When `FFT == true`, `Xvalue` represents frequency (Hz) and `Yvalue` represents magnitude or PSD. When `FFT == false`, `Xvalue` represents time.
|
|
|
|
3. **Statistics Default**: `MinY`, `MaxY`, `AvgY` default to `Strings.Table_NA` (not null or empty string).
|
|
|
|
4. **GraphColor Thread Safety**: `GraphColor` getter creates a new `SolidColorBrush` on each call; the underlying color data is stored as `byte[] _graphColorARGB` to ensure thread safety (per comment referencing issue #34455).
|
|
|
|
5. **FFT/PSD Filter Bypass**: When `chartOptions.UnitType` is `FFT` or `PSD`, `channel.SoftwareFilter` is forcibly set to `"none"` before reading data.
|
|
|
|
6. **PSD Data Length**: PSD calculations require input length to be an even power of 2; `Utils.GetEnclosingPower2()` is used to resize the array with zero-padding if necessary.
|
|
|
|
7. **HIC Validity**: `HIC` is only set to `true` when `channel.HIC != 0` AND `channel.T2Sample > 0`.
|
|
|
|
---
|
|
|
|
## 4. Dependencies
|
|
|
|
### TestDataSeries Dependencies
|
|
|
|
**External Dependencies:**
|
|
- `System.Windows.Media` - `Brush`, `SolidColorBrush`, `Color`, `Colors`
|
|
- `DTS.Common.Enums.Sensors` - `SensorConstants` for serial number validation
|
|
- `DTS.Common.Interface` - `ITestDataSeries` interface
|
|
- `DTS.Common.Strings` - Localized string constants (`Table_NA`)
|
|
- `DTS.Common.Base` - `BasePropertyChanged` for INPC implementation
|
|
|
|
**Dependents (Inferred):**
|
|
- `TestDataSeriesModel` - Primary consumer/factory
|
|
- Graph view models and charting components (via `ITestDataSeries`)
|
|
|
|
### TestDataSeriesModel Dependencies
|
|
|
|
**External Dependencies:**
|
|
- `System.Windows.Media` - Color types
|
|
- `Prism.Events` - `IEventAggregator` for event publishing
|
|
- `FftSharp` - FFT/PSD transforms (`Transform.PSD_Welch`, `Transform.FFTfreq`, `WindowType`, `WindowAveragingType`)
|
|
- `Exocortex.DSP` - `PassFilter.LowPass`/`HighPass` filtering
|
|
|
|
**Internal Dependencies:**
|
|
- `DTS.Common.Interface` - `ITestChannel`, `ITestDataSeries`, `IGraphViewModel`, `IChartOptionsModel`, `IPSDReportSettingsModel`, `IBaseModel`
|
|
- `DTS.Common.Enums.Viewer` - `ChartUnitTypeEnum`, `TimeUnitTypeEnum`, `Reports.WindowType`, `Reports.WindowAveragingType`
|
|
- `DTS.Common.Enums.Sensors` - `SensorConstants.BridgeType.DigitalInput`
|
|
- `DTS.Common.Enums.DASFactory` - `DFConstantsAndEnums.RecordingMode`
|
|
- `DTS.Common.Converters` - `EnumDescriptionTypeConverter`
|
|
- `DTS.Common.Exceptions` - `OutOfDataException`
|
|
- `DTS.Common.Events` - `GraphChannelReadCalcProgressChangedEvent`, `GraphChannelReadCalcProgressChangedEventArgs`
|
|
- `DTS.Common.Utilities.Logging` - `APILogger`
|
|
- `DTS.Common.Utils` - `Utils.GetEnclosingPower2()`
|
|
- `DTS.Common.Strings` - Localized strings
|
|
- `Serialization.SliceRaw.File.Reader` - `ReadChannelsBinaryData()` for binary data deserialization
|
|
- `ChannelFilter` - `AdHoc` filter constant
|
|
|
|
**Dependents (Inferred):**
|
|
- Graph view models implementing `IGraphViewModel`
|
|
- PSD report generation components
|
|
|
|
---
|
|
|
|
## 5. Gotchas
|
|
|
|
1. **Async Methods Are Not Truly Async**: Both `GetTestDataAsync` overloads have suppressed compiler warning CS1998 and run synchronously. The `async` keyword is misleading—these methods will block the calling thread.
|
|
|
|
2. **GraphColor Getter Allocates on Every Call**: The `GraphColor` property getter instantiates a new `SolidColorBrush` on every access. Frequent access in UI binding scenarios could cause unnecessary allocations.
|
|
|
|
3. **PSD Frequency Array Mutation**: In PSD processing, `freq[0] = 1` forcibly sets the first frequency bin to 1 Hz, potentially overwriting the actual DC component value from `FftSharp.Transform.FFTfreq()`.
|
|
|
|
4. **CalculateStdDev Uses Population Formula Incorrectly**: The method divides by `(values.Length - 1)` (sample standard deviation) but does not check for single-element arrays, which would cause division by zero.
|
|
|
|
5. **T0EUValue Naming Is Misleading**: Per the source comment: *"this is the T0 value regardless of units ... it's not really EU but since it's already in use I'm not going to change it"* — historical naming debt.
|
|
|
|
6. **Envelope Channel Returns Empty Series on Null Input**: `GetEnvelopeChannel()` returns a default `TestDataSeries()` if input list is null or empty, rather than returning null or throwing.
|
|
|
|
7. **IEPE Bridge Hardcoded**: The constant `IEPE_BRIDGE = "IEPE"` is used for special-casing excitation display, but the value is not sourced from a shared constant.
|
|
|
|
8. **Digital Channel Detection Uses String Prefix**: `channel.Bridge.StartsWith(SensorConstants.BridgeType.DigitalInput.ToString())` relies on string matching rather than enum comparison.
|
|
|
|
9. **GRMS Calculation Has Index Bounds Check**: The loop condition `i < psd.Length - 2 && i < freq.Length - 2` skips the last two elements, which is correct for the pairwise calculation but may silently drop data if arrays have different lengths. |