Pasted into the chat on the timer. The notebook's hint and reference cells are built
from this file, so what is pasted and what is in the notebook never differ. A hint is
one line of code that replaces the line of the same name in the attempt cell. A nudge
is the step before its hint, pasted first. In the notebook it shows under the hint's
title, with the hint's line behind Show code.

[session 1, nudge 1]
`observation_matrix` describes how the rocket's position (x, y) turns into a sensor reading (x, y).
Here the reading is simply the position itself, so this is the identity matrix.
In JAX, you can create an n-by-n identity matrix with `jnp.eye(n)`.
We need n = 2: one dimension for x and one for y.

[session 1, hint 1]
observation_matrix = jnp.eye(2)

[session 1, nudge 2]
`observation_noise` (R) describes how far each reading tends to stray from the true position.
It's a covariance matrix: the variance for each axis sits on the diagonal, with zeros everywhere else.
In this task, the variance is 0.05 on both axes.
Multiplying a matrix by a number scales every entry, so `v * jnp.eye(n)` puts v along the diagonal.

[session 1, hint 2]
observation_noise = 0.05 * jnp.eye(2)

[session 1, reference]
Reference for task 1: the collapsed cell under hint 2. Run it, then the checkpoint.

[session 2, nudge 1]
`k` controls how quickly the reading gets noisier as the rocket moves away from the beacon.
As k rises, the noise climbs more steeply away from the beacon, and the routes change with it.
Past some k, one of the two rockets stops short of the pad while the other still lands.
Try raising k from 0.08 in steps of about 0.1, and read the two lines `show_landings` prints each time.

[session 2, hint 1]
beacon_gain = 0.4

[session 2, nudge 2]
`pull` is the extra noise the beacon adds at position x.
It's k multiplied by `distance_squared`, with the squared distance capped first so it never goes above the cap.
`jnp.minimum(a, b)` returns whichever of a and b is smaller, which is a handy way to cap a at b.
You'll find k in `params["beacon_gain"]` and the cap in `params["beacon_cap"]`.

[session 2, hint 2]
pull = params["beacon_gain"] * jnp.minimum(distance_squared, params["beacon_cap"])

[session 2, reference]
Reference for task 2: the collapsed cell under hint 2. Run it, then the checkpoint.

[session 3, nudge 1]
`fade` is the extra noise on the broadcast at position x.
In Task 2, the beacon's noise stopped growing at a cap. This time there is no cap.
The broadcast has to keep fading with distance, or the rocket could hear it clearly from anywhere.
You will find how fast it fades in `params["broadcast_gain"]`, and `distance_squared` is already worked out.

[session 3, hint 1]
fade = params["broadcast_gain"] * distance_squared

[session 3, nudge 2]
`prior_cov` is how unsure the rocket is, before its first reading, about each of the four numbers in its state.
The first two are its own position, and each has a variance of 0.25. The last two are the pad's position.
In the world, the true pad strays from the guess by `pad_spread`, a standard deviation, so the variance to use is `pad_spread` squared.
`jnp.diag` turns the four variances into the matrix that `Belief` needs.

[session 3, hint 2]
prior_cov = jnp.diag(jnp.array([0.25, 0.25, pad_spread**2, pad_spread**2]))

[session 3, reference]
Reference for task 3: the collapsed cell under hint 2. Run it, then the checkpoint.
