# Holt — Double Exponential Smoothing
**Level + trend in one primitive.** Detects not just "value is high" but
"value is getting worse over time."
| Update cost | ~11 cycles |
| Memory | ~32 bytes |
| Types | `HoltF64` |
| Priming | After 2 samples (needs 2 for initial trend) |
| Output | `Option<(T, T)>` — (level, trend) |
## What It Does
```
Signal with linear uptrend:
Value
150 ┤ · · ·
130 ┤ · ·
110 ┤ · ·
90 ┤ · ·
70 ┤ · ·
└──────────────────────────────── t
Holt output:
level = smoothed current value (like EMA)
trend = +3.5 per sample (rate of increase)
forecast(10) = level + 10 × trend ← prediction
```
Two exponential smoothing equations run in parallel:
```
level = alpha × sample + (1 - alpha) × (level + trend)
trend = beta × (level - prev_level) + (1 - beta) × trend
```
## When to Use It
- "Is latency increasing over time, or just high?"
- Trend forecasting: `level + N × trend`
- Cheaper and simpler than [Kalman1D](kalman1d.md) when fixed smoothing is sufficient
## Configuration
```rust
let mut holt = HoltF64::builder()
.alpha(0.3) // level smoothing
.beta(0.1) // trend smoothing
.build().unwrap();
if let Some((level, trend)) = holt.update(sample) {
let forecast_10 = holt.forecast(10).unwrap();
if trend > 1.0 { /* getting worse */ }
}
```
| `alpha` | Level smoothing | Higher = more reactive to level changes |
| `beta` | Trend smoothing | Higher = more reactive to trend changes |
## Performance
| `HoltF64::update` | 11 cycles | 12 cycles |
Two `mul_add` operations per update. No division, no transcendentals.