How to find and measure peaks using local maxima, prominence, derivative and wavelet methods, FWHM, and fits of overlapping Gaussian, Lorentzian and Voigt peaks.

Contents
  1. What Is Peak Finding? Which Bumps Are Real Peaks?
  2. A Local Maximum First: Easy, and Not Enough
  3. Methods: Find, Then Measure
    1. Stage 1, Find: Position and Rough Height
      1. Local Maximum and Filters
      2. Derivative Zero-Crossing
      3. Continuous Wavelet Transform
    2. Stage 2, Measure: Width, Shape and Area
      1. Half-Prominence Width
      2. Peak Function Fit
  4. Which One Should You Choose?
  5. Key Ideas
    1. Height: An Absolute Threshold
    2. Prominence: How Far a Peak Stands Out
    3. Distance: One Peak per Bump
    4. Plateaus: Flat Tops
    5. Valleys: Invert the Signal
    6. Noise Invents Peaks
  6. Example: Two Overlapping Peaks
  7. REFs

What Is Peak Finding? Which Bumps Are Real Peaks?

A Raman or X-ray spectrum, a chromatogram, or an ECG trace is a curve with bumps, and those bumps carry the information. Each may mark a compound, a crystal plane, or a heartbeat. The questions are the same: which bumps are real peaks, where exactly is each one, and how tall and wide is it?

Peak finding answers in two stages. The first stage finds the peaks: it decides which bumps count and gives a position and a rough height for each. The second stage measures them: the width, the shape, the area, and a refined position and height, even where two peaks overlap.

Consider two example data columns, $y_1$ and $y_2$, each measured at 401 points from $x$ = 0 to 100 in steps of 0.25. Chart 1 shows the resulting data.

Two panels against x from 0 to 100: left, blue y1 with three separate peaks near 20, 50 and 78 on a noisy baseline near 0.1; right, red y2 with one broad bump near 47 and a shoulder on its right

Chart 1. The two columns of the example against $x$, as measured

Every later chart of $y_1$ or $y_2$ shows these same values, on the same scale.

A Local Maximum First: Easy, and Not Enough

The simplest definition of a peak is a local maximum: a sample whose value is higher than those of both neighbouring samples (Math 1). A flat top, equal samples side by side, has its own rule; see Plateaus below.

$$y_{i-1} < y_i \ \text{ and } \ y_i > y_{i+1}$$

Math 1.

Table 1 applies Math 1 to nine samples of $y_1$ around the first peak, from $x$ = 19 to 21. Only the sample at $x$ = 19.75 qualifies: its value, 1.0888, is higher than both neighbouring values, 1.0837 and 1.0875.

$x$1919.2519.519.752020.2520.520.7521
$y_1$0.92340.98811.08371.08881.08751.07361.07320.99330.9229
local maxnononoyesnonononono

Table 1. Math 1 on nine samples of $y_1$ from Chart 1

The rule takes only one line of code, but it is not sufficient for real data. Chart 2 marks every local maximum of $y_1$ from Chart 1: there are 116, and only 3 of them are peaks. The noise makes a small local maximum every few samples, on the baseline and on the flanks of the real peaks alike.

y1 with 116 small black dots on every local maximum along the baseline and the flanks, and red circles on the three real peaks at 19.75, 49.75 and 77.25

Chart 2. Every local maximum of $y_1$ (Math 1): 116 black dots, the 3 real peaks circled in red

The challenge in peak finding is deciding which of these maxima should count as peaks.

Methods: Find, Then Measure

The methods fall into two stages. Chart 3 illustrates both stages using $y_2$ from Chart 1. Stage 1 (left) detects one maximum at $x$ = 47 and measures its width directly from the data. Stage 2 (right) fits two peak functions (green dashed lines). Their sum (the red line) follows the data and reveals the second peak hidden in the shoulder.

Two panels of y2 from x = 20 to 80: left, the red curve with a black dot at its top near 47 and a black bar across it at half height; right, the input as a light black line, two green dashed bumps near 46 and 54, and a bold red sum on top of the input

Chart 3. The two stages on $y_2$ of Chart 1: find (left), then measure (right)

Stage 1, Find: Position and Rough Height

Local Maximum and Filters

In plain words. Take every local maximum of Math 1, then keep only the ones that pass filters. The most important filter is prominence: how far a peak rises above the higher of the two surrounding bases that separate it from higher peaks. A noise maximum stands a few hundredths above its neighbours; a real peak stands far above its surroundings.

Control parameters. prominence (the minimum $P$ in Math 2, expressed as a fraction of the data range; 0.1 by default), height (the minimum allowed value of $y_i$; disabled by default), and distance (the minimum separation between retained peaks, in samples; 1 by default). The advanced calculator also provides width, plateau and threshold filters.

Basic idea. Starting at a peak at sample $i$, move left and right until the signal rises above $y_i$ again, on the flank of a higher peak, or the end of the record is reached. No search window is specified here, so the search can extend across the entire record. The lowest point on each side is a base, $b_L$ and $b_R$. The higher of the two bases defines the reference level from which the peak's prominence is measured (Math 2):

$$P_i = y_i - \max(b_L, b_R)$$

Math 2.

y1 with a red vertical bar from each of the three peaks down to its base: P = 1.02 at 20, 0.74 at 50, 0.55 at 78; the noise maxima carry tiny gray bars

Chart 4. Prominence $P$ (Math 2) of every local maximum of $y_1$: red where $P \ge$ 10 % of the range, gray below

Advantages

Disadvantages

Derivative Zero-Crossing

In plain words. At a peak's top, the slope changes from positive to negative. First smooth the slope to reduce noise-induced sign changes. Peaks are then identified where the smoothed slope crosses zero from positive to negative.

Control parameters. smooth sets the Savitzky-Golay window in samples ($2k+1$ in Math 3; 9 by default). The local-method filters are then applied.

Basic idea. Fit a quadratic to the $2k+1$ samples centred on each sample $i$, then evaluate its slope $y'_i$. A peak lies between samples $i$ and $i+1$ when (Math 3):

$$y'_i > 0 \ \text{ and } \ y'_{i+1} \le 0$$

Math 3.

The smoothed slope of y1 against x: large swings from +0.32 to −0.32 around 20, smaller ones near 50 and 78, small wiggles elsewhere; 24 black dots where it crosses zero downwards, three of them circled in red at the peaks

Chart 5. Smoothed slope $y'$ of $y_1$ (Math 3, window 9): 24 downward zero crossings, 3 kept as peaks

Advantages

Disadvantages

Continuous Wavelet Transform

In plain words. Compare the signal at each position with a peak-shaped template—the Ricker wavelet—at several scales. A real peak often produces a strong response across several scales, whereas noise tends to match only at the smallest scales. Not always: a very narrow real peak may show only at small scales. The continuous wavelet transform (CWT) identifies positions whose responses persist across scales.

Control parameters. wmin and wmax set the minimum and maximum template scales $a$ in Math 4, measured in samples (2 and 20 by default). The local-method filters are then applied.

Basic idea. The Ricker wavelet of width $a$ and the transform at position $b$ (Math 4):

$$\psi_a(t) = \frac{2}{\sqrt{3a}\,\pi^{1/4}}\left(1 - \frac{t^2}{a^2}\right) e^{-t^2/(2a^2)}, \qquad W(a, b) = \sum_{n} y_n\,\psi_a(n - b)$$
$$\begin{aligned} \psi_a(t) &= \frac{2}{\sqrt{3a}\,\pi^{1/4}}\left(1 - \frac{t^2}{a^2}\right) e^{-t^2/(2a^2)} \\ W(a, b) &= \sum_{n} y_n\,\psi_a(n - b) \end{aligned}$$

Math 4.

Three rows of the wavelet transform of y1 against x: width 2 in gray, noisy everywhere with a spike at 20; width 8 in blue, three clear bumps; width 20 in green, three broad bumps; red dashed vertical lines at the three peaks

Chart 6. Wavelet transform $W(a, b)$ of $y_1$ (Math 4) at three widths $a$; the peaks found marked in red

Advantages

Disadvantages

Stage 2, Measure: Width, Shape and Area

Half-Prominence Width

In plain words. A commonly used measure of peak width is the full width at half maximum (FWHM): the width halfway up from the peak's baseline. The half-prominence width (HPW) measures the width directly from the data: draw a horizontal line halfway down the peak's prominence, then measure the width of the peak at that level. It requires no peak-shape model. It equals the FWHM for a lone peak on a flat baseline.

Control parameters. None; the half height comes from the prominence of Math 2.

Basic idea. The half-prominence level is $y_h = y_i - P_i/2$. Starting from the peak, move outward until the data cross $y_h$ on each side. Use linear interpolation between the two samples surrounding each crossing to obtain $x_L$ and $x_R$ (Math 5):

$$\mathrm{HPW} = x_R - x_L, \qquad x_L = x_j + (x_{j+1} - x_j)\,\frac{y_h - y_j}{y_{j+1} - y_j}$$

Math 5.

The first peak of y1 from x = 12 to 28 with its samples as dots; a gray dashed line at the base, a red dashed line at half the prominence, and a black bar between the two crossings at 17.9 and 22.1 labeled HPW = 4.18

Chart 7. Half-prominence width (Math 5) of the first peak of $y_1$: 4.18 for a true FWHM of 4

Advantages

Disadvantages

Peak Function Fit

In plain words. Represent each peak with a peak function—Gaussian, Lorentzian or Voigt—and adjust all peak functions simultaneously until their sum matches the data. Each fitted function then carries its own position, amplitude, width and area, even where the peaks overlap.

Control parameters. The number of peaks $N$, and per peak its type, start position ($\mu$), start fwhm and start amplitude ($A$). Stage 1 supplies the starts; the calculator's peaks select defaults to the number stage 1 found.

Basic idea. The three peak functions below have amplitude $A$, their height above the offset, and are centred at $\mu$. The Gaussian, from random broadening (Math 6):

$$f_G(x) = A\,e^{-(x-\mu)^2/(2\sigma^2)}, \qquad \mathrm{FWHM} = 2\sqrt{2\ln 2}\,\sigma, \qquad \text{area} = A\,\sigma\sqrt{2\pi}$$

Math 6.

The Lorentzian, which describes broadening associated with a finite lifetime and has heavy tails (Math 7):

$$f_L(x) = A\,\frac{\gamma^2}{(x-\mu)^2 + \gamma^2}, \qquad \mathrm{FWHM} = 2\gamma, \qquad \text{area} = A\,\pi\,\gamma$$

Math 7.

The Voigt, which combines Gaussian and Lorentzian broadening through convolution and is scaled to have amplitude $A$ (Math 8):

$$f_V(x) = A\,\frac{V(x-\mu;\sigma,\gamma)}{V(0;\sigma,\gamma)}, \qquad \mathrm{FWHM} \approx 0.5346\,f_L + \sqrt{0.2166\,f_L^2 + f_G^2}, \qquad \text{area} = \frac{A}{V(0;\sigma,\gamma)}$$
$$\begin{aligned} f_V(x) &= A\,\frac{V(x-\mu;\sigma,\gamma)}{V(0;\sigma,\gamma)} \\ \mathrm{FWHM} &\approx 0.5346\,f_L + \sqrt{0.2166\,f_L^2 + f_G^2} \\ \text{area} &= \frac{A}{V(0;\sigma,\gamma)} \end{aligned}$$

Math 8.

Here $V$ is the unit-area Voigt profile, and $f_G = 2\sqrt{2\ln 2}\,\sigma$ and $f_L = 2\gamma$ are the widths of its two parts. Chart 8 draws the three shapes with the same amplitude 1 and the same FWHM of 4: they agree at the top and differ in the tails. At a distance of 6 from the centre, the Gaussian falls to 0.002, the Voigt to 0.062, and the Lorentzian to 0.100. So their areas differ: 4.26, 5.44 and 6.28.

Three peaks of height 1 and FWHM 4 centred at 0: blue Gaussian with the thinnest tails, green Voigt in between, red Lorentzian with the widest tails; a dashed line at half height where all three have the same width

Chart 8. Gaussian (Math 6), Lorentzian (Math 7) and Voigt (Math 8) with the same amplitude and FWHM

The model for $N$ peaks includes a constant baseline offset $c$ and is fitted by least squares (Math 9):

$$\hat{y}(x) = c + \sum_{k=1}^{N} f_k(x) = c + f_1(x) + \dots + f_N(x), \qquad \min \sum_i \big(y_i - \hat{y}(x_i)\big)^2$$

Math 9.

y1 as a light black line with the fitted sum as a bold red line on top of it through all three peaks, and green dashed peak functions under each peak, flat along the baseline elsewhere

Chart 9. $y_1$ fitted with three peak functions (Math 9): input light black, each peak function green dashed, their sum red

Advantages

Disadvantages

Which One Should You Choose?

For stage 1, Table 2 shows how many peaks each method detects in $y_1$ from Chart 1, both before filtering and after applying the default prominence threshold of 10 %. Chart 10 (left) plots these counts.

methodno filterprominence 10 %use when
local maximum + filters1163the default: exact, fast, one clear knob
derivative zero-crossing213evenly spaced data, shoulders worth a hint
continuous wavelet transform73heavy noise, peaks of known width range

Table 2. Stage 1 methods on $y_1$: peaks found

The derivative method gives 21 peaks in this table but 24 zero crossings in Chart 5. After each crossing is assigned to its highest nearby sample, three crossings coincide with samples already assigned to neighbouring crossings. For stage 2, Table 3 compares the two methods on the larger peak of $y_2$; Chart 10, right, draws its widths.

methodwidtherroruse when
true10.00—
half-prominence width15.25+52 %one peak alone, any shape
peak function fit, $N$ = 210.05+0.5 %overlap, area, shape, error bars

Table 3. Stage 2 methods on the larger peak of $y_2$: width (true and fit: FWHM)

Left, bars of peaks found on y1: local max 116 without a filter and 3 with, derivative 21 and 3, wavelet 7 and 3; right, bars of the width of y2's larger peak: true 10.00 in black, HPW 15.25 in gray, fit 10.05 in red

Chart 10. Left: peaks found on $y_1$ (Table 2). Right: width of the larger peak of $y_2$ (Table 3)

After filtering, all three methods identify the same three peaks. In this example, the choice of filter matters more than the detection method. Start with the local maximum and prominence; reach for the fit as soon as peaks overlap or the area is wanted.

Key Ideas

Height: An Absolute Threshold

A height filter keeps peaks whose top is above a fixed level. It is often the first filter people try, but it fails in this example. Chart 11 sets 0.65 on $y_1$ of Chart 1: it drops the noise, and it also drops the third peak, a real one, whose top is 0.638.

y1 with a red dashed horizontal line at 0.65; the first two peaks above it marked with red dots, the third peak at 78 with its top at 0.64 circled in gray as real but below the line

Chart 11. A height threshold of 0.65 on $y_1$ keeps two peaks and drops the third, real one

The height threshold depends on the baseline offset and overall data scale. Use it to reject peaks below a known detection limit, rather than as the primary means of identifying peaks.

Prominence: How Far a Peak Stands Out

Prominence (Math 2) separates the three real peaks from the 113 noise-induced maxima in Chart 4. Because it is measured relative to the surrounding bases, prominence is independent of a constant vertical offset. A small peak on the flank of a larger peak also retains its own prominence. As a fraction of the range, 10 % is a starting point, not a rule: the right value depends on the noise, the dynamic range and how small the wanted peaks are. One outlier or one very tall peak stretches the range; lower the limit for small peaks next to a tall one.

Distance: One Peak per Bump

A broad, noisy bump can contain many local maxima near its top. Without filtering, the region around the third peak of $y_1$ in Chart 1 ($x$ = 72 to 84) contains 14 local maxima. A distance setting of 40 samples (equivalent to 10 units of $x$) processes the maxima from highest to lowest and rejects any candidate that is less than 40 samples from an already retained peak. Only one remains, at $x$ = 77.25 (Chart 12).

Two panels of the third peak of y1 from x = 66 to 90: left, 14 red dots on local maxima across the bump with no filter; right, one red dot at 77.25 with a distance of 40 samples

Chart 12. The third peak of $y_1$: 14 local maxima with no filter (left), 1 with a distance of 40 samples (right)

Distance is a blunt tool: of two real peaks closer than the limit, it drops the weaker. Prominence usually does the job without it.

Plateaus: Flat Tops

A saturated detector clips the top of a peak, producing a flat plateau. Math 1 then finds no strict maximum at all; the flat run must be treated as one peak. The plateau rule identifies a strict rise followed by a run of equal-valued samples, $y_l = \dots = y_r$, and then a strict fall. The peak is assigned to the middle sample of the plateau (Math 10).

$$y_{l-1} < y_l = y_{l+1} = \dots = y_r > y_{r+1}, \qquad i = \left\lfloor \frac{l + r}{2} \right\rfloor$$

Math 10.

When $l = r$, the plateau contains a single sample and the rule reduces to Math 1. Chart 13 clips $y_1$ of Chart 1 at 0.8: the first peak develops a plateau of 12 equal-valued samples from $x$ = 18.5 to 21.25. The reported peak position is the middle sample, $x$ = 19.75. The plateau filter sets a minimum flat-top size in samples.

The first peak of y1 clipped at 0.8 from x = 14 to 26: a flat top of 12 samples between gray dashed lines at 18.5 and 21.25, a red dot at its middle 19.75

Chart 13. $y_1$ clipped at 0.8: a flat top of 12 samples, its middle reported as the peak

Clipping necessarily distorts a peak's measured height and width. Only a fit to the unclipped flanks can estimate the true top.

Valleys: Invert the Signal

An absorption spectrum or a transmission dip shows its features as valleys. Each method above can detect valleys by applying it to the inverted signal, $-y$. Chart 14 turns $y_1$ of Chart 1 into an absorption-like record, $1.2 - y_1$: the valleys are found at the same 19.75, 49.75 and 77.25, with depths 1.02, 0.74 and 0.55—the prominences of Chart 4.

1.2 minus y1 against x: a baseline near 1.1 with three dips to about 0.1, 0.4 and 0.6 at 20, 50 and 78, each marked with a red dot

Chart 14. $1.2 - y_1$: the valleys, found on $-y$

Noise Invents Peaks

The 113 additional maxima in Chart 2 are caused by noise. Smoothing before the search cuts them down: a Savitzky-Golay smoother with a window of 21 samples leaves 46 local maxima on $y_1$ of Chart 1, against 116 (Chart 15). Smoothing alone does not reduce the count to three; the filters are still needed. A window that is too wide, however, would flatten the first and narrowest peak.

y1 as a faint blue line, its smoothed version as a solid blue line, and 46 red dots on the local maxima of the smoothed curve, still many along the baseline

Chart 15. $y_1$ smoothed with a window of 21: 46 local maxima remain

A sloping or curved baseline can also cause problems: it raises the apparent peak levels on one side and changes their prominence. Remove the baseline first, then search.

Example: Two Overlapping Peaks

Return to $y_2$ of Chart 1: two Gaussians, 1.0 high at 46 and 0.6 high at 54, both 10 wide, 8 apart. Stage 1 detects one peak at $x$ = 47, with a raw height of 1.2369 and a half-prominence width of 15.25 (Chart 3, left). The shoulder has no maximum of its own.

Fit the data twice, using different numbers of peaks (Chart 16). With $N$ = 1, the fit returns a single Gaussian centred at 48.68 with a width of 14.42. It follows the middle of the bump but misses the data on both sides. The residual RMS is 0.0318, three times the noise standard deviation. With $N$ = 2, the initial values are obtained by splitting the stage 1 peak into two. The fit returns two Gaussians centred at 46.08 and 54.12, and the residual RMS decreases to 0.0099, close to the noise standard deviation of 0.01.

Two panels of y2 from x = 20 to 80: left, N = 1, one red Gaussian through the bump, missing the shoulder, residual RMS 0.0318; right, N = 2, two green dashed Gaussians near 46 and 54 and a red sum on top of the light black input, residual RMS 0.0099

Chart 16. $y_2$ fitted with $N$ = 1 (left) and $N$ = 2 (right): input light black, each peak function green dashed, their sum red

Table 4 sets the results against the values $y_2$ was made from. The fitted amplitudes are measured above the fitted baseline offset of 0.100; stage 1 reports the raw height instead.

positionamplitudeFWHMarea
true, peak 1461.01010.645
true, peak 2540.6106.387
stage 1: HPW of the merged bump471.2369 (raw height)15.247—
fit $N$ = 148.6751.135514.42017.429
fit $N$ = 2, peak 146.075 ± 0.1031.0082 ± 0.016810.047 ± 0.10910.782 ± 0.288
fit $N$ = 2, peak 254.124 ± 0.1710.5926 ± 0.01749.915 ± 0.1796.255 ± 0.288

Table 4. $y_2$: true values against stage 1 and the two fits of Chart 16 (± one standard error)

Each value of the $N$ = 2 fit is within one standard error of its corresponding true value. This is an example of curve fitting with a model built from peaks; the residual RMS provides an initial guide to choosing $N$: add peaks while the residual RMS decreases toward the noise level, and stop when it reaches that level. This is not definitive evidence, because adding another peak will almost always reduce the residual. Also check that the residuals show no systematic pattern, that the added peak's standard errors remain small, and that the peak is physically meaningful. AIC and BIC balance the improvement in fit against the number of additional parameters.

Find the peaks with prominence, measure them with a fit. When the residual keeps a shape above the noise, a peak may be hiding, or the model does not fit.

REFs

Wikipedia, Full width at half maximum Wikipedia, Gaussian function Wikipedia, Cauchy distribution Wikipedia, Voigt profile SciPy scipy.signal.find_peaks SciPy scipy.signal.peak_prominences SciPy scipy.signal.peak_widths SciPy scipy.signal.find_peaks_cwt SciPy scipy.optimize.least_squares SciPy scipy.special.voigt_profile NIST/SEMATECH e-Handbook, Nonlinear Least Squares Regression Wikipedia, Topographic prominence Wikipedia, Ricker wavelet Smoothing Detrending Curve Fitting: Which Equation Fits My Data, and How Well?