examples/LorenzAttractor/README.md
This project simulates and visualizes the Lorenz attractor, a chaotic system of differential equations, entirely inside Serial Studio. There is no external generator: a JavaScript control loop integrates the Lorenz trajectory in real time, writes the ($x$, $y$, $z$) values into a data table, and ticks the dashboard so the plots render. No data ever arrives from the network.
The Lorenz system, introduced by Edward Lorenz in 1963, is a set of three coupled differential equations commonly used to model atmospheric convection. Its iconic butterfly-shaped attractor is a symbol of chaos theory. For more, see this article.
This project uses features available only with a paid license. See serial-studio.com for details.
The system is governed by:
$$ \frac{dx}{dt} = \sigma (y - x) $$ $$ \frac{dy}{dt} = x (\rho - z) - y $$ $$ \frac{dz}{dt} = x y - \beta z $$
Where:
The control loop uses the Euler method for numerical integration to evolve the system over time.
The whole example runs from the control script, with no helper process to launch:
setup() seeds the clock and posts a notification.loop() advances the Lorenz state one Euler step, writes x, y and z into the Lorenz data table with tableSet(), then calls dashboardTick() to force a render.Lorenz table, so the dashboard is fed straight from the control loop.{} (no frame); no bytes are ever parsed, and the control loop's dashboardTick() drives both the dashboard and the exports.Because the loop free-runs (the worker re-arms it about once per millisecond), this project also doubles as a control-loop benchmark. loop() advances STEPS_PER_TICK integration steps per dashboard refresh, and every STATS_EVERY steps it reports the measured step rate as a notification, so you can see how fast and how steadily the control loop runs. Raise STEPS_PER_TICK to push raw integration throughput past the refresh rate.
dashboardTick()also fans the synthesized frame out to whatever export sinks are enabled, so a control-script simulation like this one can be recorded to CSV/MDF4/Session-database/MQTT just like real device data. (refreshDashboard(), by contrast, only refreshes the view.)
Open LorenzAttractor.ssproj in Serial Studio and click Connect. That is all. The control loop starts with the connection and stops again when you disconnect, switch projects, or quit.
The bundled project is already set up: its data source is a dummy UDP socket on local port 9000, and it contains both visualizations, a Multi-Plot group (2D Visualization) and a 3D plot group (3D Visualization). The X/Y/Z values come from the Lorenz data table that the control loop writes; the frame parser is a Lua stub that returns {}.
Here is how the project editor should look:
Serial Studio's custom X-axis feature lets you map any dataset to serve as the X-axis source for plots. It is particularly useful for:
In the bundled project the three datasets cross-reference each other ($x$ against $y$, $y$ against $z$, $z$ against $x$) to draw the attractor.
Lorenz data table and that the X/Y/Z datasets are marked virtual.STEPS_PER_TICK (integration steps per refresh) or DT (Euler step size) at the top of the control script.