1. The interactive cockpit

1.1. Description

The cockpit is a browser-based demonstration layer for RISE-solved models. The user manipulates the structure that generates outcomes — policy-rule coefficients, regime persistence, credibility and attention, the equilibrium concept itself — and watches the entire model economy reorganize in real time.

Two constraints drive the design:

  1. Latency. Every on-screen response to a gesture completes in well under 100 ms. Nothing is re-solved in the browser: where a feature needs solutions at many parameter values, they are precomputed on a grid and interpolated; where it needs distributions, fixed common-random-number ensembles are re-propagated or reweighted.

  2. Zero-failure demo mode. The suite runs as a fully self-contained static page (HTML + JavaScript + precomputed binary bundles): no backend, no network, and no MATLAB session at demonstration time.

The front end is content-agnostic: variable names, parameter names, regime labels, slider ranges and landmark rules all arrive via a manifest and per-feature data bundles exported from RISE. Swapping the model requires zero front-end changes.

The system has two halves:

  • the bake (MATLAB): the rise.cockpit package solves the model, runs whatever smoothing or simulation the enabled features need, and writes manifest.json plus one binary bundle per feature;

  • the front end (JavaScript): a static single-page application in <RISE root>/cockpit/web that loads the bundles and runs every interaction client-side. Feature tabs appear only for bundles listed in the manifest.

1.2. Features

Tab

Interaction

Bake function

Policy Rule Cockpit

sliders / 2-D pad on policy-rule coefficients; fans, IRFs, moments and welfare update per gesture; determinacy region masked and snapped

rise.cockpit.bake_policy_grid

Rewriting History

shock toggles and scale sliders redraw counterfactual history and re-stack the decomposition

rise.cockpit.bake_history

Regime Dial

transition-probability sliders and a regime paintbrush; fans go bimodal / fat-tailed as regime uncertainty rises

rise.cockpit.bake_regime_dial

Entropic Tilting

drag any fan’s median; all other fans update to the tilted distribution; effective-sample-size meter guards over-tilting

rise.cockpit.bake_ensemble

Commitment–Discretion

one slider on the probability of commitment (loose commitment; linear-quadratic models)

rise.cockpit.bake_policy_grid with export_all_regimes=true

Credibility / Attention

attention sliders; the response to an announced policy shock collapses as attention falls (forward guidance)

rise.cockpit.bake_policy_grid with anticipated=...

1.3. Quick start: one call from model to browser

rise.cockpit.demo bakes every exercise its ingredients allow, writes the manifest from the model’s own metadata (labels come from the model file’s quoted descriptions, slider baselines from the current parameter values), starts a local server, and opens the browser:

m = dsge_model('mymodel');
m = set(m, 'parameters', p);
rise.cockpit.demo(m)

1.4. The ingredients: each one you add unlocks one exercise

Ingredient (option on demo)

Exercise unlocked

Notes

nothing — just the parameterized model

Entropic Tilting

drag forecast medians; always available

grid=struct(phi_pi=..., phi_x=..., ...) — two or more rule coefficients with knot vectors

Policy Rule Cockpit

baseline = current values; must lie inside the grid

grid=struct(gamma_prob=0:0.005:1) — a single coefficient, on a planner model with a commitment chain solved by loose_commitment

Commitment vs Discretion

see the modernized Canonical_plain.rs for the model pattern

data=... — the observables, as the ts struct you would pass to filter

Rewriting History

one smoother pass; toggles re-weight the decomposition

the model itself is Markov-switching

Regime Dial

automatic; chain_labels= names the states

attention_grid=struct(mbar=...) together with anticipated=struct(shock=..., horizons=[4 8 12])

Credibility / Attention

anticipated-shock (forward guidance) IRFs baked per grid node

Ingredients compose: one call with several of them bakes several tabs into the same page. To rebuild and reopen after changing something, just call demo again; rise.cockpit.launch(outdir) reopens an existing bundle without rebaking, and browser=false on either returns the URL instead of opening it. The lower-level bake_* functions remain available when you need full control over grids, welfare, landmarks, or the manifest.

A complete start-to-finish walk-through lives in rise-modern-tutorials/Cockpit (howto.m and verify.m).

1.5. The bake functions

All functions validate their inputs via arguments blocks; see each function’s help text for the full reference. Highlights:

rise.cockpit.bake_policy_grid

Solves the model over a tensor grid of parameters. Per node it stores the (row-restricted) solution matrices, a determinacy flag, unconditional standard deviations and a quadratic welfare loss (ergodic-weighted across regimes for switching solutions), plus fixed common shock draws and the exact baseline solution for the front end’s reset. Options extend the same engine to three tabs: anticipated=struct(shock=...,horizons=...,periods=...) bakes forward-guidance IRF curves per node; export_all_regimes=true additionally ships per-regime matrices and uniform draws so the front end can simulate a regime-switching process (used by the loose-commitment tab); name=... sets the bundle base name.

rise.cockpit.bake_history

Runs the smoother once and exports smoothed shocks, the historical decomposition and the solution matrices. Asserts two identities at bake time: the decomposition sums to smoothed history (additivity), and propagating the smoothed shocks reproduces it (P1). The level-vs-deviation convention of the decomposition is detected automatically and recorded in the meta.

rise.cockpit.bake_regime_dial

Exports the per-regime solutions of a Markov-switching model, the small-chain transition matrices and the composite-regime map, plus common draws for shocks and regime transitions.

rise.cockpit.bake_ensemble

Simulates one large baseline ensemble (default 10,000 paths) of the reported variables — the only heavy blob in the suite; the front end reweights it live by exponential tilting.

rise.cockpit.write_blob

The shared binary writer: named arrays, little-endian, column-major, byte offsets recorded for the JavaScript side.

1.6. Interpolation validation

Every grid bake compares exactly solved impulse responses against multilinearly interpolated ones at random interior points and records the error distribution in the bundle meta (default acceptance: maximum relative error below 1%). Two practical caveats the validator handles:

  • Never interpolate across the determinacy boundary. A grid cell is usable only if all its corners are determinate; the front end snaps queries in unusable cells to the nearest usable cell and marks the boundary visually.

  • Frontier-adjacent cells hold steep gradients by nature. When the determinacy frontier is an interior curve that no box trimming avoids, validate_interior_only=true certifies the frontier-free interior separately and records how many frontier cells were excluded from sampling.

1.7. Bundle format

Each feature ships <name>.json (meta) and <name>.bin (blob). The meta’s arrays section maps array names to byte offsets, dtypes (float32, float64, int32, uint8) and shapes in MATLAB (column-major) order; the bake writes A(:) little-endian. Grid bundles store per-node blocks contiguously, which is exactly the layout the front end’s multilinear interpolator consumes. The manifest lists model metadata, variable/shock/regime labels, and one {bundle, meta} entry per enabled feature.

1.8. Testing

The MATLAB side is covered in RISE-unit-tests (models/dsge/cockpit_export/cockpitBakeTest); the front end carries a MATLAB-free JavaScript test suite (cd cockpit/web && node --test test/) including integration tests that exercise a committed 250 KB fixture bundle.