# Demo — Route Planner

A notional 400 km × 300 km battlespace, five surface-to-air sites, an ingress point and a target. The planner lays a 10 km grid over the map, prices every leg by its length and its exposure, and runs Dijkstra's algorithm on every change you make. One slider decides how much length you will trade for survival; a sweep of that slider traces the Pareto front; a fuel limit picks the route off it. A three-way switch decides what radar cross-section the planner believes — and a second readout tells you what that belief costs.

## The model

**The graph.** One node per 10 km cell center — 40 × 30 = 1,200 nodes — each linked to its 8 neighbors by legs of 10 km or $10\sqrt{2} = 14.1$ km. Coordinates are East and North in km; headings are clockwise from North.

**The sites.** Each site has a nose-on detection range $R_\text{nose}$, a MEZ radius, and a hazard from L31: it takes a shot every $\Delta s$ km of track, each killing with probability $p_\text{shot}$, so

$$
\lambda = \frac{-\ln(1-p_\text{shot})}{\Delta s} \ \text{per km}.
$$

| Site | Class | Position (E, N), km | $R_\text{nose}$ | MEZ | $p_\text{shot}$, $\Delta s$ | $\lambda$ (per km) |
|---|---|---|---|---|---|---|
| LR | long-range SAM | (171, 79) | 50 km | 90 km | 0.30, 40 km | 0.00892 |
| MR-1, MR-2, MR-3 | medium-range SAM | (137, 207), (239, 199), (329, 171) | 35 km | 45 km | 0.25, 20 km | 0.01438 |
| SR | short-range SAM | (63, 223) | 20 km | 25 km | 0.30, 10 km | 0.03567 |

The ingress IN is at (25, 35) and the target TGT at (375, 255). Every number here is notional.

**The signature.** A simple two-lobe radar cross-section, in dB above the nose-on value, as a function of the aspect $\theta$ each radar sees (0° nose-on, 180° tail-on):

$$
\Delta\sigma(\theta) = b(\theta) + \big(16 - b(\theta)\big)\sin^4\theta, \qquad b(\theta) = 6\,\frac{1-\cos\theta}{2}.
$$

The nose is the smallest, the tail is 6 dB brighter, and the two beam lobes peak 16 dB above the nose. Detection range follows the fourth-root law, $R_\text{det}(\theta) = R_\text{nose}\,10^{\Delta\sigma(\theta)/40}$ — so the beam is seen $10^{16/40} = 2.51$ times farther than the nose, and the tail 1.41 times farther. With every class's beam range outside its MEZ, the MEZ bounds the lethal zone at the beam.

**The cost.** A site's lethal zone is where the aircraft is inside *both* its detection range and its MEZ. Each edge is checked at five evenly spaced points; each point inside site $i$'s lethal zone adds $\lambda_i$ times a fifth of the edge's length. So

$$
r_e = \sum_i \lambda_i\,\ell_{i,e}, \qquad c_e = \ell_e + w\,r_e, \qquad P_S = e^{-\sum_e r_e}.
$$

The weight $w = w_r/w_d$ is in km per unit of exposure. (A negligible $10^{-6}\,r_e$ is added to every edge so that, among routes of equal cost, the planner keeps the safer one.)

**The σ model.** *Aspect-aware* computes each edge's aspect from its own heading — a leg flown toward a site shows it the nose, the same leg flown away shows it the tail — so the graph is directed. *Nose-on* and *Worst case* give every heading one $\sigma$, the nose value or the beam value, and the graph is undirected.

## Interactive demo

<a class="demo-fullscreen" href="../_static/demos/RoutePlanner.html" target="_blank" rel="noopener">Open in full screen</a>

<div class="demo-wrap">
<iframe src="../_static/demos/RoutePlanner.html"
        title="Interactive route planner: Dijkstra on a threat grid with a weight sweep, fuel limit and aspect-aware costs"
        width="100%"
        loading="lazy">
</iframe>
</div>

## Walkthrough

Drag any of the five sites, the ingress (IN) or the target (TGT); the route re-plans as you drag. The six tiles under the map read the planned route's length against the fuel limit, its summed exposure, its $P_S$ under the planner's own model, its $P_S$ re-scored with the aspect-aware model, the same path flown backward, and — once you have swept — the fuel-limited pick.

1. **Start at $w = 0$.** The planner takes the shortest route: 441 km, $\sum\lambda\ell = 1.741$, $P_S = 0.175$. The red legs are the ones inside a lethal zone. Notice the staircase: on an 8-connected grid a straight line becomes a zig-zag, and among the many equally short staircases the planner keeps the least exposed.
2. **Raise the weight.** At $w = 20$ km the route gives up 12 km for $P_S = 0.348$; at 40 km it is 476 km and 0.704; at 200 km, 519 km and 0.897; at 1,000 km it finds a route with no exposure at all, 552 km around the north of every site. Each step is a fresh Dijkstra run on a new cost.
3. **Press Sweep.** The front appears: eight distinct routes from 441 km at 0.175 to 552 km at 1.000, with the dashed fuel line at 530 km. The fuel-limited pick reads $w = 200$: 519 km at $P_S = 0.897$ — the safest route that fits. Press **Fly the fuel pick**. The small kink south of MR-1 is the aspect-aware planner turning toward LR for one leg, nose-on, to shrink LR's detection range as it squeezes between the two zones. Now drag the fuel limit: at 440 km the pick reads *infeasible* (the shortest route is 441 km); at 650 km it becomes the zero-exposure route.
4. **Switch the σ model to Nose-on.** The weight stops mattering — the planner believes the detection ranges are the small dashed rings, finds a gap between them, and promises $P_S = 1.000$ on the shortest route. The *with aspect* tile re-scores the same route with the real signature: $P_S = 0.077$. The route skirts LR and threads between MR-2 and MR-3, beam-on to all three. Nothing is wrong with Dijkstra; the cost described a different aircraft from the one flying. Then try **Worst case**: now every ring is at its largest, the shortest route scores 0.129, and the front tops out at 517 km and 0.856 before the 552 km zero-exposure route.
5. **Back to Aspect-aware, $w = 200$.** The *same path reversed* tile reads 0.840 against 0.897 forward: the legs flown backward show the sites different aspects. Press **Swap IN ↔ TGT** and the egress plan at the same weight is a different route (505 km, 0.876). In either blind mode the reversed tile always equals the forward one, and swapping the ends just flies the same route backward.
6. **Turn on the frontier animation.** Dijkstra's settled set spreads out from IN in order of cost-to-come, filling the cheap cells first and bending around expensive ones, and stops the moment TGT settles. It is presentation only — every readout is identical with it on or off.
7. **Drag a site.** Park MR-2 on the straight line, push LR against the map edge (sites stop at the border), or drop a site on top of IN (every route out then starts exposed). The front, the pick and every tile follow.

## Key observations

- **Risk has to add.** Survival multiplies along a route and Dijkstra adds, so exposure is carried as $r_e = -\ln(1-p) = \sum\lambda\ell$; the minimum-cost route is then exactly the maximum-$P_S$ route for that weight.
- **The weight is a price.** $w$ is the kilometers you pay per unit of exposure. Sweeping it traces the Pareto front, and the front — not any single route — is the honest answer to "shorter or safer?".
- **Fuel picks the point.** The limit is applied to the sweep's answers: fly the safest route that fits, or report the mission infeasible.
- **Aspect makes the graph directed.** A leg's heading sets the aspect each site sees, so $a \to b$ and $b \to a$ cost differently, and the planner weaves to present its nose.
- **Low cost is not low risk.** A nose-on plan can promise perfect survival on a route the aspect-aware model scores below 0.1. Re-score every plan under a better model than the one that chose it.

## Source

<a class="matlab-link" href="../_static/downloads/ECE%20495%20EW%20%E2%80%93%20Code.zip#code/L34_RoutePlanner.m" download title="Downloads the full course code bundle (.zip). This lesson&#39;s file: code/L34_RoutePlanner.m"><svg viewBox="0 0 22 22" width="14" height="14" aria-hidden="true" style="vertical-align:-2px;margin-right:6px;"><rect width="22" height="22" rx="3" fill="#e87722"/><text x="11" y="15.5" text-anchor="middle" font-family="'Inter',sans-serif" font-size="9" font-weight="800" fill="#fff" letter-spacing="-0.04em">MAT</text></svg><span class="ml-text">MATLAB bundle · L34_RoutePlanner.m</span><span class="ml-arrow">↓</span></a>

The companion script builds the same grid, the same five sites and the same aspect-aware edge risks, stores them in a `digraph`, and runs `shortestpath` once per weight in the demo's sweep, printing each route's length and $P_S$. It then applies the 530 km fuel limit to the sweep, re-scores the chosen path flown backward, and plots the shortest and fuel-limited routes beside the Pareto front — reproducing steps 1 to 3 and the reversed-path number in step 5 exactly.
