Blog

Modelling nitrate in my aquarium

How I model nitrate accumulation in my aquarium, accounting for water changes and uncertainty in the colour-chart readings.

In the first post, I introduced my aquarium and explained why I monitor nitrate. The quantity I am particularly interested in is how quickly nitrate accumulates between water changes, after plant uptake and other losses.

To estimate that, I need a model for how the concentration changes over time and how my water tests relate to it. I have kept the model fairly small: three quantities, with the effects of feeding, nitrification and plant uptake combined into a net accumulation rate.

The state

The model describes the aquarium using the state vector

x(t)=(N(t)r(t)T(t)),x(t)= \begin{pmatrix} N(t)\\ r(t)\\ T(t) \end{pmatrix},

where NN is nitrate concentration in the tank, rr is its net accumulation rate between water changes, and TT is nitrate concentration in the tap water. Time is measured in weeks, so NN and TT have units of parts per million (ppm) and rr has units of ppm/week.

The water in the tank is assumed to be well mixed, with approximately constant water volume between water changes. Therefore, the rate of change of nitrate concentration is

dNdt=r.\frac{\mathrm{d}N}{\mathrm{d}t}=r.

A positive rr means nitrate is accumulating. A negative rr means the processes removing nitrate (e.g., plant uptake) outweigh those adding it (e.g., feeding). Even if I knew rr exactly, it would not tell me separately how much nitrate was produced and how much the plants removed.

Tap water belongs in the state vector because it contains nitrate and is what I use to refill the aquarium. Its nitrate concentration affects what happens at every water change.

Between water changes

If rr were constant, predicting nitrate would be straightforward:

N(t+Δt)=N(t)+r(t)Δt.N(t+\Delta t)=N(t)+r(t)\Delta t.

The net balance can change as plants grow, feeding changes or the aquarium settles after an intervention. I therefore allow rr to drift randomly:

dN=r dt,dr=q dWr.\begin{aligned} \mathrm{d}N &= r\,\mathrm{d}t,\\ \mathrm{d}r &= \sqrt{q}\,\mathrm{d}W_r. \end{aligned}

Here WrW_r is a standard Wiener process and qq controls how much the rate is allowed to change. Over an interval Δt\Delta t, the change in rr has mean zero and variance qΔtq\Delta t. A larger qq permits more variation in the rate.

The random forcing represents variation in the net balance that has not been modelled explicitly. For a given current state, x(t)x(t), the expected nitrate concentration follows the current slope, with uncertainty from rate changes growing over the forecast.

This is an integrated Wiener-process model, also used in target tracking as a nearly constant velocity model.1 Nitrate concentration takes the role of position, and accumulation rate the role of velocity.

For the tap water, I assume a separate random walk,

dT=qT dWT,\mathrm{d}T=\sqrt{q_T}\,\mathrm{d}W_T,

with independent noise. This allows the supply concentration to vary over time, with qTq_T controlling the size of those changes.

For this model, the equations give an exact transition over any elapsed time between water changes:

x(t+Δt)=F(Δt)x(t)+η,η∼N(0,Q(Δt)),x(t+\Delta t)=F(\Delta t)x(t)+\eta, \qquad \eta\sim\mathcal{N}\bigl(0,Q(\Delta t)\bigr),

where the new increment η\eta is independent of the current state. The transition matrix is

F(Δt)=(1Δt0010001).F(\Delta t)= \begin{pmatrix} 1 & \Delta t & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{pmatrix}.

Mathematically, FF maps the current state to its conditional mean after an interval Δt\Delta t. The first row gives N+rΔtN+r\Delta t, while the other two rows retain the current values of rr and TT. Physically, the expected nitrate concentration follows the current net accumulation rate, with no systematic change in the rate or tap-water concentration over that interval. Actual values can vary through the random increment η\eta.

The process-covariance matrix is

Q(Δt)=(qΔt3/3qΔt2/20qΔt2/2qΔt000qTΔt).Q(\Delta t)= \begin{pmatrix} q\Delta t^3/3 & q\Delta t^2/2 & 0\\ q\Delta t^2/2 & q\Delta t & 0\\ 0 & 0 & q_T\Delta t \end{pmatrix}.

This is the covariance of η\eta: the new uncertainty accumulated during the interval. The diagonal entries give the variances of its nitrate, rate and tap-water components. The rate component has variance qΔtq\Delta t, while integrating those rate changes gives the qΔt3/3q\Delta t^3/3 contribution to nitrate variance. The tap-water component has variance qTΔtq_T\Delta t.

The off-diagonal terms qΔt2/2q\Delta t^2/2 describe correlated changes in nitrate and its accumulation rate. A rate that wanders upwards also tends to produce extra nitrate during the same interval. The zeros involving TT express the assumption of independent tap-water driving noise; they do not require the uncertain tank and tap concentrations themselves to be independent.

The forecast also carries forward uncertainty already present in the current state. Using the actual elapsed time Δt\Delta t lets the model handle irregular gaps between tests.

Water changes

Water changes are recorded as interventions. Draining and refilling the tank changes its nitrate concentration, so the model needs to account for that intervention.

Suppose the water volume is VV, the tank concentration before draining is N−N^-, and I replace a fraction ff with tap water with nitrate concentration TT. Assuming the tank is well mixed, the nitrate remaining after draining is proportional to (1−f)VN−(1-f)VN^-, and the replacement water contributes fVTfVT.

After refilling to the original volume,

N+=(1−f)N−+fT.N^+=(1-f)N^-+fT.

The superscripts denote the concentrations immediately before and after the water change. The change is assumed to be instantaneous relative to the intervals between water tests. It changes NN directly; rr and TT are left unchanged at that instant.

For example, if the tank contains 10 ppm, the tap water contains 3 ppm, and I replace 25% of the water, the model gives

N+=0.75×10+0.25×3=8.25 ppm.N^+=0.75\times10+0.25\times3=8.25\ \mathrm{ppm}.

A partial water change moves the concentration towards that of the incoming water. The size and direction of the change depend on the difference between the two concentrations as well as on how much water I replace.

The fraction ff is uncertain too: I estimate it from the drop in water level.

Writing fˉ\bar f for its mean and σf2\sigma_f^2 for its variance, and assuming ff is independent of the state, gives

E[N+]=(1−fˉ)E[N−]+fˉE[T]\mathbb{E}[N^+] =(1-\bar f)\mathbb{E}[N^-]+\bar f\mathbb{E}[T]

and

Var⁡(N+)=Var⁡((1−fˉ)N−+fˉT)+σf2 E[(T−N−)2].\operatorname{Var}(N^+) = \operatorname{Var}\bigl((1-\bar f)N^-+\bar fT\bigr) +\sigma_f^2\,\mathbb{E}\bigl[(T-N^-)^2\bigr].

The first term includes the existing uncertainty in tank and tap concentrations, and their covariance. The second accounts for uncertainty in the amount of water replaced. Its effect grows with the difference between tank and tap nitrate: when their concentrations are similar, replacing a little more or less water makes little difference.

These two moments are exact under the independence assumption, but they do not determine the full distribution. For a fixed ff, the water-change rule is linear in the state, so a jointly Gaussian starting state remains Gaussian. With uncertain ff, the fraction multiplies uncertain concentrations. Each possible fraction can give a Gaussian distribution with a different mean and variance; averaging over those possibilities produces a mixture, which need not be Gaussian.

This matters because distributions with the same mean and variance can assign different probabilities to the next colour-chart reading, or to unusually high or low nitrate concentrations. As we shall see in the next post, the filter approximates the updated joint state by a Gaussian with the same mean and covariance. Those moments are preserved, but some information about the shape is lost. How much that affects the predictions is something to test.

What the test measures

Consumer nitrate tests typically require users to match the colour of a treated water sample to a printed chart. For my particular test, the freshwater scale is labelled

<0.5, 1, 3, 5, 15, 30, 60, 120, 200 ppm.<0.5,\ 1,\ 3,\ 5,\ 15,\ 30,\ 60,\ 120,\ 200\ \mathrm{ppm}.

I record the chosen category. To relate it to the state, I assume a noisy continuous assay response,

z∗=c+ε,ε∼N(0,σ2),z^*=c+\varepsilon, \qquad \varepsilon\sim\mathcal{N}(0,\sigma^2),

where c=Nc=N for a tank test and c=Tc=T for a tap-water test. The reported swatch tells me which interval contains z∗z^*.

I choose to place the boundaries at geometric midpoints between adjacent positive labels, except that I use 0.5 ppm as the boundary above the lowest category. Under that choice, the 5 ppm swatch corresponds to an assay response between

3×5≈3.87and5×15≈8.66 ppm.\sqrt{3\times5}\approx3.87 \quad\text{and}\quad \sqrt{5\times15}\approx8.66\ \mathrm{ppm}.

Those boundaries apply to the noisy assay response. The true concentration can lie outside that interval and still produce the same swatch.

For a category with boundaries aa and bb, the probability of observing it at concentration cc is

P⁡(y∣c)=Φ(b−cσ)−Φ(a−cσ),\operatorname{P}(y\mid c) = \Phi\left(\frac{b-c}{\sigma}\right) - \Phi\left(\frac{a-c}{\sigma}\right),

where Φ\Phi is the standard normal cumulative distribution function. I currently use σ=2\sigma=2 ppm and assume it does not depend on concentration. The outermost categories extend to minus and plus infinity in the assay-response model.

I should emphasise that the boundary locations and noise level are modelling assumptions. They determine how strongly a colour comparison should affect the estimates, so they deserve checking (which I will do in a later post) along with the dynamics.

What I can infer

The model keeps track of a net rate. An inferred reduction in that rate could be consistent with increasing plant uptake, but changes in feeding or other processes could also account for it. Nitrate readings alone cannot identify the cause.

There are mathematical limitations too. The model permits negative values of NN and TT, even though physical concentrations are non-negative. That matters near zero, and the uncertainty grows without bound over a long forecast. Its intended use is over the short intervals between water tests.

The remaining step is to update the distribution of NN, rr and TT as each new tank or tap-water result arrives. I use a Gaussian assumed-density filter for that, which I will work through in the next post.

Footnotes

  1. Simo Särkkä and Arno Solin (2019), Applied Stochastic Differential Equations, Cambridge University Press, Section 6.2, Example 6.3. ↩