This web page is a divertissement. For fun, we took configurations close to those of our lab and used them to simulate some typical DDM experiments in your browser. The simulations are simple (for example, the particles do not interact) and rely on many approximations. Found something wrong or not working? Please let us know through the contact page.

Differential dynamic microscopy

Sizing particles from how they move

Particles in a liquid jiggle because the molecules around them keep kicking them, and small particles jiggle faster than large ones. Differential dynamic microscopy (DDM) measures this motion from an ordinary microscope movie without following any single particle, so it works even when the particles are too small, too faint or too crowded to be followed one by one. From how fast they wander follows their size: the same principle as dynamic light scattering (DLS), but with a microscope, many scattering angles at once, and in samples where DLS struggles (turbid or fluorescent ones, or a drop too small for a cuvette). Particle sizing is one use of DDM among many (see "Beyond sizing" below). Here a simulated microscope lets you run the whole analysis yourself, from the raw movie to a particle size.

How deep do you want to go?
Simulating the movie...
Live simulated bright-field movie

Hands on

The bench

Change the sample, the microscope or the camera with the controls (on the left, or just below on a phone). The movie is recorded again and every step below updates. A run takes from a few seconds to about a minute, because every particle is imaged through a detailed model of the microscope's optics.

1

Set up the microscope

The microscope sees a round field 25 mm across in its image plane. A camera chip covers a rectangle in it, and you choose which part of the chip to read out: a smaller region can be read faster. A point-scanning confocal instead sweeps a laser spot over a square, line by line.

How one particle looks

The math: how each image is computed

Bright field. The condenser fills its aperture with mutually incoherent plane waves (spatial coherence) at the wavelengths of the lamp spectrum (temporal coherence). For each of them, the light scattered by the sphere, computed exactly with Mie theory from the particle and liquid refractive indices, interferes with the transmitted light after passing the objective pupil. The intensities are then added. The same formula covers the other transmitted-light methods by changing the illumination and the pupil: phase contrast lights the sample through a thin annulus and gives the objective pupil a ring that dims the direct light and shifts its phase by a quarter wave; dark field uses illumination steeper than the objective can collect, so only the |Es|2 term is left; DIC multiplies the pupil by i sin((κ·s + φ)/2), with s the shear and φ the bias, so the image depends on the direction of q. For a particle at distance z from focus, the Fourier transform of its image is

K(q, z) = ⟨ −(2π/k) P(κ)P(κ+q) S(θ) ei(kz(κ) − kz(κ+q))z / kz + c.c.(−q) ⟩source, λ + |Es|2 term

with S = (S1 + S2)/2 the Mie amplitude at the scattering angle θ and P the pupil with aplanatic apodization. At q = 0 the interference term equals minus the extinction cross-section (optical theorem), which the code checks.

Fluorescence. Emission is incoherent: the image is the dyed sphere convolved with the Debye point spread function (scalar, or vector at high NA). Confocal (spinning disk or point scanning): excitation spread times emission spread convolved with the pinhole projected on the sample; cross-talk between the disk pinholes is neglected.

Movie. Dilute particles diffuse in 3D (Stokes-Einstein, reflecting walls); each frame is the sum of their images, recorded with the detector's pixel size, quantum efficiency, shot noise, read noise and full well. Each particle is imaged when its row is exposed (rolling shutters) or scanned (point scanners). Included: spherical aberration from focusing into the liquid; optionally vector (high-NA) optics, settling under gravity and slower translation near the glass. Neglected: multiple scattering, interference between light scattered by different particles, other aberrations (for example a wrong cover-glass thickness), polarizers acting on rods and ellipsoids beyond the paraxial approximation, imperfect DIC prisms, stray light in dark field other than a fixed share of the illumination, slower rotation near the glass.

Particles that turn. Each particle carries an axis u that diffuses on the sphere (rotational diffusion DR), and moves with D∥ along it and D⊥ across it in its own frame (Perrin's formulas for ellipsoids, Tirado and Garcia de la Torre for rods). Its polarizability is a tensor α = α⊥ I + (α∥ − α⊥) u u, from the material's birefringence and from the shape. With a polarizer along eP and an analyzer along eA, the interference term is weighted by (eA·eP)(eA·α·eP) and the scattered intensity by |eA·α·eP|2. Spheres keep their exact Mie field, scaled by these weights. Rods and ellipsoids are filled with small scatterers (Rayleigh-Gans), which also gives their shape in the image; in the scattered intensity the shape sets a tilt-dependent brightness ⟨|F(Q)|2⟩ over the illumination and collection angles.

Checked against miepython (amplitudes to 1e-10), the optical theorem, a brute-force sum over 3000 source points, and the amplitude formula of fastDDM tutorial 6 in its range of validity.

2

Record a movie

In fastDDM

The analysis below uses the same steps as fastDDM. With your own movie you would start from the image files:

import fastddm as fd
img_seq = fd.read_images(file_names)
3

Subtract two frames

Subtract a frame from one taken a little later. Everything that stays still, such as dust or uneven light, cancels out. What is left is what moved, plus the camera noise.

Move the delay slider. With a short delay the difference is faint. With a longer one it grows, until the two frames have nothing left in common.

The math: the difference image
ΔI(x; t, Δt) = I(x, t + Δt) − I(x, t)

Anything that does not change in time disappears from ΔI. This is why DDM tolerates dirty optics and uneven illumination.

4

Split it into stripe patterns

Strength of each pattern (click it)
The pattern you picked

Any image can be built by adding up stripe patterns of different spacing and direction. The Fourier transform tells how much of each pattern the difference image contains, averaged over the whole movie.

The centre of the map holds wide stripes, the edge holds fine ones. Click the map to see which pattern a point stands for. The map uses the same delay as step 3.

Distance from the centre is the size of the wave vector, q = 2π / spacing. The particles have no preferred direction, so the map is round (DIC and drift are exceptions), and we average it along circles to get one value for each q. The dashed circle marks the finest pattern the objective can resolve.

The math: image structure function
d(q, Δt) = ⟨ |F[ΔI](q; t, Δt)|2 ⟩t

Here F is the two-dimensional Fourier transform and the average runs over all start times t. For motion with no preferred direction, d depends only on q = |q|, and the azimuthal average gives d(q, Δt). The cross qx = 0 or qy = 0 is left out because image edges add artefacts there.

dqt = fd.ddm(img_seq, range(1, len(img_seq) // 2))
dqt.pixel_size = pixel_size        # um
dqt.set_frame_rate(frame_rate)     # frames per second
ccm = fd.mask.central_cross_mask(dqt.shape[1:])
aa = fd.azimuthal_average(dqt, bins=len(dqt.ky) // 2,
                          range=(0, dqt.ky[-1]), mask=ccm)
5

Watch each pattern change

For each stripe spacing, ask how different the movie looks after a given delay. Fine stripes (red) change quickly, because a particle only has to move a little to shift them. Wide stripes (blue) take longer.

Each curve rises from 0, nothing has changed, to 1, the pattern is completely renewed. The points are the measurement, the lines a fit.

Each curve is the structure function d(q, Δt) for one q. It rises from the camera noise level B(q) to A(q) + B(q). The delay where it is about two thirds of the way up is the relaxation time τ(q) = 1/Γ(q). The "Change" view removes A and B so all curves share one scale.

Show
Predict first: the particles become twice as large. Do the curves move to the left or to the right?
The math: fitting the curves
d(q, Δt) = A(q) [1 − f(q, Δt)] + B(q)

A(q) holds the sample's signal seen through the microscope, B(q) the camera noise. For particles in Brownian motion the intermediate scattering function is a simple exponential, f = exp(−ΓΔt). For a mixture of sizes a stretched exponential, f = exp[−(ΓΔt)β] with β < 1, describes the data better.

First guesses as in fastDDM: B from the flat noise floor beyond the optical cut-off when the image reaches it, otherwise from the zero-delay intercept of a quadratic fit to the first five delays, A + B from twice the temporal variance of each Fourier mode, Γ from the delay where f falls to 1/e. Then a least-squares fit for every q.

B_est, _ = fd.noise_est.estimate_camera_noise(aa, mode='polyfit', num_points=5)
A_est = 2 * aa.var - B_est
from fastddm.fit import fit_multik
from fastddm.fit_models import simple_exponential_model as model
fit_res, model_res = fit_multik(aa, model, k_ref, use_err=True,
                                return_model_results=True)
6

From speed of change to particle size

Now plot how fast each pattern changes against how fine it is. For particles that wander at random, halving the stripe spacing makes the change four times faster. On these logarithmic axes the points fall on a straight line of slope 2.

The height of that line gives the diffusion coefficient. The Stokes-Einstein relation turns it into a size, using the temperature and the viscosity of the liquid.

Hollow grey points are outside what this movie can measure: patterns as large as the image or finer than the microscope resolves, changes faster than one frame or slower than half the movie, signal lost in the camera noise. They are left out of the result.

Below the plot the result compares the size from several ways of fitting, and checks it against the quality criteria of the standard for dynamic light scattering, ISO 22412. "Repeat 5 times" records five new movies with the same settings, as the standard asks for repeatability.

Particles that turn add a second, faster step to each curve. Its rate is the translation rate plus a constant, 6 DR, so on this plot it lies above the line and flattens out at small q. The squares show it when the fit finds it.

    Predict first: you warm the water from 22 to 45 °C. Does the measured size change?
    Apparent size at each q: what Stokes-Einstein gives from that pattern alone (dots, with their uncertainty; squares: cumulant fits). For identical particles the dots scatter around a flat line. With a spread of sizes they change with q, because each size shows with a different weight at each q (dashed red line: what the simulated particles give); at small q particles leaving the focal plane can pull them down. The black line is the measured size. This is the microscope's counterpart of measuring DLS at several angles.
    Signal A(q) and camera noise B(q). A falls at high q because the optics blur fine patterns; where it sinks into B the rates can no longer be read.
    The math: from rates to size
    Γ(q) = D q2   ⇒   dh = kBT / (3πηD)

    Only points inside the measurable window count:

    2π/L < q < 2π NA/λ,    1/Δtmax < Γ < 1/Δtmin

    with L the field of view. D is the weighted mean of Γ/q2 over those points; its uncertainty comes from their scatter. A free power-law fit should give an exponent close to 2; other values point to drift, swimming or crowding.

    def log_Dq2(x, D):
        return np.log(D * x**2)
    model_Gamma = lmfit.Model(log_Dq2)
    res = fit(model_Gamma, xdata=fr['k'], ydata=np.log(fr['Gamma']),
              weights=fr['Gamma'] / fr['Gamma_stderr'])

    As in fastDDM tutorial 1, sections 2.C to 2.E.

    Particles that turn. In the decoupling approximation the intermediate scattering function is a product of a translational and an orientational part. Keeping the first orientational mode (spherical harmonics of order 2):

    f(q, Δt) = a(q) e−DTq2Δt + [1 − a(q)] e−(DTq2 + 6DR)Δt

    The page fits all q at once with shared DT and DR and free amplitudes at each q. A second mode is kept only if it removes most (60 %) of the misfit of a single shared diffusion mode. For a sphere DR = kBT / (8πηR3). Between exactly crossed polarizers and in dark field the measured intensity also carries the next mode, 20 DR, which a two-mode fit absorbs into a rate that is too high; slightly uncrossed polarizers avoid this (Giavazzi et al. 2016). Between crossed polarizers the page therefore fits a third term, [1 − a − b] e−(DTq2 + 20DR)Δt, with the same DR. It is not used automatically elsewhere: left free, it can lock onto a slower spurious mode at about 0.3 of the true rate.

    The math: mean size, polydispersity and repeatability, as in DLS

    With a spread of sizes the intermediate scattering function at each q is an average over the decay rates of all particles, weighted by how strongly each shows in the images (in DLS: by the scattered intensity). The cumulant expansion keeps its first two moments:

    ln f(q, Δt) ≈ −Γ̄ Δt + μ2 Δt2 / 2,    PI = μ2 / Γ̄2

    with f = 1 − (d − B) / A, fitted by weighted least squares (weights f2) from the first delay down to a tenth of the first value, as ISO 22412:2025 (annex A.1.2) prescribes for DLS, here for the first-order function. The mean size follows from Γ̄/q2, the polydispersity index PI is averaged over q. If the rates follow a Schulz (gamma) distribution, the average is exact:

    f(q, Δt) = (1 + PI Γ̄ Δt)−1/PI

    which becomes the simple exponential as PI → 0. The table fits it to all q at once with one PI shared by all (each q keeps its own amplitude, noise and mean rate), which is much less noisy than a PI fitted at each q separately. Both PIs may come out below zero: the same formula is continued there so that noise is not pushed up against a bound at zero; only a PI clearly above zero means a spread of sizes. Its uncertainty comes from repeating the shared fit on four interleaved groups of q. For broad distributions the second-order cumulants read low, as in DLS (for example 0.14 for a true PI of 0.2, because the third cumulant is left out); third-order cumulants are less biased but noisier (researcher level, under Details).

    What a spread of sizes means for PI. PI is the relative variance of the decay rates, not of the sizes. For a narrow distribution PI ≈ (relative spread)2; for small particles, whose signal grows as d6, a Schulz spread s gives PI = s2/(1 + 4s2): 0.0025 for 5 %, 0.035 for 20 %, 0.066 for 30 %, 0.125 for 50 % (a little less in practice, as the optics weighs large particles down at high q). The width shown next to each PI is √PI. With the movies simulated here (256 frames, a few thousand particles) one movie fixes PI to about ± 0.02-0.04, so spreads below about 20-35 % cannot be told from identical particles (the PI check gives the limit for each run), and broad distributions read low (about 0.03-0.08 for a true 0.1). A DLS run averages over far more particles and time; averaging five repeated movies helps. In the simulation a Schulz size distribution of mean d̄ and relative standard deviation σ is p(d) ∝ dz exp[−(z+1)d/d̄] with z = 1/σ2 − 1, represented by five sizes (generalised Gauss-Laguerre quadrature, exact moments up to the ninth). The true PI shown is computed from the simulated particles and their actual brightness at each q.

    Repeatability and bias. Everything below uses the fit chosen under Analysis (the headline). A quick estimate cuts the movie into 4 parts (2 below 256 frames), analyses each at the same q and takes their spread divided by √N; it is a lower bound, because the parts share the same particles. "Repeat 5 times" does what ISO 22412 (10.3) asks: five new movies with the same settings and new particles; their relative standard deviation should be below 2 % for monodisperse particles of 50-200 nm. The mean of the five is then compared with the true size as in the reference-material test of ISO 10.1: the difference must stay within the expanded uncertainty, 2 × 1.5 % = 3 % here (the simulation's true value has no uncertainty of its own). The uncertainty quoted with the headline is the larger of the scatter between q and the quick estimate.

    Other checks. The size from the lower and the upper half of the q used must agree (ISO 10.2: the result must not depend on the range analysed); a free power law must give an exponent near 2; cumulants and the fit at each q must agree.

    Test report, in the style of ISO 22412
    
              
    Settings used for this run
    
              

    In a real experiment

    What matters

    Each card sets the bench to a typical problem and shows where to look. Use "Back to the standard sample" to start again.

    Beyond sizing

    Sizing dilute particles is only one application. Staying with colloids, the same kind of movie also gives:

    The first three are not simulated here: they need particles that interact with each other or with a surrounding material, and the particles on this page do not.

    About this tool

    This page is a simple tool, generated with Claude Opus 5.5, that simulates a realistic microscopy experiment in which DDM is used to study the roto-translational Brownian motion of colloidal particles. The microscope, light sources, cameras, spinning disk and point scanner are modelled mostly on the instruments of our SoMeX lab. The particles do not interact with each other: each one diffuses and turns on its own (if you choose, it also settles under gravity and slows down near the glass), so every sample is a dilute suspension. The aim is not to produce accurate, research-quality data, but to give anyone thinking of using DDM an idea of the many options and of how each one affects a DDM experiment.

    If you find something that looks wrong or does not work, please let us know through the contact page.

    Go further