# BPF (Bandpass Filter)

> "Most market data is noise. A sliver is signal. The rest is just detailed evidence of human panic."

The **BPF** (BandPass Filter) is a second-order IIR architecture designed to surgically excise specific frequency components from a time series. By cascading a HighPass Filter (to reject trend) and a LowPass Filter (to reject noise), it isolates cyclic energy within a user-defined window. Unlike simple moving average crossovers which smear data, the BPF relies on Gaussian-based coefficients to achieve steeper roll-off with deterministic phase characteristics.

## Historical Context

In the signal processing evolution of technical analysis, early practitioners relied on generic smoothing (SMA, EMA) which dampened everything indiscriminately. John Ehlers and others introduced the concept of "spectral decomposition" to trading—filtering price data not just to smooth it, but to extract specific wave components.

The BPF represents a shift from "noise suppression" to "feature extraction." It acknowledges that markets often exhibit regime-specific periodicities (cycles). This implementation uses a 2nd-order Gaussian approximation, favored for its optimal trade-off between step response (timeliness) and frequency rejection (smoothness).

## Architecture & Physics

The filter operates as a sequential cascade, adhering to linear systems theory where order of operations is commutative (though implementation fixes the order for numerical stability).

1. **Stage 1: Detrending (HighPass)**
    The signal enters a 2nd-order HighPass filter. This stage removes "DC bias" and low-frequency drift (trends), effectively centering the oscillator around zero. It introduces specific negative feedback to nullify long-period inertia.

2. **Stage 2: Denoising (LowPass)**
    The detrended signal flows into a 2nd-order LowPass filter. This stage suppresses high-frequency jitter (quantization noise, tick bounce). It uses positive feedback to sustain momentum within the passband.

### Inertial Physics

* **Recursive Stability**: As an IIR filter, BPF has "infinite memory." A single outlier impulse ($x[t]$) decays exponentially but theoretically never reaches zero. This provides smoothness but implies that state recovery after a data gap is non-trivial.
* **Warmup Mechanics**: The filter's settling time is dominated by the longest period (`max(LowerPeriod, UpperPeriod)`). Until coefficients effectively decay the initial conditions, output is considered "cold."

## Mathematical Foundation

The coefficients are derived from Gaussian filter prototypes, ensuring critical damping.

### 1. Angular Frequencies

For a given cutoff period $P$:

$$ \lambda = \frac{\pi\sqrt{2}}{P} $$
$$ \alpha = e^{-\lambda} $$
$$ C_2 = 2\alpha\cos(\lambda) $$
$$ C_3 = -\alpha^2 $$

### 2. HighPass Stage (Detrending)

Calculated using $P = Period_{lower}$ (cutoff for low frequencies):

$$ \text{Gain}_{hp} = \frac{1 + C_{2,hp} - C_{3,hp}}{4} $$
$$ HP[t] = \text{Gain}_{hp}(x[t] - 2x[t-1] + x[t-2]) + C_{2,hp}HP[t-1] + C_{3,hp}HP[t-2] $$

### 3. LowPass Stage (Smoothing)

Calculated using $P = Period_{upper}$ (cutoff for high frequencies):

$$ \text{Gain}_{lp} = 1 - C_{2,lp} - C_{3,lp} $$
$$ BPF[t] = \text{Gain}_{lp}HP[t] + C_{2,lp}BPF[t-1] + C_{3,lp}BPF[t-2] $$

## Performance Profile

| Metric | Impact | Notes |
| :--- | :--- | :--- |
| **Throughput** | 4 ns | Measured on AVX2-enabled Core i7. O(1) ops per bar. |
| **Allocations** | 0 | Zero-allocation recursive structure. |
| **Complexity** | O(N) | Linear scan; constant state update. |
| **Accuracy** | High | 2nd-order attenuation (-12 dB/octave) outside passband. |
| **Timeliness** | Variable | Phase lag is a function of cutoff periods. |
| **Stability** | High | Poles located inside unit circle ensure convergence. |

## Validation

| Library | Status | Notes |
| :--- | :--- | :--- |
| **Pine Script** | ✅ | Ported from validated Ehlers/TradingView logic. |
| **Synthetic** | ✅ | Verified on multi-frequency sine waves; amplitude attenuation matches theory. |

## Usage

```csharp
using QuanTAlib;

// ISOLATE cycles between 10 bars (noise threshold) and 40 bars (trend threshold)
// LowerPeriod = 40 (HP cutoff: passes frequencies faster than 40)
// UpperPeriod = 10 (LP cutoff: passes frequencies slower than 10)
var bpf = new Bpf(lowerPeriod: 40, upperPeriod: 10);

// Update
var result = bpf.Update(new TValue(DateTime.UtcNow, price));

// Static Analysis (Zero Allocation)
double[] output = new double[prices.Length];
Bpf.Calculate(prices, output, 40, 10);
```
