Noise in Analog Circuits

The fundamental limit on small signals. Learn noise as a random signal (RMS, spectral density, bandwidth, peak-to-peak ≈ 6.6 × RMS), thermal (Johnson) noise, shot noise, flicker (1/f) noise and popcorn noise, kT/C noise in sampled circuits, op-amp e_n and i_n models, adding uncorrelated sources in RSS, input-referred noise, noise bandwidth of filters, noise figure and SNR, choosing low-noise parts for a given source impedance, and reduction by filtering, averaging and chopping — with Python building a full noise budget for an op-amp stage and integrating 1/f noise.

Every resistor and transistor generates random noise. When signals are microvolts — thermocouples, microphones, biopotentials, radio antennas — noise decides the smallest thing you can measure.

Noise analysis is bookkeeping: identify each source, refer it to the input, add powers, and multiply by bandwidth. The result tells you which component to improve.

An analogy

Noise is like the background chatter in a crowded room: every person (electron) talks randomly. You can't silence them, but you can listen in a narrow band (filtering), average what you hear over time, or move to a quieter room (lower resistance, lower temperature).

Noise sources

Physical origins:

Working with densities

Datasheets give e_n in nV/√Hz and i_n in pA/√Hz. Multiply by √(noise bandwidth) to get RMS. Uncorrelated sources add as the square root of the sum of squares, so the largest one dominates: halving a minor source achieves almost nothing. Peak-to-peak noise is conventionally 6.6 × RMS (99.9% of the time).

Matching the amplifier to the source

The optimum source resistance for an amplifier is R_opt = e_n/i_n. Low-impedance sources (dynamic microphones, strain-gauge bridges, thermocouples) need low-e_n bipolar amplifiers; high-impedance sources (piezo sensors, photodiodes, pH electrodes) need low-i_n JFET/CMOS amplifiers. Noise figure compares the amplifier's added noise with the source's own thermal noise.

Reducing noise

Limit bandwidth to what the signal needs (filters), use lower resistances in the signal path, cool critical parts, average N samples (noise drops by √N), use chopper/auto-zero amplifiers to remove 1/f noise and drift, correlated double sampling in imagers, lock-in detection for buried signals, and larger sampling capacitors in ADCs (kT/C). Separately, fight interference with shielding, grounding, differential signalling and layout.

Formulas

Worked example: Resistor noise

Given: 10 kΩ, 300 K, 10 kHz bandwidth

Find: V_rms.

Answer: ≈ 1.29 µV rms

Worked example: kT/C

Given: 1 pF sampling capacitor

Find: Noise.

Answer: ≈ 64 µV rms

Worked example: Averaging

Given: 100 samples

Find: Noise reduction.

Answer: 10× (20 dB)

Op-amp noise model

  R_s (4kTR_s)          e_n (op-amp voltage noise, in series with + input)
  ─/\/\──(~)──(~)──┬──┤+
                   i_n↓   │  ▷──┬── out
                         ┌┤−    │
                    i_n↓ ├─ R_f ┘   (each resistor has its own 4kTR source)
                         R_g
  Input-referred noise² = e_n² + (i_n R_s)² + (i_n R_f∥R_g)² + 4kT(R_s + R_f∥R_g)

Model every source, refer each to the non-inverting input, and add powers. Voltage noise dominates with low source resistances; current noise dominates with high ones — which decides whether a bipolar (low e_n) or FET (low i_n) op-amp is better.

Noise budget and 1/f integration

import math
# Noise: resistor thermal noise, op-amp noise total, 1/f region, SNR and noise figure
k, T = 1.380649e-23, 300.0
def vn_res(R): return math.sqrt(4 * k * T * R)          # V/sqrt(Hz)
for R in (50, 1e3, 1e6):
    print(f"R = {R:>9.0f} ohm: {vn_res(R)*1e9:7.2f} nV/rtHz")
# Non-inverting amp, gain 101 (Rf 100k, Rg 1k), source 1k, op-amp en 5 nV/rtHz, in 1 pA/rtHz, B = 20 kHz
en, inn, Rs, Rf, Rg, B = 5e-9, 1e-12, 1e3, 100e3, 1e3, 20e3
Rpar = Rf * Rg / (Rf + Rg)
terms = {
    "op-amp en": en,
    "in * Rs": inn * Rs,
    "in * (Rf||Rg)": inn * Rpar,
    "Rs thermal": vn_res(Rs),
    "Rf||Rg thermal": vn_res(Rpar),
}
tot = math.sqrt(sum(v**2 for v in terms.values()))
for name, v in terms.items():
    print(f"  {name:15s} {v*1e9:6.2f} nV/rtHz")
print(f"input-referred total {tot*1e9:.2f} nV/rtHz -> {tot*math.sqrt(B)*1e6:.3f} uV rms in 20 kHz -> output {tot*math.sqrt(B)*101*1e6:.1f} uV rms")
print(f"noise figure vs source 1k: {20*math.log10(tot/vn_res(Rs)):.2f} dB")
# 1/f noise: en_white 10 nV, corner 100 Hz, band 0.1 Hz - 10 Hz
e_w, fc, fl, fh = 10e-9, 100.0, 0.1, 10.0
vrms = e_w * math.sqrt(fc * math.log(fh / fl) + (fh - fl))
print(f"0.1-10 Hz noise with 100 Hz corner: {vrms*1e9:.0f} nV rms ~ {vrms*6.6*1e6:.2f} uV pp")
# R =        50 ohm:    0.91 nV/rtHz
# R =      1000 ohm:    4.07 nV/rtHz
# R =   1000000 ohm:  128.72 nV/rtHz
#   op-amp en         5.00 nV/rtHz
#   in * Rs           1.00 nV/rtHz
#   in * (Rf||Rg)     0.99 nV/rtHz
#   Rs thermal        4.07 nV/rtHz
#   Rf||Rg thermal    4.05 nV/rtHz
# input-referred total 7.74 nV/rtHz -> 1.095 uV rms in 20 kHz -> output 110.6 uV rms
# noise figure vs source 1k: 5.59 dB
# 0.1-10 Hz noise with 100 Hz corner: 217 nV rms ~ 1.43 uV pp

The 1 kΩ source alone contributes 4.07 nV/√Hz; the op-amp's 5 nV/√Hz and the feedback network's thermal noise raise the total to 7.7 nV/√Hz — a 5.6 dB noise figure. Over 20 kHz that is 1.1 µV rms at the input and 111 µV rms at the output. Lowering R_f/R_g by 10× would remove most of the feedback-network noise. In the 0.1–10 Hz band, 1/f noise (corner 100 Hz) dominates the white floor.

Common mistakes

Applications

Key takeaways

Going further