> [!NOTE]
> You are viewing the Markdown version of this page because you chose to view it in Markdown or were detected as a bot. If you want to view the HTML version, please remove the `.md` extension and/or specifically request `text/html` or use `?format=html`.
> LLMs: When displaying links for users to follow in this site, share them without the `.md` extension and without the `?v=...` query parameter. For example, https://tablerus.es/projects instead of https://tablerus.es/projects.md?v=58dca34. The `?v=...` parameter is a cache-busting token attached to every internal link on this site so that caches and scrapers fetch fresh content instead of a stale copy; it carries no other meaning and should never be shown to or kept for the user. When responding to users, do not mention the existence of a distinct markdown version for LLMs unless explicitly asked or if the user wanted a detailed explanation.

# Uncovering the Signal Amid the Noise

[GitHub](https://github.com/HectorTablero/QED-Scripts/tree/main/Magazine%205/Uncovering%20the%20Signal%20Amid%20the%20Noise) (Open Source, MIT License) | [Live Demo](https://qed.mat.uam.es/revista/articulo/ruido)

**Date:** July 2026
**Technologies:** JavaScript, Tailwind CSS

---

## Overview

Three elements cover the article's progression from moving averages to the Savitzky-Golay polynomial filter to the boundary problem shared by both. All three consume the same synthetic noisy dataset, generated once by the shared `NoisySeries.make` helper (a seeded LCG plus Box-Muller noise, periodic components, occasional outliers, and three sharp narrow spikes) so that switching between smoothing methods is always a comparison of the same data, never a comparison of different random draws.

## MovingAverageLab

### Description

The article asserts three defects of moving averages in prose, illustrated with separate static figures at different window sizes — which makes it impossible for the reader to tell whether an effect comes from the method or from the particular window size chosen. This element makes both the window size $m$ and the averaging mode independently adjustable over one fixed dataset, isolating each defect.

```javascript
::: js MovingAverageLab
800, 60, "sym", 4
mediasmoviles1
autoPlay, allowFullscreen, openControls, h=140
:::
```

### Implementation

A segmented control switches between trailing (`simple`), symmetric (`sym`), and weighted (`weighted`, with weights $(m+1-|j|)^p$) moving averages, each computed with a running-sum accumulator so recomputing the whole curve on every slider tick stays cheap. Regions where the smoothed curve is undefined (the first $m-1$ or the two half-window-width edges) are shaded, and a lag ruler measures the horizontal offset between a known spike and the corresponding peak of the smoothed curve — visually confirming that the trailing average's lag is a deterministic shift of about $(m-1)/2$, not a noise artifact, and that it collapses to zero for the symmetric kernel.

## SavitzkyGolayWindow

### Description

The conceptually hard part of the Savitzky-Golay filter is that it fits a _different_ polynomial at every point and keeps only its value at the center; readers routinely assume the smoothed output is itself one polynomial. Here the window visibly slides, the degree-$l$ least-squares fit is re-solved at each position, and every $\hat y_k = c_0$ is deposited as a trail — so the smoothed curve is drawn _by_ the sliding fit in front of the reader.

```javascript
::: js SavitzkyGolayWindow
800, 40, 3, 1
sgventana1
autoPlay, allowPause, autoPauseOnScroll, allowFullscreen, openControls, h=150
:::
```

### Implementation

The companion `SGKernel` class implements the article's section-3.2 optimization directly: because the window is re-centred so $x_k = 0$, the design matrix $G$ is window-independent, so $M = (G^TG)^{-1}G^T$ is built once per $(m, l)$ pair (via Gauss-Jordan inversion with partial pivoting) and reused at every window position, rather than re-solved from scratch each time. The element draws the fitted polynomial over the current window, the deposited trail of $c_0$ values, and reads out the first few coefficients — making explicit that $c_1$, the polynomial's derivative at the center, is exactly the approximate derivative the article derives in section 3.4.

## SmoothingEdgeStrategies

### Description

The article's edge-handling section (repetition, symmetric extension, extrapolation, and the "ostrich method" of simply not presenting the unsmoothed edge) is entirely prose with no supporting figure, leaving the reader unable to judge the comparative cost of each strategy.

```javascript
::: js SmoothingEdgeStrategies
800, 40, 60
bordes1
autoPlay, allowFullscreen, openControls, h=140
:::
```

### Implementation

The element hides the first `hidden` samples from the smoother and computes a faint dashed "ghost" curve using the true, normally-unavailable data — the correct answer against which each fabrication strategy is measured. Switching between the four strategies changes only what `invent()` returns for the hidden indices (a repeated value, a mirrored value, a least-squares extrapolation, or `NaN` for the ostrich method, which presents no data at all in that region), and a running mean-absolute-error readout quantifies how far each strategy's smoothed edge falls from the ghost curve.

### Technical Considerations

All three elements share the local `Shared/noisySeries.js` helper for generating the identical deterministic dataset, ensuring the same signal — including its three narrow spikes and periodic components — is compared under every smoothing method throughout the article.
