Skip to content

Examples

github-actions[bot] edited this page Mar 23, 2026 · 16 revisions

Examples

FastSense includes 80+ runnable examples in the examples/ directory covering basic plots, dashboards, sensor monitoring, event detection, and stress tests. Each demonstrates core features with realistic datasets.

Running Examples

install;              % Set up FastSense and compile MEX acceleration
cd examples
example_basic;        % Run individual example
run_all_examples;     % Run all examples with 5-second pauses
demo_all;             % Interactive mode (prompts to advance, keeps plots open)

Basic Plotting

Simple Multi-Point Visualization

% example_basic.m — Plot 10M noisy sine with thresholds
fp = FastSense('Theme', 'dark');
x = linspace(0, 100, 1e7);
y = sin(x) + 0.1 * randn(size(x));
fp.addLine(x, y, 'DisplayName', 'Sensor 1');
fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true, ...
    'Color', 'r', 'Label', 'Upper Alarm');
fp.addThreshold(-0.8, 'Direction', 'lower', 'ShowViolations', true, ...
    'Color', [1 0.6 0], 'Label', 'Lower Warning');
fp.render();

Key features demonstrated:

  • Creating a FastSense instance with theme selection
  • Adding a data line with 10M points
  • Adding upper/lower threshold lines
  • Violation marker display (scatter overlay at threshold crossings)
  • Interactive zoom/pan with dynamic downsampling

Multiple Lines with Auto Color Cycling

% example_multi.m — Five sensors, shared thresholds
fp = FastSense();
for i = 1:5
    x = linspace(0, 100, 1e6);
    y = sin(x + i) + 0.2*randn(size(x));
    fp.addLine(x, y, 'DisplayName', sprintf('Sensor %d', i), ...
        'DownsampleMethod', 'minmax');
end
fp.addThreshold(1.2, 'Direction', 'upper');
fp.render();

Features:

  • Multiple lines with automatic color assignment from theme palette
  • Downsampling method specification per line
  • Shared threshold across all lines

Handling Missing Data (NaN Gaps)

% example_nan_gaps.m — Data with sensor dropouts
x = linspace(0, 100, 1e6);
y = sin(x);
% Inject dropout regions
y(100000:105000) = NaN;
y(500000:502000) = NaN;
fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Temp with dropouts');
fp.addThreshold(0.5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();

Output: Visible gaps in the line where NaN values appear; thresholds and violations computed only across contiguous segments.


Dashboard Layouts

Tiled Grid with Spanning

% example_dashboard.m — 2×2 grid with spanning tiles
fig = FastSenseGrid(2, 2, 'Theme', 'dark');
fig.setTileSpan(1, [1 2]);  % Top tile spans 2 columns (double width)

x = linspace(0, 100, 2e6);

% Tile 1: Pressure (spans 2 cols)
fp1 = fig.tile(1);
fp1.addLine(x, 5 + 2*sin(x) + 0.1*randn(size(x)), 'DisplayName', 'Pressure');
fp1.addBand(6, 6.5, 'FaceColor', [1 0 0], 'FaceAlpha', 0.15, 'Label', 'Alarm Zone');
fig.setTileTitle(1, 'Pressure Monitor (bar)');

% Tile 2: Temperature
fp2 = fig.tile(2);
fp2.addLine(x, 70 + 5*cos(x) + 0.2*randn(size(x)), 'DisplayName', 'Temperature');
fp2.addThreshold(75, 'Direction', 'upper', 'ShowViolations', true);
fig.setTileTitle(2, 'Temperature (°C)');

% Tile 3: Vibration
fp3 = fig.tile(3);
fp3.addLine(x, 2*randn(size(x)), 'DisplayName', 'Acceleration');
fp3.addThreshold(3, 'Direction', 'upper', 'ShowViolations', true);
fig.setTileTitle(3, 'Vibration (g)');

fig.renderAll();

Features:

  • Multi-tile responsive grid (FastSenseGrid)
  • Per-tile spanning (setTileSpan)
  • Per-tile titles via setTileTitle
  • Independent FastSense instances per tile with shared theme
  • Bands and thresholds on different tiles
graph TB
    subgraph Grid["2×2 Grid Layout"]
        T1["Tile 1: Pressure<br/>(spans 2 cols)"]
        T2["Tile 2: Temp"]
        T3["Tile 3: Vibration"]
    end
    T1 ---|double width| T2
    T2 ---|single width| T3
Loading

Tabbed Multi-Dashboard

% example_dock.m — 5 tabbed dashboards in one window
dock = FastSenseDock();

for tabIdx = 1:5
    grid = FastSenseGrid(2, 2, 'Theme', 'ocean');
    
    for tileIdx = 1:4
        fp = grid.tile(tileIdx);
        x = linspace(0, 100, 1e6 * tabIdx);
        y = sin(x * tabIdx) + 0.1*randn(size(x));
        fp.addLine(x, y, 'DisplayName', ...
            sprintf('Tab %d, Sensor %d', tabIdx, tileIdx));
        fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
        grid.setTileTitle(tileIdx, sprintf('Sensor %d (Tab %d)', tileIdx, tabIdx));
    end
    
    grid.renderAll();
    dock.addTab(grid, sprintf('Tab %d', tabIdx));
end

Features:

  • FastSenseDock container for multiple grids
  • Per-tab independence with scrollable tab bar
  • Each tab can have its own layout and data

Visual Enhancements

Shaded Bands and Fills

% example_visual_features.m — Confidence bands, fills, markers
fp = FastSense('Theme', 'scientific');
x = linspace(0, 50, 5e5);
y = exp(-0.05*x) .* cos(x);

% Main signal
fp.addLine(x, y, 'DisplayName', 'Signal', 'Color', 'b', 'LineWidth', 1.5);

% Confidence envelope (shaded band between two curves)
y_upper = y + 0.1 + 0.05*randn(size(y));
y_lower = y - 0.1 + 0.05*randn(size(y));
fp.addShaded(x, y_upper, y_lower, 'FaceColor', [0.3 0.7 1], ...
    'FaceAlpha', 0.2, 'EdgeColor', 'none', 'DisplayName', '±1σ');

% Horizontal alarm band (constant Y bounds)
fp.addBand(-0.3, 0.3, 'FaceColor', [1 1 0], 'FaceAlpha', 0.1, ...
    'Label', 'Safe Zone');

% Area fill to baseline
fp.addFill(x, y, 'FaceColor', [1 0.5 0], 'FaceAlpha', 0.1, ...
    'DisplayName', 'Energy');

% Event markers at specific points
event_idx = 1:50000:numel(x);
fp.addMarker(x(event_idx), y(event_idx), 'Marker', '*', ...
    'MarkerSize', 10, 'Color', 'r', 'DisplayName', 'Events');

fp.render();

Output:

Rendered plot showing:
- Blue line (main signal)
- Light-blue shaded confidence band
- Yellow horizontal alarm zone
- Orange area fill under the curve
- Red asterisk event markers

All Six Themes

% example_themes.m — Visual comparison of theme presets
x = linspace(0, 100, 1e6);
y = sin(x) + 0.1*randn(size(x));

themes = {'default', 'dark', 'light', 'industrial', 'scientific', 'ocean'};

for i = 1:length(themes)
    subplot(2, 3, i);
    fp = FastSense('Parent', gca, 'Theme', themes{i});
    fp.addLine(x, y);
    fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
    fp.render();
    title(themes{i});
end

Sensor Monitoring

Sensor with State-Dependent Thresholds

% example_sensor_threshold.m — Thresholds change based on machine state
x = linspace(0, 200, 1e6);
y = 50 + 10*randn(size(x));

% Create sensor
sensor = Sensor('chamber_pressure');
sensor.X = x;
sensor.Y = y;

% Machine state: idle (0) → running (1) → shutdown (2)
state_chan = StateChannel('machine_state');
state_chan.X = [0 50 150 200];
state_chan.Y = [0 1 2 1];
sensor.addStateChannel(state_chan);

% Different thresholds per state
sensor.addThresholdRule(struct('machine_state', 0), 65, ...
    'Direction', 'upper', 'Label', 'Idle HI', 'Color', 'y');
sensor.addThresholdRule(struct('machine_state', 1), 75, ...
    'Direction', 'upper', 'Label', 'Run HI', 'Color', 'r');
sensor.addThresholdRule(struct('machine_state', 2), 70, ...
    'Direction', 'upper', 'Label', 'Shutdown HI', 'Color', [1 0.5 0]);

% Resolve thresholds and violations
sensor.resolve();

% Plot with all resolved thresholds
fp = FastSense('Theme', 'industrial');
fp.addSensor(sensor, 'ShowThresholds', true);
fp.render();

Output: Line plot with three different threshold lines active in different time regions based on machine state.

Multiple Sensors from Registry

% example_sensor_registry.m — Use predefined sensor catalog
registry = SensorRegistry();
sensors = registry.getMultiple({'temperature', 'pressure', 'vibration'});

% Create dashboard
fig = FastSenseGrid(1, 3, 'Theme', 'dark');

for i = 1:3
    fp = fig.tile(i);
    fp.addSensor(sensors{i}, 'ShowThresholds', true);
    fig.setTileTitle(i, sensors{i}.Name);
end

fig.renderAll();

Event Detection

Real-Time Event Detection with Viewer

% example_event_detection_live.m — Detect threshold violations as events
% Setup three mock sensors with realistic data
sources = {
    MockDataSource('temperature', 65, 5, 2);
    MockDataSource('pressure', 100, 15, 1);
    MockDataSource('vibration', 2, 0.5, 5);
};

% Configure event detection
cfg = EventConfig();
cfg.MinDuration = 0.5;  % Ignore violations < 0.5 seconds
cfg.OnEventStart = eventLogger();  % Log each event to console

for i = 1:3
    src = sources{i};
    data = src.fetchNew();
    cfg.addSensor(create_sensor(data, src.Name), data.X, data.Y);
end

% Run detection
events = cfg.runDetection();

% Open interactive viewer
viewer = EventViewer(events);

Features:

  • Mock data sources with configurable noise, drift, violations
  • EventConfig orchestration
  • Console logging callback
  • Interactive EventViewer with Gantt timeline and click-to-plot

Event Store with Auto-Refresh

% example_event_viewer_from_file.m — Persistent event storage
% Part 1: Detect and save events
cfg = EventConfig();
cfg.EventFile = 'events.mat';
cfg.MaxBackups = 5;
for i = 1:6
    cfg.addSensor(sensors{i}, t{i}, y{i});
end
events1 = cfg.runDetection();  % Auto-saves to events.mat

% Part 2: Open viewer with auto-refresh
viewer = EventViewer.fromFile('events.mat', 'AutoRefresh', true, ...
    'RefreshInterval', 2);

% Part 3: Simulate background updates
timer_obj = timer('Period', 5, 'ExecutionMode', 'fixedRate', ...
    'TimerFcn', @(~,~) update_event_file('events.mat'));
start(timer_obj);

Disk-Backed Storage for Large Datasets

Automatic Memory-to-Disk Offloading

% example_disk_storage.m — Handle 100M+ point datasets
fp = FastSense('StorageMode', 'auto', 'MemoryLimit', 500e6);  % 500 MB RAM

% Add 50M point line (exceeds memory limit → automatic disk storage)
x = linspace(0, 1000, 50e6);
y = sin(x / 100) + 0.01*randn(size(x));
fp.addLine(x, y, 'DisplayName', '50M Points');

fp.addThreshold(0.5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();

% Zoom operations automatically fetch only visible slice from disk
% GPU memory remains ~0.06 MB regardless of dataset size

Key behaviors:

  • Data written to SQLite chunked database automatically
  • Only visible range loaded into memory during zoom/pan
  • Thresholds and violations computed on-disk when possible
  • Transparent to user (same API as in-memory)

Explicit Disk-Backed Sensor

% Sensor with 100M points moved to disk
sensor = Sensor('large_dataset');
sensor.X = linspace(0, 1e6, 100e6);
sensor.Y = randn(1, 100e6);  % 800 MB

% Offload to disk
sensor.toDisk();  % Creates DataStore, stores in .fpdb file

% Add thresholds and plot
sensor.addThresholdRule(struct(), 2, 'Direction', 'upper');
sensor.resolve();

fp = FastSense();
fp.addSensor(sensor, 'ShowThresholds', true);
fp.render();

Interactive Toolbar

Data Cursor, Crosshair, and PNG Export

% example_toolbar.m — Full interactive controls
fp = FastSense('Theme', 'dark');
x = linspace(0, 100, 5e6);
y = sin(x) + 0.1*randn(size(x));
fp.addLine(x, y, 'DisplayName', 'Sensor');
fp.render();

% Add toolbar to figure
toolbar = FastSenseToolbar(fp);
toolbar.show();

% User interactions:
% - Data cursor (click) → snaps to nearest data point, displays value
% - Crosshair (toggle) → crosshairs follow mouse, show X/Y coords
% - Grid (toggle) → show/hide background grid
% - Legend (toggle) → show/hide plot legend
% - Y-auto (button) → rescale Y to data range
% - PNG (button) → export current view as image
% - Violations (toggle) → show/hide violation markers

Datetime X-Axis

% example_datetime.m — Human-readable dates and times
t_datetime = datetime(2024, 1, 1) + hours(0:1000);
x = datenum(t_datetime);  % or pass datetime directly
y = sin(linspace(0, 2*pi, numel(x))) + 0.01*randn(size(x));

fp = FastSense('Theme', 'dark');
fp.addLine(x, y, 'DisplayName', 'Temperature');
fp.render();

toolbar = FastSenseToolbar(fp);
% X-axis labels auto-format based on zoom level:
% - Full range (1000 hours) → "Jan 01 00:00", "Jan 02 00:00", ...
% - Zoomed to 1 hour → "00:00:15", "00:00:30", "00:01:00", ...
% - Zoomed to 1 minute → "00:30:15.123", "00:30:16.456", ...

Stress Tests

100 Million Point Single Plot

% example_100M.m — Maximum dataset size
fp = FastSense('DeferDraw', true, 'ShowProgress', true);

x = linspace(0, 1e6, 100e7);
y = sin(x / 1e5) + 0.001*randn(size(x));

tic;
fp.addLine(x, y, 'DisplayName', '100M Points');
fp.addThreshold(0.5, 'Direction', 'upper');
fp.render();
toc;

fprintf('Rendered 100M points: interactive zoom/pan at 212 FPS\n');
fprintf('Point reduction: 99.99%% (100M → ~4K on screen)\n');

26 Sensors × 60M Points in Tabbed Dock

% example_stress_test.m — Large multi-sensor system
dock = FastSenseDock();

for tab = 1:5
    grid = FastSenseGrid(2, 3, 'Theme', 'industrial');
    
    for tile = 1:6
        fp = grid.tile(tile);
        sensor_idx = (tab-1)*6 + tile;
        
        x = linspace(0, 1000, 12e6);  % 12M points per sensor
        y = sin(x * (sensor_idx / 20)) + 0.1*randn(size(x));
        
        fp.addLine(x, y, 'DisplayName', sprintf('Sensor %d', sensor_idx));
        fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
        
        grid.setTileTitle(tile, sprintf('Sensor %d', sensor_idx));
    end
    
    grid.renderAll();
    dock.addTab(grid, sprintf('Tab %d', tab));
end

fprintf('Total: 60M points across 26 sensors\n');
fprintf('Rendering and zoom performance: sub-5ms per frame\n');

Advanced Patterns

Linked Multi-Sensor Dashboard

% example_linked.m — Synchronized zoom across subplots
fp1 = FastSense('LinkGroup', 'system1');
fp2 = FastSense('LinkGroup', 'system1');
fp3 = FastSense('LinkGroup', 'system1');

x = linspace(0, 200, 5e6);

% Pressure (2 columns)
ax1 = subplot(2, 3, [1 4]);
fp1.ParentAxes = ax1;
fp1.addLine(x, 100 + 20*sin(x/50) + 2*randn(size(x)));
fp1.addThreshold(120, 'Direction', 'upper');
fp1.render();
title('Pressure');

% Temperature (1 column)
ax2 = subplot(2, 3, 2);
fp2.ParentAxes = ax2;
fp2.addLine(x, 70 + 10*cos(x/40) + 1*randn(size(x)));
fp2.addThreshold(80, 'Direction', 'upper');
fp2.render();
title('Temperature');

% Vibration (1 column)
ax3 = subplot(2, 3, 3);
fp3.ParentAxes = ax3;
fp3.addLine(x, 5*randn(size(x)));
fp3.addThreshold(10, 'Direction', 'upper');
fp3.render();
title('Vibration');

% Zoom any one → all three auto-sync

Live Data with Auto-Refresh

% example_event_detection_live.m excerpt — Live mode
fp = FastSense('Theme', 'dark');
fp.addLine(x, y, 'DisplayName', 'Live Sensor');
fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
fp.render();

% Configure live polling
fp.LiveMatFile = 'sensor_data.mat';  % .mat file updated by background process
fp.LiveInterval = 1;  % Poll every 1 second
fp.ViewMode = 'follow';  % Auto-scroll to end

% Start polling (blocking loop in Octave; timer in MATLAB)
fp.startLive();

See Also

Clone this wiki locally