# Model and Path Classes Documentation

## Overview

The **Model** and **Path** classes implement realistic HF radio channel simulation based on ITU-R and CCIR standards. They model ionospheric propagation effects including multipath, Doppler spreading, and frequency shifts.

---

## Path Class

### Purpose

The `Path` class models a single propagation path through the ionosphere, simulating the physical characteristics of one signal route from transmitter to receiver.

### Physical Model

HF radio signals travel through the ionosphere via multiple mechanisms:

#### 1. Direct Path (Ground Wave)
- **Characteristics**: Shortest path, typically strongest signal
- **Delay**: ~0 ms
- **Spread**: 0.1-0.5 Hz (minimal)
- **Attenuation**: 0-3 dB
- **Use case**: Short-range HF communication

#### 2. One-Hop Sky Wave
- **Characteristics**: Single bounce off E or F layer
- **Delay**: 0.1-2.0 ms
- **Spread**: 0.5-2.0 Hz
- **Attenuation**: 3-10 dB
- **Use case**: Medium-range HF (300-2000 km)

#### 3. Two-Hop Sky Wave
- **Characteristics**: Ionosphere → Ground → Ionosphere
- **Delay**: 2.0-10.0 ms
- **Spread**: 1.0-5.0 Hz
- **Attenuation**: 10-20 dB
- **Use case**: Long-range HF (2000+ km)

#### 4. Scatter Paths
- **Characteristics**: Off-angle scatter from irregularities
- **Delay**: Variable
- **Spread**: 5.0-20.0 Hz (highly dispersed)
- **Attenuation**: 20-40 dB (very weak)
- **Use case**: Over-the-horizon, disturbed conditions

### Signal Processing Pipeline

```
Input Signal (Complex I/Q)
    ↓
[1] Extract Delayed Samples
    ↓ (from delay line at 'delay' ms ago)
[2] Apply Doppler Offset (if configured)
    ↓ (frequency shift: multiply by e^(j·2πf·t))
[3] Apply Doppler Spreading (if configured)
    ↓ (time-varying amplitude/phase via Gaussian noise)
[4] Apply Path Gain
    ↓ (scale by linear gain factor)
[5] Accumulate to Output
    (add to output buffers)
```

### Key Parameters

#### Delay (milliseconds)
**Physical Meaning**: Time-of-arrival difference due to path length

**Formula**: `delay = (path_length - reference_length) / c`
- c = speed of light (~300,000 km/s)

**Examples**:
```
Direct path: 0.0 ms
100 km difference: 0.33 ms
500 km difference: 1.67 ms
1500 km difference: 5.0 ms
```

**Typical Ranges**:
- Direct: 0 ms
- 1-hop E-layer: 0.1-0.5 ms
- 1-hop F-layer: 0.5-2.0 ms
- 2-hop: 2.0-10.0 ms
- Multi-hop: 10+ ms

#### Doppler Spread (Hz)
**Physical Meaning**: Frequency dispersion from ionospheric turbulence

Caused by:
- Random motion of electrons in ionospheric plasma
- Turbulence and irregularities in ionization density
- Traveling ionospheric disturbances (TIDs)
- Magnetic storm effects

**Effects**:
- Creates time-varying amplitude (fading)
- Creates time-varying phase (frequency modulation)
- Produces Rayleigh fading statistics
- Spreads signal energy across frequency range

**ITU-R F.1487 Recommendations**:
```
Quiet conditions:   0.1-0.5 Hz
Moderate conditions: 0.5-2.0 Hz
Disturbed conditions: 2.0-5.0 Hz
Severe/Flutter:      5.0-20.0 Hz
```

**Typical by Latitude**:
```
Low latitude (0-30°):    0.5-2.0 Hz
Mid latitude (30-60°):   1.0-3.0 Hz
High latitude (60-90°):  2.0-10.0 Hz (more disturbed)
```

**Day vs Night**:
```
Daytime:  Lower spread (0.5-2 Hz) - more stable D-layer
Nighttime: Higher spread (1-5 Hz) - D-layer disappears
```

#### Doppler Offset (Hz)
**Physical Meaning**: Constant frequency shift from bulk ion motion

Caused by:
- Ionospheric layer moving toward/away from transmitter
- Earth's rotation effects (hundreds of m/s at ionospheric height)
- Geomagnetic field variations
- Large-scale traveling ionospheric disturbances

**Different from Spread**:
- Offset: Constant frequency translation (f₀ → f₀ + Δf)
- Spread: Frequency dispersion (f₀ → [f₀-Δf, f₀+Δf])

**Typical Values**:
```
Quiet conditions:   ±0.1-0.5 Hz
Moderate conditions: ±0.5-2.0 Hz
Disturbed conditions: ±2.0-5.0 Hz
```

**Sign Convention**:
```
Positive offset: Layer moving toward receiver (blue shift)
Negative offset: Layer moving away from receiver (red shift)
```

**Example**: E-layer velocity of 50 m/s at 14 MHz
```
Doppler offset = ±(2 × v/c) × f
                = ±(2 × 50 / 3×10⁸) × 14×10⁶
                = ±4.7 Hz
```

#### Attenuation (dB)
**Physical Meaning**: Path strength relative to strongest path

Caused by:
- D-layer absorption (day vs night, solar activity)
- Free-space path loss
- Ground reflection losses
- Ionospheric focusing/defocusing
- Off-angle scatter losses

**Typical Values by Path Type**:
```
Direct path:        0-3 dB (strongest)
Primary sky wave:   3-10 dB
Secondary sky wave: 10-20 dB
Scatter paths:      20-40 dB (very weak)
```

**Day vs Night Differences**:
```
Daytime:  Higher attenuation (5-15 dB) - D-layer absorption
Nighttime: Lower attenuation (0-5 dB) - D-layer disappears
```

### Code Examples

#### Example 1: Quiet HF Channel (Good Conditions)
```objc
// Single strong path with minimal multipath
Path *path = [[Path alloc] init];
[path setDelay:0.0];              // Direct or single-hop
[path setDopplerSpread:0.3];      // Quiet ionosphere
[path setDopplerOffset:0.2];      // Slight frequency shift
[path setAttenuation:0.0];        // Strong signal
[path setEnabled:YES];
```

#### Example 2: Moderate Two-Path Channel
```objc
// ITU-R F.1487 Moderate Conditions, Mid Latitude
Path *direct = [[Path alloc] init];
[direct setDelay:0.0];
[direct setDopplerSpread:1.0];
[direct setDopplerOffset:0.5];
[direct setAttenuation:0.0];       // Strongest path

Path *reflected = [[Path alloc] init];
[reflected setDelay:0.5];          // 0.5 ms delay
[reflected setDopplerSpread:1.5];  // Slightly more spread
[reflected setDopplerOffset:-0.3]; // Different offset
[reflected setAttenuation:6.0];    // -6 dB (half power)
```

#### Example 3: Disturbed Three-Path Channel
```objc
// CCIR 520 Poor Conditions
Path *p1 = [[Path alloc] init];
[p1 setDelay:0.0];
[p1 setDopplerSpread:2.0];
[p1 setDopplerOffset:1.0];
[p1 setAttenuation:0.0];

Path *p2 = [[Path alloc] init];
[p2 setDelay:0.7];
[p2 setDopplerSpread:3.0];         // More turbulent
[p2 setDopplerOffset:-0.8];
[p2 setAttenuation:8.0];

Path *p3 = [[Path alloc] init];
[p3 setDelay:1.5];
[p3 setDopplerSpread:5.0];         // Highly dispersed
[p3 setDopplerOffset:0.5];
[p3 setAttenuation:15.0];          // Much weaker
```

#### Example 4: Flutter Fading (Rapid Variations)
```objc
// Single path with severe Doppler spread
Path *flutter = [[Path alloc] init];
[flutter setDelay:0.3];
[flutter setDopplerSpread:10.0];   // Very high spread
[flutter setDopplerOffset:2.0];    // Significant offset
[flutter setAttenuation:5.0];
// Creates rapid fading characteristic of flutter conditions
```

### Implementation Details

#### Doppler Offset Application
The frequency offset is applied using complex multiplication:

```
output(t) = input(t) × e^(j·2π·f_offset·t)
         = input(t) × (cos(ωt) + j·sin(ωt))
```

Where:
- `ω = 2π × f_offset`
- Phase accumulator avoids repeated cos/sin lookups
- `offsetPhase += offsetDeltaPhase` each sample

**Complex Multiplication**:
```
Real:      output.re = input.re × cos(φ) - input.im × sin(φ)
Imaginary: output.im = input.re × sin(φ) + input.im × cos(φ)
```

#### Power Normalization
```
gain     = 10^(-attenuation/20)      // Linear amplitude scaling
refGain  = gain × √2                 // For power matching with I/Q
```

The √2 factor ensures:
```
Power of I/Q pair = 2 × Power of single component
Therefore: single component needs √2 scaling to match total power
```

### Performance Characteristics

**CPU Usage** (per sample):
```
Delay only:               ~1 μs
Delay + Offset:           ~3 μs
Delay + Offset + Spread:  ~5 μs
```

**Memory Usage**:
```
Path object:           ~200 bytes
offsetBuffer[512]:     ~8 KB
Spread object:         ~50 KB (if configured)
Total per path:        ~8-58 KB
```

---

## Model Class

### Purpose

The `Model` class represents a complete HF propagation channel by combining multiple `Path` instances. It manages path configuration, signal processing, and user interface.

### Architecture

```
Model
├── Path 1 (Direct)
│   ├── Delay: 0 ms
│   ├── Spread: 0.5 Hz
│   └── Gain: 0 dB
├── Path 2 (Reflected)
│   ├── Delay: 0.5 ms
│   ├── Spread: 1.0 Hz
│   └── Gain: -6 dB
└── Path N (Scatter)
    ├── Delay: 2.0 ms
    ├── Spread: 5.0 Hz
    └── Gain: -15 dB
```

### Signal Processing

#### Processing Pipeline
```
Input (Complex I/Q from Hilbert Transform)
    ↓
┌───────────────────────────────┐
│ Path 1 → Output Buffer (add) │
│ Path 2 → Output Buffer (add) │
│ Path N → Output Buffer (add) │
└───────────────────────────────┘
    ↓
Normalize I/Q by √2/N
Normalize Reference by 1/N
    ↓
Final Output
```

#### Accumulation Mode
Each path ADDS its contribution to output buffers:
```objc
// Pseudo-code
float output[512] = {0};  // Must be zeroed initially

for (Path *path in paths) {
    [path processAndAccumulate:delayline 
                          into:output 
                    quadrature:nil 
              unspreadedResult:nil 
                       samples:512];
    // output now contains sum of all paths processed so far
}

// Normalize
for (int i = 0; i < 512; i++) {
    output[i] *= sqrt(2.0) / pathCount;
}
```

#### Power Normalization

**Why √2/N for I/Q outputs?**

1. **√2 factor**: Power equivalence
   ```
   Single-sided signal x(t):  Power = E[x²]
   Analytic signal z(t):      Power = E[|z|²] = E[x² + H{x}²] = 2E[x²]
   
   To extract x(t) with correct power: scale I channel by √2
   ```

2. **1/N factor**: Path averaging
   ```
   N paths contribute independently
   Average power: divide by N
   Average amplitude: divide by √N
   ```

3. **Combined**: √2/N
   ```
   scale = √2 / N = 1.41421 / N
   ```

**Why 1/N for reference output?**
```
Reference is already real-valued (not analytic)
Only needs path averaging: divide by N
```

### Standard Models

The simulator includes ITU-R and CCIR standard models:

#### ITU-R F.1487 Models

**Format**: `ITU-R {Condition} {Latitude}`

**Quiet Conditions** (0.5 Hz spread):
```
Low Latitude:   2 paths, 0-0.5 ms delay, 0-10 dB range
Mid Latitude:   2 paths, 0-0.7 ms delay, 0-8 dB range
High Latitude:  2 paths, 0-1.0 ms delay, 0-12 dB range
```

**Moderate Conditions** (1.0 Hz spread):
```
Low Latitude:   2 paths, 0-0.7 ms delay, 0-12 dB range
Mid Latitude:   2 paths, 0-1.0 ms delay, 0-10 dB range
High Latitude:  2 paths, 0-1.5 ms delay, 0-15 dB range
```

**Disturbed Conditions** (2.0 Hz spread):
```
Low Latitude:   2-3 paths, 0-1.0 ms delay, 0-15 dB range
Mid Latitude:   2-3 paths, 0-1.5 ms delay, 0-12 dB range
High Latitude:  3 paths, 0-2.0 ms delay, 0-18 dB range
```

#### CCIR Report 520-2 Models

**Good Conditions**:
```
Paths:  1-2
Spread: 0.1-0.5 Hz
Delay:  0-0.2 ms
Range:  0-5 dB
Use:    Short-range, quiet ionosphere
```

**Moderate Conditions**:
```
Paths:  2
Spread: 0.5-2.0 Hz
Delay:  0-0.5 ms
Range:  0-10 dB
Use:    Medium-range, normal conditions
```

**Poor Conditions**:
```
Paths:  2-3
Spread: 2.0-5.0 Hz
Delay:  0-2.0 ms
Range:  0-15 dB
Use:    Long-range, disturbed ionosphere
```

**Rayleigh Fading**:
```
Paths:  1 (but with high spread)
Spread: 10+ Hz
Delay:  0 ms
Range:  N/A
Use:    Single-path severe fading
```

**Flutter**:
```
Paths:  1-2
Spread: 5-20 Hz (rapid variations)
Delay:  0-1.0 ms
Range:  0-10 dB
Use:    Auroral/polar path disturbances
```

### Code Examples

#### Example 1: Create and Use Model
```objc
// Create model
Model *model = [[Model alloc] initWithName:@"Custom 2-Path"];

// Add first path (direct)
Path *p1 = [model newPath];
[p1 setDelay:0.0];
[p1 setDopplerSpread:0.5];
[p1 setAttenuation:0.0];

// Add second path (reflected)
Path *p2 = [model newPath];
[p2 setDelay:0.5];
[p2 setDopplerSpread:1.0];
[p2 setAttenuation:6.0];

// Process signal
float inphase[512], quadrature[512];
memset(inphase, 0, sizeof(float)*512);
memset(quadrature, 0, sizeof(float)*512);

[model processDelayline:hilbert
                   into:inphase
             quadrature:quadrature
       unspreadedResult:nil
                samples:512];
```

#### Example 2: Load Preset Model
```objc
// Models are created at startup in Application.m
// Access via menu or model list

Model *ituQuiet = // ... get from model list
NSLog(@"Model: %@", [ituQuiet name]);
NSLog(@"Paths: %ld", [[ituQuiet paths] count]);

for (Path *path in [ituQuiet paths]) {
    NSLog(@"  Delay: %.2f ms", [path delay]);
    NSLog(@"  Spread: %.2f Hz", [path dopplerSpread]);
    NSLog(@"  Offset: %.2f Hz", [path dopplerOffset]);
    NSLog(@"  Atten: %.1f dB", [path attenuation]);
}
```

#### Example 3: Save Custom Model
```objc
// Create and configure model
Model *custom = [[Model alloc] initWithName:@"My Channel"];
// ... add and configure paths ...

// Export to file
[custom export:self];  // Presents save panel
// User saves as "MyChannel.model"

// Later, load from file
NSString *path = @"/path/to/MyChannel.model";
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];

Model *loaded = [[Model alloc] initWithName:@""];
[loaded importModel:dict];
```

#### Example 4: Measure SNR Using Reference Output
```objc
float output[512], reference[512];
memset(output, 0, sizeof(float)*512);
memset(reference, 0, sizeof(float)*512);

// Process with both outputs
[model processDelayline:hilbert
                   into:output
             quadrature:nil
       unspreadedResult:reference
                samples:512];

// Compute powers
float signalPower = 0, referencePower = 0;
for (int i = 0; i < 512; i++) {
    signalPower += output[i] * output[i];
    referencePower += reference[i] * reference[i];
}

// SNR in dB
float snr = 10.0 * log10(referencePower / (signalPower - referencePower + 1e-9));
NSLog(@"SNR: %.1f dB", snr);
```

### File Format

Models are saved as XML property lists (.model extension):

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
          "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Model Name</key>
    <string>My Custom Model</string>
    <key>Model Paths</key>
    <array>
        <dict>
            <key>Path Delay</key>
            <real>0.0</real>
            <key>Path Spread</key>
            <real>0.5</real>
            <key>Path Offset</key>
            <real>0.2</real>
            <key>Path Gain</key>
            <real>1.0</real>
        </dict>
        <dict>
            <key>Path Delay</key>
            <real>0.5</real>
            <key>Path Spread</key>
            <real>1.0</real>
            <key>Path Offset</key>
            <real>-0.3</real>
            <key>Path Gain</key>
            <real>0.5012</real>
        </dict>
    </array>
</dict>
</plist>
```

### Performance Characteristics

**CPU Usage** (per sample):
```
1-path model:  ~5 μs
2-path model:  ~10 μs
3-path model:  ~15 μs
N-path model:  ~5N μs
```

**Memory Usage**:
```
Model object:      ~1 KB
Path objects:      ~8-58 KB each
NIB resources:     ~50 KB
Total (3-path):    ~175 KB
```

---

## Mathematical Background

### Multipath Signal Model

The received signal r(t) in a multipath channel:

```
r(t) = Σ aₙ(t) · s(t - τₙ) · e^(j2πfₙt + φₙ(t))
       n=1..N

Where:
  aₙ(t)  = time-varying amplitude (Rayleigh fading)
  τₙ     = path delay
  fₙ     = Doppler offset
  φₙ(t)  = time-varying phase (from Doppler spread)
  s(t)   = transmitted signal
```

### Rayleigh Fading Statistics

For Doppler spread σ_D:

**Amplitude distribution**:
```
p(a) = (a/σ²) · exp(-a²/2σ²)    Rayleigh distribution
```

**Fade duration** (below threshold):
```
T_fade ≈ 1/(π · f_D · √(10^(-L/10) - 1))

Where:
  f_D = Doppler spread
  L   = fade depth in dB
```

**Level crossing rate**:
```
N_R = √(2π) · f_D · ρ · exp(-ρ²)

Where:
  ρ = R/R_rms (normalized threshold)
```

### Power Spectral Density

Classical Doppler spectrum (Jakes model):

```
S(f) = 1 / (π·f_D·√(1-(f/f_D)²))    for |f| < f_D
     = 0                             for |f| ≥ f_D

Where:
  f_D = maximum Doppler spread
```

Our implementation uses Gaussian spectrum:
```
S(f) = exp(-f²/2σ_D²)

Where:
  σ_D = Doppler spread parameter
```

---

## Common Use Cases

### 1. Testing HF Modems

```objc
// Use ITU-R standard models for modem testing
Model *moderate = // ITU-R Moderate Mid Latitude
[moderate processDelayline:hilbert into:output ...];

// Measure BER, throughput, sync time, etc.
```

### 2. Propagation Research

```objc
// Create custom models matching measured channels
Model *measured = [[Model alloc] initWithName:@"Measured Channel"];
// Configure paths from channel sounding data
```

### 3. Training and Education

```objc
// Demonstrate multipath effects
Model *twoPath = [[Model alloc] initWithName:@"Demo"];
// Show students how delay creates frequency-selective fading
```

### 4. System Design

```objc
// Test system under worst-case conditions
Model *disturbed = // ITU-R Disturbed High Latitude
// Verify system works under severe multipath
```

---

## References

### ITU-R Recommendations
- **ITU-R F.1487**: "Testing of HF modems with bandwidths of up to about 12 kHz using ionospheric channel simulators"
- **ITU-R F.1489**: "Standardized method for the characterization of ionospheric HF radio propagation channels"

### CCIR Reports
- **CCIR Report 520-2**: "Use and characteristics of ionospheric channel simulators"
- **CCIR Report 549-2**: "HF propagation prediction method"

### Scientific Papers
- W. C. Jakes, "Microwave Mobile Communications," Wiley-IEEE Press, 1974.
- A. F. Molisch, "Wireless Communications," 2nd ed., Wiley, 2010.
- P. A. Bello, "Characterization of Randomly Time-Variant Linear Channels," *IEEE Trans. Commun. Sys.*, 1963.

### HF Propagation
- K. Davies, "Ionospheric Radio," Peter Peregrinus, 1990.
- G. W. Haydon, "The Fundamentals of Packet Radio," TAPR, 1986.

---

**Last Updated**: Based on implementation analysis and ITU-R/CCIR standards
**Maintainer**: HF Channel Simulator Project  
**License**: Copyright 2008 Kok Chen, W7AY. All rights reserved.
