diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index b6f8457b..9c8cd092 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -23,10 +23,10 @@ jobs:
uses: actions/cache@v4
with:
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
- key: mex-linux-${{ hashFiles('libs/FastPlot/private/mex_src/**', 'libs/FastPlot/build_mex.m') }}
+ libs/FastSense/mksqlite.mex
+ key: mex-linux-${{ hashFiles('libs/FastSense/private/mex_src/**', 'libs/FastSense/build_mex.m') }}
- name: Compile MEX files
if: steps.cache-mex.outputs.cache-hit != 'true'
@@ -37,9 +37,9 @@ jobs:
with:
name: mex-linux-bench
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
+ libs/FastSense/mksqlite.mex
retention-days: 1
benchmark:
@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
container: gnuoctave/octave:8.4.0
env:
- FASTPLOT_SKIP_BUILD: "1"
+ FASTSENSE_SKIP_BUILD: "1"
steps:
- uses: actions/checkout@v4
@@ -61,7 +61,7 @@ jobs:
run: |
xvfb-run octave --eval "
addpath(pwd); setup();
- addpath(fullfile(pwd, 'libs', 'FastPlot', 'private'));
+ addpath(fullfile(pwd, 'libs', 'FastSense', 'private'));
n = 1e6;
x = linspace(0, 100, n);
@@ -79,7 +79,8 @@ jobs:
end
t_bs = toc / 1000;
- fp = FastPlot();
+ % Measure full render cycle
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'bench');
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
@@ -109,12 +110,12 @@ jobs:
"
- name: Fix git ownership
- run: git config --global --add safe.directory /__w/FastPlot/FastPlot
+ run: git config --global --add safe.directory /__w/FastSense/FastSense
- name: Store benchmark results
uses: benchmark-action/github-action-benchmark@v1
with:
- name: FastPlot Performance
+ name: FastSense Performance
tool: customSmallerIsBetter
output-file-path: benchmark-results.json
github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml
index 251aacff..123715b8 100644
--- a/.github/workflows/examples.yml
+++ b/.github/workflows/examples.yml
@@ -19,10 +19,10 @@ jobs:
uses: actions/cache@v4
with:
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
- key: mex-linux-${{ hashFiles('libs/FastPlot/private/mex_src/**', 'libs/FastPlot/build_mex.m') }}
+ libs/FastSense/mksqlite.mex
+ key: mex-linux-${{ hashFiles('libs/FastSense/private/mex_src/**', 'libs/FastSense/build_mex.m') }}
- name: Compile MEX files
if: steps.cache-mex.outputs.cache-hit != 'true'
@@ -33,9 +33,9 @@ jobs:
with:
name: mex-linux-examples
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
+ libs/FastSense/mksqlite.mex
retention-days: 1
smoke-test:
@@ -44,7 +44,7 @@ jobs:
runs-on: ubuntu-latest
container: gnuoctave/octave:8.4.0
env:
- FASTPLOT_SKIP_BUILD: "1"
+ FASTSENSE_SKIP_BUILD: "1"
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml
index dfe7cb16..079551c2 100644
--- a/.github/workflows/generate-docs.yml
+++ b/.github/workflows/generate-docs.yml
@@ -27,7 +27,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- git clone "https://x-access-token:${GITHUB_TOKEN}@github.com/HanSur94/FastPlot.wiki.git" wiki
+ git clone "https://x-access-token:${GITHUB_TOKEN}@github.com/HanSur94/FastSense.wiki.git" wiki
- name: Generate API docs
run: python3 scripts/generate_api_docs.py
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index daa9e8df..396c160f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -51,7 +51,7 @@ jobs:
- name: Package release
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
- DIRNAME="FastPlot-${VERSION}"
+ DIRNAME="FastSense-${VERSION}"
mkdir -p "${DIRNAME}"
# Copy release contents (allowlist — excludes tests/, benchmarks/, docs/, bridge/, private/, .git/)
@@ -82,5 +82,5 @@ jobs:
Download the archive, extract it, and run `setup` in MATLAB/Octave to add libraries to path and compile MEX accelerators.
files: |
- FastPlot-${{ steps.version.outputs.VERSION }}.tar.gz
- FastPlot-${{ steps.version.outputs.VERSION }}.zip
+ FastSense-${{ steps.version.outputs.VERSION }}.tar.gz
+ FastSense-${{ steps.version.outputs.VERSION }}.zip
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 66a50fda..b4a89ed5 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -38,10 +38,10 @@ jobs:
uses: actions/cache@v4
with:
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
- key: mex-linux-${{ hashFiles('libs/FastPlot/private/mex_src/**', 'libs/FastPlot/build_mex.m') }}
+ libs/FastSense/mksqlite.mex
+ key: mex-linux-${{ hashFiles('libs/FastSense/private/mex_src/**', 'libs/FastSense/build_mex.m') }}
- name: Compile MEX files
if: steps.cache-mex.outputs.cache-hit != 'true'
@@ -52,9 +52,9 @@ jobs:
with:
name: mex-linux
path: |
- libs/FastPlot/private/*.mex
+ libs/FastSense/private/*.mex
libs/SensorThreshold/private/*.mex
- libs/FastPlot/mksqlite.mex
+ libs/FastSense/mksqlite.mex
retention-days: 1
octave:
@@ -64,8 +64,8 @@ jobs:
runs-on: ubuntu-latest
container: gnuoctave/octave:8.4.0
env:
- FASTPLOT_SKIP_BUILD: "1"
- FASTPLOT_RESULTS_FILE: /tmp/test-results.txt
+ FASTSENSE_SKIP_BUILD: "1"
+ FASTSENSE_RESULTS_FILE: /tmp/test-results.txt
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/wiki-links.yml b/.github/workflows/wiki-links.yml
index bd2295f5..40278431 100644
--- a/.github/workflows/wiki-links.yml
+++ b/.github/workflows/wiki-links.yml
@@ -18,7 +18,7 @@ jobs:
- name: Clone wiki
run: |
- git clone https://github.com/HanSur94/FastPlot.wiki.git wiki-check
+ git clone https://github.com/HanSur94/FastSense.wiki.git wiki-check
- name: Check markdown links
uses: lycheeverse/lychee-action@v2
@@ -26,7 +26,7 @@ jobs:
args: >-
--no-progress
--exclude-loopback
- --exclude 'github.com/HanSur94/FastPlot/wiki'
+ --exclude 'github.com/HanSur94/FastSense/wiki'
--suggest
wiki-check/*.md
fail: true
diff --git a/CITATION.cff b/CITATION.cff
index a5880490..24226621 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -1,11 +1,11 @@
cff-version: 1.2.0
-message: "If you use FastPlot in your research, please cite it as below."
-title: "FastPlot: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave"
+message: "If you use FastSense in your research, please cite it as below."
+title: "FastSense: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave"
type: software
authors:
- family-names: Suhr
given-names: Hannes
-repository-code: "https://github.com/HanSur94/FastPlot"
+repository-code: "https://github.com/HanSur94/FastSense"
license: MIT
keywords:
- MATLAB
diff --git a/README.md b/README.md
index 49b59c2c..530b1ca2 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# FastPlot
+# FastSense
-[](https://github.com/HanSur94/FastPlot/actions/workflows/tests.yml)
-[](https://codecov.io/gh/HanSur94/FastPlot)
+[](https://github.com/HanSur94/FastSense/actions/workflows/tests.yml)
+[](https://codecov.io/gh/HanSur94/FastSense)
[](LICENSE)
[](https://www.mathworks.com/products/matlab.html)
[](https://octave.org)
@@ -9,7 +9,7 @@
Ultra-fast time series plotting for MATLAB and GNU Octave. Plot 100M+ data points with fluid zoom and pan — rendering only ~4,000 points at any zoom level.
-
+
## Performance
@@ -47,7 +47,7 @@ setup; % adds libraries to path + compiles MEX
x = linspace(0, 100, 1e7);
y = sin(x) + 0.1 * randn(size(x));
-fp = FastPlot('Theme', 'dark');
+fp = FastSense('Theme', 'dark');
fp.addLine(x, y, 'DisplayName', 'Sensor');
fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
@@ -57,8 +57,8 @@ fp.render();
## Installation
```bash
-git clone https://github.com/HanSur94/FastPlot.git
-cd FastPlot
+git clone https://github.com/HanSur94/FastSense.git
+cd FastSense
```
Then in MATLAB or Octave:
@@ -73,26 +73,26 @@ No toolbox dependencies. MEX compilation is optional — pure MATLAB fallbacks a
## Documentation
-Full documentation is available in the [Wiki](https://github.com/HanSur94/FastPlot/wiki):
+Full documentation is available in the [Wiki](https://github.com/HanSur94/FastSense/wiki):
-- [Getting Started](https://github.com/HanSur94/FastPlot/wiki/Getting-Started) — tutorial with examples
-- [API Reference: FastPlot](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-FastPlot) — core plotting class
-- [API Reference: Dashboard](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Dashboard) — layouts, widgets, engine
-- [API Reference: Sensors](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Sensors) — sensor system
-- [API Reference: Event Detection](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Event-Detection) — event pipeline
-- [Architecture](https://github.com/HanSur94/FastPlot/wiki/Architecture) — render pipeline, data flow
-- [MEX Acceleration](https://github.com/HanSur94/FastPlot/wiki/MEX-Acceleration) — SIMD details
-- [Performance](https://github.com/HanSur94/FastPlot/wiki/Performance) — benchmarks
+- [Getting Started](https://github.com/HanSur94/FastSense/wiki/Getting-Started) — tutorial with examples
+- [API Reference: FastSense](https://github.com/HanSur94/FastSense/wiki/API-Reference:-FastSense) — core plotting class
+- [API Reference: Dashboard](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Dashboard) — layouts, widgets, engine
+- [API Reference: Sensors](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Sensors) — sensor system
+- [API Reference: Event Detection](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Event-Detection) — event pipeline
+- [Architecture](https://github.com/HanSur94/FastSense/wiki/Architecture) — render pipeline, data flow
+- [MEX Acceleration](https://github.com/HanSur94/FastSense/wiki/MEX-Acceleration) — SIMD details
+- [Performance](https://github.com/HanSur94/FastSense/wiki/Performance) — benchmarks
## Examples
-See the [`examples/`](examples/) directory for 40+ runnable scripts covering basic plotting, dashboards, sensors, event detection, live mode, and disk-backed storage. A categorized guide is in the [wiki](https://github.com/HanSur94/FastPlot/wiki/Examples).
+See the [`examples/`](examples/) directory for 40+ runnable scripts covering basic plotting, dashboards, sensors, event detection, live mode, and disk-backed storage. A categorized guide is in the [wiki](https://github.com/HanSur94/FastSense/wiki/Examples).
## Libraries
| Library | Path | Description |
|---------|------|-------------|
-| FastPlot | `libs/FastPlot/` | Core plotting engine, layouts, toolbar, themes, disk storage |
+| FastSense | `libs/FastSense/` | Core plotting engine, layouts, toolbar, themes, disk storage |
| SensorThreshold | `libs/SensorThreshold/` | Sensor containers, state channels, threshold rules |
| EventDetection | `libs/EventDetection/` | Event detection, viewer, live pipeline, notifications |
| Dashboard | `libs/Dashboard/` | Dashboard engine with widgets and JSON persistence |
@@ -100,17 +100,17 @@ See the [`examples/`](examples/) directory for 40+ runnable scripts covering bas
## Contributing
-Contributions are welcome! Please open an issue to discuss your idea before submitting a pull request. See the [wiki](https://github.com/HanSur94/FastPlot/wiki) for architecture details and API references.
+Contributions are welcome! Please open an issue to discuss your idea before submitting a pull request. See the [wiki](https://github.com/HanSur94/FastSense/wiki) for architecture details and API references.
## Citation
-If you use FastPlot in your research, please cite it:
+If you use FastSense in your research, please cite it:
```bibtex
-@software{fastplot,
+@software{fastsense,
author = {Suhr, Hannes},
- title = {FastPlot: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave},
- url = {https://github.com/HanSur94/FastPlot},
+ title = {FastSense: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave},
+ url = {https://github.com/HanSur94/FastSense},
license = {MIT}
}
```
diff --git a/benchmarks/benchmark.m b/benchmarks/benchmark.m
index 24246d50..f47a3035 100644
--- a/benchmarks/benchmark.m
+++ b/benchmarks/benchmark.m
@@ -1,8 +1,8 @@
-%% FastPlot Benchmark — Compare FastPlot vs standard plot()
+%% FastSense Benchmark — Compare FastSense vs standard plot()
% Measures render time, zoom stress, point reduction, and memory footprint.
%
% NOTE: Octave's Qt/OpenGL backend clips lines in hardware, making raw
-% plot() very fast even with millions of points. FastPlot's interpreted
+% plot() very fast even with millions of points. FastSense's interpreted
% downsampling adds overhead in Octave. The primary wins are:
% 1. Point reduction (99%+ fewer points in the pipeline)
% 2. Lower GPU memory usage (critical when datasets exceed VRAM)
@@ -11,7 +11,7 @@
% In MATLAB (with JIT compilation), the downsampling cost is much lower.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
-addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastPlot', 'private'));
+addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastSense', 'private'));
sizes = [1e4, 1e5, 1e6, 5e6, 10e6, 50e6];
labels = {'10K', '100K', '1M', '5M', '10M', '50M'};
@@ -20,7 +20,7 @@
n_cases = numel(sizes);
t_std_init = NaN(1, n_cases); % figure + axes + plot() call
t_std_render = NaN(1, n_cases); % drawnow after plot()
-t_fp_init = NaN(1, n_cases); % FastPlot() + addLine + addThreshold
+t_fp_init = NaN(1, n_cases); % FastSense() + addLine + addThreshold
t_fp_render = NaN(1, n_cases); % render() + drawnow
t_std_zoom = NaN(1, n_cases);
t_fp_zoom = NaN(1, n_cases);
@@ -31,7 +31,7 @@
t_fp_ds = NaN(1, n_cases); % downsampling time only
fprintf('================================================================\n');
-fprintf(' FastPlot Benchmark\n');
+fprintf(' FastSense Benchmark\n');
fprintf(' Initial render + %d zoom ops + point reduction + memory\n', n_zooms);
fprintf('================================================================\n\n');
@@ -75,9 +75,9 @@
[~, ~] = minmax_downsample(x, y, 1000);
t_fp_ds(c) = toc;
- % ======== FastPlot ========
+ % ======== FastSense ========
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.addThreshold(-1.5, 'Direction', 'lower', 'ShowViolations', true, 'Color', 'r');
@@ -100,13 +100,13 @@
close(fp.hFigure);
reduction = (1 - pts_fp(c)/pts_std(c)) * 100;
- fprintf(' Init: plot()=%7.3fs FastPlot=%7.3fs\n', t_std_init(c), t_fp_init(c));
- fprintf(' Render: plot()=%7.3fs FastPlot=%7.3fs\n', t_std_render(c), t_fp_render(c));
- fprintf(' Total: plot()=%7.3fs FastPlot=%7.3fs\n', t_std_init(c)+t_std_render(c), t_fp_init(c)+t_fp_render(c));
- fprintf(' %2d zooms: plot()=%7.3fs FastPlot=%7.3fs\n', n_zooms, t_std_zoom(c), t_fp_zoom(c));
+ fprintf(' Init: plot()=%7.3fs FastSense=%7.3fs\n', t_std_init(c), t_fp_init(c));
+ fprintf(' Render: plot()=%7.3fs FastSense=%7.3fs\n', t_std_render(c), t_fp_render(c));
+ fprintf(' Total: plot()=%7.3fs FastSense=%7.3fs\n', t_std_init(c)+t_std_render(c), t_fp_init(c)+t_fp_render(c));
+ fprintf(' %2d zooms: plot()=%7.3fs FastSense=%7.3fs\n', n_zooms, t_std_zoom(c), t_fp_zoom(c));
fprintf(' Downsample: %.3fs (pure computation, no rendering)\n', t_fp_ds(c));
- fprintf(' GPU points: plot()=%-10d FastPlot=%-6d (%.1f%% reduction)\n', pts_std(c), pts_fp(c), reduction);
- fprintf(' GPU memory: plot()=%7.1f MB FastPlot=%7.3f MB\n', mem_std_MB(c), mem_fp_MB(c));
+ fprintf(' GPU points: plot()=%-10d FastSense=%-6d (%.1f%% reduction)\n', pts_std(c), pts_fp(c), reduction);
+ fprintf(' GPU memory: plot()=%7.1f MB FastSense=%7.3f MB\n', mem_std_MB(c), mem_fp_MB(c));
fprintf('\n');
clear x y fp;
@@ -130,22 +130,22 @@
fprintf('\n');
fprintf('Key takeaways:\n');
-fprintf(' - FastPlot reduces GPU pipeline data by 91-100%%\n');
+fprintf(' - FastSense reduces GPU pipeline data by 91-100%%\n');
fprintf(' - At 50M points: %.1f MB in pipeline vs %.3f MB (%.0fx reduction)\n', ...
mem_std_MB(end), mem_fp_MB(end), mem_std_MB(end)/mem_fp_MB(end));
-fprintf(' - FastPlot adds threshold lines + color-coded violation markers\n');
+fprintf(' - FastSense adds threshold lines + color-coded violation markers\n');
fprintf(' - Octave Qt/OpenGL backend clips efficiently in hardware,\n');
fprintf(' so raw plot() zoom appears fast despite pushing all points.\n');
fprintf(' - In MATLAB (JIT-compiled), downsampling overhead is much lower.\n');
fprintf('\n');
% ---- Plot results ----
-fig = figure('Name', 'FastPlot Benchmark', 'Position', [100 100 1800 800]);
+fig = figure('Name', 'FastSense Benchmark', 'Position', [100 100 1800 800]);
subplot(2,3,1);
loglog(sizes, t_std_init, 'ro-', 'LineWidth', 2, 'DisplayName', 'plot()');
hold on;
-loglog(sizes, t_fp_init, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastPlot');
+loglog(sizes, t_fp_init, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastSense');
xlabel('Data points');
ylabel('Time (s)');
title('Instantiation Time');
@@ -155,7 +155,7 @@
subplot(2,3,2);
loglog(sizes, t_std_render, 'ro-', 'LineWidth', 2, 'DisplayName', 'plot()');
hold on;
-loglog(sizes, t_fp_render, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastPlot');
+loglog(sizes, t_fp_render, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastSense');
xlabel('Data points');
ylabel('Time (s)');
title('Render Time (drawnow)');
@@ -165,7 +165,7 @@
subplot(2,3,3);
loglog(sizes, t_std_init + t_std_render, 'ro-', 'LineWidth', 2, 'DisplayName', 'plot()');
hold on;
-loglog(sizes, t_fp_init + t_fp_render, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastPlot');
+loglog(sizes, t_fp_init + t_fp_render, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastSense');
xlabel('Data points');
ylabel('Time (s)');
title('Total Time (Init + Render)');
@@ -175,7 +175,7 @@
subplot(2,3,4);
loglog(sizes, t_std_zoom, 'ro-', 'LineWidth', 2, 'DisplayName', 'plot()');
hold on;
-loglog(sizes, t_fp_zoom, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastPlot');
+loglog(sizes, t_fp_zoom, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastSense');
loglog(sizes, t_fp_ds, 'g^--', 'LineWidth', 1.5, 'DisplayName', 'Downsample only');
xlabel('Data points');
ylabel('Time (s)');
@@ -186,7 +186,7 @@
subplot(2,3,5);
loglog(sizes, mem_std_MB, 'ro-', 'LineWidth', 2, 'DisplayName', 'plot()');
hold on;
-loglog(sizes, mem_fp_MB, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastPlot');
+loglog(sizes, mem_fp_MB, 'bs-', 'LineWidth', 2, 'DisplayName', 'FastSense');
xlabel('Data points');
ylabel('GPU Memory (MB)');
title('GPU Pipeline Memory');
diff --git a/benchmarks/benchmark_datastore.m b/benchmarks/benchmark_datastore.m
index 04415ab9..e521faab 100644
--- a/benchmarks/benchmark_datastore.m
+++ b/benchmarks/benchmark_datastore.m
@@ -13,7 +13,7 @@ function benchmark_datastore()
matMaxSize = 50e6;
fprintf('\n============================================================\n');
- fprintf(' FastPlot DataStore Benchmark: .mat vs SQLite\n');
+ fprintf(' FastSense DataStore Benchmark: .mat vs SQLite\n');
fprintf('============================================================\n\n');
hasSqlite = (exist('mksqlite', 'file') == 3);
@@ -72,7 +72,7 @@ function benchmark_datastore()
% --- DataStore create (SQLite or binary) ---
tic;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
tDsCreate = toc;
% Free source data immediately to reclaim memory
@@ -181,7 +181,7 @@ function benchmark_datastore()
ce = min(c + chunkSz - 1, zoomN);
y(c:ce) = y(c:ce) + 0.1 * randn(1, ce - c + 1);
end
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
clear x y;
% Simulate 20 zoom levels from full view down to 0.01% of data
diff --git a/benchmarks/benchmark_features.m b/benchmarks/benchmark_features.m
index f87ca9c7..76f10ac6 100644
--- a/benchmarks/benchmark_features.m
+++ b/benchmarks/benchmark_features.m
@@ -1,17 +1,17 @@
-%% FastPlot Feature Benchmark — Theme, Band, Shaded, Fill, Marker, Dashboard
-% Measures overhead of each new feature vs baseline FastPlot rendering.
+%% FastSense Feature Benchmark — Theme, Band, Shaded, Fill, Marker, Dashboard
+% Measures overhead of each new feature vs baseline FastSense rendering.
%
% Tests:
-% 1. FastPlotTheme creation overhead
+% 1. FastSenseTheme creation overhead
% 2. addBand rendering cost (constant-y fill — trivial geometry)
% 3. addShaded rendering + zoom cost (data-driven fill — downsampled)
% 4. addFill rendering + zoom cost (area under curve)
% 5. addMarker rendering cost
-% 6. FastPlotGrid tiled dashboard overhead
+% 6. FastSenseGrid tiled dashboard overhead
% 7. Combined: all features together vs baseline
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
-addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastPlot', 'private'));
+addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastSense', 'private'));
sizes = [1e4, 1e5, 1e6, 5e6, 10e6];
labels = {'10K', '100K', '1M', '5M', '10M'};
@@ -21,7 +21,7 @@
% Timing arrays
t_theme_create = NaN(1, 5); % theme creation (5 presets)
-t_baseline = NaN(1, n_cases); % FastPlot + addLine + render
+t_baseline = NaN(1, n_cases); % FastSense + addLine + render
t_band = NaN(1, n_cases); % + 4 bands
t_shaded = NaN(1, n_cases); % + shaded region
t_fill = NaN(1, n_cases); % + fill region
@@ -34,7 +34,7 @@
t_combined_zoom = NaN(1, n_cases);
fprintf('================================================================\n');
-fprintf(' FastPlot Feature Benchmark\n');
+fprintf(' FastSense Feature Benchmark\n');
fprintf(' Render + %d zoom ops per size\n', n_zooms);
fprintf('================================================================\n\n');
@@ -44,7 +44,7 @@
for i = 1:5
tic;
for rep = 1:10000
- t = FastPlotTheme(presets{i});
+ t = FastSenseTheme(presets{i});
end
t_theme_create(i) = toc / 10000;
end
@@ -72,7 +72,7 @@
% ---- Baseline: addLine only ----
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.render();
t_baseline(c) = toc;
@@ -88,7 +88,7 @@
% ---- addBand: 4 bands (trivial geometry) ----
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addBand(60, 65, 'FaceColor', [1 0.8 0.3], 'FaceAlpha', 0.2, 'Label', 'Warning');
fp.addBand(65, 75, 'FaceColor', [1 0.3 0.3], 'FaceAlpha', 0.2, 'Label', 'Alarm');
@@ -100,7 +100,7 @@
% ---- addShaded: confidence envelope ----
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addShaded(x, envelope_hi, envelope_lo, 'FaceColor', [0.2 0.5 0.9], 'FaceAlpha', 0.15);
fp.render();
@@ -118,7 +118,7 @@
% ---- addFill: area under curve ----
y_abs = abs(y);
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y_abs, 'DisplayName', 'Signal');
fp.addFill(x, y_abs, 'FaceColor', [0.2 0.7 0.3], 'FaceAlpha', 0.3);
fp.render();
@@ -127,7 +127,7 @@
% ---- addMarker: 50 event markers ----
tic;
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addMarker(event_x, event_y, 'Marker', 'v', 'MarkerSize', 10, ...
'Color', [0.9 0.2 0.2], 'Label', 'Anomaly');
@@ -137,7 +137,7 @@
% ---- Combined: all features together ----
tic;
- fp = FastPlot('Theme', 'light');
+ fp = FastSense('Theme', 'light');
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addBand(60, 65, 'FaceColor', [1 0.8 0.3], 'FaceAlpha', 0.2);
fp.addBand(65, 75, 'FaceColor', [1 0.3 0.3], 'FaceAlpha', 0.2);
@@ -158,7 +158,7 @@
% ---- Dashboard: 2x2 with all features ----
tic;
- fig = FastPlotGrid(2, 2, 'Theme', 'light', 'Name', 'Bench');
+ fig = FastSenseGrid(2, 2, 'Theme', 'light', 'Name', 'Bench');
fp1 = fig.tile(1); fp1.addLine(x, y); fp1.addBand(60, 65, 'FaceColor', [1 0.8 0.3]);
fp2 = fig.tile(2); fp2.addLine(x, y); fp2.addShaded(x, envelope_hi, envelope_lo);
fp3 = fig.tile(3); fp3.addLine(x, y_abs); fp3.addFill(x, y_abs, 'FaceColor', [0.2 0.7 0.3]);
diff --git a/benchmarks/benchmark_memory.m b/benchmarks/benchmark_memory.m
index 5c572342..be874502 100644
--- a/benchmarks/benchmark_memory.m
+++ b/benchmarks/benchmark_memory.m
@@ -13,7 +13,7 @@ function benchmark_memory()
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- fprintf('=== FastPlot Memory Benchmark ===\n\n');
+ fprintf('=== FastSense Memory Benchmark ===\n\n');
%% 1. Scaling: memory vs disk across sizes
sizes = [1e5, 5e5, 1e6, 2e6, 5e6, 10e6];
diff --git a/benchmarks/benchmark_zoom.m b/benchmarks/benchmark_zoom.m
index 18cea701..a0493411 100644
--- a/benchmarks/benchmark_zoom.m
+++ b/benchmarks/benchmark_zoom.m
@@ -1,9 +1,9 @@
-%% FastPlot Zoom & Pan Latency Benchmark
+%% FastSense Zoom & Pan Latency Benchmark
% Measures per-frame latency for individual zoom and pan operations.
% Forces GPU flush with getframe() to get true frame delivery time.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
-addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastPlot', 'private'));
+addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastSense', 'private'));
sizes = [1e5, 1e6, 10e6, 50e6];
labels = {'100K', '1M', '10M', '50M'};
@@ -15,7 +15,7 @@
n_pan_steps = 20; % pan operations per zoom level
fprintf('================================================================\n');
-fprintf(' FastPlot Zoom & Pan Latency Benchmark\n');
+fprintf(' FastSense Zoom & Pan Latency Benchmark\n');
fprintf(' Per-frame timing with forced GPU flush (getframe)\n');
fprintf('================================================================\n\n');
@@ -32,7 +32,7 @@
plot(ax_std, x, y);
drawnow;
- fprintf(' %-6s | %-22s | %-22s\n', 'Zoom', 'plot() per-frame (ms)', 'FastPlot per-frame (ms)');
+ fprintf(' %-6s | %-22s | %-22s\n', 'Zoom', 'plot() per-frame (ms)', 'FastSense per-frame (ms)');
fprintf(' %-6s-+-%-22s-+-%-22s\n', '------', '----------------------', '----------------------');
std_zoom_times = {};
@@ -59,8 +59,8 @@
close(fig_std);
- % --- FastPlot ---
- fp = FastPlot();
+ % --- FastSense ---
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.addThreshold(-1.5, 'Direction', 'lower', 'ShowViolations', true, 'Color', 'r');
@@ -120,8 +120,8 @@
end
close(fig_std);
- % FastPlot
- fp = FastPlot();
+ % FastSense
+ fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Signal');
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.addThreshold(-1.5, 'Direction', 'lower', 'ShowViolations', true, 'Color', 'r');
@@ -140,12 +140,12 @@
fprintf(' plot(): avg=%5.1f ms p95=%5.1f ms max=%5.1f ms\n', ...
mean(std_pan), prctile(std_pan, 95), max(std_pan));
- fprintf(' FastPlot: avg=%5.1f ms p95=%5.1f ms max=%5.1f ms\n', ...
+ fprintf(' FastSense: avg=%5.1f ms p95=%5.1f ms max=%5.1f ms\n', ...
mean(fp_pan), prctile(fp_pan, 95), max(fp_pan));
std_fps = 1000 / mean(std_pan);
fp_fps = 1000 / mean(fp_pan);
- fprintf(' Effective FPS: plot()=%.0f FastPlot=%.0f\n', std_fps, fp_fps);
+ fprintf(' Effective FPS: plot()=%.0f FastSense=%.0f\n', std_fps, fp_fps);
fprintf('\n');
clear x y fp;
@@ -155,7 +155,7 @@
fprintf(' Notes\n');
fprintf('================================================================\n');
fprintf(' - getframe() forces GPU pipeline flush (true frame delivery).\n');
-fprintf(' - At deep zoom (0.1%%), FastPlot only processes ~0.1%% of data\n');
+fprintf(' - At deep zoom (0.1%%), FastSense only processes ~0.1%% of data\n');
fprintf(' via binary search, while plot() still has all points in GPU.\n');
fprintf(' - "p95" = 95th percentile latency (worst-case interactive feel).\n');
fprintf(' - Target for smooth interaction: <33 ms (30 fps) per frame.\n');
diff --git a/benchmarks/profile_datastore.m b/benchmarks/profile_datastore.m
index 6c8ead89..483ec8ce 100644
--- a/benchmarks/profile_datastore.m
+++ b/benchmarks/profile_datastore.m
@@ -1,5 +1,5 @@
function profile_datastore()
-%PROFILE_DATASTORE Profile FastPlotDataStore and disk-backed rendering.
+%PROFILE_DATASTORE Profile FastSenseDataStore and disk-backed rendering.
% Uses MATLAB's profiler to identify bottlenecks in:
% 1. DataStore creation (chunked write)
% 2. Range queries (zoom simulation)
@@ -16,14 +16,14 @@ function profile_datastore()
%% 1. Profile DataStore creation
fprintf('\n=== Profiling DataStore creation (%dM pts) ===\n', n/1e6);
profile on;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
profile off;
printTopFunctions('DataStore creation');
ds.cleanup();
%% 2. Profile range queries
fprintf('\n=== Profiling 50 range queries ===\n');
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
profile on;
for i = 1:50
xCenter = rand * 800 + 100;
@@ -35,7 +35,7 @@ function profile_datastore()
%% 3. Profile slice reads
fprintf('\n=== Profiling 50 slice reads ===\n');
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
profile on;
for i = 1:50
startIdx = randi(n - 10000);
@@ -47,7 +47,7 @@ function profile_datastore()
%% 4. Profile full render with disk-backed line
fprintf('\n=== Profiling render (disk-backed, %dM pts) ===\n', n/1e6);
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(x, y, 'DisplayName', 'Profile Test');
profile on;
fp.render();
@@ -69,7 +69,7 @@ function profile_datastore()
%% 6. Profile render with memory-backed line (for comparison)
fprintf('\n=== Profiling render (memory-backed, %dM pts) ===\n', n/1e6);
- fp2 = FastPlot('StorageMode', 'memory');
+ fp2 = FastSense('StorageMode', 'memory');
fp2.addLine(x, y, 'DisplayName', 'Memory Test');
profile on;
fp2.render();
@@ -89,7 +89,7 @@ function profile_datastore()
y(c:ce) = y(c:ce) + 0.1 * randn(1, ce - c + 1);
end
profile on;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
profile off;
printTopFunctions('DataStore creation (50M)');
clear x y;
diff --git a/bridge/python/fastplot_bridge/__init__.py b/bridge/python/fastplot_bridge/__init__.py
deleted file mode 100644
index 7ec79e67..00000000
--- a/bridge/python/fastplot_bridge/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""FastPlot Bridge — serves MATLAB dashboard data via REST/WebSocket."""
diff --git a/bridge/python/fastsense_bridge/__init__.py b/bridge/python/fastsense_bridge/__init__.py
new file mode 100644
index 00000000..21d37678
--- /dev/null
+++ b/bridge/python/fastsense_bridge/__init__.py
@@ -0,0 +1 @@
+"""FastSense Bridge — serves MATLAB dashboard data via REST/WebSocket."""
diff --git a/bridge/python/fastplot_bridge/__main__.py b/bridge/python/fastsense_bridge/__main__.py
similarity index 91%
rename from bridge/python/fastplot_bridge/__main__.py
rename to bridge/python/fastsense_bridge/__main__.py
index fdbdaf56..3dead316 100644
--- a/bridge/python/fastplot_bridge/__main__.py
+++ b/bridge/python/fastsense_bridge/__main__.py
@@ -1,11 +1,11 @@
-"""CLI entry point for the FastPlot bridge server.
+"""CLI entry point for the FastSense bridge server.
Connects to MATLAB's TCP server, receives the init message, starts
the FastAPI HTTP/WebSocket server, and notifies MATLAB when ready.
Usage:
- fastplot-bridge --matlab-port 5555
- fastplot-bridge --matlab-port 5555 --host 0.0.0.0 --port 9090
+ fastsense-bridge --matlab-port 5555
+ fastsense-bridge --matlab-port 5555 --host 0.0.0.0 --port 9090
"""
import argparse
@@ -61,7 +61,7 @@ async def notify_ready() -> None:
def main() -> None:
"""Parse CLI arguments and run the bridge server."""
parser = argparse.ArgumentParser(
- description="FastPlot Bridge Server"
+ description="FastSense Bridge Server"
)
parser.add_argument(
"--matlab-port",
diff --git a/bridge/python/fastplot_bridge/blob_decoder.py b/bridge/python/fastsense_bridge/blob_decoder.py
similarity index 100%
rename from bridge/python/fastplot_bridge/blob_decoder.py
rename to bridge/python/fastsense_bridge/blob_decoder.py
diff --git a/bridge/python/fastplot_bridge/server.py b/bridge/python/fastsense_bridge/server.py
similarity index 97%
rename from bridge/python/fastplot_bridge/server.py
rename to bridge/python/fastsense_bridge/server.py
index 6795b89f..ff5d619d 100644
--- a/bridge/python/fastplot_bridge/server.py
+++ b/bridge/python/fastsense_bridge/server.py
@@ -119,7 +119,7 @@ def create_app(state: AppState) -> FastAPI:
Returns:
Configured FastAPI app instance.
"""
- app = FastAPI(title="FastPlot Bridge")
+ app = FastAPI(title="FastSense Bridge")
# --- REST API ---
@@ -212,8 +212,8 @@ async def websocket_endpoint(ws: WebSocket) -> None:
# --- Static files ---
- # server.py is at bridge/python/fastplot_bridge/server.py
- # Go up: fastplot_bridge -> python -> bridge, then into /web
+ # server.py is at bridge/python/fastsense_bridge/server.py
+ # Go up: fastsense_bridge -> python -> bridge, then into /web
web_dir = Path(__file__).resolve().parent.parent.parent / "web"
if web_dir.is_dir():
diff --git a/bridge/python/fastplot_bridge/sqlite_reader.py b/bridge/python/fastsense_bridge/sqlite_reader.py
similarity index 98%
rename from bridge/python/fastplot_bridge/sqlite_reader.py
rename to bridge/python/fastsense_bridge/sqlite_reader.py
index 97c46e67..a940cbdd 100644
--- a/bridge/python/fastplot_bridge/sqlite_reader.py
+++ b/bridge/python/fastsense_bridge/sqlite_reader.py
@@ -1,4 +1,4 @@
-"""Read FastPlotDataStore SQLite files and decode typed BLOBs.
+"""Read FastSenseDataStore SQLite files and decode typed BLOBs.
Opens .fpdb files in read-only mode and provides methods to query chunks
by x-range, decode mksqlite typed BLOBs, and optionally apply minmax
@@ -13,7 +13,7 @@
class SqliteReader:
- """Synchronous reader for .fpdb files created by FastPlotDataStore.
+ """Synchronous reader for .fpdb files created by FastSenseDataStore.
Opens the database in read-only mode (URI mode) so it can safely
read while MATLAB writes with WAL mode enabled.
diff --git a/bridge/python/fastplot_bridge/tcp_client.py b/bridge/python/fastsense_bridge/tcp_client.py
similarity index 100%
rename from bridge/python/fastplot_bridge/tcp_client.py
rename to bridge/python/fastsense_bridge/tcp_client.py
diff --git a/bridge/python/pyproject.toml b/bridge/python/pyproject.toml
index a4bc099d..fe3443bc 100644
--- a/bridge/python/pyproject.toml
+++ b/bridge/python/pyproject.toml
@@ -1,5 +1,5 @@
[project]
-name = "fastplot-bridge"
+name = "fastsense-bridge"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
@@ -13,7 +13,7 @@ dependencies = [
dev = ["pytest>=7.0", "pytest-asyncio>=0.21", "httpx>=0.25"]
[project.scripts]
-fastplot-bridge = "fastplot_bridge.__main__:main"
+fastsense-bridge = "fastsense_bridge.__main__:main"
[tool.pytest.ini_options]
asyncio_mode = "auto"
diff --git a/bridge/python/tests/test_blob_decoder.py b/bridge/python/tests/test_blob_decoder.py
index f32675e7..b01fe806 100644
--- a/bridge/python/tests/test_blob_decoder.py
+++ b/bridge/python/tests/test_blob_decoder.py
@@ -5,7 +5,7 @@
import numpy as np
import pytest
-from fastplot_bridge.blob_decoder import MKSQ_MAGIC, decode_typed_blob
+from fastsense_bridge.blob_decoder import MKSQ_MAGIC, decode_typed_blob
MX_DOUBLE = 6
MX_SINGLE = 7
diff --git a/bridge/python/tests/test_server.py b/bridge/python/tests/test_server.py
index 4504b672..f8114ef5 100644
--- a/bridge/python/tests/test_server.py
+++ b/bridge/python/tests/test_server.py
@@ -10,8 +10,8 @@
import pytest
from fastapi.testclient import TestClient
-from fastplot_bridge.blob_decoder import MKSQ_MAGIC
-from fastplot_bridge.server import AppState, create_app
+from fastsense_bridge.blob_decoder import MKSQ_MAGIC
+from fastsense_bridge.server import AppState, create_app
def _make_double_blob(values: list[float]) -> bytes:
diff --git a/bridge/python/tests/test_sqlite_reader.py b/bridge/python/tests/test_sqlite_reader.py
index dd627f9c..c7b721f9 100644
--- a/bridge/python/tests/test_sqlite_reader.py
+++ b/bridge/python/tests/test_sqlite_reader.py
@@ -7,8 +7,8 @@
import numpy as np
import pytest
-from fastplot_bridge.blob_decoder import MKSQ_MAGIC
-from fastplot_bridge.sqlite_reader import SqliteReader, _minmax_downsample
+from fastsense_bridge.blob_decoder import MKSQ_MAGIC
+from fastsense_bridge.sqlite_reader import SqliteReader, _minmax_downsample
def _make_double_blob(values: list[float]) -> bytes:
@@ -20,7 +20,7 @@ def _make_double_blob(values: list[float]) -> bytes:
@pytest.fixture
def sample_db(tmp_path: Path) -> Path:
- """Create a minimal .fpdb file matching FastPlotDataStore schema."""
+ """Create a minimal .fpdb file matching FastSenseDataStore schema."""
db_path = tmp_path / "test.fpdb"
conn = sqlite3.connect(str(db_path))
diff --git a/bridge/python/tests/test_tcp_client.py b/bridge/python/tests/test_tcp_client.py
index beda72ad..5758d09a 100644
--- a/bridge/python/tests/test_tcp_client.py
+++ b/bridge/python/tests/test_tcp_client.py
@@ -6,7 +6,7 @@
import pytest
import pytest_asyncio
-from fastplot_bridge.tcp_client import MatlabTcpClient
+from fastsense_bridge.tcp_client import MatlabTcpClient
@pytest_asyncio.fixture
diff --git a/bridge/web/css/style.css b/bridge/web/css/style.css
index e28ed783..3f3a665a 100644
--- a/bridge/web/css/style.css
+++ b/bridge/web/css/style.css
@@ -1,5 +1,5 @@
/* ============================================================
- FastPlot Dashboard — Styles
+ FastSense Dashboard — Styles
============================================================ */
/* --- CSS Variables ----------------------------------------- */
diff --git a/bridge/web/index.html b/bridge/web/index.html
index 9f86d846..2042acc7 100644
--- a/bridge/web/index.html
+++ b/bridge/web/index.html
@@ -3,13 +3,13 @@
- FastPlot Dashboard
+ FastSense Dashboard
diff --git a/bridge/web/js/chart.js b/bridge/web/js/chart.js
index 599209b2..7dbd963f 100644
--- a/bridge/web/js/chart.js
+++ b/bridge/web/js/chart.js
@@ -1,5 +1,5 @@
/* ============================================================
- chart.js — uPlot wrapper for FastPlot time-series signals
+ chart.js — uPlot wrapper for FastSense time-series signals
============================================================ */
var Chart = (function () {
diff --git a/bridge/web/js/widgets.js b/bridge/web/js/widgets.js
index 425f6ca8..19ce4322 100644
--- a/bridge/web/js/widgets.js
+++ b/bridge/web/js/widgets.js
@@ -9,7 +9,7 @@ var Widgets = (function () {
function render(config, bodyEl) {
var type = config.type || "text";
switch (type) {
- case "fastplot": return renderFastplot(config, bodyEl);
+ case "fastsense": return renderFastSense(config, bodyEl);
case "kpi": return renderKPI(config, bodyEl);
case "status": return renderStatus(config, bodyEl);
case "table": return renderTable(config, bodyEl);
@@ -22,8 +22,8 @@ var Widgets = (function () {
}
}
- /* --- fastplot (uPlot chart) ---------------------------- */
- function renderFastplot(cfg, el) {
+ /* --- fastsense (uPlot chart) ---------------------------- */
+ function renderFastSense(cfg, el) {
el.classList.add("chart-body");
var signalId = cfg.signalId || cfg.id;
Chart.create(signalId, el);
diff --git a/docs/2026-03-06-fastplot-design.md b/docs/2026-03-06-fastsense-design.md
similarity index 93%
rename from docs/2026-03-06-fastplot-design.md
rename to docs/2026-03-06-fastsense-design.md
index 33198c3d..b16b9e3d 100644
--- a/docs/2026-03-06-fastplot-design.md
+++ b/docs/2026-03-06-fastsense-design.md
@@ -1,4 +1,4 @@
-# FastPlot — Ultra-Fast Time Series Plotting Library for MATLAB 2020b
+# FastSense — Ultra-Fast Time Series Plotting Library for MATLAB 2020b
## Design Document
@@ -41,7 +41,7 @@ MATLAB's built-in `plot()` chokes on large time series data (10M-100M points). Z
## 3. Architecture
```
-FastPlot (handle class)
+FastSense (handle class)
|
+-- Properties
| +-- Lines[] — array of line config structs
@@ -131,14 +131,14 @@ During zoom/pan callbacks, axis limits are managed manually. Auto-limit recalcul
```matlab
% Create with new figure (default)
-fp = FastPlot();
+fp = FastSense();
% Create targeting existing axes
-fp = FastPlot('Parent', ax);
+fp = FastSense('Parent', ax);
% Linked axes (opt-in)
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'sensors');
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'sensors');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'sensors');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'sensors');
```
### 5.2 Adding Lines
@@ -186,13 +186,13 @@ This:
### 5.5 UserData Tagging
-Every graphics object created by FastPlot carries identification metadata:
+Every graphics object created by FastSense carries identification metadata:
```matlab
-h.UserData.FastPlot = struct( ...
+h.UserData.FastSense = struct( ...
'Type', 'data_line', ... % 'data_line' | 'threshold' | 'violation_marker'
'Name', 'Sensor1', ... % DisplayName or threshold Label
- 'LineIndex', 1, ... % index in FastPlot's line array
+ 'LineIndex', 1, ... % index in FastSense's line array
'ThresholdValue', [] ... % populated for threshold/violation types
);
```
@@ -201,7 +201,7 @@ Usage example:
```matlab
% Find all threshold lines programmatically
lines = findobj(ax, '-function', ...
- @(h) isfield(h.UserData, 'FastPlot') && strcmp(h.UserData.FastPlot.Type, 'threshold'));
+ @(h) isfield(h.UserData, 'FastSense') && strcmp(h.UserData.FastSense.Type, 'threshold'));
```
---
@@ -229,7 +229,7 @@ Recompute violation markers for visible range
|
v
If LinkGroup active:
- |-- propagate XLim to all linked FastPlot instances (skip self)
+ |-- propagate XLim to all linked FastSense instances (skip self)
|
v
drawnow limitrate
@@ -240,8 +240,8 @@ drawnow limitrate
## 7. File Structure
```
-FastPlot/
-+-- FastPlot.m — main handle class
+FastSense/
++-- FastSense.m — main handle class
+-- private/
| +-- minmax_downsample.m — MinMax per-pixel downsampling
| +-- lttb_downsample.m — Largest Triangle Three Buckets
diff --git a/docs/generate_readme_images.m b/docs/generate_readme_images.m
index 9b459433..c277661c 100644
--- a/docs/generate_readme_images.m
+++ b/docs/generate_readme_images.m
@@ -1,5 +1,5 @@
-% generate_readme_images.m — Generate README screenshots for FastPlot features
-% Run from the FastPlot root directory:
+% generate_readme_images.m — Generate README screenshots for FastSense features
+% Run from the FastSense root directory:
% octave --no-gui --eval "setup; run('docs/generate_readme_images.m')"
img_dir = fullfile(fileparts(mfilename('fullpath')), 'images');
@@ -12,7 +12,7 @@
x = linspace(0, 100, 1e6);
y = sin(x * 2*pi / 10) + 0.5 * randn(1, numel(x));
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Sensor1', 'Color', 'b');
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.addThreshold(-1.5, 'Direction', 'lower', 'ShowViolations', true, 'Color', 'r');
@@ -30,7 +30,7 @@
y3 = sin(x * 2*pi / 8) * 15 + 30 + 4 * randn(1, numel(x));
y4 = cumsum(randn(1, numel(x))) / 100 + 10;
-fig = FastPlotGrid(2, 2, 'Theme', 'dark');
+fig = FastSenseGrid(2, 2, 'Theme', 'dark');
fig.setTileSpan(1, [1 2]);
fp1 = fig.tile(1);
@@ -63,7 +63,7 @@
hFig = figure('Position', [50 50 1600 600], 'Color', [0.95 0.95 0.95]);
for i = 1:5
ax = subplot(1, 5, i, 'Parent', hFig);
- fp = FastPlot('Parent', ax, 'Theme', themes{i});
+ fp = FastSense('Parent', ax, 'Theme', themes{i});
fp.addLine(x, y1, 'DisplayName', 'Sine');
fp.addLine(x, y2, 'DisplayName', 'Cosine');
fp.addThreshold(1.2, 'Direction', 'upper', 'ShowViolations', true);
@@ -83,21 +83,21 @@
hFig = figure('Position', [100 100 1200 700]);
ax1 = subplot(3, 1, 1, 'Parent', hFig);
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'sensors');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'sensors');
fp1.addLine(x, y_pressure, 'DisplayName', 'Pressure', 'Color', [0 0.45 0.74]);
fp1.addThreshold(125, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp1.render();
title(ax1, 'Pressure (linked)');
ax2 = subplot(3, 1, 2, 'Parent', hFig);
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'sensors');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'sensors');
fp2.addLine(x, y_temp, 'DisplayName', 'Temperature', 'Color', [0.85 0.33 0.1]);
fp2.addThreshold(75, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp2.render();
title(ax2, 'Temperature (linked)');
ax3 = subplot(3, 1, 3, 'Parent', hFig);
-fp3 = FastPlot('Parent', ax3, 'LinkGroup', 'sensors');
+fp3 = FastSense('Parent', ax3, 'LinkGroup', 'sensors');
fp3.addLine(x, y_vibration, 'DisplayName', 'Vibration', 'Color', [0.47 0.67 0.19]);
fp3.render();
title(ax3, 'Vibration (linked)');
@@ -113,7 +113,7 @@
y(250000:280000) = NaN;
y(400000:410000) = NaN;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Sensor (with dropouts)', 'Color', [0 0.45 0.74]);
fp.render();
title(fp.hAxes, 'NaN Gap Handling');
@@ -126,7 +126,7 @@
x = linspace(0, 100, 5e5);
y = sin(x * 2*pi / 15) * 40 + 50 + 8 * randn(1, numel(x));
-fp = FastPlot('Theme', 'dark');
+fp = FastSense('Theme', 'dark');
fp.addLine(x, y, 'DisplayName', 'Process Value', 'Color', [0.3 0.75 0.93]);
fp.addBand(85, 95, 'FaceColor', [1 0 0], 'FaceAlpha', 0.12, 'Label', 'HH Alarm');
fp.addBand(75, 85, 'FaceColor', [1 0.6 0], 'FaceAlpha', 0.10, 'Label', 'H Alarm');
@@ -161,7 +161,7 @@
s.addThresholdRule(struct('machine', 1), 30, 'Direction', 'lower', 'Label', 'Run LO');
s.resolve();
-fp = FastPlot('Theme', 'dark');
+fp = FastSense('Theme', 'dark');
fp.addSensor(s);
fp.render();
title(fp.hAxes, 'Condition-Dependent Sensor Thresholds');
@@ -174,7 +174,7 @@
x = datenum(2024,1,1) + (0:499999)/86400;
y = sin((1:500000) * 2*pi/3600) + 0.3 * randn(1, 500000);
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'XType', 'datenum', 'DisplayName', 'Sensor');
fp.addThreshold(1.0, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.render();
diff --git a/docs/plans/2026-03-06-dashboard-visual-design.md b/docs/plans/2026-03-06-dashboard-visual-design.md
index 1231c3f0..4f3927a6 100644
--- a/docs/plans/2026-03-06-dashboard-visual-design.md
+++ b/docs/plans/2026-03-06-dashboard-visual-design.md
@@ -1,4 +1,4 @@
-# FastPlot Enhancement: Visual Customization + Dashboard Layouts
+# FastSense Enhancement: Visual Customization + Dashboard Layouts
**Date:** 2026-03-06
**Status:** Approved
@@ -7,9 +7,9 @@
## 1. Problem Statement
-FastPlot today is a single-axes class. Building multi-panel dashboards requires manual `subplot()` calls, manual `Parent`/`LinkGroup` wiring, and no theming support. Visual customization is limited to pass-through MATLAB line properties. There are no shaded regions, band fills, or custom markers.
+FastSense today is a single-axes class. Building multi-panel dashboards requires manual `subplot()` calls, manual `Parent`/`LinkGroup` wiring, and no theming support. Visual customization is limited to pass-through MATLAB line properties. There are no shaded regions, band fills, or custom markers.
-**Goal:** Add a figure-level layout manager (`FastPlotFigure`) for tiled dashboards with spanning, a comprehensive theming system with inheritance, and new visual elements (shaded fills, bands, markers) — all while keeping full backward compatibility.
+**Goal:** Add a figure-level layout manager (`FastSenseFigure`) for tiled dashboards with spanning, a comprehensive theming system with inheritance, and new visual elements (shaded fills, bands, markers) — all while keeping full backward compatibility.
---
@@ -18,7 +18,7 @@ FastPlot today is a single-axes class. Building multi-panel dashboards requires
### Functional
- Tiled grid layout with configurable rows/columns
- Tiles can span multiple rows and/or columns
-- Every tile is a FastPlot axes (no non-plot tiles for now)
+- Every tile is a FastSense axes (no non-plot tiles for now)
- Theme system with presets and custom definitions
- Theme inheritance: element override > tile theme > figure theme > default preset
- Auto line color cycling from theme palette
@@ -27,7 +27,7 @@ FastPlot today is a single-axes class. Building multi-panel dashboards requires
- Area fills from line to baseline
- Custom event markers with configurable shape/size/color
- Link groups remain explicit (not auto-linked in dashboards)
-- Standalone FastPlot gains theme support without requiring FastPlotFigure
+- Standalone FastSense gains theme support without requiring FastSenseFigure
### Non-Functional
- Full backward compatibility — all existing scripts unchanged
@@ -41,13 +41,13 @@ FastPlot today is a single-axes class. Building multi-panel dashboards requires
### 3.1 Class Structure
```
-FastPlotFigure (handle class) -- figure + layout + theme
+FastSenseFigure (handle class) -- figure + layout + theme
hFigure -- figure handle
- Theme -- FastPlotTheme struct
+ Theme -- FastSenseTheme struct
Grid [rows, cols] -- layout grid dimensions
- Tiles{} -- cell array of FastPlot instances
+ Tiles{} -- cell array of FastSense instances
TileSpans{} -- per-tile [rowSpan, colSpan]
- tile(n) -> FastPlot -- get/create FastPlot for tile n
+ tile(n) -> FastSense -- get/create FastSense for tile n
setTileSpan(n, [r,c]) -- make tile span multiple rows/cols
tileTitle(n, str) -- set title for tile n
tileXLabel(n, str) -- set xlabel for tile n
@@ -56,7 +56,7 @@ FastPlotFigure (handle class) -- figure + layout + theme
renderAll() -- render all unrendered tiles
render() -- alias for renderAll()
-FastPlot (handle class) -- per-axes (extended)
+FastSense (handle class) -- per-axes (extended)
existing API unchanged
addShaded(x, y1, y2, ...) -- fill between two curves
addBand(yLow, yHigh, ...) -- horizontal band fill
@@ -65,7 +65,7 @@ FastPlot (handle class) -- per-axes (extended)
Theme (inherited or overridden) -- per-tile theme
auto line color cycling -- from theme LineColorOrder
-FastPlotTheme (function, not class) -- returns theme struct
+FastSenseTheme (function, not class) -- returns theme struct
Background, AxesColor, GridColor, GridAlpha
GridStyle, FontName, FontSize, TitleFontSize
ForegroundColor -- text, tick labels, axis lines
@@ -80,10 +80,10 @@ FastPlotTheme (function, not class) -- returns theme struct
| File | Purpose |
|------|---------|
-| `FastPlotFigure.m` | Figure-level layout manager with tiled grid, spanning, theming |
-| `FastPlotTheme.m` | Function returning theme preset structs and merge logic |
+| `FastSenseFigure.m` | Figure-level layout manager with tiled grid, spanning, theming |
+| `FastSenseTheme.m` | Function returning theme preset structs and merge logic |
-### 3.3 Extended: `FastPlot.m`
+### 3.3 Extended: `FastSense.m`
| Addition | Description |
|----------|-------------|
@@ -96,20 +96,20 @@ FastPlotTheme (function, not class) -- returns theme struct
---
-## 4. FastPlotFigure API
+## 4. FastSenseFigure API
```matlab
%% Construction
-fig = FastPlotFigure(rows, cols);
-fig = FastPlotFigure(rows, cols, 'Theme', 'dark');
-fig = FastPlotFigure(rows, cols, 'Theme', myCustomTheme);
-fig = FastPlotFigure(rows, cols, 'Position', [100 100 1400 800], 'Name', 'Dashboard');
+fig = FastSenseFigure(rows, cols);
+fig = FastSenseFigure(rows, cols, 'Theme', 'dark');
+fig = FastSenseFigure(rows, cols, 'Theme', myCustomTheme);
+fig = FastSenseFigure(rows, cols, 'Position', [100 100 1400 800], 'Name', 'Dashboard');
%% Tile spanning
fig.setTileSpan(1, [1 2]); % tile 1 spans 1 row, 2 columns
fig.setTileSpan(3, [2 1]); % tile 3 spans 2 rows, 1 column
-%% Getting tiles (returns FastPlot instance, creates axes on first call)
+%% Getting tiles (returns FastSense instance, creates axes on first call)
fp = fig.tile(1);
fp.addLine(x, y, 'DisplayName', 'Sensor1');
fp.render();
@@ -132,7 +132,7 @@ Tiles are numbered left-to-right, top-to-bottom (same as MATLAB's `subplot`). Wh
### Key Behaviors
-- `tile(n)` is lazy -- axes and FastPlot are created on first access
+- `tile(n)` is lazy -- axes and FastSense are created on first access
- `renderAll()` calls `render()` on all tiles that haven't been rendered yet
- Figure is kept invisible until `renderAll()` or the first `tile.render()` call
- Standard figure properties (`Name`, `Position`, `Color`) forwarded to underlying figure handle
@@ -170,7 +170,7 @@ fp.addMarker(x_events, y_events, ...
- `addBand` creates a rectangle patch -- no downsampling (constant bounds)
- `addFill` is sugar for `addShaded(x, y, baseline)`
- `addMarker` creates a line object with `'none'` LineStyle and configurable marker props
-- All new elements get `UserData.FastPlot` tagging (`'shaded'`, `'band'`, `'fill'`, `'marker'`)
+- All new elements get `UserData.FastSense` tagging (`'shaded'`, `'band'`, `'fill'`, `'marker'`)
### Rendering Order (back to front)
@@ -227,7 +227,7 @@ myTheme = struct( ...
| `'colorblind'` | Deuteranopia-safe 8-color palette |
| Custom | Nx3 matrix of RGB values |
-Auto-cycling: when `addLine` is called without a `Color` argument, the next color from `LineColorOrder` is assigned automatically. Each FastPlot instance tracks its position in the cycle.
+Auto-cycling: when `addLine` is called without a `Color` argument, the next color from `LineColorOrder` is assigned automatically. Each FastSense instance tracks its position in the cycle.
### 6.4 Theme Inheritance
@@ -235,27 +235,27 @@ Auto-cycling: when `addLine` is called without a `Color` argument, the next colo
Element override > Tile theme > Figure theme > 'default' preset
```
-- `FastPlotTheme('dark')` returns the full dark preset struct
-- `FastPlotTheme('dark', 'LineColorOrder', 'colorblind')` returns dark with one field overridden
+- `FastSenseTheme('dark')` returns the full dark preset struct
+- `FastSenseTheme('dark', 'LineColorOrder', 'colorblind')` returns dark with one field overridden
- Merging: simple `fieldnames` loop, override wins
- Unset fields in custom themes inherit from `'default'`
---
-## 7. Standalone FastPlot Enhancements
+## 7. Standalone FastSense Enhancements
```matlab
-%% Standalone with theme (no FastPlotFigure required)
-fp = FastPlot('Theme', 'dark');
+%% Standalone with theme (no FastSenseFigure required)
+fp = FastSense('Theme', 'dark');
fp.addLine(x, y);
fp.render();
%% Full constructor signature
-fp = FastPlot();
-fp = FastPlot('Parent', ax);
-fp = FastPlot('LinkGroup', 'sensors');
-fp = FastPlot('Theme', 'dark');
-fp = FastPlot('Parent', ax, 'LinkGroup', 'g1', 'Theme', myTheme);
+fp = FastSense();
+fp = FastSense('Parent', ax);
+fp = FastSense('LinkGroup', 'sensors');
+fp = FastSense('Theme', 'dark');
+fp = FastSense('Parent', ax, 'LinkGroup', 'g1', 'Theme', myTheme);
```
No theme = `'default'` preset. All new methods are optional additions.
diff --git a/docs/plans/2026-03-06-dashboard-visual-impl.md b/docs/plans/2026-03-06-dashboard-visual-impl.md
index ea21fc55..5e034371 100644
--- a/docs/plans/2026-03-06-dashboard-visual-impl.md
+++ b/docs/plans/2026-03-06-dashboard-visual-impl.md
@@ -2,9 +2,9 @@
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
-**Goal:** Add FastPlotFigure (tiled dashboard layouts), FastPlotTheme (5 presets + custom themes), and new visual elements (addShaded, addBand, addFill, addMarker) to FastPlot while maintaining full backward compatibility.
+**Goal:** Add FastSenseFigure (tiled dashboard layouts), FastSenseTheme (5 presets + custom themes), and new visual elements (addShaded, addBand, addFill, addMarker) to FastSense while maintaining full backward compatibility.
-**Architecture:** Three layers — `FastPlotTheme.m` (function returning theme structs), extended `FastPlot.m` (theme support + 4 new visual methods), and `FastPlotFigure.m` (figure layout manager). Theme inheritance flows: element override > tile theme > figure theme > 'default' preset. All visual enhancements use `patch()` or `line()` objects with UserData tagging and downsampling on zoom.
+**Architecture:** Three layers — `FastSenseTheme.m` (function returning theme structs), extended `FastSense.m` (theme support + 4 new visual methods), and `FastSenseFigure.m` (figure layout manager). Theme inheritance flows: element override > tile theme > figure theme > 'default' preset. All visual enhancements use `patch()` or `line()` objects with UserData tagging and downsampling on zoom.
**Tech Stack:** Pure MATLAB/Octave — no toolboxes, no MEX. Uses `figure()`, `axes()`, `patch()`, `line()`, `set()`/`get()`.
@@ -12,10 +12,10 @@
---
-### Task 1: FastPlotTheme — Default Preset & Merge Logic
+### Task 1: FastSenseTheme — Default Preset & Merge Logic
**Files:**
-- Create: `FastPlotTheme.m`
+- Create: `FastSenseTheme.m`
- Create: `tests/test_theme.m`
**Step 1: Write the failing test**
@@ -24,12 +24,12 @@ Create `tests/test_theme.m`:
```matlab
function test_theme()
-%TEST_THEME Tests for FastPlotTheme function.
+%TEST_THEME Tests for FastSenseTheme function.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
% testDefaultPreset
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
assert(isstruct(t), 'testDefaultPreset: must return struct');
assert(isequal(t.Background, [1 1 1]), 'testDefaultPreset: Background');
assert(isfield(t, 'AxesColor'), 'testDefaultPreset: AxesColor field');
@@ -50,12 +50,12 @@ function test_theme()
assert(size(t.LineColorOrder, 2) == 3, 'testDefaultPreset: LineColorOrder must be Nx3');
% testNoArgsReturnsDefault
- t0 = FastPlotTheme();
- t1 = FastPlotTheme('default');
+ t0 = FastSenseTheme();
+ t1 = FastSenseTheme('default');
assert(isequal(t0, t1), 'testNoArgsReturnsDefault');
% testMergeOverrides
- t = FastPlotTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
+ t = FastSenseTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
assert(t.FontSize == 14, 'testMergeOverrides: FontSize');
assert(t.LineWidth == 2.0, 'testMergeOverrides: LineWidth');
assert(isequal(t.Background, [1 1 1]), 'testMergeOverrides: Background unchanged');
@@ -63,7 +63,7 @@ function test_theme()
% testInvalidPresetErrors
threw = false;
try
- FastPlotTheme('nonexistent');
+ FastSenseTheme('nonexistent');
catch
threw = true;
end
@@ -76,18 +76,18 @@ end
**Step 2: Run test to verify it fails**
Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_theme;"`
-Expected: FAIL — `FastPlotTheme` not found
+Expected: FAIL — `FastSenseTheme` not found
**Step 3: Write minimal implementation**
-Create `FastPlotTheme.m`:
+Create `FastSenseTheme.m`:
```matlab
-function theme = FastPlotTheme(preset, varargin)
-%FASTPLOTTHEME Return a theme struct for FastPlot styling.
-% theme = FastPlotTheme() — returns 'default' preset
-% theme = FastPlotTheme('dark') — returns named preset
-% theme = FastPlotTheme('dark', 'FontSize', 14) — preset with overrides
+function theme = FastSenseTheme(preset, varargin)
+%FASTSENSETHEME Return a theme struct for FastSense styling.
+% theme = FastSenseTheme() — returns 'default' preset
+% theme = FastSenseTheme('dark') — returns named preset
+% theme = FastSenseTheme('dark', 'FontSize', 14) — preset with overrides
if nargin == 0
preset = 'default';
@@ -209,7 +209,7 @@ function t = getPreset(name)
'BandAlpha', 0.1 ...
);
otherwise
- error('FastPlotTheme:unknownPreset', ...
+ error('FastSenseTheme:unknownPreset', ...
'Unknown theme preset: ''%s''. Use ''default'', ''dark'', ''light'', ''industrial'', or ''scientific''.', name);
end
end
@@ -251,7 +251,7 @@ function colors = getPalette(name)
0.00 0.00 0.00; ... % black
];
otherwise
- error('FastPlotTheme:unknownPalette', ...
+ error('FastSenseTheme:unknownPalette', ...
'Unknown palette: ''%s''. Use ''vibrant'', ''muted'', or ''colorblind''.', name);
end
end
@@ -273,13 +273,13 @@ Expected: PASS — All 4 theme tests passed.
**Step 5: Commit**
```bash
-git add FastPlotTheme.m tests/test_theme.m
-git commit -m "Add FastPlotTheme with 5 presets, 3 palettes, and merge logic"
+git add FastSenseTheme.m tests/test_theme.m
+git commit -m "Add FastSenseTheme with 5 presets, 3 palettes, and merge logic"
```
---
-### Task 2: FastPlotTheme — All Presets & Palettes
+### Task 2: FastSenseTheme — All Presets & Palettes
**Files:**
- Modify: `tests/test_theme.m`
@@ -290,23 +290,23 @@ Append to `tests/test_theme.m` (before the final fprintf):
```matlab
% testDarkPreset
- t = FastPlotTheme('dark');
+ t = FastSenseTheme('dark');
assert(all(t.Background < [0.2 0.2 0.2]), 'testDarkPreset: Background should be dark');
assert(all(t.ForegroundColor > [0.7 0.7 0.7]), 'testDarkPreset: ForegroundColor should be light');
assert(size(t.LineColorOrder, 2) == 3, 'testDarkPreset: LineColorOrder Nx3');
% testLightPreset
- t = FastPlotTheme('light');
+ t = FastSenseTheme('light');
assert(all(t.Background > [0.9 0.9 0.9]), 'testLightPreset: Background');
assert(size(t.LineColorOrder, 2) == 3, 'testLightPreset: LineColorOrder Nx3');
% testIndustrialPreset
- t = FastPlotTheme('industrial');
+ t = FastSenseTheme('industrial');
assert(t.LineWidth >= 1.0, 'testIndustrialPreset: LineWidth');
assert(size(t.LineColorOrder, 2) == 3, 'testIndustrialPreset: LineColorOrder Nx3');
% testScientificPreset
- t = FastPlotTheme('scientific');
+ t = FastSenseTheme('scientific');
assert(strcmp(t.FontName, 'Times New Roman'), 'testScientificPreset: FontName');
assert(t.GridAlpha == 0, 'testScientificPreset: no grid');
assert(t.LineWidth < 1.0, 'testScientificPreset: thin lines');
@@ -314,18 +314,18 @@ Append to `tests/test_theme.m` (before the final fprintf):
% testStructAsPreset
custom = struct('Background', [0 0 0], 'FontSize', 16);
- t = FastPlotTheme(custom);
+ t = FastSenseTheme(custom);
assert(isequal(t.Background, [0 0 0]), 'testStructAsPreset: Background');
assert(t.FontSize == 16, 'testStructAsPreset: FontSize');
assert(isfield(t, 'GridColor'), 'testStructAsPreset: inherits defaults');
% testPaletteResolution
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
assert(size(t.LineColorOrder, 1) >= 6, 'testPaletteResolution: at least 6 colors');
% testCustomPaletteMatrix
customColors = [1 0 0; 0 1 0; 0 0 1];
- t = FastPlotTheme('default', 'LineColorOrder', customColors);
+ t = FastSenseTheme('default', 'LineColorOrder', customColors);
assert(isequal(t.LineColorOrder, customColors), 'testCustomPaletteMatrix');
```
@@ -349,42 +349,42 @@ git commit -m "Add comprehensive theme preset and palette tests"
---
-### Task 3: FastPlot Theme Integration — Constructor & applyTheme
+### Task 3: FastSense Theme Integration — Constructor & applyTheme
**Files:**
-- Modify: `FastPlot.m:12-54` (properties + constructor)
-- Modify: `FastPlot.m:161-328` (render method)
-- Create: `tests/test_fastplot_theme.m`
+- Modify: `FastSense.m:12-54` (properties + constructor)
+- Modify: `FastSense.m:161-328` (render method)
+- Create: `tests/test_fastsense_theme.m`
**Step 1: Write the failing test**
-Create `tests/test_fastplot_theme.m`:
+Create `tests/test_fastsense_theme.m`:
```matlab
-function test_fastplot_theme()
-%TEST_FASTPLOT_THEME Tests for FastPlot theme integration.
+function test_fastsense_theme()
+%TEST_FASTSENSE_THEME Tests for FastSense theme integration.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'private'));
% testThemeConstructorString
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
assert(isstruct(fp.Theme), 'testThemeConstructorString: Theme must be struct');
assert(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testThemeConstructorString: dark bg');
% testThemeConstructorStruct
custom = struct('Background', [0.5 0.5 0.5]);
- fp = FastPlot('Theme', custom);
+ fp = FastSense('Theme', custom);
assert(isequal(fp.Theme.Background, [0.5 0.5 0.5]), 'testThemeConstructorStruct');
assert(isfield(fp.Theme, 'FontSize'), 'testThemeConstructorStruct: inherits defaults');
% testDefaultThemeWhenNoneSpecified
- fp = FastPlot();
+ fp = FastSense();
assert(isstruct(fp.Theme), 'testDefaultTheme: must have theme');
assert(isequal(fp.Theme.Background, [1 1 1]), 'testDefaultTheme: default bg');
% testThemeAppliedOnRender
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
bgColor = get(fp.hFigure, 'Color');
@@ -394,7 +394,7 @@ function test_fastplot_theme()
close(fp.hFigure);
% testThemeFontApplied
- fp = FastPlot('Theme', 'scientific');
+ fp = FastSense('Theme', 'scientific');
fp.addLine(1:100, rand(1,100));
fp.render();
assert(strcmp(get(fp.hAxes, 'FontName'), 'Times New Roman'), 'testThemeFontApplied');
@@ -403,7 +403,7 @@ function test_fastplot_theme()
% testThemeWithParentAxes
fig = figure('Visible', 'off');
ax = axes('Parent', fig);
- fp = FastPlot('Parent', ax, 'Theme', 'dark');
+ fp = FastSense('Parent', ax, 'Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
axColor = get(ax, 'Color');
@@ -411,7 +411,7 @@ function test_fastplot_theme()
close(fig);
% testBackwardCompatNoTheme
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
assert(isgraphics(fp.hAxes), 'testBackwardCompatNoTheme');
@@ -423,16 +423,16 @@ end
**Step 2: Run test to verify it fails**
-Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastplot_theme;"`
+Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastsense_theme;"`
Expected: FAIL — `fp.Theme` property does not exist
**Step 3: Write implementation**
-Modify `FastPlot.m`:
+Modify `FastSense.m`:
Add to public properties (after line 14):
```matlab
- Theme = [] % theme struct (from FastPlotTheme)
+ Theme = [] % theme struct (from FastSenseTheme)
```
Add to private properties (after line 35):
@@ -442,7 +442,7 @@ Add to private properties (after line 35):
Modify constructor (lines 45-54) to handle 'theme':
```matlab
- function obj = FastPlot(varargin)
+ function obj = FastSense(varargin)
for k = 1:2:numel(varargin)
switch lower(varargin{k})
case 'parent'
@@ -452,7 +452,7 @@ Modify constructor (lines 45-54) to handle 'theme':
case 'theme'
val = varargin{k+1};
if ischar(val) || isstruct(val)
- obj.Theme = FastPlotTheme(val);
+ obj.Theme = FastSenseTheme(val);
else
obj.Theme = val;
end
@@ -460,12 +460,12 @@ Modify constructor (lines 45-54) to handle 'theme':
end
% Default theme if none set
if isempty(obj.Theme)
- obj.Theme = FastPlotTheme('default');
+ obj.Theme = FastSenseTheme('default');
end
end
```
-Add private method `applyTheme` to FastPlot.m (in the `methods (Access = private)` block):
+Add private method `applyTheme` to FastSense.m (in the `methods (Access = private)` block):
```matlab
function applyTheme(obj)
t = obj.Theme;
@@ -501,7 +501,7 @@ In `render()`, call `obj.applyTheme()` right after creating/assigning axes (afte
**Step 4: Run test to verify it passes**
-Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastplot_theme;"`
+Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastsense_theme;"`
Expected: PASS — All 7 theme integration tests passed.
**Step 5: Run existing tests to verify backward compatibility**
@@ -512,8 +512,8 @@ Expected: All existing tests pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_fastplot_theme.m
-git commit -m "Add theme support to FastPlot constructor and render"
+git add FastSense.m tests/test_fastsense_theme.m
+git commit -m "Add theme support to FastSense constructor and render"
```
---
@@ -521,16 +521,16 @@ git commit -m "Add theme support to FastPlot constructor and render"
### Task 4: Auto Line Color Cycling
**Files:**
-- Modify: `FastPlot.m` (addLine method, lines 56-116)
-- Modify: `tests/test_fastplot_theme.m`
+- Modify: `FastSense.m` (addLine method, lines 56-116)
+- Modify: `tests/test_fastsense_theme.m`
**Step 1: Write the failing test**
-Append to `tests/test_fastplot_theme.m` (before final fprintf):
+Append to `tests/test_fastsense_theme.m` (before final fprintf):
```matlab
% testAutoColorCycling
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
@@ -541,7 +541,7 @@ Append to `tests/test_fastplot_theme.m` (before final fprintf):
assert(~isequal(c2, c3), 'testAutoColorCycling: colors 2 and 3 differ');
% testExplicitColorSkipsCycle
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', [1 0 0]);
fp.addLine(1:10, rand(1,10));
assert(isequal(fp.Lines(1).Options.Color, [1 0 0]), 'testExplicitColorSkipsCycle: explicit');
@@ -557,7 +557,7 @@ Expected: FAIL — auto-assigned colors not present in Options
**Step 3: Write implementation**
-Modify `addLine` in `FastPlot.m`. After the name-value parsing loop (around line 100), before building the line struct, add:
+Modify `addLine` in `FastSense.m`. After the name-value parsing loop (around line 100), before building the line struct, add:
```matlab
% Auto-assign color from theme palette if not explicitly set
@@ -571,7 +571,7 @@ Modify `addLine` in `FastPlot.m`. After the name-value parsing loop (around line
**Step 4: Run test to verify it passes**
-Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastplot_theme;"`
+Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastsense_theme;"`
Expected: PASS
**Step 5: Run all tests**
@@ -582,7 +582,7 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_fastplot_theme.m
+git add FastSense.m tests/test_fastsense_theme.m
git commit -m "Add auto line color cycling from theme palette"
```
@@ -591,7 +591,7 @@ git commit -m "Add auto line color cycling from theme palette"
### Task 5: addBand — Horizontal Band Fill
**Files:**
-- Modify: `FastPlot.m` (new property struct, addBand method, render updates)
+- Modify: `FastSense.m` (new property struct, addBand method, render updates)
- Create: `tests/test_add_band.m`
**Step 1: Write the failing test**
@@ -600,13 +600,13 @@ Create `tests/test_add_band.m`:
```matlab
function test_add_band()
-%TEST_ADD_BAND Tests for FastPlot.addBand method.
+%TEST_ADD_BAND Tests for FastSense.addBand method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'private'));
% testAddBand
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-1, 1, 'FaceColor', [1 0.9 0.9], 'FaceAlpha', 0.3, 'Label', 'Safe');
assert(numel(fp.Bands) == 1, 'testAddBand: count');
assert(fp.Bands(1).YLow == -1, 'testAddBand: YLow');
@@ -614,24 +614,24 @@ function test_add_band()
assert(strcmp(fp.Bands(1).Label, 'Safe'), 'testAddBand: Label');
% testAddMultipleBands
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-2, -1);
fp.addBand(1, 2);
assert(numel(fp.Bands) == 2, 'testAddMultipleBands');
% testBandRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addBand(0.2, 0.8, 'FaceColor', [0 1 0], 'FaceAlpha', 0.2);
fp.render();
assert(~isempty(fp.Bands(1).hPatch), 'testBandRendered: hPatch created');
assert(ishandle(fp.Bands(1).hPatch), 'testBandRendered: hPatch valid');
ud = get(fp.Bands(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'band'), 'testBandRendered: UserData type');
+ assert(strcmp(ud.FastSense.Type, 'band'), 'testBandRendered: UserData type');
close(fp.hFigure);
% testBandRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
threw = false;
@@ -644,7 +644,7 @@ function test_add_band()
close(fp.hFigure);
% testBandDefaults
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(0, 1);
assert(fp.Bands(1).FaceAlpha > 0, 'testBandDefaults: FaceAlpha');
assert(numel(fp.Bands(1).FaceColor) == 3, 'testBandDefaults: FaceColor');
@@ -659,7 +659,7 @@ Expected: FAIL — `addBand` method does not exist
**Step 3: Write implementation**
-Add new property struct in `FastPlot.m` properties (SetAccess = private), after the Thresholds line (around line 24):
+Add new property struct in `FastSense.m` properties (SetAccess = private), after the Thresholds line (around line 24):
```matlab
Bands = struct('YLow', {}, 'YHigh', {}, 'FaceColor', {}, ...
@@ -676,7 +676,7 @@ Add `addBand` method in the public methods block (after `addThreshold`):
% fp.addBand(yLow, yHigh, 'FaceColor', [1 0.9 0.9], 'FaceAlpha', 0.3)
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add bands after render() has been called.');
end
@@ -733,7 +733,7 @@ Actually, bands need the X range which is computed later. Better approach: rende
'FaceAlpha', B.FaceAlpha, ...
'EdgeColor', B.EdgeColor, ...
'HandleVisibility', 'off');
- udB.FastPlot = struct( ...
+ udB.FastSense = struct( ...
'Type', 'band', ...
'Name', B.Label, ...
'LineIndex', [], ...
@@ -758,7 +758,7 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_add_band.m
+git add FastSense.m tests/test_add_band.m
git commit -m "Add addBand for horizontal band fills"
```
@@ -767,7 +767,7 @@ git commit -m "Add addBand for horizontal band fills"
### Task 6: addMarker — Custom Event Markers
**Files:**
-- Modify: `FastPlot.m` (new Markers property, addMarker method, render)
+- Modify: `FastSense.m` (new Markers property, addMarker method, render)
- Create: `tests/test_add_marker.m`
**Step 1: Write the failing test**
@@ -776,37 +776,37 @@ Create `tests/test_add_marker.m`:
```matlab
function test_add_marker()
-%TEST_ADD_MARKER Tests for FastPlot.addMarker method.
+%TEST_ADD_MARKER Tests for FastSense.addMarker method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'private'));
% testAddMarker
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([10 20 30], [1 2 3], 'Marker', 'v', 'Color', [1 0 0], 'Label', 'Faults');
assert(numel(fp.Markers) == 1, 'testAddMarker: count');
assert(isequal(fp.Markers(1).X, [10 20 30]), 'testAddMarker: X');
assert(strcmp(fp.Markers(1).Label, 'Faults'), 'testAddMarker: Label');
% testMarkerRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addMarker([10 50], [0.5 0.8], 'Marker', 'd', 'MarkerSize', 10);
fp.render();
assert(~isempty(fp.Markers(1).hLine), 'testMarkerRendered: hLine');
assert(ishandle(fp.Markers(1).hLine), 'testMarkerRendered: valid handle');
ud = get(fp.Markers(1).hLine, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'marker'), 'testMarkerRendered: UserData type');
+ assert(strcmp(ud.FastSense.Type, 'marker'), 'testMarkerRendered: UserData type');
close(fp.hFigure);
% testMarkerDefaults
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([5], [1]);
assert(~isempty(fp.Markers(1).Marker), 'testMarkerDefaults: Marker shape');
assert(fp.Markers(1).MarkerSize > 0, 'testMarkerDefaults: MarkerSize');
% testMarkerRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
threw = false;
@@ -845,7 +845,7 @@ Add `addMarker` method (after `addBand`):
% fp.addMarker(x, y, 'Marker', 'v', 'MarkerSize', 8, 'Color', [1 0 0])
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add markers after render() has been called.');
end
@@ -893,7 +893,7 @@ In `render()`, add marker rendering after threshold/violation markers section (r
'MarkerSize', M.MarkerSize, ...
'Color', M.Color, ...
'HandleVisibility', 'off');
- udM.FastPlot = struct( ...
+ udM.FastSense = struct( ...
'Type', 'marker', ...
'Name', M.Label, ...
'LineIndex', [], ...
@@ -916,7 +916,7 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_add_marker.m
+git add FastSense.m tests/test_add_marker.m
git commit -m "Add addMarker for custom event markers"
```
@@ -925,7 +925,7 @@ git commit -m "Add addMarker for custom event markers"
### Task 7: addShaded — Fill Between Two Curves
**Files:**
-- Modify: `FastPlot.m` (new Shaded property, addShaded method, render + zoom updates)
+- Modify: `FastSense.m` (new Shaded property, addShaded method, render + zoom updates)
- Create: `tests/test_add_shaded.m`
**Step 1: Write the failing test**
@@ -934,7 +934,7 @@ Create `tests/test_add_shaded.m`:
```matlab
function test_add_shaded()
-%TEST_ADD_SHADED Tests for FastPlot.addShaded method.
+%TEST_ADD_SHADED Tests for FastSense.addShaded method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'private'));
@@ -943,7 +943,7 @@ function test_add_shaded()
x = 1:100;
y1 = ones(1,100) * 2;
y2 = ones(1,100) * -2;
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded(x, y1, y2, 'FaceColor', [0 0 1], 'FaceAlpha', 0.2);
assert(numel(fp.Shadings) == 1, 'testAddShaded: count');
assert(isequal(fp.Shadings(1).X, x), 'testAddShaded: X');
@@ -951,18 +951,18 @@ function test_add_shaded()
assert(isequal(fp.Shadings(1).Y2, y2), 'testAddShaded: Y2');
% testShadedRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addShaded(1:100, ones(1,100), zeros(1,100), 'FaceColor', [1 0 0]);
fp.render();
assert(~isempty(fp.Shadings(1).hPatch), 'testShadedRendered: hPatch');
assert(ishandle(fp.Shadings(1).hPatch), 'testShadedRendered: valid');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'shaded'), 'testShadedRendered: type');
+ assert(strcmp(ud.FastSense.Type, 'shaded'), 'testShadedRendered: type');
close(fp.hFigure);
% testShadedValidation
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded(1:10, 1:10, 1:5); % mismatched lengths
@@ -972,7 +972,7 @@ function test_add_shaded()
assert(threw, 'testShadedValidation: length mismatch');
% testShadedMonotonicX
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded([3 1 2], [1 1 1], [0 0 0]);
@@ -982,7 +982,7 @@ function test_add_shaded()
assert(threw, 'testShadedMonotonicX');
% testShadedRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
threw = false;
@@ -995,7 +995,7 @@ function test_add_shaded()
close(fp.hFigure);
% testShadedColumnVectors
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded((1:10)', (1:10)', zeros(10,1));
assert(isrow(fp.Shadings(1).X), 'testShadedColumnVectors: X row');
assert(isrow(fp.Shadings(1).Y1), 'testShadedColumnVectors: Y1 row');
@@ -1029,7 +1029,7 @@ Add `addShaded` method (after `addMarker`):
% fp.addShaded(x, y1, y2, 'FaceColor', [0 0 1], 'FaceAlpha', 0.2)
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add shaded regions after render() has been called.');
end
@@ -1038,14 +1038,14 @@ Add `addShaded` method (after `addMarker`):
if ~isrow(y2); y2 = y2(:)'; end
if numel(x) ~= numel(y1) || numel(x) ~= numel(y2)
- error('FastPlot:sizeMismatch', ...
+ error('FastSense:sizeMismatch', ...
'X, Y1, and Y2 must have the same number of elements.');
end
if numel(x) > 1
dx = diff(x);
if any(dx(~isnan(dx)) < 0)
- error('FastPlot:nonMonotonicX', ...
+ error('FastSense:nonMonotonicX', ...
'X must be monotonically increasing.');
end
end
@@ -1094,7 +1094,7 @@ In `render()`, add shading rendering after bands and before data lines:
'FaceAlpha', S.FaceAlpha, ...
'EdgeColor', S.EdgeColor, ...
'HandleVisibility', 'off');
- udS.FastPlot = struct( ...
+ udS.FastSense = struct( ...
'Type', 'shaded', ...
'Name', S.DisplayName, ...
'LineIndex', [], ...
@@ -1158,7 +1158,7 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_add_shaded.m
+git add FastSense.m tests/test_add_shaded.m
git commit -m "Add addShaded for fill between two curves with zoom downsampling"
```
@@ -1167,7 +1167,7 @@ git commit -m "Add addShaded for fill between two curves with zoom downsampling"
### Task 8: addFill — Area Fill to Baseline
**Files:**
-- Modify: `FastPlot.m` (addFill method)
+- Modify: `FastSense.m` (addFill method)
- Modify: `tests/test_add_shaded.m`
**Step 1: Write the failing test**
@@ -1176,7 +1176,7 @@ Append to `tests/test_add_shaded.m` (before final fprintf):
```matlab
% testAddFill
- fp = FastPlot();
+ fp = FastSense();
x = 1:50;
y = rand(1,50);
fp.addFill(x, y, 'FaceColor', [0 0.5 1], 'FaceAlpha', 0.2);
@@ -1184,18 +1184,18 @@ Append to `tests/test_add_shaded.m` (before final fprintf):
assert(all(fp.Shadings(1).Y2 == 0), 'testAddFill: baseline is 0');
% testAddFillCustomBaseline
- fp = FastPlot();
+ fp = FastSense();
fp.addFill(1:10, rand(1,10), 'Baseline', -1);
assert(all(fp.Shadings(1).Y2 == -1), 'testAddFillCustomBaseline');
% testAddFillRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addFill(1:100, rand(1,100), 'FaceColor', [0 1 0]);
fp.render();
assert(ishandle(fp.Shadings(1).hPatch), 'testAddFillRendered: valid patch');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'shaded'), 'testAddFillRendered: type is shaded');
+ assert(strcmp(ud.FastSense.Type, 'shaded'), 'testAddFillRendered: type is shaded');
close(fp.hFigure);
```
@@ -1248,7 +1248,7 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_add_shaded.m
+git add FastSense.m tests/test_add_shaded.m
git commit -m "Add addFill as sugar for addShaded with baseline"
```
@@ -1257,22 +1257,22 @@ git commit -m "Add addFill as sugar for addShaded with baseline"
### Task 9: Theme Defaults for Thresholds & Violations
**Files:**
-- Modify: `FastPlot.m` (addThreshold method, render)
-- Modify: `tests/test_fastplot_theme.m`
+- Modify: `FastSense.m` (addThreshold method, render)
+- Modify: `tests/test_fastsense_theme.m`
**Step 1: Write the failing test**
-Append to `tests/test_fastplot_theme.m`:
+Append to `tests/test_fastsense_theme.m`:
```matlab
% testThresholdUsesThemeDefaults
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
fp.addThreshold(5.0);
assert(isequal(fp.Thresholds(1).Color, [0 1 0]), 'testThresholdThemeDefaults: Color');
assert(strcmp(fp.Thresholds(1).LineStyle, ':'), 'testThresholdThemeDefaults: Style');
% testThresholdExplicitOverridesTheme
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0]));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0]));
fp.addThreshold(5.0, 'Color', [1 0 0]);
assert(isequal(fp.Thresholds(1).Color, [1 0 0]), 'testThresholdOverride: Color');
```
@@ -1285,7 +1285,7 @@ Expected: FAIL — threshold defaults are hardcoded, not from theme
**Step 3: Write implementation**
-Modify `addThreshold` in `FastPlot.m`. Change the defaults section (around line 132-133) to use theme:
+Modify `addThreshold` in `FastSense.m`. Change the defaults section (around line 132-133) to use theme:
```matlab
t.Color = obj.Theme.ThresholdColor;
@@ -1296,7 +1296,7 @@ These theme values are set in the constructor, so they're always available befor
**Step 4: Run test to verify it passes**
-Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastplot_theme;"`
+Run: `octave --no-gui --eval "addpath('.'); addpath('tests'); addpath('private'); test_fastsense_theme;"`
Expected: PASS
**Step 5: Run all tests**
@@ -1306,16 +1306,16 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlot.m tests/test_fastplot_theme.m
+git add FastSense.m tests/test_fastsense_theme.m
git commit -m "Use theme defaults for threshold color and style"
```
---
-### Task 10: FastPlotFigure — Basic Grid Layout
+### Task 10: FastSenseFigure — Basic Grid Layout
**Files:**
-- Create: `FastPlotFigure.m`
+- Create: `FastSenseFigure.m`
- Create: `tests/test_figure_layout.m`
**Step 1: Write the failing test**
@@ -1324,33 +1324,33 @@ Create `tests/test_figure_layout.m`:
```matlab
function test_figure_layout()
-%TEST_FIGURE_LAYOUT Tests for FastPlotFigure layout manager.
+%TEST_FIGURE_LAYOUT Tests for FastSenseFigure layout manager.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'private'));
% testConstruction
- fig = FastPlotFigure(2, 3);
+ fig = FastSenseFigure(2, 3);
assert(isequal(fig.Grid, [2 3]), 'testConstruction: Grid');
assert(~isempty(fig.hFigure), 'testConstruction: hFigure');
assert(ishandle(fig.hFigure), 'testConstruction: hFigure valid');
close(fig.hFigure);
- % testTileReturnsFastPlot
- fig = FastPlotFigure(2, 1);
+ % testTileReturnsFastSense
+ fig = FastSenseFigure(2, 1);
fp = fig.tile(1);
- assert(isa(fp, 'FastPlot'), 'testTileReturnsFastPlot');
+ assert(isa(fp, 'FastSense'), 'testTileReturnsFastSense');
close(fig.hFigure);
% testTileLazy
- fig = FastPlotFigure(2, 1);
+ fig = FastSenseFigure(2, 1);
fp1a = fig.tile(1);
fp1b = fig.tile(1);
assert(fp1a == fp1b, 'testTileLazy: same object on repeat call');
close(fig.hFigure);
% testTileCreatesAxes
- fig = FastPlotFigure(2, 1);
+ fig = FastSenseFigure(2, 1);
fp = fig.tile(1);
fp.addLine(1:100, rand(1,100));
fp.render();
@@ -1359,7 +1359,7 @@ function test_figure_layout()
close(fig.hFigure);
% testMultipleTiles
- fig = FastPlotFigure(2, 2);
+ fig = FastSenseFigure(2, 2);
for i = 1:4
fp = fig.tile(i);
fp.addLine(1:50, rand(1,50));
@@ -1372,7 +1372,7 @@ function test_figure_layout()
close(fig.hFigure);
% testRenderAllSkipsRendered
- fig = FastPlotFigure(2, 1);
+ fig = FastSenseFigure(2, 1);
fp1 = fig.tile(1);
fp1.addLine(1:10, rand(1,10));
fp1.render();
@@ -1383,7 +1383,7 @@ function test_figure_layout()
close(fig.hFigure);
% testOutOfBoundsTileErrors
- fig = FastPlotFigure(2, 2);
+ fig = FastSenseFigure(2, 2);
threw = false;
try
fig.tile(5); % only 4 tiles in 2x2
@@ -1399,26 +1399,26 @@ end
**Step 2: Run test to verify it fails**
-Expected: FAIL — `FastPlotFigure` does not exist
+Expected: FAIL — `FastSenseFigure` does not exist
**Step 3: Write implementation**
-Create `FastPlotFigure.m`:
+Create `FastSenseFigure.m`:
```matlab
-classdef FastPlotFigure < handle
- %FASTPLOTFIGURE Tiled layout manager for FastPlot dashboards.
- % fig = FastPlotFigure(rows, cols)
- % fig = FastPlotFigure(rows, cols, 'Theme', 'dark')
+classdef FastSenseFigure < handle
+ %FASTSENSEFIGURE Tiled layout manager for FastSense dashboards.
+ % fig = FastSenseFigure(rows, cols)
+ % fig = FastSenseFigure(rows, cols, 'Theme', 'dark')
properties (Access = public)
Grid = [1 1] % [rows, cols]
- Theme = [] % FastPlotTheme struct
+ Theme = [] % FastSenseTheme struct
hFigure = [] % figure handle
end
properties (SetAccess = private)
- Tiles = {} % cell array of FastPlot instances
+ Tiles = {} % cell array of FastSense instances
TileAxes = {} % cell array of axes handles
TileSpans = {} % cell array of [rowSpan, colSpan]
TileThemes = {} % cell array of theme override structs
@@ -1432,7 +1432,7 @@ classdef FastPlotFigure < handle
end
methods (Access = public)
- function obj = FastPlotFigure(rows, cols, varargin)
+ function obj = FastSenseFigure(rows, cols, varargin)
obj.Grid = [rows, cols];
nTiles = rows * cols;
obj.Tiles = cell(1, nTiles);
@@ -1452,7 +1452,7 @@ classdef FastPlotFigure < handle
case 'theme'
val = varargin{k+1};
if ischar(val) || isstruct(val)
- obj.Theme = FastPlotTheme(val);
+ obj.Theme = FastSenseTheme(val);
else
obj.Theme = val;
end
@@ -1463,7 +1463,7 @@ classdef FastPlotFigure < handle
end
if isempty(obj.Theme)
- obj.Theme = FastPlotTheme('default');
+ obj.Theme = FastSenseTheme('default');
end
obj.hFigure = figure('Visible', 'off', ...
@@ -1471,10 +1471,10 @@ classdef FastPlotFigure < handle
end
function fp = tile(obj, n)
- %TILE Get or create the FastPlot instance for tile n.
+ %TILE Get or create the FastSense instance for tile n.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotFigure:outOfBounds', ...
+ error('FastSenseFigure:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
@@ -1491,7 +1491,7 @@ classdef FastPlotFigure < handle
end
end
- fp = FastPlot('Parent', ax, 'Theme', tileTheme);
+ fp = FastSense('Parent', ax, 'Theme', tileTheme);
obj.Tiles{n} = fp;
else
fp = obj.Tiles{n};
@@ -1503,7 +1503,7 @@ classdef FastPlotFigure < handle
% fig.setTileSpan(1, [2 1]) — tile 1 spans 2 rows, 1 col
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotFigure:outOfBounds', ...
+ error('FastSenseFigure:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
obj.TileSpans{n} = span;
@@ -1519,7 +1519,7 @@ classdef FastPlotFigure < handle
%SETTILETHEME Set per-tile theme overrides.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotFigure:outOfBounds', ...
+ error('FastSenseFigure:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
obj.TileThemes{n} = themeOverrides;
@@ -1622,13 +1622,13 @@ Expected: All pass.
**Step 6: Commit**
```bash
-git add FastPlotFigure.m tests/test_figure_layout.m
-git commit -m "Add FastPlotFigure with tiled grid layout and lazy tile creation"
+git add FastSenseFigure.m tests/test_figure_layout.m
+git commit -m "Add FastSenseFigure with tiled grid layout and lazy tile creation"
```
---
-### Task 11: FastPlotFigure — Tile Spanning & Theme Inheritance
+### Task 11: FastSenseFigure — Tile Spanning & Theme Inheritance
**Files:**
- Modify: `tests/test_figure_layout.m`
@@ -1639,7 +1639,7 @@ Append to `tests/test_figure_layout.m` (before final fprintf):
```matlab
% testTileSpanning
- fig = FastPlotFigure(2, 2);
+ fig = FastSenseFigure(2, 2);
fig.setTileSpan(1, [1 2]); % tile 1 spans both columns
fp1 = fig.tile(1);
fp1.addLine(1:50, rand(1,50));
@@ -1650,13 +1650,13 @@ Append to `tests/test_figure_layout.m` (before final fprintf):
close(fig.hFigure);
% testFigureThemePassedToTiles
- fig = FastPlotFigure(2, 1, 'Theme', 'dark');
+ fig = FastSenseFigure(2, 1, 'Theme', 'dark');
fp = fig.tile(1);
assert(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testFigureThemePassedToTiles');
close(fig.hFigure);
% testTileThemeOverride
- fig = FastPlotFigure(2, 1, 'Theme', 'dark');
+ fig = FastSenseFigure(2, 1, 'Theme', 'dark');
fig.setTileTheme(1, struct('AxesColor', [0.3 0 0]));
fp = fig.tile(1);
assert(isequal(fp.Theme.AxesColor, [0.3 0 0]), 'testTileThemeOverride: AxesColor');
@@ -1664,13 +1664,13 @@ Append to `tests/test_figure_layout.m` (before final fprintf):
close(fig.hFigure);
% testFigureProperties
- fig = FastPlotFigure(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
+ fig = FastSenseFigure(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
name = get(fig.hFigure, 'Name');
assert(strcmp(name, 'MyDash'), 'testFigureProperties: Name');
close(fig.hFigure);
% testTileLabels
- fig = FastPlotFigure(2, 1);
+ fig = FastSenseFigure(2, 1);
fp = fig.tile(1);
fp.addLine(1:50, rand(1,50));
fp.render();
@@ -1733,8 +1733,8 @@ git commit -m "Fix integration issues from full test suite"
Create `examples/example_dashboard.m`:
```matlab
-%% FastPlot Dashboard — Tiled layout with themes and visual enhancements
-% Demonstrates FastPlotFigure, theming, bands, shading, and markers
+%% FastSense Dashboard — Tiled layout with themes and visual enhancements
+% Demonstrates FastSenseFigure, theming, bands, shading, and markers
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
@@ -1744,8 +1744,8 @@ x = linspace(0, 300, n);
fprintf('Dashboard example: 4 tiles, %d points each, dark theme...\n', n);
tic;
-fig = FastPlotFigure(2, 2, 'Theme', 'dark', ...
- 'Name', 'FastPlot Dashboard Demo', 'Position', [50 50 1400 800]);
+fig = FastSenseFigure(2, 2, 'Theme', 'dark', ...
+ 'Name', 'FastSense Dashboard Demo', 'Position', [50 50 1400 800]);
% --- Tile 1: Temperature with alarm bands (spans 2 columns) ---
fig.setTileSpan(1, [1 2]);
@@ -1813,7 +1813,7 @@ git commit -m "Add dashboard example with tiled layout, bands, shading, and mark
Create `examples/example_themes.m`:
```matlab
-%% FastPlot Theme Comparison — All 5 built-in themes side by side
+%% FastSense Theme Comparison — All 5 built-in themes side by side
% Opens one figure per theme to compare visual styles
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));
@@ -1828,7 +1828,7 @@ themes = {'default', 'dark', 'light', 'industrial', 'scientific'};
for i = 1:numel(themes)
themeName = themes{i};
- fp = FastPlot('Theme', themeName);
+ fp = FastSense('Theme', themeName);
fp.addLine(x, y1, 'DisplayName', 'Signal A');
fp.addLine(x, y2, 'DisplayName', 'Signal B');
fp.addLine(x, y3, 'DisplayName', 'Signal C');
@@ -1863,7 +1863,7 @@ git commit -m "Add theme comparison example showing all 5 presets"
**Step 1: Update README**
Add sections for:
-- FastPlotFigure (tiled layouts with spanning)
+- FastSenseFigure (tiled layouts with spanning)
- Theming system (5 presets, custom themes, color palettes)
- New visual methods (addShaded, addBand, addFill, addMarker)
- Updated example table with new examples
@@ -1872,9 +1872,9 @@ Add sections for:
Key additions to the API Reference section:
```markdown
-### `FastPlotFigure(rows, cols, ...)` -- Dashboard Layout
+### `FastSenseFigure(rows, cols, ...)` -- Dashboard Layout
-### `FastPlotTheme(preset, ...)` -- Theme Presets
+### `FastSenseTheme(preset, ...)` -- Theme Presets
### `addShaded(x, y1, y2, ...)` -- Fill Between Curves
diff --git a/docs/plans/2026-03-06-fastplot-implementation.md b/docs/plans/2026-03-06-fastsense-implementation.md
similarity index 89%
rename from docs/plans/2026-03-06-fastplot-implementation.md
rename to docs/plans/2026-03-06-fastsense-implementation.md
index 591f619b..962e50f7 100644
--- a/docs/plans/2026-03-06-fastplot-implementation.md
+++ b/docs/plans/2026-03-06-fastsense-implementation.md
@@ -1,37 +1,37 @@
-# FastPlot Implementation Plan
+# FastSense Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Build a pure-MATLAB plotting library that renders 100M time series points with fluid zoom/pan via dynamic MinMax downsampling.
-**Architecture:** Handle class `FastPlot` with builder API. Data lines, thresholds, and violation markers are configured before `render()`. On zoom/pan, an XLim listener triggers binary search → MinMax downsample → XData/YData update on reused line handles. No object recreation, `drawnow limitrate` for frame capping.
+**Architecture:** Handle class `FastSense` with builder API. Data lines, thresholds, and violation markers are configured before `render()`. On zoom/pan, an XLim listener triggers binary search → MinMax downsample → XData/YData update on reused line handles. No object recreation, `drawnow limitrate` for frame capping.
**Tech Stack:** Pure MATLAB 2020b, classic `figure()`, OpenGL renderer, `matlab.unittest` for testing.
-**Design doc:** `FastPlot/docs/2026-03-06-fastplot-design.md`
+**Design doc:** `FastSense/docs/2026-03-06-fastsense-design.md`
---
## Task 1: Project Scaffolding
**Files:**
-- Create: `FastPlot/FastPlot.m` (skeleton only)
-- Create: `FastPlot/private/` (directory)
-- Create: `FastPlot/tests/` (directory)
-- Create: `FastPlot/examples/` (directory)
+- Create: `FastSense/FastSense.m` (skeleton only)
+- Create: `FastSense/private/` (directory)
+- Create: `FastSense/tests/` (directory)
+- Create: `FastSense/examples/` (directory)
-**Step 1: Create the FastPlot class skeleton**
+**Step 1: Create the FastSense class skeleton**
-Create `FastPlot/FastPlot.m`:
+Create `FastSense/FastSense.m`:
```matlab
-classdef FastPlot < handle
- %FASTPLOT Ultra-fast time series plotting with dynamic downsampling.
+classdef FastSense < handle
+ %FASTSENSE Ultra-fast time series plotting with dynamic downsampling.
% Handles 1K to 100M data points with fluid zoom/pan.
% Uses MinMax downsampling to reduce data to screen resolution.
%
% Usage:
- % fp = FastPlot();
+ % fp = FastSense();
% fp.addLine(x, y, 'DisplayName', 'Sensor1');
% fp.addThreshold(4.5, 'Direction', 'upper', 'ShowViolations', true);
% fp.render();
@@ -66,7 +66,7 @@ classdef FastPlot < handle
end
methods (Access = public)
- function obj = FastPlot(varargin)
+ function obj = FastSense(varargin)
% Parse name-value pairs: 'Parent', 'LinkGroup'
p = inputParser;
addParameter(p, 'Parent', [], @(x) isempty(x) || isgraphics(x, 'axes'));
@@ -110,7 +110,7 @@ end
Create empty files so the directory structure exists:
-`FastPlot/private/binary_search.m`:
+`FastSense/private/binary_search.m`:
```matlab
function idx = binary_search(x, val, direction)
%BINARY_SEARCH Find index in sorted array via binary search.
@@ -120,7 +120,7 @@ function idx = binary_search(x, val, direction)
end
```
-`FastPlot/private/minmax_downsample.m`:
+`FastSense/private/minmax_downsample.m`:
```matlab
function [xOut, yOut] = minmax_downsample(x, y, numBuckets)
%MINMAX_DOWNSAMPLE Reduce data to min/max pairs per bucket.
@@ -129,7 +129,7 @@ function [xOut, yOut] = minmax_downsample(x, y, numBuckets)
end
```
-`FastPlot/private/lttb_downsample.m`:
+`FastSense/private/lttb_downsample.m`:
```matlab
function [xOut, yOut] = lttb_downsample(x, y, numOut)
%LTTB_DOWNSAMPLE Largest Triangle Three Buckets downsampling.
@@ -138,7 +138,7 @@ function [xOut, yOut] = lttb_downsample(x, y, numOut)
end
```
-`FastPlot/private/compute_violations.m`:
+`FastSense/private/compute_violations.m`:
```matlab
function [xViol, yViol] = compute_violations(x, y, thresholdValue, direction)
%COMPUTE_VIOLATIONS Find points that violate a threshold.
@@ -149,10 +149,10 @@ end
**Step 3: Create test runner helper**
-Create `FastPlot/tests/run_all_tests.m`:
+Create `FastSense/tests/run_all_tests.m`:
```matlab
function results = run_all_tests()
-%RUN_ALL_TESTS Execute all FastPlot unit tests.
+%RUN_ALL_TESTS Execute all FastSense unit tests.
import matlab.unittest.TestSuite;
suite = TestSuite.fromFolder(fileparts(mfilename('fullpath')));
results = run(suite);
@@ -164,7 +164,7 @@ end
In MATLAB, run:
```matlab
-cd FastPlot
+cd FastSense
dir
dir private
dir tests
@@ -176,12 +176,12 @@ Expected: all files present.
## Task 2: Binary Search
**Files:**
-- Modify: `FastPlot/private/binary_search.m`
-- Create: `FastPlot/tests/TestBinarySearch.m`
+- Modify: `FastSense/private/binary_search.m`
+- Create: `FastSense/tests/TestBinarySearch.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestBinarySearch.m`:
+Create `FastSense/tests/TestBinarySearch.m`:
```matlab
classdef TestBinarySearch < matlab.unittest.TestCase
@@ -258,13 +258,13 @@ end
**Step 2: Run test — expect FAIL**
```matlab
-cd FastPlot; runtests('tests/TestBinarySearch');
+cd FastSense; runtests('tests/TestBinarySearch');
```
Expected: failures (placeholder returns 1 always).
**Step 3: Implement binary_search**
-Replace `FastPlot/private/binary_search.m`:
+Replace `FastSense/private/binary_search.m`:
```matlab
function idx = binary_search(x, val, direction)
%BINARY_SEARCH Find index in sorted array via binary search.
@@ -319,12 +319,12 @@ Expected: all 11 tests pass.
## Task 3: MinMax Downsampling
**Files:**
-- Modify: `FastPlot/private/minmax_downsample.m`
-- Create: `FastPlot/tests/TestMinMaxDownsample.m`
+- Modify: `FastSense/private/minmax_downsample.m`
+- Create: `FastSense/tests/TestMinMaxDownsample.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestMinMaxDownsample.m`:
+Create `FastSense/tests/TestMinMaxDownsample.m`:
```matlab
classdef TestMinMaxDownsample < matlab.unittest.TestCase
@@ -426,7 +426,7 @@ runtests('tests/TestMinMaxDownsample');
**Step 3: Implement minmax_downsample**
-Replace `FastPlot/private/minmax_downsample.m`:
+Replace `FastSense/private/minmax_downsample.m`:
```matlab
function [xOut, yOut] = minmax_downsample(x, y, numBuckets)
%MINMAX_DOWNSAMPLE Reduce time series to min/max pairs per bucket.
@@ -545,12 +545,12 @@ Expected: all 8 tests pass.
## Task 4: LTTB Downsampling
**Files:**
-- Modify: `FastPlot/private/lttb_downsample.m`
-- Create: `FastPlot/tests/TestLTTBDownsample.m`
+- Modify: `FastSense/private/lttb_downsample.m`
+- Create: `FastSense/tests/TestLTTBDownsample.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestLTTBDownsample.m`:
+Create `FastSense/tests/TestLTTBDownsample.m`:
```matlab
classdef TestLTTBDownsample < matlab.unittest.TestCase
@@ -617,7 +617,7 @@ runtests('tests/TestLTTBDownsample');
**Step 3: Implement lttb_downsample**
-Replace `FastPlot/private/lttb_downsample.m`:
+Replace `FastSense/private/lttb_downsample.m`:
```matlab
function [xOut, yOut] = lttb_downsample(x, y, numOut)
%LTTB_DOWNSAMPLE Largest Triangle Three Buckets downsampling.
@@ -759,12 +759,12 @@ Expected: all 6 tests pass.
## Task 5: Compute Violations
**Files:**
-- Modify: `FastPlot/private/compute_violations.m`
-- Create: `FastPlot/tests/TestComputeViolations.m`
+- Modify: `FastSense/private/compute_violations.m`
+- Create: `FastSense/tests/TestComputeViolations.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestComputeViolations.m`:
+Create `FastSense/tests/TestComputeViolations.m`:
```matlab
classdef TestComputeViolations < matlab.unittest.TestCase
@@ -821,7 +821,7 @@ runtests('tests/TestComputeViolations');
**Step 3: Implement compute_violations**
-Replace `FastPlot/private/compute_violations.m`:
+Replace `FastSense/private/compute_violations.m`:
```matlab
function [xViol, yViol] = compute_violations(x, y, thresholdValue, direction)
%COMPUTE_VIOLATIONS Find data points that strictly violate a threshold.
@@ -855,21 +855,21 @@ Expected: all 5 tests pass.
---
-## Task 6: FastPlot.addLine()
+## Task 6: FastSense.addLine()
**Files:**
-- Modify: `FastPlot/FastPlot.m` — `addLine` method
-- Create: `FastPlot/tests/TestAddLine.m`
+- Modify: `FastSense/FastSense.m` — `addLine` method
+- Create: `FastSense/tests/TestAddLine.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestAddLine.m`:
+Create `FastSense/tests/TestAddLine.m`:
```matlab
classdef TestAddLine < matlab.unittest.TestCase
methods (Test)
function testAddSingleLine(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = 1:100;
y = rand(1, 100);
fp.addLine(x, y);
@@ -879,7 +879,7 @@ classdef TestAddLine < matlab.unittest.TestCase
end
function testAddMultipleLines(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:20, rand(1,20));
fp.addLine(1:5, rand(1,5));
@@ -887,47 +887,47 @@ classdef TestAddLine < matlab.unittest.TestCase
end
function testLineOptions(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', 'r', 'DisplayName', 'S1');
testCase.verifyEqual(fp.Lines(1).Options.Color, 'r');
testCase.verifyEqual(fp.Lines(1).Options.DisplayName, 'S1');
end
function testDownsampleMethodDefault(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
testCase.verifyEqual(fp.Lines(1).DownsampleMethod, 'minmax');
end
function testDownsampleMethodOverride(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'DownsampleMethod', 'lttb');
testCase.verifyEqual(fp.Lines(1).DownsampleMethod, 'lttb');
end
function testRejectsNonMonotonicX(testCase)
- fp = FastPlot();
+ fp = FastSense();
testCase.verifyError(@() fp.addLine([1 3 2 4], rand(1,4)), ...
- 'FastPlot:nonMonotonicX');
+ 'FastSense:nonMonotonicX');
end
function testRejectsMismatchedLengths(testCase)
- fp = FastPlot();
+ fp = FastSense();
testCase.verifyError(@() fp.addLine(1:10, rand(1,5)), ...
- 'FastPlot:sizeMismatch');
+ 'FastSense:sizeMismatch');
end
function testRejectsAfterRender(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
testCase.verifyError(@() fp.addLine(1:5, rand(1,5)), ...
- 'FastPlot:alreadyRendered');
+ 'FastSense:alreadyRendered');
close(fp.hFigure);
end
function testColumnVectorsAccepted(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine((1:10)', rand(10,1));
testCase.verifyEqual(numel(fp.Lines(1).X), 10);
testCase.verifyTrue(isrow(fp.Lines(1).X));
@@ -942,9 +942,9 @@ end
runtests('tests/TestAddLine');
```
-**Step 3: Implement addLine in FastPlot.m**
+**Step 3: Implement addLine in FastSense.m**
-Replace the `addLine` method in `FastPlot.m`:
+Replace the `addLine` method in `FastSense.m`:
```matlab
function addLine(obj, x, y, varargin)
%ADDLINE Add a data line to the plot.
@@ -953,7 +953,7 @@ function addLine(obj, x, y, varargin)
% fp.addLine(x, y, 'DownsampleMethod', 'lttb')
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add lines after render() has been called.');
end
@@ -963,14 +963,14 @@ function addLine(obj, x, y, varargin)
% Validate sizes match
if numel(x) ~= numel(y)
- error('FastPlot:sizeMismatch', ...
+ error('FastSense:sizeMismatch', ...
'X and Y must have the same number of elements.');
end
% Validate monotonically increasing X (ignoring NaN)
xValid = x(~isnan(x));
if any(diff(xValid) < 0)
- error('FastPlot:nonMonotonicX', ...
+ error('FastSense:nonMonotonicX', ...
'X must be monotonically increasing.');
end
@@ -1021,21 +1021,21 @@ Expected: all 9 tests pass (the `testRejectsAfterRender` will fail until render(
---
-## Task 7: FastPlot.addThreshold()
+## Task 7: FastSense.addThreshold()
**Files:**
-- Modify: `FastPlot/FastPlot.m` — `addThreshold` method
-- Create: `FastPlot/tests/TestAddThreshold.m`
+- Modify: `FastSense/FastSense.m` — `addThreshold` method
+- Create: `FastSense/tests/TestAddThreshold.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestAddThreshold.m`:
+Create `FastSense/tests/TestAddThreshold.m`:
```matlab
classdef TestAddThreshold < matlab.unittest.TestCase
methods (Test)
function testAddUpperThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5, 'Direction', 'upper');
testCase.verifyEqual(numel(fp.Thresholds), 1);
testCase.verifyEqual(fp.Thresholds(1).Value, 4.5);
@@ -1043,13 +1043,13 @@ classdef TestAddThreshold < matlab.unittest.TestCase
end
function testAddLowerThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(-2.0, 'Direction', 'lower');
testCase.verifyEqual(fp.Thresholds(1).Direction, 'lower');
end
function testDefaults(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(5.0);
testCase.verifyEqual(fp.Thresholds(1).Direction, 'upper');
testCase.verifyEqual(fp.Thresholds(1).ShowViolations, false);
@@ -1058,7 +1058,7 @@ classdef TestAddThreshold < matlab.unittest.TestCase
end
function testCustomOptions(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(3.0, 'Direction', 'lower', ...
'ShowViolations', true, 'Color', [1 0 0], ...
'LineStyle', ':', 'Label', 'LowerBound');
@@ -1070,7 +1070,7 @@ classdef TestAddThreshold < matlab.unittest.TestCase
end
function testMultipleThresholds(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(1.0);
fp.addThreshold(2.0);
fp.addThreshold(3.0);
@@ -1086,7 +1086,7 @@ end
runtests('tests/TestAddThreshold');
```
-**Step 3: Implement addThreshold in FastPlot.m**
+**Step 3: Implement addThreshold in FastSense.m**
Replace the `addThreshold` method:
```matlab
@@ -1096,7 +1096,7 @@ function addThreshold(obj, value, varargin)
% fp.addThreshold(4.5, 'Direction', 'upper', 'ShowViolations', true)
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add thresholds after render() has been called.');
end
@@ -1132,21 +1132,21 @@ Expected: all 5 tests pass.
---
-## Task 8: FastPlot.render() — Core Rendering
+## Task 8: FastSense.render() — Core Rendering
**Files:**
-- Modify: `FastPlot/FastPlot.m` — `render`, `getAxesPixelWidth`, private helpers
-- Create: `FastPlot/tests/TestRender.m`
+- Modify: `FastSense/FastSense.m` — `render`, `getAxesPixelWidth`, private helpers
+- Create: `FastSense/tests/TestRender.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestRender.m`:
+Create `FastSense/tests/TestRender.m`:
```matlab
classdef TestRender < matlab.unittest.TestCase
methods (Test)
function testCreatesNewFigure(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Test');
fp.render();
testCase.verifyTrue(isgraphics(fp.hFigure, 'figure'));
@@ -1157,7 +1157,7 @@ classdef TestRender < matlab.unittest.TestCase
function testUsesExistingAxes(testCase)
fig = figure('Visible', 'off');
ax = axes(fig);
- fp = FastPlot('Parent', ax);
+ fp = FastSense('Parent', ax);
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.verifyEqual(fp.hAxes, ax);
@@ -1165,7 +1165,7 @@ classdef TestRender < matlab.unittest.TestCase
end
function testCreatesLineObjects(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L1');
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L2');
fp.render();
@@ -1176,31 +1176,31 @@ classdef TestRender < matlab.unittest.TestCase
end
function testUserDataTagging(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Sensor1');
fp.addThreshold(0.5, 'Label', 'UpperLim');
fp.render();
% Check data line tag
ud = fp.Lines(1).hLine.UserData;
- testCase.verifyEqual(ud.FastPlot.Type, 'data_line');
- testCase.verifyEqual(ud.FastPlot.Name, 'Sensor1');
- testCase.verifyEqual(ud.FastPlot.LineIndex, 1);
+ testCase.verifyEqual(ud.FastSense.Type, 'data_line');
+ testCase.verifyEqual(ud.FastSense.Name, 'Sensor1');
+ testCase.verifyEqual(ud.FastSense.LineIndex, 1);
close(fp.hFigure);
end
function testThresholdLineCreated(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addThreshold(0.5, 'Direction', 'upper', 'Label', 'UL');
fp.render();
testCase.verifyTrue(isgraphics(fp.hThreshLines, 'line'));
ud = fp.hThreshLines.UserData;
- testCase.verifyEqual(ud.FastPlot.Type, 'threshold');
+ testCase.verifyEqual(ud.FastSense.Type, 'threshold');
close(fp.hFigure);
end
function testViolationMarkersCreated(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [0.1 0.2 0.8 0.9 0.3 0.1];
fp.addLine(1:6, y);
fp.addThreshold(0.5, 'Direction', 'upper', 'ShowViolations', true);
@@ -1215,15 +1215,15 @@ classdef TestRender < matlab.unittest.TestCase
end
function testDoubleRenderError(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
- testCase.verifyError(@() fp.render(), 'FastPlot:alreadyRendered');
+ testCase.verifyError(@() fp.render(), 'FastSense:alreadyRendered');
close(fp.hFigure);
end
function testStaticAxisLimits(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
ax = fp.hAxes;
@@ -1241,7 +1241,7 @@ end
runtests('tests/TestRender');
```
-**Step 3: Implement render and helper methods in FastPlot.m**
+**Step 3: Implement render and helper methods in FastSense.m**
Update the `hAxes` and `hThreshLines` and `hViolMarkers` to `SetAccess = private` (public read):
```matlab
@@ -1265,11 +1265,11 @@ function render(obj)
%RENDER Create the plot with all configured lines and thresholds.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
- 'render() has already been called on this FastPlot.');
+ error('FastSense:alreadyRendered', ...
+ 'render() has already been called on this FastSense.');
end
if isempty(obj.Lines)
- error('FastPlot:noLines', 'Add at least one line before render().');
+ error('FastSense:noLines', 'Add at least one line before render().');
end
% Create or use axes
@@ -1316,7 +1316,7 @@ function render(obj)
if isfield(opts, 'DisplayName')
displayName = opts.DisplayName;
end
- h.UserData.FastPlot = struct( ...
+ h.UserData.FastSense = struct( ...
'Type', 'data_line', ...
'Name', displayName, ...
'LineIndex', i, ...
@@ -1353,7 +1353,7 @@ function render(obj)
'Color', obj.Thresholds(1).Color, ...
'LineStyle', obj.Thresholds(1).LineStyle, ...
'HandleVisibility', 'off');
- obj.hThreshLines.UserData.FastPlot = struct( ...
+ obj.hThreshLines.UserData.FastSense = struct( ...
'Type', 'threshold', ...
'Name', 'thresholds', ...
'LineIndex', [], ...
@@ -1385,7 +1385,7 @@ function render(obj)
'LineStyle', 'none', 'Marker', 'o', ...
'MarkerSize', 4, 'Color', 'r', ...
'HandleVisibility', 'off');
- obj.hViolMarkers.UserData.FastPlot = struct( ...
+ obj.hViolMarkers.UserData.FastSense = struct( ...
'Type', 'violation_marker', ...
'Name', 'violations', ...
'LineIndex', [], ...
@@ -1450,18 +1450,18 @@ Expected: all 8 tests pass. (Note: `SizeChangedFcn` listener may need adjustment
## Task 9: Zoom/Pan Callbacks
**Files:**
-- Modify: `FastPlot/FastPlot.m` — `onXLimChanged`, `updateLines`, `updateViolations`, `onResize`
-- Create: `FastPlot/tests/TestZoomPan.m`
+- Modify: `FastSense/FastSense.m` — `onXLimChanged`, `updateLines`, `updateViolations`, `onResize`
+- Create: `FastSense/tests/TestZoomPan.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestZoomPan.m`:
+Create `FastSense/tests/TestZoomPan.m`:
```matlab
classdef TestZoomPan < matlab.unittest.TestCase
methods (Test)
function testZoomUpdatesPlottedData(testCase)
- fp = FastPlot();
+ fp = FastSense();
n = 100000;
x = linspace(0, 100, n);
y = sin(x);
@@ -1485,7 +1485,7 @@ classdef TestZoomPan < matlab.unittest.TestCase
end
function testLazySkipsRedundantUpdate(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:1000, rand(1,1000));
fp.render();
@@ -1501,7 +1501,7 @@ classdef TestZoomPan < matlab.unittest.TestCase
end
function testViolationsUpdateOnZoom(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,500), ones(1,500)*10, zeros(1,500)];
x = 1:1500;
fp.addLine(x, y);
@@ -1540,7 +1540,7 @@ end
runtests('tests/TestZoomPan');
```
-**Step 3: Implement zoom/pan callbacks in FastPlot.m**
+**Step 3: Implement zoom/pan callbacks in FastSense.m**
Replace `onXLimChanged`:
```matlab
@@ -1679,12 +1679,12 @@ Expected: all 3 tests pass.
## Task 10: Linked Axes
**Files:**
-- Modify: `FastPlot/FastPlot.m` — add `propagateXLim` method, class-level registry
-- Create: `FastPlot/tests/TestLinkedAxes.m`
+- Modify: `FastSense/FastSense.m` — add `propagateXLim` method, class-level registry
+- Create: `FastSense/tests/TestLinkedAxes.m`
**Step 1: Write the test**
-Create `FastPlot/tests/TestLinkedAxes.m`:
+Create `FastSense/tests/TestLinkedAxes.m`:
```matlab
classdef TestLinkedAxes < matlab.unittest.TestCase
@@ -1694,11 +1694,11 @@ classdef TestLinkedAxes < matlab.unittest.TestCase
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'testgroup');
+ fp1 = FastSense('Parent', ax1, 'LinkGroup', 'testgroup');
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'testgroup');
+ fp2 = FastSense('Parent', ax2, 'LinkGroup', 'testgroup');
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
@@ -1718,11 +1718,11 @@ classdef TestLinkedAxes < matlab.unittest.TestCase
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1);
+ fp1 = FastSense('Parent', ax1);
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2);
+ fp2 = FastSense('Parent', ax2);
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
@@ -1747,11 +1747,11 @@ runtests('tests/TestLinkedAxes');
**Step 3: Implement linked axes**
-Add a persistent registry. Add to `FastPlot.m` a static method section:
+Add a persistent registry. Add to `FastSense.m` a static method section:
```matlab
methods (Static, Access = private)
function registry = getLinkRegistry(action, group, obj)
- %GETLINKREGISTRY Persistent registry for linked FastPlot instances.
+ %GETLINKREGISTRY Persistent registry for linked FastSense instances.
persistent reg;
if isempty(reg)
reg = struct();
@@ -1790,7 +1790,7 @@ end
Add `propagateXLim` to private methods:
```matlab
function propagateXLim(obj, newXLim)
- members = FastPlot.getLinkRegistry('get', obj.LinkGroup, []);
+ members = FastSense.getLinkRegistry('get', obj.LinkGroup, []);
for i = 1:numel(members)
other = members{i};
if other ~= obj && isvalid(other) && isgraphics(other.hAxes)
@@ -1807,7 +1807,7 @@ In `render()`, after setting `obj.IsRendered = true`, add registration:
```matlab
% Register in link group
if ~isempty(obj.LinkGroup)
- FastPlot.getLinkRegistry('register', obj.LinkGroup, obj);
+ FastSense.getLinkRegistry('register', obj.LinkGroup, obj);
end
```
@@ -1823,7 +1823,7 @@ Expected: both tests pass.
## Task 11: Resize Handling Fix
**Files:**
-- Modify: `FastPlot/FastPlot.m` — fix resize listener for 2020b
+- Modify: `FastSense/FastSense.m` — fix resize listener for 2020b
**Step 1: Fix resize listener**
@@ -1846,7 +1846,7 @@ obj.hFigure.ResizeFcn = @(s,e) obj.onResize(s,e);
**Step 2: Run all tests**
```matlab
-cd FastPlot; runtests('tests');
+cd FastSense; runtests('tests');
```
Expected: all tests pass.
@@ -1855,25 +1855,25 @@ Expected: all tests pass.
## Task 12: Example Scripts
**Files:**
-- Create: `FastPlot/examples/example_basic.m`
-- Create: `FastPlot/examples/example_multi.m`
-- Create: `FastPlot/examples/example_100M.m`
-- Create: `FastPlot/examples/example_linked.m`
+- Create: `FastSense/examples/example_basic.m`
+- Create: `FastSense/examples/example_multi.m`
+- Create: `FastSense/examples/example_100M.m`
+- Create: `FastSense/examples/example_linked.m`
**Step 1: Create example_basic.m**
```matlab
-%% FastPlot Basic Example — 10M points single line
+%% FastSense Basic Example — 10M points single line
% Demonstrates basic usage with a large time series
n = 10e6;
x = linspace(0, 100, n);
y = sin(x * 2 * pi / 10) + 0.5 * randn(1, n);
-fprintf('Creating FastPlot with %d points...\n', n);
+fprintf('Creating FastSense with %d points...\n', n);
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Noisy Sine', 'Color', [0 0.4470 0.7410]);
fp.addThreshold(1.5, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', 'r', 'Label', 'Upper');
@@ -1882,14 +1882,14 @@ fp.addThreshold(-1.5, 'Direction', 'lower', 'ShowViolations', true, ...
fp.render();
fprintf('Rendered in %.3f seconds. Try zooming and panning!\n', toc);
-title(fp.hAxes, 'FastPlot — 10M Points');
+title(fp.hAxes, 'FastSense — 10M Points');
legend(fp.hAxes, 'show');
```
**Step 2: Create example_multi.m**
```matlab
-%% FastPlot Multi-Line Example — 5 sensors, 1M points each
+%% FastSense Multi-Line Example — 5 sensors, 1M points each
% Demonstrates multiple lines with thresholds
n = 1e6;
@@ -1898,7 +1898,7 @@ x = linspace(0, 60, n); % 60 seconds
fprintf('Creating 5 lines x %d points = %d total...\n', n, 5*n);
tic;
-fp = FastPlot();
+fp = FastSense();
colors = lines(5);
for i = 1:5
y = sin(x * 2 * pi * i / 10) + 0.3 * randn(1, n) + i * 2;
@@ -1910,14 +1910,14 @@ fp.addThreshold(10, 'Direction', 'upper', 'ShowViolations', true, ...
fp.render();
fprintf('Rendered in %.3f seconds.\n', toc);
-title(fp.hAxes, 'FastPlot — 5 Lines x 1M Points');
+title(fp.hAxes, 'FastSense — 5 Lines x 1M Points');
legend(fp.hAxes, 'show');
```
**Step 3: Create example_100M.m**
```matlab
-%% FastPlot Stress Test — 100M points
+%% FastSense Stress Test — 100M points
% Demonstrates performance at maximum scale
n = 100e6;
@@ -1930,30 +1930,30 @@ fprintf('Data generated in %.1f seconds.\n', toc);
fprintf('Rendering...\n');
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', '100M Random Walk', 'Color', [0 0.4 0.8]);
fp.addThreshold(3, 'Direction', 'upper', 'ShowViolations', true);
fp.addThreshold(-3, 'Direction', 'lower', 'ShowViolations', true);
fp.render();
fprintf('Rendered in %.3f seconds. Zoom in to see detail!\n', toc);
-title(fp.hAxes, 'FastPlot — 100M Points Stress Test');
+title(fp.hAxes, 'FastSense — 100M Points Stress Test');
```
**Step 4: Create example_linked.m**
```matlab
-%% FastPlot Linked Axes Example
+%% FastSense Linked Axes Example
% Demonstrates synchronized zoom/pan across subplots
n = 5e6;
x = linspace(0, 100, n);
-fig = figure('Name', 'FastPlot Linked Axes', 'Position', [100 100 1200 600]);
+fig = figure('Name', 'FastSense Linked Axes', 'Position', [100 100 1200 600]);
% Top plot
ax1 = subplot(3,1,1, 'Parent', fig);
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'sync');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'sync');
fp1.addLine(x, sin(x * 2 * pi / 5) + 0.2*randn(1,n), ...
'DisplayName', 'Pressure', 'Color', 'b');
fp1.addThreshold(1.2, 'Direction', 'upper', 'ShowViolations', true);
@@ -1962,7 +1962,7 @@ title(ax1, 'Pressure');
% Middle plot
ax2 = subplot(3,1,2, 'Parent', fig);
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'sync');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'sync');
fp2.addLine(x, cos(x * 2 * pi / 8) + 0.3*randn(1,n), ...
'DisplayName', 'Temperature', 'Color', [0.8 0.3 0]);
fp2.render();
@@ -1970,7 +1970,7 @@ title(ax2, 'Temperature');
% Bottom plot
ax3 = subplot(3,1,3, 'Parent', fig);
-fp3 = FastPlot('Parent', ax3, 'LinkGroup', 'sync');
+fp3 = FastSense('Parent', ax3, 'LinkGroup', 'sync');
fp3.addLine(x, cumsum(randn(1,n))/sqrt(n), ...
'DisplayName', 'Vibration', 'Color', [0 0.6 0]);
fp3.render();
@@ -1984,13 +1984,13 @@ fprintf('All 3 plots linked. Zoom one — all follow!\n');
## Task 13: Final Assembly and README
**Files:**
-- Create: `FastPlot/README.md`
+- Create: `FastSense/README.md`
- Verify full test suite passes
**Step 1: Create README.md**
```markdown
-# FastPlot
+# FastSense
Ultra-fast time series plotting for MATLAB 2020b. Plot 100M+ data points with fluid zoom and pan.
@@ -2008,9 +2008,9 @@ Ultra-fast time series plotting for MATLAB 2020b. Plot 100M+ data points with fl
## Quick Start
```matlab
-addpath('FastPlot');
+addpath('FastSense');
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Sensor1', 'Color', 'b');
fp.addThreshold(4.5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
@@ -2028,7 +2028,7 @@ See `examples/` folder for complete demos.
**Step 2: Run full test suite**
```matlab
-cd FastPlot; runtests('tests');
+cd FastSense; runtests('tests');
```
Expected: all tests pass across all test files.
diff --git a/docs/plans/2026-03-06-lazy-pyramid-design.md b/docs/plans/2026-03-06-lazy-pyramid-design.md
index 25c2c552..e66ffb06 100644
--- a/docs/plans/2026-03-06-lazy-pyramid-design.md
+++ b/docs/plans/2026-03-06-lazy-pyramid-design.md
@@ -1,4 +1,4 @@
-# Lazy Multi-Resolution Pyramid for FastPlot
+# Lazy Multi-Resolution Pyramid for FastSense
## Design Document
@@ -77,9 +77,9 @@ Replaces the inner loop of `updateLines()`:
| Component | Change |
|---|---|
-| `FastPlot.m` Lines struct | Add `Pyramid` field (cell array) |
-| `FastPlot.m` `updateLines()` | Level selection + pyramid query |
-| `FastPlot.m` new private method | `buildPyramidLevel()`, `selectPyramidLevel()` |
+| `FastSense.m` Lines struct | Add `Pyramid` field (cell array) |
+| `FastSense.m` `updateLines()` | Level selection + pyramid query |
+| `FastSense.m` new private method | `buildPyramidLevel()`, `selectPyramidLevel()` |
| `private/minmax_downsample.m` | No change |
| Tests | New `test_pyramid.m` |
@@ -95,6 +95,6 @@ Full zoom-out query: read level 2 (5K points) → downsample to ~4K → **<1ms**
## 6. Constraints
-- Pyramid is invalidated if data changes (FastPlot data is immutable after `addLine()`, so this is safe)
+- Pyramid is invalidated if data changes (FastSense data is immutable after `addLine()`, so this is safe)
- NaN-aware: pyramid levels preserve NaN segment structure via `minmax_downsample`
- No render-time cost: zero overhead if user never zooms out far enough to trigger pyramid build
diff --git a/docs/plans/2026-03-06-mex-acceleration-design.md b/docs/plans/2026-03-06-mex-acceleration-design.md
index 91ee4df8..bc46871c 100644
--- a/docs/plans/2026-03-06-mex-acceleration-design.md
+++ b/docs/plans/2026-03-06-mex-acceleration-design.md
@@ -1,4 +1,4 @@
-# FastPlot MEX Acceleration — Design Document
+# FastSense MEX Acceleration — Design Document
**Date:** 2026-03-06
**Status:** Approved
@@ -7,7 +7,7 @@
## 1. Goal
-Add C MEX implementations with SIMD intrinsics (AVX2 for x86_64, NEON for ARM64) for the three performance-critical functions in FastPlot. Existing pure-MATLAB implementations remain as automatic fallbacks.
+Add C MEX implementations with SIMD intrinsics (AVX2 for x86_64, NEON for ARM64) for the three performance-critical functions in FastSense. Existing pure-MATLAB implementations remain as automatic fallbacks.
---
@@ -28,7 +28,7 @@ Add C MEX implementations with SIMD intrinsics (AVX2 for x86_64, NEON for ARM64)
### File Layout
```
-FastPlot/
+FastSense/
├── private/
│ ├── minmax_downsample.m (modified: calls minmax_core_mex or minmax_core)
│ ├── lttb_downsample.m (modified: calls lttb_core_mex or lttb_core)
@@ -130,7 +130,7 @@ Provides unified macros for: load, store, min, max, fabs, multiply, subtract ope
## 8. What Does NOT Change
- All existing `.m` files keep their pure-MATLAB fallback implementations
-- Public FastPlot API is unchanged
+- Public FastSense API is unchanged
- Test suite passes with or without MEX compiled
- Octave compatibility preserved for pure-MATLAB path
- No new toolbox dependencies
diff --git a/docs/plans/2026-03-06-mex-acceleration-implementation.md b/docs/plans/2026-03-06-mex-acceleration-implementation.md
index 212f271c..219a0731 100644
--- a/docs/plans/2026-03-06-mex-acceleration-implementation.md
+++ b/docs/plans/2026-03-06-mex-acceleration-implementation.md
@@ -8,22 +8,22 @@
**Tech Stack:** C11, MATLAB MEX API (`mex.h`), AVX2/SSE2 intrinsics (`immintrin.h`), ARM NEON intrinsics (`arm_neon.h`), MATLAB R2020b+.
-**Design doc:** `FastPlot/docs/plans/2026-03-06-mex-acceleration-design.md`
+**Design doc:** `FastSense/docs/plans/2026-03-06-mex-acceleration-design.md`
---
## Task 1: SIMD Abstraction Header
**Files:**
-- Create: `FastPlot/private/mex_src/simd_utils.h`
+- Create: `FastSense/private/mex_src/simd_utils.h`
**Step 1: Create directory and write simd_utils.h**
```bash
-mkdir -p FastPlot/private/mex_src
+mkdir -p FastSense/private/mex_src
```
-Create `FastPlot/private/mex_src/simd_utils.h`:
+Create `FastSense/private/mex_src/simd_utils.h`:
```c
#ifndef SIMD_UTILS_H
@@ -33,7 +33,7 @@ Create `FastPlot/private/mex_src/simd_utils.h`:
#include
/*
- * simd_utils.h — Compile-time SIMD abstraction for FastPlot MEX files.
+ * simd_utils.h — Compile-time SIMD abstraction for FastSense MEX files.
*
* Provides unified operations on packed doubles:
* - AVX2: 4 doubles per vector (__m256d)
@@ -177,7 +177,7 @@ static inline double simd_hmin(simd_double v) { return v; }
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add private/mex_src/simd_utils.h
git commit -m "Add SIMD abstraction header for MEX acceleration
@@ -190,11 +190,11 @@ Provides unified macros for packed-double min/max/mul/sub/abs."
## Task 2: binary_search_mex
**Files:**
-- Create: `FastPlot/private/mex_src/binary_search_mex.c`
+- Create: `FastSense/private/mex_src/binary_search_mex.c`
**Step 1: Write binary_search_mex.c**
-Create `FastPlot/private/mex_src/binary_search_mex.c`:
+Create `FastSense/private/mex_src/binary_search_mex.c`:
```c
/*
@@ -223,19 +223,19 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:nrhs",
"Three inputs required: x, val, direction.");
}
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notDouble",
"x must be a real double array.");
}
if (!mxIsDouble(prhs[1]) || mxGetNumberOfElements(prhs[1]) != 1) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notScalar",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notScalar",
"val must be a scalar double.");
}
if (!mxIsChar(prhs[2])) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notChar",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notChar",
"direction must be a char array.");
}
@@ -288,7 +288,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add private/mex_src/binary_search_mex.c
git commit -m "Add binary_search MEX implementation
@@ -301,11 +301,11 @@ loop overhead for O(log n) search on sorted double arrays."
## Task 3: minmax_core_mex
**Files:**
-- Create: `FastPlot/private/mex_src/minmax_core_mex.c`
+- Create: `FastSense/private/mex_src/minmax_core_mex.c`
**Step 1: Write minmax_core_mex.c**
-Create `FastPlot/private/mex_src/minmax_core_mex.c`:
+Create `FastSense/private/mex_src/minmax_core_mex.c`:
```c
/*
@@ -335,11 +335,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:minmax_core_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:minmax_core_mex:nrhs",
"Three inputs required: x, y, numBuckets.");
}
if (!mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1])) {
- mexErrMsgIdAndTxt("FastPlot:minmax_core_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:minmax_core_mex:notDouble",
"x and y must be real double arrays.");
}
@@ -433,7 +433,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add private/mex_src/minmax_core_mex.c
git commit -m "Add minmax_core MEX implementation with SIMD
@@ -446,11 +446,11 @@ index-tracking pass. Handles remainder by extending last bucket."
## Task 4: lttb_core_mex
**Files:**
-- Create: `FastPlot/private/mex_src/lttb_core_mex.c`
+- Create: `FastSense/private/mex_src/lttb_core_mex.c`
**Step 1: Write lttb_core_mex.c**
-Create `FastPlot/private/mex_src/lttb_core_mex.c`:
+Create `FastSense/private/mex_src/lttb_core_mex.c`:
```c
/*
@@ -479,11 +479,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:lttb_core_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:lttb_core_mex:nrhs",
"Three inputs required: x, y, numOut.");
}
if (!mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1])) {
- mexErrMsgIdAndTxt("FastPlot:lttb_core_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:lttb_core_mex:notDouble",
"x and y must be real double arrays.");
}
@@ -611,7 +611,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add private/mex_src/lttb_core_mex.c
git commit -m "Add lttb_core MEX implementation with SIMD
@@ -624,15 +624,15 @@ Sequential outer loop preserved (each bucket depends on previous)."
## Task 5: Build Script
**Files:**
-- Create: `FastPlot/build_mex.m`
+- Create: `FastSense/build_mex.m`
**Step 1: Write build_mex.m**
-Create `FastPlot/build_mex.m`:
+Create `FastSense/build_mex.m`:
```matlab
function build_mex()
-%BUILD_MEX Compile FastPlot MEX files with platform-appropriate SIMD flags.
+%BUILD_MEX Compile FastSense MEX files with platform-appropriate SIMD flags.
% build_mex()
%
% Detects CPU architecture, sets compiler flags for AVX2/SSE2/NEON,
@@ -734,7 +734,7 @@ end
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add build_mex.m
git commit -m "Add build_mex.m script for MEX compilation
@@ -747,9 +747,9 @@ Compiles all 3 MEX files into private/. Safe to re-run."
## Task 6: Wire MEX Fallback into MATLAB Wrappers
**Files:**
-- Modify: `FastPlot/private/binary_search.m` (lines 1-39)
-- Modify: `FastPlot/private/minmax_downsample.m` (lines 21, 73)
-- Modify: `FastPlot/private/lttb_downsample.m` (lines 59)
+- Modify: `FastSense/private/binary_search.m` (lines 1-39)
+- Modify: `FastSense/private/minmax_downsample.m` (lines 21, 73)
+- Modify: `FastSense/private/lttb_downsample.m` (lines 59)
**Step 1: Modify binary_search.m — add MEX dispatch**
@@ -874,7 +874,7 @@ with:
**Step 4: Run existing tests to verify fallback path still works**
```bash
-cd FastPlot && matlab -batch "addpath('tests'); addpath('private'); run_all_tests()"
+cd FastSense && matlab -batch "addpath('tests'); addpath('private'); run_all_tests()"
```
Expected: All existing tests pass (MEX not compiled yet, so fallback path runs).
@@ -882,7 +882,7 @@ Expected: All existing tests pass (MEX not compiled yet, so fallback path runs).
**Step 5: Commit**
```bash
-cd FastPlot
+cd FastSense
git add private/binary_search.m private/minmax_downsample.m private/lttb_downsample.m
git commit -m "Wire MEX fallback dispatch into MATLAB wrappers
@@ -895,11 +895,11 @@ availability. Falls back to existing pure-MATLAB code if not compiled."
## Task 7: MEX Parity Tests
**Files:**
-- Create: `FastPlot/tests/test_mex_parity.m`
+- Create: `FastSense/tests/test_mex_parity.m`
**Step 1: Write test_mex_parity.m**
-Create `FastPlot/tests/test_mex_parity.m`:
+Create `FastSense/tests/test_mex_parity.m`:
```matlab
function test_mex_parity()
@@ -1117,7 +1117,7 @@ end
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add tests/test_mex_parity.m
git commit -m "Add MEX parity tests
@@ -1131,11 +1131,11 @@ Skips gracefully if MEX not compiled."
## Task 8: MEX Edge Case Tests
**Files:**
-- Create: `FastPlot/tests/test_mex_edge_cases.m`
+- Create: `FastSense/tests/test_mex_edge_cases.m`
**Step 1: Write test_mex_edge_cases.m**
-Create `FastPlot/tests/test_mex_edge_cases.m`:
+Create `FastSense/tests/test_mex_edge_cases.m`:
```matlab
function test_mex_edge_cases()
@@ -1263,7 +1263,7 @@ end
**Step 2: Commit**
```bash
-cd FastPlot
+cd FastSense
git add tests/test_mex_edge_cases.m
git commit -m "Add MEX edge case tests
@@ -1278,7 +1278,7 @@ negative values, and remainder handling for all 3 MEX functions."
**Step 1: Compile MEX files**
```matlab
-cd FastPlot
+cd FastSense
build_mex()
```
@@ -1287,7 +1287,7 @@ Expected: `3/3 MEX files compiled successfully.`
**Step 2: Run full test suite**
```matlab
-cd FastPlot
+cd FastSense
addpath('tests'); addpath('private');
run_all_tests()
```
@@ -1304,18 +1304,18 @@ Add a "Building MEX (optional)" section after "Requirements" in `README.md`:
For maximum performance, compile the C MEX accelerators:
```matlab
-cd FastPlot
+cd FastSense
build_mex()
```
Requires a C compiler (Xcode on macOS, GCC on Linux, MSVC on Windows). Uses AVX2/NEON SIMD intrinsics when available.
-If MEX files are not compiled, FastPlot automatically uses the pure-MATLAB implementations — no functionality is lost.
+If MEX files are not compiled, FastSense automatically uses the pure-MATLAB implementations — no functionality is lost.
```
**Step 4: Add `*.mex*` to .gitignore**
-Create or update `FastPlot/.gitignore`:
+Create or update `FastSense/.gitignore`:
```
*.mexmaci64
@@ -1328,7 +1328,7 @@ Create or update `FastPlot/.gitignore`:
**Step 5: Commit**
```bash
-cd FastPlot
+cd FastSense
git add README.md .gitignore
git commit -m "Update README with MEX build instructions, add .gitignore
@@ -1343,16 +1343,16 @@ binaries and .DS_Store files."
**Step 1: Run existing benchmark to compare**
```matlab
-cd FastPlot/examples
+cd FastSense/examples
benchmark()
```
-Expected: With MEX compiled, FastPlot zoom/downsample times should be noticeably faster, especially for LTTB at large data sizes.
+Expected: With MEX compiled, FastSense zoom/downsample times should be noticeably faster, especially for LTTB at large data sizes.
**Step 2: Verify benchmark_zoom still works**
```matlab
-cd FastPlot/examples
+cd FastSense/examples
benchmark_zoom()
```
diff --git a/docs/plans/2026-03-07-datetime-design.md b/docs/plans/2026-03-07-datetime-design.md
index 83143a54..19127e6a 100644
--- a/docs/plans/2026-03-07-datetime-design.md
+++ b/docs/plans/2026-03-07-datetime-design.md
@@ -1,8 +1,8 @@
-# FastPlot Datetime Support — Design
+# FastSense Datetime Support — Design
## Goal
-Add datetime-aware X axis display to FastPlot. Users pass `datenum` values (or MATLAB `datetime` objects, auto-converted) and get human-readable date/time tick labels that adapt to zoom level.
+Add datetime-aware X axis display to FastSense. Users pass `datenum` values (or MATLAB `datetime` objects, auto-converted) and get human-readable date/time tick labels that adapt to zoom level.
## Architecture
@@ -18,7 +18,7 @@ Add datetime-aware X axis display to FastPlot. Users pass `datenum` values (or M
### Storage
- New field in `Lines` struct: `XType` — `'numeric'` (default) or `'datenum'`
-- New property on `FastPlot`: `XType` — set from first line that declares `'datenum'`, enforced consistent across all lines on same axes
+- New property on `FastSense`: `XType` — set from first line that declares `'datenum'`, enforced consistent across all lines on same axes
### Tick Formatting
@@ -37,18 +37,18 @@ Tick formatter re-runs on every zoom/pan (inside `onXLimChanged`).
- **Crosshair text:** `datestr(xp, 'mmm dd HH:MM:SS')` instead of `sprintf('x=%.4g', xp)`
- **Data cursor label:** `datestr(sx, 'mmm dd HH:MM:SS')` instead of `sprintf('(%.4g, %.4g)', sx, sy)`
-- Toolbar checks `fp.XType` (or first `FastPlots{i}.XType`) to decide formatting
+- Toolbar checks `fp.XType` (or first `FastSenses{i}.XType`) to decide formatting
-### FastPlotFigure
+### FastSenseFigure
-Each tile can independently have `XType == 'datenum'` or `'numeric'`. No figure-level setting needed — it inherits from the FastPlot instances.
+Each tile can independently have `XType == 'datenum'` or `'numeric'`. No figure-level setting needed — it inherits from the FastSense instances.
## What Changes
| File | Change |
|---|---|
-| `FastPlot.m` | Add `XType` property; detect datetime input in `addLine`; install tick formatter in `render`; update ticks in `onXLimChanged` |
-| `FastPlotToolbar.m` | Format crosshair/cursor display based on `XType` |
+| `FastSense.m` | Add `XType` property; detect datetime input in `addLine`; install tick formatter in `render`; update ticks in `onXLimChanged` |
+| `FastSenseToolbar.m` | Format crosshair/cursor display based on `XType` |
| `tests/test_toolbar.m` | Add datetime formatting tests |
| `tests/test_datetime.m` | New: datenum axes, tick formatting, datetime auto-conversion |
| `examples/example_toolbar.m` | Add datetime demo section |
@@ -61,8 +61,8 @@ Each tile can independently have `XType == 'datenum'` or `'numeric'`. No figure-
- `lttb_downsample.m` / MEX
- `compute_violations.m`
- Zoom/pan pipeline (internally)
-- `FastPlotFigure.m`
-- `FastPlotTheme.m`
+- `FastSenseFigure.m`
+- `FastSenseTheme.m`
## Compatibility
diff --git a/docs/plans/2026-03-07-datetime.md b/docs/plans/2026-03-07-datetime.md
index d3b8b7a2..1ee1f30b 100644
--- a/docs/plans/2026-03-07-datetime.md
+++ b/docs/plans/2026-03-07-datetime.md
@@ -4,7 +4,7 @@
**Goal:** Add datetime-aware X axis display so users can pass `datenum` values (or MATLAB `datetime` objects) and get auto-formatted date/time tick labels that adapt to zoom level.
-**Architecture:** Store `XType` (`'numeric'` or `'datenum'`) on each FastPlot instance. Internally everything stays as doubles — no changes to binary_search, downsampling, or MEX. On render and zoom, a tick formatter picks date format based on visible range. Toolbar crosshair/cursor uses `datestr()` for display. MATLAB `datetime` input is auto-converted to `datenum`.
+**Architecture:** Store `XType` (`'numeric'` or `'datenum'`) on each FastSense instance. Internally everything stays as doubles — no changes to binary_search, downsampling, or MEX. On render and zoom, a tick formatter picks date format based on visible range. Toolbar crosshair/cursor uses `datestr()` for display. MATLAB `datetime` input is auto-converted to `datenum`.
**Tech Stack:** MATLAB/Octave `datenum`/`datestr`, `XTick`/`XTickLabel` axis properties, `datetick` (reference only — we roll our own for zoom-aware formatting).
@@ -13,7 +13,7 @@
### Task 1: XType property + datenum detection in addLine
**Files:**
-- Modify: `FastPlot.m` (properties, addLine method)
+- Modify: `FastSense.m` (properties, addLine method)
- Create: `tests/test_datetime.m`
**Step 1: Write the failing test**
@@ -31,12 +31,12 @@ function test_datetime()
drawnow;
% testXTypeDefaultIsNumeric
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
assert(strcmp(fp.XType, 'numeric'), 'testXTypeDefault: should be numeric');
% testXTypeDatenum
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24;
fp.addLine(x, rand(1,100), 'XType', 'datenum');
assert(strcmp(fp.XType, 'datenum'), 'testXTypeDatenum: should be datenum');
@@ -44,7 +44,7 @@ function test_datetime()
% testDatetimeAutoConvert
% Only run in MATLAB where datetime exists
if exist('datetime', 'class')
- fp = FastPlot();
+ fp = FastSense();
dt = datetime(2024,1,1) + hours(0:99);
fp.addLine(dt, rand(1,100));
assert(strcmp(fp.XType, 'datenum'), 'testDatetimeAutoConvert: should be datenum');
@@ -62,13 +62,13 @@ Expected: FAIL — `XType` property not defined
**Step 3: Write minimal implementation**
-In `FastPlot.m`, add `XType` to public properties (after `Theme`):
+In `FastSense.m`, add `XType` to public properties (after `Theme`):
```matlab
XType = 'numeric' % 'numeric' or 'datenum'
```
-In `FastPlot.m`, modify `addLine` method. After the row vector coercion (line 92-93) and before the size validation (line 96), add datetime detection and conversion:
+In `FastSense.m`, modify `addLine` method. After the row vector coercion (line 92-93) and before the size validation (line 96), add datetime detection and conversion:
```matlab
% Detect and convert datetime input
@@ -88,7 +88,7 @@ In `addLine`, inside the varargin parsing loop (after the `DownsampleMethod` che
if strcmp(obj.XType, 'numeric') || strcmp(obj.XType, val)
obj.XType = val;
else
- error('FastPlot:mixedXType', ...
+ error('FastSense:mixedXType', ...
'All lines must use the same XType.');
end
```
@@ -101,7 +101,7 @@ Expected: PASS
**Step 5: Commit**
```bash
-git add FastPlot.m tests/test_datetime.m
+git add FastSense.m tests/test_datetime.m
git commit -m "Add XType property and datenum/datetime detection in addLine"
```
@@ -110,7 +110,7 @@ git commit -m "Add XType property and datenum/datetime detection in addLine"
### Task 2: Tick formatter — auto-format based on zoom level
**Files:**
-- Modify: `FastPlot.m` (render, onXLimChanged, new private method)
+- Modify: `FastSense.m` (render, onXLimChanged, new private method)
- Modify: `tests/test_datetime.m`
**Step 1: Write the failing test**
@@ -119,7 +119,7 @@ Append to `tests/test_datetime.m` before the final fprintf:
```matlab
% testTickLabelsAreDateStrings
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24; % ~4 days of hourly data
fp.addLine(x, rand(1,100), 'XType', 'datenum');
fp.render();
@@ -136,7 +136,7 @@ Append to `tests/test_datetime.m` before the final fprintf:
close(fp.hFigure);
% testTickFormatChangesOnZoom
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:9999)/86400; % ~0.1s resolution
fp.addLine(x, rand(1,10000), 'XType', 'datenum');
fp.render();
@@ -165,7 +165,7 @@ Expected: FAIL — tick labels are plain numbers
**Step 3: Write minimal implementation**
-Add a new private method to `FastPlot.m`:
+Add a new private method to `FastSense.m`:
```matlab
function updateDatetimeTicks(obj)
@@ -210,7 +210,7 @@ Expected: PASS
**Step 5: Commit**
```bash
-git add FastPlot.m tests/test_datetime.m
+git add FastSense.m tests/test_datetime.m
git commit -m "Add auto-format datetime tick labels based on zoom level"
```
@@ -219,7 +219,7 @@ git commit -m "Add auto-format datetime tick labels based on zoom level"
### Task 3: Toolbar datetime display — crosshair and cursor
**Files:**
-- Modify: `FastPlotToolbar.m` (onMouseMove, onMouseClick)
+- Modify: `FastSenseToolbar.m` (onMouseMove, onMouseClick)
- Modify: `tests/test_datetime.m`
**Step 1: Write the failing test**
@@ -230,9 +230,9 @@ Append to `tests/test_datetime.m`:
% testToolbarFormatX
% Verify the static helper returns date string for datenum XType
xVal = datenum(2024, 3, 15, 10, 30, 45);
- result = FastPlotToolbar.formatX(xVal, 'datenum');
+ result = FastSenseToolbar.formatX(xVal, 'datenum');
assert(any(result == ':'), 'testToolbarFormatX: should contain colon');
- resultNum = FastPlotToolbar.formatX(42.5, 'numeric');
+ resultNum = FastSenseToolbar.formatX(42.5, 'numeric');
assert(~any(resultNum == ':'), 'testToolbarFormatXNum: should not contain colon');
```
@@ -242,7 +242,7 @@ Expected: FAIL — `formatX` not defined
**Step 3: Write minimal implementation**
-Add a new static method to `FastPlotToolbar.m` (in the `methods (Static)` block, after `makeIcon`):
+Add a new static method to `FastSenseToolbar.m` (in the `methods (Static)` block, after `makeIcon`):
```matlab
function str = formatX(xVal, xtype)
@@ -277,10 +277,10 @@ With:
```matlab
'String', sprintf('x=%s y=%.4g', ...
- FastPlotToolbar.formatX(xp, obj.getXType([])), yp));
+ FastSenseToolbar.formatX(xp, obj.getXType([])), yp));
```
-But we need the active FastPlot to get XType. Modify `onMouseMove` to also get `fp`:
+But we need the active FastSense to get XType. Modify `onMouseMove` to also get `fp`:
Change line 197 from:
```matlab
@@ -295,7 +295,7 @@ And update both crosshair text lines to use:
```matlab
'String', sprintf('x=%s y=%.4g', ...
- FastPlotToolbar.formatX(xp, obj.getXType(fp)), yp));
+ FastSenseToolbar.formatX(xp, obj.getXType(fp)), yp));
```
In `onMouseClick`, replace the cursor label (line 250):
@@ -308,7 +308,7 @@ With:
```matlab
label = sprintf('(%s, %.4g)', ...
- FastPlotToolbar.formatX(sx, obj.getXType(fp)), sy);
+ FastSenseToolbar.formatX(sx, obj.getXType(fp)), sy);
```
**Step 4: Run test to verify it passes**
@@ -319,7 +319,7 @@ Expected: PASS
**Step 5: Commit**
```bash
-git add FastPlotToolbar.m tests/test_datetime.m
+git add FastSenseToolbar.m tests/test_datetime.m
git commit -m "Add datetime formatting to toolbar crosshair and cursor"
```
@@ -340,12 +340,12 @@ Append to `examples/example_toolbar.m`:
x = datenum(2024,1,1) + (0:99999)/86400; % ~1 day at 1-second resolution
y = sin((1:100000) * 2*pi/3600) + 0.2*randn(1,100000);
-fp3 = FastPlot('Theme', 'dark');
+fp3 = FastSense('Theme', 'dark');
fp3.addLine(x, y, 'DisplayName', 'Sensor', 'XType', 'datenum');
fp3.render();
title(fp3.hAxes, 'Datetime Axis — zoom to see format change');
-tb3 = FastPlotToolbar(fp3);
+tb3 = FastSenseToolbar(fp3);
fprintf('Datetime axis with toolbar ready. Zoom to see tick format adapt.\n');
```
@@ -362,7 +362,7 @@ Pass `datenum` values as X data with `'XType', 'datenum'` to get auto-formatted
x = datenum(2024,1,1) + (0:99999)/86400; % 1-second resolution
y = sin((1:100000) * 2*pi/3600);
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'XType', 'datenum');
fp.render();
\```
diff --git a/docs/plans/2026-03-09-event-detection-design.md b/docs/plans/2026-03-09-event-detection-design.md
index 7e06f592..c09f98b9 100644
--- a/docs/plans/2026-03-09-event-detection-design.md
+++ b/docs/plans/2026-03-09-event-detection-design.md
@@ -2,7 +2,7 @@
## Overview
-Third library (`libs/EventDetection/`) for FastPlot — detects events from threshold violations, groups consecutive violations into events with statistics, and supports configurable callbacks, debounce, UI viewer, console output, and live detection.
+Third library (`libs/EventDetection/`) for FastSense — detects events from threshold violations, groups consecutive violations into events with statistics, and supports configurable callbacks, debounce, UI viewer, console output, and live detection.
## Structure
@@ -102,7 +102,7 @@ Standalone MATLAB figure with two panels.
- Columns: Start, End, Duration, Sensor, Threshold, Direction, Peak, NumPts, Min, Max, Mean, RMS, Std
- Dropdown filter: sensor name
- Dropdown filter: threshold label
-- Clicking a row → opens FastPlot showing that sensor's signal zoomed to the event time range
+- Clicking a row → opens FastSense showing that sensor's signal zoomed to the event time range
### Methods
@@ -174,6 +174,6 @@ events = detectEventsFromSensor(sensor, detector)
## Integration
-- No direct FastPlot dependency in core classes — `EventViewer` uses FastPlot for click-to-plot
+- No direct FastSense dependency in core classes — `EventViewer` uses FastSense for click-to-plot
- No direct SensorThreshold dependency in core — `detectEventsFromSensor` and `EventConfig` bridge the two libraries
- Path setup: root `setup.m` updated to add `libs/EventDetection/`
diff --git a/docs/plans/2026-03-09-event-detection-plan.md b/docs/plans/2026-03-09-event-detection-plan.md
index 85a38b4a..40576b5b 100644
--- a/docs/plans/2026-03-09-event-detection-plan.md
+++ b/docs/plans/2026-03-09-event-detection-plan.md
@@ -79,7 +79,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event"`
Expected: FAIL — `Event` class not found.
**Step 3: Write minimal implementation**
@@ -155,7 +155,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event"`
Expected: PASS
**Step 5: Commit**
@@ -242,7 +242,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_group_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_group_violations"`
Expected: FAIL — `groupViolations` not found.
**Step 3: Write minimal implementation**
@@ -285,7 +285,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_group_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_group_violations"`
Expected: PASS
**Step 5: Commit**
@@ -406,7 +406,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_detector"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_detector"`
Expected: FAIL — `EventDetector` class not found.
**Step 3: Write minimal implementation**
@@ -509,7 +509,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_detector"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_detector"`
Expected: PASS
**Step 5: Commit**
@@ -587,7 +587,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_detect_events_from_sensor"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_detect_events_from_sensor"`
Expected: FAIL — `detectEventsFromSensor` not found.
**Step 3: Write minimal implementation**
@@ -672,7 +672,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_detect_events_from_sensor"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_detect_events_from_sensor"`
Expected: PASS
**Step 5: Commit**
@@ -753,7 +753,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_integration"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_integration"`
Expected: Fails if setup.m hasn't been updated yet (EventDetection not on path).
**Step 3: Update setup.m**
@@ -762,25 +762,25 @@ In `setup.m`, add the EventDetection library path:
```matlab
function setup()
-%SETUP Add FastPlot, SensorThreshold, and EventDetection libraries to the MATLAB path.
+%SETUP Add FastSense, SensorThreshold, and EventDetection libraries to the MATLAB path.
% Run this once per session to make all library classes available.
root = fileparts(mfilename('fullpath'));
- addpath(fullfile(root, 'libs', 'FastPlot'));
+ addpath(fullfile(root, 'libs', 'FastSense'));
addpath(fullfile(root, 'libs', 'SensorThreshold'));
addpath(fullfile(root, 'libs', 'EventDetection'));
- fprintf('FastPlot + SensorThreshold + EventDetection libraries added to path.\n');
+ fprintf('FastSense + SensorThreshold + EventDetection libraries added to path.\n');
end
```
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_integration"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_integration"`
Expected: PASS
**Step 5: Run full test suite**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); run_all_tests"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); run_all_tests"`
Expected: All tests pass, including the 4 new test files.
**Step 6: Commit**
@@ -850,7 +850,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_console"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_console"`
Expected: FAIL — `printEventSummary` not found.
**Step 3: Write printEventSummary implementation**
@@ -916,7 +916,7 @@ end
**Step 5: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_console"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_console"`
Expected: PASS
**Step 6: Commit**
@@ -1005,7 +1005,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_config"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_config"`
Expected: FAIL — `EventConfig` class not found.
**Step 3: Write minimal implementation**
@@ -1106,7 +1106,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_config"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_config"`
Expected: PASS
**Step 5: Commit**
@@ -1206,7 +1206,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_viewer"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_viewer"`
Expected: FAIL — `EventViewer` class not found.
**Step 3: Write implementation**
@@ -1454,8 +1454,8 @@ classdef EventViewer < handle
sd = obj.SensorData(sIdx);
- % Open FastPlot for this sensor, zoomed to event
- fp = FastPlot();
+ % Open FastSense for this sensor, zoomed to event
+ fp = FastSense();
fp.addLine(sd.t, sd.y, 'Label', sd.name);
% Add threshold line
@@ -1477,7 +1477,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); test_event_viewer"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); test_event_viewer"`
Expected: PASS
**Step 5: Commit**
@@ -1665,7 +1665,7 @@ end
**Step 2: Verify example runs**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('examples'); example_event_detection_live"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('examples'); example_event_detection_live"`
Expected: Console output shows initial detection + live logging. EventViewer figure opens with Gantt timeline and table. Timer appends data every 2 seconds.
**Step 3: Commit**
@@ -1681,7 +1681,7 @@ git commit -m "feat: add live event detection demo with industrial mock data"
**Step 1: Run full test suite**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); run_all_tests"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); run_all_tests"`
Expected: All tests pass, including the 6 new test files:
- `test_event.m`
- `test_group_violations.m`
diff --git a/docs/plans/2026-03-09-sensor-threshold-optimization-design.md b/docs/plans/2026-03-09-sensor-threshold-optimization-design.md
index 2e6a252f..fbf182ae 100644
--- a/docs/plans/2026-03-09-sensor-threshold-optimization-design.md
+++ b/docs/plans/2026-03-09-sensor-threshold-optimization-design.md
@@ -164,10 +164,10 @@ A dedicated benchmark script compares old `resolve()` vs new at multiple data sc
|------|--------|
| `libs/SensorThreshold/ThresholdRule.m` | `ConditionFn` -> `Condition` (struct), add `matchesState()` |
| `libs/SensorThreshold/Sensor.m` | Rewrite `resolve()` with segment algorithm + condition batching |
-| `libs/FastPlot/private/compute_violations_mex.c` | New: SIMD multi-threshold violation scan |
-| `libs/FastPlot/private/compute_violations_vec.m` | New: vectorized pure-MATLAB fallback |
-| `libs/FastPlot/private/compute_violations.m` | Keep for standalone FastPlot thresholds (no sensor) |
-| `libs/FastPlot/build_mex.m` | Add `compute_violations_mex` target |
+| `libs/FastSense/private/compute_violations_mex.c` | New: SIMD multi-threshold violation scan |
+| `libs/FastSense/private/compute_violations_vec.m` | New: vectorized pure-MATLAB fallback |
+| `libs/FastSense/private/compute_violations.m` | Keep for standalone FastSense thresholds (no sensor) |
+| `libs/FastSense/build_mex.m` | Add `compute_violations_mex` target |
| `examples/*.m` | Update to new struct condition API |
| `examples/benchmark_resolve.m` | New: before/after benchmark comparison |
diff --git a/docs/plans/2026-03-09-sensor-threshold-optimization.md b/docs/plans/2026-03-09-sensor-threshold-optimization.md
index b527f5dc..6c9c620e 100644
--- a/docs/plans/2026-03-09-sensor-threshold-optimization.md
+++ b/docs/plans/2026-03-09-sensor-threshold-optimization.md
@@ -72,7 +72,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_declarative_condition.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_declarative_condition.m')"`
Expected: FAIL — ThresholdRule constructor expects function_handle, not struct
**Step 3: Implement ThresholdRule with declarative conditions**
@@ -158,7 +158,7 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_declarative_condition.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_declarative_condition.m')"`
Expected: PASS — All 6 tests
**Step 5: Commit**
@@ -235,7 +235,7 @@ Replace all `@(st) st.xxx == N` with `struct('xxx', N)` in `tests/test_sensor.m`
**Step 5: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_sensor.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_sensor.m')"`
Expected: PASS — All 5 tests
**Step 6: Commit**
@@ -342,7 +342,7 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_resolve_segments.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_resolve_segments.m')"`
Expected: FAIL — addThresholdRule still expects old API in resolve()
**Step 3: Rewrite resolve() in Sensor.m**
@@ -646,7 +646,7 @@ In `tests/test_sensor_resolve.m`, replace all function-handle conditions:
**Step 6: Run all sensor tests**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_sensor_resolve.m'); run('tests/test_resolve_segments.m'); run('tests/test_declarative_condition.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_sensor_resolve.m'); run('tests/test_resolve_segments.m'); run('tests/test_declarative_condition.m')"`
Expected: PASS — All tests
**Step 7: Commit**
@@ -665,8 +665,8 @@ git commit -m "feat: rewrite Sensor.resolve() with segment-based vectorized algo
### Task 4: SIMD MEX — compute_violations_mex.c
**Files:**
-- Create: `libs/FastPlot/private/mex_src/compute_violations_mex.c`
-- Modify: `libs/FastPlot/build_mex.m:61-65` (add to mex_files list)
+- Create: `libs/FastSense/private/mex_src/compute_violations_mex.c`
+- Modify: `libs/FastSense/build_mex.m:61-65` (add to mex_files list)
- Create: `tests/test_violations_mex_parity.m`
**Step 1: Write MEX parity test**
@@ -780,7 +780,7 @@ end
**Step 2: Write compute_violations_mex.c**
-Create `libs/FastPlot/private/mex_src/compute_violations_mex.c`:
+Create `libs/FastSense/private/mex_src/compute_violations_mex.c`:
```c
/*
@@ -874,7 +874,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
if (nrhs != 5) {
- mexErrMsgIdAndTxt("FastPlot:compute_violations_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:compute_violations_mex:nrhs",
"Five inputs required: sensorY, segLo, segHi, thresholdValues, directions.");
}
@@ -942,7 +942,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
**Step 3: Add to build_mex.m**
-In `libs/FastPlot/build_mex.m`, add to the `mex_files` cell array (line 61-65):
+In `libs/FastSense/build_mex.m`, add to the `mex_files` cell array (line 61-65):
```matlab
mex_files = {
@@ -955,19 +955,19 @@ mex_files = {
**Step 4: Compile MEX**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('setup.m'); build_mex()"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('setup.m'); build_mex()"`
Expected: All 4 MEX files compile, including compute_violations_mex
**Step 5: Run parity test**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/test_violations_mex_parity.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/test_violations_mex_parity.m')"`
Expected: PASS — All 5 parity tests
**Step 6: Commit**
```bash
-git add libs/FastPlot/private/mex_src/compute_violations_mex.c \
- libs/FastPlot/build_mex.m tests/test_violations_mex_parity.m
+git add libs/FastSense/private/mex_src/compute_violations_mex.c \
+ libs/FastSense/build_mex.m tests/test_violations_mex_parity.m
git commit -m "feat: add SIMD MEX for batch threshold violation detection"
```
@@ -1046,7 +1046,7 @@ end
**Step 2: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/run_all_tests.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/run_all_tests.m')"`
Expected: All 31+ tests pass
**Step 3: Commit**
@@ -1157,7 +1157,7 @@ end
**Step 2: Run benchmark**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('examples/benchmark_resolve.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('examples/benchmark_resolve.m')"`
Expected: Sub-second times for all data sizes (vs multi-second for old implementation)
**Step 3: Commit**
@@ -1175,17 +1175,17 @@ git commit -m "feat: add before/after benchmark for Sensor.resolve() optimizatio
**Step 1: Compile MEX**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('setup.m'); build_mex()"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('setup.m'); build_mex()"`
Expected: All 4 MEX files compiled
**Step 2: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('tests/run_all_tests.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('tests/run_all_tests.m')"`
Expected: All tests pass (31 original + 3 new = 34 tests)
**Step 3: Run benchmark**
-Run: `cd /Users/hannessuhr/FastPlot && octave --eval "run('examples/benchmark_resolve.m')"`
+Run: `cd /Users/hannessuhr/FastSense && octave --eval "run('examples/benchmark_resolve.m')"`
Expected: Performance table printed with sub-second resolve times
**Step 4: Final commit (if any fixups needed)**
diff --git a/docs/plans/2026-03-09-unified-threshold-api-design.md b/docs/plans/2026-03-09-unified-threshold-api-design.md
index 2d2ad3d7..3583ac26 100644
--- a/docs/plans/2026-03-09-unified-threshold-api-design.md
+++ b/docs/plans/2026-03-09-unified-threshold-api-design.md
@@ -2,9 +2,9 @@
**Goal:** Eliminate the dual rendering path for threshold violations by extending `addThreshold` to accept time-varying thresholds (X/Y arrays), then routing `addSensor` through it.
-**Architecture:** Sensor/resolve handles domain logic (which threshold value at which time). FastPlot handles rendering logic (what to show on screen now). Pre-computed violations are no longer fed to the renderer.
+**Architecture:** Sensor/resolve handles domain logic (which threshold value at which time). FastSense handles rendering logic (what to show on screen now). Pre-computed violations are no longer fed to the renderer.
-**Tech Stack:** MATLAB/Octave, existing FastPlot private function pattern.
+**Tech Stack:** MATLAB/Octave, existing FastSense private function pattern.
---
diff --git a/docs/plans/2026-03-09-unified-threshold-api.md b/docs/plans/2026-03-09-unified-threshold-api.md
index d9bff40f..963cbe15 100644
--- a/docs/plans/2026-03-09-unified-threshold-api.md
+++ b/docs/plans/2026-03-09-unified-threshold-api.md
@@ -6,15 +6,15 @@
**Architecture:** Extend `addThreshold` to accept X/Y arrays (time-varying step functions) in addition to scalar values. Add `compute_violations_dynamic` for comparing data against interpolated thresholds. Rewrite `addSensor` to use `addThreshold` exclusively. Remove `addThresholdConnectors` (step transitions become native).
-**Tech Stack:** MATLAB/Octave, existing FastPlot private function pattern, `interp1(..., 'previous')` for step-function lookup.
+**Tech Stack:** MATLAB/Octave, existing FastSense private function pattern, `interp1(..., 'previous')` for step-function lookup.
---
### Task 1: Extend Thresholds struct and `addThreshold` to accept X/Y arrays
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:90-93` (Thresholds struct definition)
-- Modify: `libs/FastPlot/FastPlot.m:395-425` (addThreshold method)
+- Modify: `libs/FastSense/FastSense.m:90-93` (Thresholds struct definition)
+- Modify: `libs/FastSense/FastSense.m:395-425` (addThreshold method)
- Test: `tests/test_add_threshold.m`
**Step 1: Write the failing test**
@@ -23,7 +23,7 @@ Add to `tests/test_add_threshold.m` before the final fprintf:
```matlab
% testTimeVaryingThreshold
- fp = FastPlot();
+ fp = FastSense();
thX = [0 10 20 30];
thY = [5.0 5.0 7.0 7.0];
fp.addThreshold(thX, thY, 'Direction', 'upper', 'ShowViolations', true, 'Label', 'StepTh');
@@ -35,7 +35,7 @@ Add to `tests/test_add_threshold.m` before the final fprintf:
assert(fp.Thresholds(1).ShowViolations == true, 'testTimeVarying: ShowViolations');
% testMixedThresholds — scalar and time-varying coexist
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5);
fp.addThreshold([0 10], [3.0 5.0], 'Direction', 'lower');
assert(numel(fp.Thresholds) == 2, 'testMixed: count');
@@ -52,7 +52,7 @@ Expected: FAIL — addThreshold doesn't accept 3+ positional args.
**Step 3: Implement the changes**
-In `libs/FastPlot/FastPlot.m`, modify the Thresholds struct definition (line 90-93) to add X and Y fields:
+In `libs/FastSense/FastSense.m`, modify the Thresholds struct definition (line 90-93) to add X and Y fields:
```matlab
Thresholds = struct('Value', {}, 'X', {}, 'Y', {}, ...
@@ -72,7 +72,7 @@ Rewrite `addThreshold` (line 395-425) to detect scalar vs X/Y:
% fp.addThreshold(thX, thY, 'Direction', 'upper', 'ShowViolations', true)
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add thresholds after render() has been called.');
end
@@ -141,7 +141,7 @@ feat: extend addThreshold to accept time-varying X/Y arrays
### Task 2: Create `compute_violations_dynamic` for time-varying thresholds
**Files:**
-- Create: `libs/FastPlot/private/compute_violations_dynamic.m`
+- Create: `libs/FastSense/private/compute_violations_dynamic.m`
- Create: `tests/test_compute_violations_dynamic.m`
**Step 1: Write the failing test**
@@ -153,7 +153,7 @@ function test_compute_violations_dynamic()
%TEST_COMPUTE_VIOLATIONS_DYNAMIC Tests for time-varying threshold violations.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testUpperStepFunction: threshold steps from 5 to 8 at x=10
thX = [0 10 20];
@@ -235,7 +235,7 @@ Expected: FAIL — `compute_violations_dynamic` not found.
**Step 3: Implement `compute_violations_dynamic.m`**
-Create `libs/FastPlot/private/compute_violations_dynamic.m`:
+Create `libs/FastSense/private/compute_violations_dynamic.m`:
```matlab
function [xViol, yViol] = compute_violations_dynamic(x, y, thX, thY, direction)
@@ -252,7 +252,7 @@ function [xViol, yViol] = compute_violations_dynamic(x, y, thX, thY, direction)
% direction — 'upper' (violation when y > threshold)
% 'lower' (violation when y < threshold)
%
-% See also compute_violations, FastPlot.addThreshold.
+% See also compute_violations, FastSense.addThreshold.
if isempty(x)
xViol = zeros(1, 0);
@@ -296,7 +296,7 @@ feat: add compute_violations_dynamic for time-varying thresholds
### Task 3: Update threshold rendering for time-varying thresholds
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:770-834` (render method — threshold section)
+- Modify: `libs/FastSense/FastSense.m:770-834` (render method — threshold section)
**Step 1: Modify threshold line rendering**
@@ -324,7 +324,7 @@ Replace the threshold line creation block (lines 774-785) with logic that handle
'LineWidth', 1.5, ...
'HandleVisibility', 'off');
end
- udT.FastPlot = struct( ...
+ udT.FastSense = struct( ...
'Type', 'threshold', ...
'Name', T.Label, ...
'LineIndex', [], ...
@@ -391,7 +391,7 @@ feat: render time-varying thresholds and their violation markers
### Task 4: Update `updateViolations` for time-varying thresholds
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:1977-2015` (updateViolations method)
+- Modify: `libs/FastSense/FastSense.m:1977-2015` (updateViolations method)
**Step 1: Modify updateViolations inner loop**
@@ -450,7 +450,7 @@ feat: updateViolations supports time-varying thresholds
### Task 5: Rewrite `addSensor` to use unified `addThreshold` path
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:344-393` (addSensor method)
+- Modify: `libs/FastSense/FastSense.m:344-393` (addSensor method)
- Test: `tests/test_add_sensor.m`
**Step 1: Update test expectations**
@@ -474,7 +474,7 @@ Update it to check Thresholds instead of Lines:
s.addThresholdRule(struct('machine', 1), 10, 'Direction', 'upper', 'Label', 'HH');
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
assert(numel(fp.Lines) == 1, 'testWithThresholds: only data line');
assert(numel(fp.Thresholds) >= 1, 'testWithThresholds: threshold(s) added');
@@ -485,7 +485,7 @@ Update it to check Thresholds instead of Lines:
Also update `testAddSensorNoThresholds`:
```matlab
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', false);
assert(numel(fp.Lines) == 1, 'testNoThresholds: only data line');
assert(numel(fp.Thresholds) == 0, 'testNoThresholds: no thresholds');
@@ -543,7 +543,7 @@ feat: addSensor uses unified addThreshold path for time-varying thresholds
### Task 6: Clean up dead code
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:1438-1477` (remove addThresholdConnectors)
+- Modify: `libs/FastSense/FastSense.m:1438-1477` (remove addThresholdConnectors)
**Step 1: Remove `addThresholdConnectors` method**
diff --git a/docs/plans/2026-03-09-violation-cull-mex-design.md b/docs/plans/2026-03-09-violation-cull-mex-design.md
index be445e1d..21fed4f9 100644
--- a/docs/plans/2026-03-09-violation-cull-mex-design.md
+++ b/docs/plans/2026-03-09-violation-cull-mex-design.md
@@ -45,7 +45,7 @@ Single-pass over data array:
## MATLAB Wrapper
-`compute_violations.m` and `compute_violations_dynamic.m` gain MEX fast-paths. The render/updateViolations loops in `FastPlot.m` are updated to call a fused path that skips `downsample_violations` when MEX is available.
+`compute_violations.m` and `compute_violations_dynamic.m` gain MEX fast-paths. The render/updateViolations loops in `FastSense.m` are updated to call a fused path that skips `downsample_violations` when MEX is available.
## Files Changed
@@ -55,7 +55,7 @@ Single-pass over data array:
- **Modify:** `compute_violations.m` — add MEX fast-path
- **Modify:** `compute_violations_dynamic.m` — add MEX fast-path
- **Modify:** `downsample_violations.m` — no change (still used as MATLAB fallback)
-- **Modify:** `FastPlot.m` render + updateViolations — fused call path
+- **Modify:** `FastSense.m` render + updateViolations — fused call path
- **Create:** `tests/test_violation_cull_mex.m` — parity tests against MATLAB fallback
## Compatibility
diff --git a/docs/plans/2026-03-09-violation-cull-mex.md b/docs/plans/2026-03-09-violation-cull-mex.md
index dc2bdb7c..cbc2a9f8 100644
--- a/docs/plans/2026-03-09-violation-cull-mex.md
+++ b/docs/plans/2026-03-09-violation-cull-mex.md
@@ -4,7 +4,7 @@
**Goal:** Replace the separate compute_violations + downsample_violations pipeline with a single SIMD-accelerated MEX function that fuses step-function threshold lookup, violation detection, and pixel-density culling into one pass.
-**Architecture:** A new `violation_cull_mex.c` replaces the unused `compute_violations_mex.c`. It accepts data arrays, threshold knots, direction, and pixel parameters, returning culled violation points directly. The MATLAB wrappers (`compute_violations.m`, `compute_violations_dynamic.m`) gain MEX fast-paths, and `FastPlot.m` render/updateViolations call a fused path skipping `downsample_violations` when MEX is available.
+**Architecture:** A new `violation_cull_mex.c` replaces the unused `compute_violations_mex.c`. It accepts data arrays, threshold knots, direction, and pixel parameters, returning culled violation points directly. The MATLAB wrappers (`compute_violations.m`, `compute_violations_dynamic.m`) gain MEX fast-paths, and `FastSense.m` render/updateViolations call a fused path skipping `downsample_violations` when MEX is available.
**Tech Stack:** C with `simd_utils.h` (AVX2/SSE2/NEON/scalar), MATLAB MEX API, Octave mkoctfile.
@@ -13,18 +13,18 @@
### Task 1: Delete unused `compute_violations_mex` and clean up `build_mex.m`
**Files:**
-- Delete: `libs/FastPlot/private/mex_src/compute_violations_mex.c`
-- Delete: `libs/FastPlot/private/compute_violations_mex.mex`
-- Delete: `libs/FastPlot/private/compute_violations_mex.mexmaca64`
-- Modify: `libs/FastPlot/build_mex.m:84-90` (mex_files list)
-- Modify: `libs/FastPlot/build_mex.m:142-144` (copy_mex_to call)
+- Delete: `libs/FastSense/private/mex_src/compute_violations_mex.c`
+- Delete: `libs/FastSense/private/compute_violations_mex.mex`
+- Delete: `libs/FastSense/private/compute_violations_mex.mexmaca64`
+- Modify: `libs/FastSense/build_mex.m:84-90` (mex_files list)
+- Modify: `libs/FastSense/build_mex.m:142-144` (copy_mex_to call)
**Step 1: Delete the old MEX source and compiled binaries**
```bash
-rm libs/FastPlot/private/mex_src/compute_violations_mex.c
-rm -f libs/FastPlot/private/compute_violations_mex.mex
-rm -f libs/FastPlot/private/compute_violations_mex.mexmaca64
+rm libs/FastSense/private/mex_src/compute_violations_mex.c
+rm -f libs/FastSense/private/compute_violations_mex.mex
+rm -f libs/FastSense/private/compute_violations_mex.mexmaca64
rm -f libs/SensorThreshold/private/compute_violations_mex.mex
rm -f libs/SensorThreshold/private/compute_violations_mex.mexmaca64
```
@@ -73,11 +73,11 @@ refactor: remove unused compute_violations_mex, prepare for violation_cull_mex
### Task 2: Create `violation_cull_mex.c`
**Files:**
-- Create: `libs/FastPlot/private/mex_src/violation_cull_mex.c`
+- Create: `libs/FastSense/private/mex_src/violation_cull_mex.c`
**Step 1: Write the MEX C source**
-Create `libs/FastPlot/private/mex_src/violation_cull_mex.c`:
+Create `libs/FastSense/private/mex_src/violation_cull_mex.c`:
```c
/*
@@ -131,7 +131,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
if (nrhs != 7) {
- mexErrMsgIdAndTxt("FastPlot:violation_cull_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:violation_cull_mex:nrhs",
"Seven inputs required: x, y, thX, thY, direction, pixelWidth, xmin.");
}
@@ -317,7 +317,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
**Step 2: Compile**
-Run: `octave --eval "cd libs/FastPlot; build_mex"` (or in MATLAB: `cd libs/FastPlot; build_mex`)
+Run: `octave --eval "cd libs/FastSense; build_mex"` (or in MATLAB: `cd libs/FastSense; build_mex`)
Expected: `violation_cull_mex.c ... OK`
@@ -343,7 +343,7 @@ function test_violation_cull_mex()
%TEST_VIOLATION_CULL_MEX Parity tests: MEX vs MATLAB fallback.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
hasMex = (exist('violation_cull_mex', 'file') == 3);
if ~hasMex
@@ -471,7 +471,7 @@ end
**Step 2: Run test**
-Run: `octave --eval "cd libs/FastPlot; build_mex" && octave --eval "cd tests; addpath('..'); setup; test_violation_cull_mex"`
+Run: `octave --eval "cd libs/FastSense; build_mex" && octave --eval "cd tests; addpath('..'); setup; test_violation_cull_mex"`
Expected: All 7 parity tests pass.
@@ -486,8 +486,8 @@ test: add violation_cull_mex parity tests against MATLAB reference
### Task 4: Wire MEX into MATLAB wrappers
**Files:**
-- Modify: `libs/FastPlot/private/compute_violations.m`
-- Modify: `libs/FastPlot/private/compute_violations_dynamic.m`
+- Modify: `libs/FastSense/private/compute_violations.m`
+- Modify: `libs/FastSense/private/compute_violations_dynamic.m`
**Step 1: Add MEX fast-path to `compute_violations.m`**
@@ -500,7 +500,7 @@ function [xViol, yViol] = compute_violations(x, y, thresholdValue, direction)
%
% Uses violation_cull_mex if compiled (without pixel culling — pw=0 skips it).
%
-% See also compute_violations_dynamic, FastPlot.addThreshold.
+% See also compute_violations_dynamic, FastSense.addThreshold.
if strcmp(direction, 'upper')
mask = y > thresholdValue;
@@ -513,15 +513,15 @@ function [xViol, yViol] = compute_violations(x, y, thresholdValue, direction)
end
```
-Note: we keep this function simple — the MEX fast-path is wired at the FastPlot.m level in Task 5 where we have pixel parameters available. This function remains the pure "find violations" step for callers that don't need culling.
+Note: we keep this function simple — the MEX fast-path is wired at the FastSense.m level in Task 5 where we have pixel parameters available. This function remains the pure "find violations" step for callers that don't need culling.
**Step 2: Same for `compute_violations_dynamic.m`**
-No changes needed — keep as-is. The MEX fast-path is at the FastPlot.m level.
+No changes needed — keep as-is. The MEX fast-path is at the FastSense.m level.
**Step 3: Create a new helper `violation_cull.m`**
-Create `libs/FastPlot/private/violation_cull.m` — the MATLAB-side entry point that tries MEX, falls back to MATLAB:
+Create `libs/FastSense/private/violation_cull.m` — the MATLAB-side entry point that tries MEX, falls back to MATLAB:
```matlab
function [xOut, yOut] = violation_cull(x, y, thX, thY, direction, pixelWidth, xmin)
@@ -580,11 +580,11 @@ feat: add violation_cull wrapper with MEX fast-path
---
-### Task 5: Wire fused path into FastPlot.m render and updateViolations
+### Task 5: Wire fused path into FastSense.m render and updateViolations
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:827-865` (render violation section)
-- Modify: `libs/FastPlot/FastPlot.m:2003-2051` (updateViolations)
+- Modify: `libs/FastSense/FastSense.m:827-865` (render violation section)
+- Modify: `libs/FastSense/FastSense.m:2003-2051` (updateViolations)
**Step 1: Update render violation loop**
diff --git a/docs/plans/2026-03-09-violation-marker-optimization.md b/docs/plans/2026-03-09-violation-marker-optimization.md
index d759e7c1..8f8961ec 100644
--- a/docs/plans/2026-03-09-violation-marker-optimization.md
+++ b/docs/plans/2026-03-09-violation-marker-optimization.md
@@ -4,20 +4,20 @@
**Goal:** Optimize violation marker rendering with faster marker style, pixel-density downsampling, and dirty-flag caching to skip redundant recomputation.
-**Architecture:** Three independent optimizations applied to `FastPlot.m` and its private functions: (1) swap `'o'` → `'.'` marker, (2) cull violations to 1-per-pixel-column via new `downsample_violations.m`, (3) cache `[xlim ylim]` to skip `updateViolations()` when view unchanged.
+**Architecture:** Three independent optimizations applied to `FastSense.m` and its private functions: (1) swap `'o'` → `'.'` marker, (2) cull violations to 1-per-pixel-column via new `downsample_violations.m`, (3) cache `[xlim ylim]` to skip `updateViolations()` when view unchanged.
-**Tech Stack:** MATLAB/Octave, existing FastPlot private function pattern.
+**Tech Stack:** MATLAB/Octave, existing FastSense private function pattern.
---
### Task 1: Change marker style from `'o'` to `'.'`
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:813` (render method)
+- Modify: `libs/FastSense/FastSense.m:813` (render method)
**Step 1: Change marker in render()**
-In `libs/FastPlot/FastPlot.m:811-813`, change the `line()` call marker from `'o'` to `'.'`:
+In `libs/FastSense/FastSense.m:811-813`, change the `line()` call marker from `'o'` to `'.'`:
```matlab
hM = line(vxAll, vyAll, 'Parent', obj.hAxes, ...
@@ -30,7 +30,7 @@ Note: `MarkerSize` bumped from 4 to 6 because `'.'` renders smaller than `'o'` a
**Step 2: Run existing tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup; test_compute_violations"` (or Octave equivalent)
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup; test_compute_violations"` (or Octave equivalent)
Expected: All 5 tests pass (marker style is a rendering detail, not tested by compute_violations).
**Step 3: Commit**
@@ -44,10 +44,10 @@ feat: use '.' marker for violation rendering (faster than 'o')
### Task 2: Pixel-density downsampling of violation markers
**Files:**
-- Create: `libs/FastPlot/private/downsample_violations.m`
+- Create: `libs/FastSense/private/downsample_violations.m`
- Create: `tests/test_downsample_violations.m`
-- Modify: `libs/FastPlot/FastPlot.m:785-810` (render — apply downsampling after compute_violations)
-- Modify: `libs/FastPlot/FastPlot.m:1953-2000` (updateViolations — apply downsampling after compute_violations)
+- Modify: `libs/FastSense/FastSense.m:785-810` (render — apply downsampling after compute_violations)
+- Modify: `libs/FastSense/FastSense.m:1953-2000` (updateViolations — apply downsampling after compute_violations)
**Step 1: Write the test**
@@ -58,7 +58,7 @@ function test_downsample_violations()
%TEST_DOWNSAMPLE_VIOLATIONS Tests for violation marker pixel-density culling.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testBasicDownsample: 10 violations in 3 pixel columns -> 3 points
xV = [1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 3.0, 3.1, 3.2, 3.3];
@@ -119,12 +119,12 @@ end
**Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup; test_downsample_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup; test_downsample_violations"`
Expected: FAIL — `downsample_violations` not found.
**Step 3: Implement `downsample_violations.m`**
-Create `libs/FastPlot/private/downsample_violations.m`:
+Create `libs/FastSense/private/downsample_violations.m`:
```matlab
function [xOut, yOut] = downsample_violations(xViol, yViol, pixelWidth, thresholdValue)
@@ -137,7 +137,7 @@ function [xOut, yOut] = downsample_violations(xViol, yViol, pixelWidth, threshol
% pixelWidth — X-axis span per pixel (diff(xlim) / axesWidthPixels)
% thresholdValue — threshold value (used to pick max-deviation point)
%
-% See also compute_violations, FastPlot.updateViolations.
+% See also compute_violations, FastSense.updateViolations.
if isempty(xViol)
xOut = xViol;
@@ -180,12 +180,12 @@ end
**Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup; test_downsample_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup; test_downsample_violations"`
Expected: All 6 tests pass.
**Step 5: Integrate into `render()` and `updateViolations()`**
-In `libs/FastPlot/FastPlot.m`, the `render()` method at lines 785-810 — after computing violations for each line, downsample before rendering. The key change is adding a downsample call after the violation collection loop, before the `line()` call.
+In `libs/FastSense/FastSense.m`, the `render()` method at lines 785-810 — after computing violations for each line, downsample before rendering. The key change is adding a downsample call after the violation collection loop, before the `line()` call.
In the render section (after line 806, before line 811), add:
@@ -209,7 +209,7 @@ And update the corresponding `set()` call to use `vxAll, vyAll` directly (no mor
**Step 6: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup; test_compute_violations; test_downsample_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup; test_compute_violations; test_downsample_violations"`
Expected: All tests pass.
**Step 7: Commit**
@@ -223,13 +223,13 @@ feat: downsample violation markers to pixel density
### Task 3: Dirty-flag caching to skip redundant `updateViolations()`
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:113-124` (add `CachedViolationLim` property)
-- Modify: `libs/FastPlot/FastPlot.m:1953-2000` (check cache at top of `updateViolations()`)
-- Modify: `libs/FastPlot/FastPlot.m:892` (invalidate on render)
+- Modify: `libs/FastSense/FastSense.m:113-124` (add `CachedViolationLim` property)
+- Modify: `libs/FastSense/FastSense.m:1953-2000` (check cache at top of `updateViolations()`)
+- Modify: `libs/FastSense/FastSense.m:892` (invalidate on render)
**Step 1: Add cached property**
-In `libs/FastPlot/FastPlot.m`, properties block at line 117, add after `CachedXLim`:
+In `libs/FastSense/FastSense.m`, properties block at line 117, add after `CachedXLim`:
```matlab
CachedViolationLim = [] % [xmin xmax ymin ymax pw] for violation skip
@@ -268,7 +268,7 @@ before the `obj.updateViolations()` call. This ensures data updates always trigg
**Step 4: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup; test_compute_violations; test_downsample_violations"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup; test_compute_violations; test_downsample_violations"`
Expected: All tests pass.
**Step 5: Commit**
diff --git a/docs/plans/2026-03-09-violations-toggle-button.md b/docs/plans/2026-03-09-violations-toggle-button.md
index 68237881..44aa0016 100644
--- a/docs/plans/2026-03-09-violations-toggle-button.md
+++ b/docs/plans/2026-03-09-violations-toggle-button.md
@@ -4,22 +4,22 @@
**Goal:** Add a toolbar toggle button that globally shows/hides all violation markers without changing per-threshold `ShowViolations` settings.
-**Architecture:** A `ViolationsVisible` property on `FastPlot` controls marker visibility. The toolbar gets a new `uitoggletool` with a `'violations'` icon. Toggling it calls `setViolationsVisible()` on each FastPlot instance, which sets `Visible` on all `hMarkers` handles and gates marker computation in `render()` and `updateViolations()`.
+**Architecture:** A `ViolationsVisible` property on `FastSense` controls marker visibility. The toolbar gets a new `uitoggletool` with a `'violations'` icon. Toggling it calls `setViolationsVisible()` on each FastSense instance, which sets `Visible` on all `hMarkers` handles and gates marker computation in `render()` and `updateViolations()`.
**Tech Stack:** MATLAB (uitoggletool, graphics handle Visible property)
---
-### Task 1: Add `ViolationsVisible` property and `setViolationsVisible` method to FastPlot
+### Task 1: Add `ViolationsVisible` property and `setViolationsVisible` method to FastSense
**Files:**
-- Modify: `libs/FastPlot/FastPlot.m:64-81` (public properties)
-- Modify: `libs/FastPlot/FastPlot.m:828` (render gate)
-- Modify: `libs/FastPlot/FastPlot.m:1995` (updateViolations gate)
+- Modify: `libs/FastSense/FastSense.m:64-81` (public properties)
+- Modify: `libs/FastSense/FastSense.m:828` (render gate)
+- Modify: `libs/FastSense/FastSense.m:1995` (updateViolations gate)
**Step 1: Add the `ViolationsVisible` property**
-In `libs/FastPlot/FastPlot.m`, in the public properties block (after line 80, `YScale`), add:
+In `libs/FastSense/FastSense.m`, in the public properties block (after line 80, `YScale`), add:
```matlab
ViolationsVisible = true % global toggle for violation markers
@@ -27,7 +27,7 @@ In `libs/FastPlot/FastPlot.m`, in the public properties block (after line 80, `Y
**Step 2: Add the `setViolationsVisible` public method**
-In `libs/FastPlot/FastPlot.m`, add a new public method (in the public methods section, near other setter-style methods). Place it after the existing public methods like `addThreshold`, etc.:
+In `libs/FastSense/FastSense.m`, add a new public method (in the public methods section, near other setter-style methods). Place it after the existing public methods like `addThreshold`, etc.:
```matlab
function setViolationsVisible(obj, on)
@@ -50,7 +50,7 @@ In `libs/FastPlot/FastPlot.m`, add a new public method (in the public methods se
**Step 3: Gate violation marker creation in `render()`**
-In `libs/FastPlot/FastPlot.m:828`, change:
+In `libs/FastSense/FastSense.m:828`, change:
```matlab
if T.ShowViolations
@@ -64,7 +64,7 @@ to:
**Step 4: Gate violation marker update in `updateViolations()`**
-In `libs/FastPlot/FastPlot.m:1984`, add an early return after the existing `ishandle` check. Before the existing dirty-flag block, insert:
+In `libs/FastSense/FastSense.m:1984`, add an early return after the existing `ishandle` check. Before the existing dirty-flag block, insert:
```matlab
if ~obj.ViolationsVisible
@@ -83,28 +83,28 @@ So lines 1984+ become:
**Step 5: Run existing tests to verify no regression**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run('tests/test_toolbar.m')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run('tests/test_toolbar.m')"`
Expected: All 13 toolbar tests pass.
**Step 6: Commit**
```bash
-git add libs/FastPlot/FastPlot.m
-git commit -m "feat: add ViolationsVisible property and setViolationsVisible method to FastPlot"
+git add libs/FastSense/FastSense.m
+git commit -m "feat: add ViolationsVisible property and setViolationsVisible method to FastSense"
```
---
-### Task 2: Add violations toggle button to FastPlotToolbar
+### Task 2: Add violations toggle button to FastSenseToolbar
**Files:**
-- Modify: `libs/FastPlot/FastPlotToolbar.m:48` (add handle property)
-- Modify: `libs/FastPlot/FastPlotToolbar.m:367-371` (createToolbar — insert before theme btn)
-- Modify: `libs/FastPlot/FastPlotToolbar.m:240-246` (rebind — sync state)
+- Modify: `libs/FastSense/FastSenseToolbar.m:48` (add handle property)
+- Modify: `libs/FastSense/FastSenseToolbar.m:367-371` (createToolbar — insert before theme btn)
+- Modify: `libs/FastSense/FastSenseToolbar.m:240-246` (rebind — sync state)
**Step 1: Add the `hViolationsBtn` handle property**
-In `libs/FastPlot/FastPlotToolbar.m`, in the private properties block, after line 48 (`hThemeBtn`), add:
+In `libs/FastSense/FastSenseToolbar.m`, in the private properties block, after line 48 (`hThemeBtn`), add:
```matlab
hViolationsBtn = [] % uitoggletool handle for violations toggle
@@ -112,11 +112,11 @@ In `libs/FastPlot/FastPlotToolbar.m`, in the private properties block, after lin
**Step 2: Create the toggle button in `createToolbar()`**
-In `libs/FastPlot/FastPlotToolbar.m`, insert after the metadata button block (after line 366) and before the theme button (line 368):
+In `libs/FastSense/FastSenseToolbar.m`, insert after the metadata button block (after line 366) and before the theme button (line 368):
```matlab
obj.hViolationsBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('violations'), ...
+ 'CData', FastSenseToolbar.makeIcon('violations'), ...
'TooltipString', 'Toggle Violations', ...
'State', 'on', ...
'OnCallback', @(s,e) obj.onViolationsOn(), ...
@@ -125,30 +125,30 @@ In `libs/FastPlot/FastPlotToolbar.m`, insert after the metadata button block (af
**Step 3: Add the On/Off callback methods**
-In `libs/FastPlot/FastPlotToolbar.m`, in the private methods section (after the `onMetadataOff` method around line 392), add:
+In `libs/FastSense/FastSenseToolbar.m`, in the private methods section (after the `onMetadataOff` method around line 392), add:
```matlab
function onViolationsOn(obj)
- for i = 1:numel(obj.FastPlots)
- obj.FastPlots{i}.setViolationsVisible(true);
+ for i = 1:numel(obj.FastSenses)
+ obj.FastSenses{i}.setViolationsVisible(true);
end
end
function onViolationsOff(obj)
- for i = 1:numel(obj.FastPlots)
- obj.FastPlots{i}.setViolationsVisible(false);
+ for i = 1:numel(obj.FastSenses)
+ obj.FastSenses{i}.setViolationsVisible(false);
end
end
```
**Step 4: Sync state in `rebind()`**
-In `libs/FastPlot/FastPlotToolbar.m`, after line 246 (`setappdata(obj.hFigure, 'FastPlotMetadataEnabled', obj.MetadataEnabled);`), add:
+In `libs/FastSense/FastSenseToolbar.m`, after line 246 (`setappdata(obj.hFigure, 'FastSenseMetadataEnabled', obj.MetadataEnabled);`), add:
```matlab
- % Sync violations toggle to first FastPlot's state
- if ~isempty(obj.FastPlots)
- if obj.FastPlots{1}.ViolationsVisible
+ % Sync violations toggle to first FastSense's state
+ if ~isempty(obj.FastSenses)
+ if obj.FastSenses{1}.ViolationsVisible
set(obj.hViolationsBtn, 'State', 'on');
else
set(obj.hViolationsBtn, 'State', 'off');
@@ -159,7 +159,7 @@ In `libs/FastPlot/FastPlotToolbar.m`, after line 246 (`setappdata(obj.hFigure, '
**Step 5: Commit**
```bash
-git add libs/FastPlot/FastPlotToolbar.m
+git add libs/FastSense/FastSenseToolbar.m
git commit -m "feat: add violations toggle button to toolbar"
```
@@ -168,13 +168,13 @@ git commit -m "feat: add violations toggle button to toolbar"
### Task 3: Add violations icon to `makeIcon()`
**Files:**
-- Modify: `libs/FastPlot/FastPlotToolbar.m:1027` (add case before `end` of switch)
-- Modify: `libs/FastPlot/FastPlotToolbar.m:1033-1034` (add to initIcons list)
-- Modify: `libs/FastPlot/FastPlotToolbar.m:880-881` (update docstring)
+- Modify: `libs/FastSense/FastSenseToolbar.m:1027` (add case before `end` of switch)
+- Modify: `libs/FastSense/FastSenseToolbar.m:1033-1034` (add to initIcons list)
+- Modify: `libs/FastSense/FastSenseToolbar.m:880-881` (update docstring)
**Step 1: Add the `'violations'` icon case**
-In `libs/FastPlot/FastPlotToolbar.m`, before the `end` of the switch block (line 1027), add a new case. The icon is a small exclamation mark in a triangle (warning style), drawn in orange/red:
+In `libs/FastSense/FastSenseToolbar.m`, before the `end` of the switch block (line 1027), add a new case. The icon is a small exclamation mark in a triangle (warning style), drawn in orange/red:
```matlab
case 'violations'
@@ -200,7 +200,7 @@ In `libs/FastPlot/FastPlotToolbar.m`, before the `end` of the switch block (line
**Step 2: Add `'violations'` to initIcons list**
-In `libs/FastPlot/FastPlotToolbar.m:1033-1034`, change:
+In `libs/FastSense/FastSenseToolbar.m:1033-1034`, change:
```matlab
names = {'cursor', 'crosshair', 'grid', 'legend', 'autoscale', ...
@@ -216,7 +216,7 @@ to:
**Step 3: Update makeIcon docstring**
-In `libs/FastPlot/FastPlotToolbar.m:880-881`, change:
+In `libs/FastSense/FastSenseToolbar.m:880-881`, change:
```matlab
% Available names: 'cursor', 'crosshair', 'grid', 'legend',
@@ -234,7 +234,7 @@ to:
**Step 4: Commit**
```bash
-git add libs/FastPlot/FastPlotToolbar.m
+git add libs/FastSense/FastSenseToolbar.m
git commit -m "feat: add violations icon to makeIcon()"
```
@@ -281,11 +281,11 @@ In `tests/test_toolbar.m`, before the final `fprintf` (line 149), add:
```matlab
% testViolationsToggle
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100) * 10);
fp.addThreshold(5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
% Violations should be visible initially
assert(fp.ViolationsVisible, 'testViolationsToggle: default true');
hM = fp.Thresholds(1).hMarkers;
@@ -316,7 +316,7 @@ to:
**Step 5: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run('tests/test_toolbar.m')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run('tests/test_toolbar.m')"`
Expected: All 14 toolbar tests pass.
**Step 6: Commit**
@@ -331,11 +331,11 @@ git commit -m "test: add violations toggle test and update button count"
### Task 5: Update toolbar docstring
**Files:**
-- Modify: `libs/FastPlot/FastPlotToolbar.m:1-22` (classdef docstring)
+- Modify: `libs/FastSense/FastSenseToolbar.m:1-22` (classdef docstring)
**Step 1: Add Violations to the button list in the docstring**
-In `libs/FastPlot/FastPlotToolbar.m`, after line 20 (`% Metadata — show/hide metadata in data cursor tooltips`), add:
+In `libs/FastSense/FastSenseToolbar.m`, after line 20 (`% Metadata — show/hide metadata in data cursor tooltips`), add:
```matlab
% Violations — toggle violation marker visibility
@@ -344,6 +344,6 @@ In `libs/FastPlot/FastPlotToolbar.m`, after line 20 (`% Metadata — sho
**Step 2: Commit**
```bash
-git add libs/FastPlot/FastPlotToolbar.m
+git add libs/FastSense/FastSenseToolbar.m
git commit -m "docs: add violations button to toolbar docstring"
```
diff --git a/docs/plans/2026-03-10-live-event-pipeline-design.md b/docs/plans/2026-03-10-live-event-pipeline-design.md
index ce495020..037cfc73 100644
--- a/docs/plans/2026-03-10-live-event-pipeline-design.md
+++ b/docs/plans/2026-03-10-live-event-pipeline-design.md
@@ -137,7 +137,7 @@ Two plots generated per notification:
- Same threshold line + violation markers
- Shows signal trend leading into the violation
-Both generated headless (`'Visible', 'off'`) via FastPlot, saved as PNG, attached to email. Old snapshots auto-cleaned after configurable retention (default: 7 days).
+Both generated headless (`'Visible', 'off'`) via FastSense, saved as PNG, attached to email. Old snapshots auto-cleaned after configurable retention (default: 7 days).
### 9. LiveEventPipeline (Orchestrator)
@@ -166,7 +166,7 @@ Both generated headless (`'Visible', 'off'`) via FastPlot, saved as PNG, attache
- `Event`, `EventDetector`, `EventConfig`
- `EventViewer` (clients use `fromFile()` + `startAutoRefresh()`)
- `Sensor`, `ThresholdRule`, `StateChannel`, `SensorRegistry`
-- `FastPlot`
+- `FastSense`
## Configuration
diff --git a/docs/plans/2026-03-10-live-event-pipeline.md b/docs/plans/2026-03-10-live-event-pipeline.md
index 9b334cbd..2d148d5c 100644
--- a/docs/plans/2026-03-10-live-event-pipeline.md
+++ b/docs/plans/2026-03-10-live-event-pipeline.md
@@ -4,9 +4,9 @@
**Goal:** Build a live event detection pipeline that reads continuously-updated sensor data, detects threshold violations incrementally, stores events to a shared `.mat` file, and sends email notifications with event snapshot plots.
-**Architecture:** Monolithic orchestrator (`LiveEventPipeline`) owns a 15-second timer. Each cycle it reads new data via swappable `DataSource` objects, runs incremental detection with open-event carry-over, writes to an atomic `EventStore`, and triggers rule-based `NotificationService` with two FastPlot snapshot PNGs per event.
+**Architecture:** Monolithic orchestrator (`LiveEventPipeline`) owns a 15-second timer. Each cycle it reads new data via swappable `DataSource` objects, runs incremental detection with open-event carry-over, writes to an atomic `EventStore`, and triggers rule-based `NotificationService` with two FastSense snapshot PNGs per event.
-**Tech Stack:** MATLAB classes, `containers.Map`, MATLAB `timer`, `sendmail`, FastPlot for snapshot rendering.
+**Tech Stack:** MATLAB classes, `containers.Map`, MATLAB `timer`, `sendmail`, FastSense for snapshot rendering.
**Test runner:** `cd tests && matlab -batch "run_all_tests"` or individual: `matlab -batch "test_data_source"`
@@ -1574,7 +1574,7 @@ function add_event_path()
repoRoot = fileparts(thisDir);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
@@ -1654,7 +1654,7 @@ Expected: FAIL — `generateEventSnapshot` not found
```matlab
function files = generateEventSnapshot(event, sensorData, varargin)
- % generateEventSnapshot Create two FastPlot PNG snapshots for an event.
+ % generateEventSnapshot Create two FastSense PNG snapshots for an event.
%
% files = generateEventSnapshot(event, sensorData, ...)
%
@@ -1796,7 +1796,7 @@ function add_event_path()
repoRoot = fileparts(thisDir);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
@@ -1910,7 +1910,7 @@ classdef NotificationService < handle
SmtpPort = 25
SmtpUser = ''
SmtpPassword = ''
- FromAddress = 'fastplot@noreply.com'
+ FromAddress = 'fastsense@noreply.com'
NotificationCount = 0
end
@@ -1921,7 +1921,7 @@ classdef NotificationService < handle
p.addParameter('DryRun', false, @islogical);
p.addParameter('SnapshotDir', '', @ischar);
p.addParameter('SmtpServer', '', @ischar);
- p.addParameter('FromAddress', 'fastplot@noreply.com', @ischar);
+ p.addParameter('FromAddress', 'fastsense@noreply.com', @ischar);
p.parse(varargin{:});
obj.Enabled = p.Results.Enabled;
obj.DryRun = p.Results.DryRun;
@@ -1929,7 +1929,7 @@ classdef NotificationService < handle
obj.SmtpServer = p.Results.SmtpServer;
obj.FromAddress = p.Results.FromAddress;
if isempty(obj.SnapshotDir)
- obj.SnapshotDir = fullfile(tempdir, 'fastplot_snapshots');
+ obj.SnapshotDir = fullfile(tempdir, 'fastsense_snapshots');
end
end
@@ -2070,7 +2070,7 @@ function add_event_path()
repoRoot = fileparts(thisDir);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
@@ -2447,7 +2447,7 @@ dsMap.add('vibration', MockDataSource( ...
'SampleInterval', 3, 'Seed', 7));
%% 3. Configure event store
-storeFile = fullfile(tempdir, 'fastplot_live_events.mat');
+storeFile = fullfile(tempdir, 'fastsense_live_events.mat');
fprintf('Event store: %s\n', storeFile);
%% 4. Create pipeline
@@ -2460,7 +2460,7 @@ pipeline = LiveEventPipeline(sensors, dsMap, ...
notif = NotificationService('DryRun', true);
notif.setDefaultRule(NotificationRule( ...
'Recipients', {{'ops-team@company.com'}}, ...
- 'Subject', '[FastPlot] {sensor}: {threshold} violation', ...
+ 'Subject', '[FastSense] {sensor}: {threshold} violation', ...
'Message', 'Sensor {sensor} violated {threshold} ({direction}) from {startTime} to {endTime}. Peak: {peak}', ...
'IncludeSnapshot', false));
diff --git a/docs/superpowers/plans/2026-03-11-eventdetection-optimization.md b/docs/superpowers/plans/2026-03-11-eventdetection-optimization.md
index bf178ddb..444fb9a5 100644
--- a/docs/superpowers/plans/2026-03-11-eventdetection-optimization.md
+++ b/docs/superpowers/plans/2026-03-11-eventdetection-optimization.md
@@ -63,7 +63,7 @@ Add `test_slice_detection_consistency();` to the function list at the top of `te
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_incremental_detector
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_incremental_detector
```
Expected: ALL PASSED (this test should pass with current code too — it's a regression test)
@@ -214,7 +214,7 @@ end
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_incremental_detector
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_incremental_detector
```
Expected: ALL PASSED (8 tests including the new one)
@@ -222,7 +222,7 @@ Expected: ALL PASSED (8 tests including the new one)
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); run_all_tests
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); run_all_tests
```
Expected: 52/52 passed, 0 failed
@@ -275,7 +275,7 @@ Add `test_bar_positions_cached();` to the test function list in `test_event_view
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_event_viewer
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_event_viewer
```
Expected: FAIL — `BarPositions` property does not exist
@@ -361,7 +361,7 @@ end
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_event_viewer
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_event_viewer
```
Expected: ALL PASSED (7 tests including the new one)
@@ -369,7 +369,7 @@ Expected: ALL PASSED (7 tests including the new one)
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); run_all_tests
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); run_all_tests
```
Expected: All passed, 0 failed
@@ -426,7 +426,7 @@ delete(tmpFile);
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_event_config
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_event_config
```
Expected: ALL PASSED (this should pass with the current EventConfig.saveEvents too — it's a regression test)
@@ -518,7 +518,7 @@ Remove the `pruneBackups` method (lines 140-153) from `EventConfig.m`. EventStor
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); test_event_config
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); test_event_config
```
Expected: ALL PASSED (9 tests including the new one)
@@ -526,7 +526,7 @@ Expected: ALL PASSED (9 tests including the new one)
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); run_all_tests
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); run_all_tests
```
Expected: All passed, 0 failed
@@ -551,7 +551,7 @@ Single backup implementation to maintain."
Run in MATLAB:
```
-cd('/Users/hannessuhr/FastPlot'); setup(); cd('tests'); run_all_tests
+cd('/Users/hannessuhr/FastSense'); setup(); cd('tests'); run_all_tests
```
Expected: All passed, 0 failed
diff --git a/docs/superpowers/plans/2026-03-11-sensor-detail-plot.md b/docs/superpowers/plans/2026-03-11-sensor-detail-plot.md
index b508f832..b23196d8 100644
--- a/docs/superpowers/plans/2026-03-11-sensor-detail-plot.md
+++ b/docs/superpowers/plans/2026-03-11-sensor-detail-plot.md
@@ -4,7 +4,7 @@
**Goal:** Build a two-panel sensor overview+detail plot with interactive navigator, threshold bands, and optional event overlay.
-**Architecture:** Two new classes (`SensorDetailPlot`, `NavigatorOverlay`) in `libs/FastPlot/`, one new method (`tilePanel`) on `FastPlotFigure`. `SensorDetailPlot` coordinates two `FastPlot` instances; `NavigatorOverlay` handles the zoom rectangle, dimming, and drag interaction on the navigator axes.
+**Architecture:** Two new classes (`SensorDetailPlot`, `NavigatorOverlay`) in `libs/FastSense/`, one new method (`tilePanel`) on `FastSenseFigure`. `SensorDetailPlot` coordinates two `FastSense` instances; `NavigatorOverlay` handles the zoom rectangle, dimming, and drag interaction on the navigator axes.
**Tech Stack:** MATLAB (handle classes, uipanel layout, axes listeners, WindowButton callbacks)
@@ -16,9 +16,9 @@
| File | Action | Responsibility |
|------|--------|---------------|
-| `libs/FastPlot/NavigatorOverlay.m` | Create | Zoom rectangle, dimming patches, drag interaction |
-| `libs/FastPlot/SensorDetailPlot.m` | Create | Coordinator: two-panel layout, sensor rendering, event overlay, sync |
-| `libs/FastPlot/FastPlotFigure.m` | Modify | Add `tilePanel(n)` method |
+| `libs/FastSense/NavigatorOverlay.m` | Create | Zoom rectangle, dimming patches, drag interaction |
+| `libs/FastSense/SensorDetailPlot.m` | Create | Coordinator: two-panel layout, sensor rendering, event overlay, sync |
+| `libs/FastSense/FastSenseFigure.m` | Modify | Add `tilePanel(n)` method |
| `tests/test_NavigatorOverlay.m` | Create | Unit tests for NavigatorOverlay |
| `tests/test_SensorDetailPlot.m` | Create | Unit tests for SensorDetailPlot |
| `examples/example_sensor_detail.m` | Create | Demo script showing standalone + events usage |
@@ -30,7 +30,7 @@
### Task 1: NavigatorOverlay — Class Skeleton + Visual Elements
**Files:**
-- Create: `libs/FastPlot/NavigatorOverlay.m`
+- Create: `libs/FastSense/NavigatorOverlay.m`
- Create: `tests/test_NavigatorOverlay.m`
- [ ] **Step 1: Write failing tests for NavigatorOverlay construction and visual elements**
@@ -43,7 +43,7 @@ function tests = test_NavigatorOverlay
end
function setup(testCase)
- addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastSense'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'SensorThreshold'));
testCase.TestData.hFig = figure('Visible', 'off');
testCase.TestData.hAxes = axes('Parent', testCase.TestData.hFig);
@@ -161,12 +161,12 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
Expected: FAIL — NavigatorOverlay class not found
- [ ] **Step 3: Implement NavigatorOverlay class — visual elements + setRange**
-Create `libs/FastPlot/NavigatorOverlay.m`:
+Create `libs/FastSense/NavigatorOverlay.m`:
```matlab
classdef NavigatorOverlay < handle
@@ -488,13 +488,13 @@ end
- [ ] **Step 4: Run tests to verify they pass**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
Expected: All 6 tests PASS
- [ ] **Step 5: Commit**
```bash
-git add libs/FastPlot/NavigatorOverlay.m tests/test_NavigatorOverlay.m
+git add libs/FastSense/NavigatorOverlay.m tests/test_NavigatorOverlay.m
git commit -m "feat: add NavigatorOverlay with visual elements and drag interaction"
```
@@ -543,7 +543,7 @@ end
- [ ] **Step 2: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_NavigatorOverlay'); disp(results)"`
Expected: All 10 tests PASS
- [ ] **Step 3: Commit**
@@ -560,7 +560,7 @@ git commit -m "test: add NavigatorOverlay boundary clamping tests"
### Task 3: SensorDetailPlot — Constructor + Layout
**Files:**
-- Create: `libs/FastPlot/SensorDetailPlot.m`
+- Create: `libs/FastSense/SensorDetailPlot.m`
- Create: `tests/test_SensorDetailPlot.m`
- [ ] **Step 1: Write failing tests for constructor and layout**
@@ -573,7 +573,7 @@ function tests = test_SensorDetailPlot
end
function setup(testCase)
- addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastSense'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'SensorThreshold'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'EventDetection'));
@@ -617,12 +617,12 @@ function test_constructor_custom_options(testCase)
delete(sdp);
end
-%% Render creates two FastPlot instances
+%% Render creates two FastSense instances
function test_render_creates_main_and_navigator(testCase)
sdp = SensorDetailPlot(testCase.TestData.sensor);
sdp.render();
- verifyClass(testCase, sdp.MainPlot, ?FastPlot);
- verifyClass(testCase, sdp.NavigatorPlot, ?FastPlot);
+ verifyClass(testCase, sdp.MainPlot, ?FastSense);
+ verifyClass(testCase, sdp.NavigatorPlot, ?FastSense);
delete(sdp);
end
@@ -664,12 +664,12 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: FAIL — SensorDetailPlot class not found
- [ ] **Step 3: Implement SensorDetailPlot — constructor + render + layout**
-Create `libs/FastPlot/SensorDetailPlot.m`:
+Create `libs/FastSense/SensorDetailPlot.m`:
```matlab
classdef SensorDetailPlot < handle
@@ -679,7 +679,7 @@ classdef SensorDetailPlot < handle
% sdp = SensorDetailPlot(sensor, Name, Value, ...)
%
% Name-Value Options:
- % 'Theme' - FastPlot theme (default: 'default')
+ % 'Theme' - FastSense theme (default: 'default')
% 'NavigatorHeight' - Fraction 0-1 for navigator (default: 0.20)
% 'ShowThresholds' - Show thresholds in main plot (default: true)
% 'ShowThresholdBands' - Show threshold bands in navigator (default: true)
@@ -690,8 +690,8 @@ classdef SensorDetailPlot < handle
properties (SetAccess = private)
Sensor % Sensor object
- MainPlot % FastPlot instance for upper panel
- NavigatorPlot % FastPlot instance for lower panel
+ MainPlot % FastSense instance for upper panel
+ NavigatorPlot % FastSense instance for lower panel
NavigatorOverlayObj % NavigatorOverlay instance
end
@@ -763,8 +763,8 @@ classdef SensorDetailPlot < handle
% Create layout
obj.createLayout();
- % Create main FastPlot
- obj.MainPlot = FastPlot('Parent', obj.hMainAxes, 'Theme', obj.Theme);
+ % Create main FastSense
+ obj.MainPlot = FastSense('Parent', obj.hMainAxes, 'Theme', obj.Theme);
obj.MainPlot.addSensor(obj.Sensor, 'ShowThresholds', obj.ShowThresholds);
% Render main plot
@@ -775,8 +775,8 @@ classdef SensorDetailPlot < handle
title(obj.hMainAxes, obj.Title);
end
- % Create navigator FastPlot
- obj.NavigatorPlot = FastPlot('Parent', obj.hNavAxes, 'Theme', obj.Theme);
+ % Create navigator FastSense
+ obj.NavigatorPlot = FastSense('Parent', obj.hNavAxes, 'Theme', obj.Theme);
obj.NavigatorPlot.addLine(obj.Sensor.X, obj.Sensor.Y, ...
'DisplayName', obj.Sensor.Name);
@@ -1084,13 +1084,13 @@ end
- [ ] **Step 4: Run tests to verify they pass**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: All 8 tests PASS
- [ ] **Step 5: Commit**
```bash
-git add libs/FastPlot/SensorDetailPlot.m tests/test_SensorDetailPlot.m
+git add libs/FastSense/SensorDetailPlot.m tests/test_SensorDetailPlot.m
git commit -m "feat: add SensorDetailPlot with two-panel layout and navigator sync"
```
@@ -1158,7 +1158,7 @@ end
- [ ] **Step 2: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: All 12 tests PASS
- [ ] **Step 3: Commit**
@@ -1170,7 +1170,7 @@ git commit -m "test: add threshold display tests for SensorDetailPlot"
---
-## Chunk 3: Events, FastPlotFigure Integration, and Example
+## Chunk 3: Events, FastSenseFigure Integration, and Example
### Task 5: SensorDetailPlot — Event Overlay Tests
@@ -1343,7 +1343,7 @@ end
- [ ] **Step 2: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: All 19 tests PASS
- [ ] **Step 3: Commit**
@@ -1355,10 +1355,10 @@ git commit -m "test: add event overlay tests for SensorDetailPlot"
---
-### Task 6: FastPlotFigure — tilePanel Method
+### Task 6: FastSenseFigure — tilePanel Method
**Files:**
-- Modify: `libs/FastPlot/FastPlotFigure.m:211-251` (add after `axes(n)` method)
+- Modify: `libs/FastSense/FastSenseFigure.m:211-251` (add after `axes(n)` method)
- Modify: `tests/test_SensorDetailPlot.m` (add integration test)
- [ ] **Step 1: Write failing test for tilePanel**
@@ -1366,30 +1366,30 @@ git commit -m "test: add event overlay tests for SensorDetailPlot"
Append to `tests/test_SensorDetailPlot.m`:
```matlab
-%% FastPlotFigure tilePanel integration
+%% FastSenseFigure tilePanel integration
function test_tilePanel_returns_uipanel(testCase)
- fig = FastPlotFigure(2, 1);
+ fig = FastSenseFigure(2, 1);
hp = fig.tilePanel(1);
verifyTrue(testCase, isa(hp, 'matlab.ui.container.Panel'));
delete(fig);
end
function test_tilePanel_conflict_with_tile(testCase)
- fig = FastPlotFigure(2, 1);
- fig.tile(1); % Occupy tile 1 as FastPlot
- verifyError(testCase, @() fig.tilePanel(1), 'FastPlotFigure:tileConflict');
+ fig = FastSenseFigure(2, 1);
+ fig.tile(1); % Occupy tile 1 as FastSense
+ verifyError(testCase, @() fig.tilePanel(1), 'FastSenseFigure:tileConflict');
delete(fig);
end
-%% Embedded in FastPlotFigure
+%% Embedded in FastSenseFigure
function test_embedded_in_figure_tile(testCase)
s = testCase.TestData.sensor;
- fig = FastPlotFigure(1, 1);
+ fig = FastSenseFigure(1, 1);
hp = fig.tilePanel(1);
sdp = SensorDetailPlot(s, 'Parent', hp);
sdp.render();
verifyTrue(testCase, sdp.IsRendered);
- verifyClass(testCase, sdp.MainPlot, ?FastPlot);
+ verifyClass(testCase, sdp.MainPlot, ?FastSense);
delete(sdp);
delete(fig);
end
@@ -1397,16 +1397,16 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot', 'ProcedureName', 'test_tilePanel*'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot', 'ProcedureName', 'test_tilePanel*'); disp(results)"`
Expected: FAIL — tilePanel method not found
-- [ ] **Step 3: Read FastPlotFigure.m to find insertion point**
+- [ ] **Step 3: Read FastSenseFigure.m to find insertion point**
-Read: `libs/FastPlot/FastPlotFigure.m:211-260` to see the `axes(n)` method and find where to add `tilePanel(n)`.
+Read: `libs/FastSense/FastSenseFigure.m:211-260` to see the `axes(n)` method and find where to add `tilePanel(n)`.
-- [ ] **Step 4: Add tilePanel method to FastPlotFigure**
+- [ ] **Step 4: Add tilePanel method to FastSenseFigure**
-Add after the `axes(n)` method (around line 251) in `libs/FastPlot/FastPlotFigure.m`. The method follows the same pattern as `axes(n)`:
+Add after the `axes(n)` method (around line 251) in `libs/FastSense/FastSenseFigure.m`. The method follows the same pattern as `axes(n)`:
```matlab
function hp = tilePanel(obj, n)
@@ -1416,11 +1416,11 @@ Add after the `axes(n)` method (around line 251) in `libs/FastPlot/FastPlotFigur
% composite widgets (e.g. SensorDetailPlot) into a tile.
%
% Throws an error if tile n is already occupied by a
- % FastPlot (via tile()) or raw axes (via axes()).
+ % FastSense (via tile()) or raw axes (via axes()).
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotFigure:invalidTile', ...
+ error('FastSenseFigure:invalidTile', ...
'Tile index %d is out of range [1, %d].', n, nTiles);
end
@@ -1430,15 +1430,15 @@ Add after the `axes(n)` method (around line 251) in `libs/FastPlot/FastPlotFigur
return;
end
- % Conflict check: occupied by FastPlot?
+ % Conflict check: occupied by FastSense?
if ~isempty(obj.Tiles{n})
- error('FastPlotFigure:tileConflict', ...
- 'Tile %d is a FastPlot tile. Use tile(%d) to access it.', n, n);
+ error('FastSenseFigure:tileConflict', ...
+ 'Tile %d is a FastSense tile. Use tile(%d) to access it.', n, n);
end
% Conflict check: occupied by raw axes?
if obj.RawAxesTiles(n)
- error('FastPlotFigure:tileConflict', ...
+ error('FastSenseFigure:tileConflict', ...
'Tile %d is a raw axes tile. Use axes(%d) to access it.', n, n);
end
@@ -1457,12 +1457,12 @@ Add after the `axes(n)` method (around line 251) in `libs/FastPlot/FastPlotFigur
- [ ] **Step 5: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: All 22 tests PASS
- [ ] **Step 6: Also make `IsRendered` accessible for test**
-In `libs/FastPlot/SensorDetailPlot.m`, change `IsRendered` access from `(Access = private)` to `(SetAccess = private, GetAccess = ?matlab.unittest.TestCase)` or simply move it to the `(SetAccess = private, GetAccess = public)` block since it's a useful read-only property:
+In `libs/FastSense/SensorDetailPlot.m`, change `IsRendered` access from `(Access = private)` to `(SetAccess = private, GetAccess = ?matlab.unittest.TestCase)` or simply move it to the `(SetAccess = private, GetAccess = public)` block since it's a useful read-only property:
Move `IsRendered` from the private properties block to the public-readable block:
@@ -1481,14 +1481,14 @@ Move `IsRendered` from the private properties block to the public-readable block
- [ ] **Step 7: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('test_SensorDetailPlot'); disp(results)"`
Expected: All 22 tests PASS
- [ ] **Step 8: Commit**
```bash
-git add libs/FastPlot/FastPlotFigure.m libs/FastPlot/SensorDetailPlot.m tests/test_SensorDetailPlot.m
-git commit -m "feat: add tilePanel method to FastPlotFigure for composite widget embedding"
+git add libs/FastSense/FastSenseFigure.m libs/FastSense/SensorDetailPlot.m tests/test_SensorDetailPlot.m
+git commit -m "feat: add tilePanel method to FastSenseFigure for composite widget embedding"
```
---
@@ -1508,10 +1508,10 @@ Create `examples/example_sensor_detail.m`:
% Demonstrates:
% 1. Standalone sensor detail plot with thresholds
% 2. Adding events from EventStore
-% 3. Embedding in a FastPlotFigure tile
+% 3. Embedding in a FastSenseFigure tile
%% Setup path
-addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastPlot'));
+addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'FastSense'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'SensorThreshold'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', 'libs', 'EventDetection'));
@@ -1589,20 +1589,20 @@ sdp2.render();
fprintf(' Press any key to continue...\n');
pause;
-%% 5. Embedded in FastPlotFigure
-fprintf('=== SensorDetailPlot: Embedded in FastPlotFigure ===\n');
-fig = FastPlotFigure(1, 2, 'Theme', 'dark', 'Name', 'Sensor Dashboard');
+%% 5. Embedded in FastSenseFigure
+fprintf('=== SensorDetailPlot: Embedded in FastSenseFigure ===\n');
+fig = FastSenseFigure(1, 2, 'Theme', 'dark', 'Name', 'Sensor Dashboard');
sdp3 = SensorDetailPlot(s, 'Parent', fig.tilePanel(1), ...
'Events', events, 'Title', 'Temperature');
sdp3.render();
-% Second tile: plain FastPlot for comparison
+% Second tile: plain FastSense for comparison
fp = fig.tile(2);
fp.addLine(t, data, 'DisplayName', 'Raw Data');
fig.tileTitle(2, 'Raw Data');
fig.renderAll();
-fprintf(' Two tiles: SensorDetailPlot + plain FastPlot\n');
+fprintf(' Two tiles: SensorDetailPlot + plain FastSense\n');
fprintf(' Press any key to exit...\n');
pause;
@@ -1611,7 +1611,7 @@ fprintf('Done.\n');
- [ ] **Step 2: Run example to verify it works**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run('examples/example_sensor_detail.m')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run('examples/example_sensor_detail.m')"`
Expected: Two figure windows open showing the sensor detail plots. No errors.
- [ ] **Step 3: Commit**
@@ -1627,12 +1627,12 @@ git commit -m "feat: add example_sensor_detail demo script"
- [ ] **Step 1: Run all tests to ensure nothing is broken**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "addpath('tests'); results = runtests('tests'); disp(table(results))"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "addpath('tests'); results = runtests('tests'); disp(table(results))"`
Expected: All tests PASS (existing tests + new tests)
- [ ] **Step 2: Fix any failures**
-If any existing tests fail, investigate and fix. The new classes should not affect existing behavior since they are additive (new files) with only one modification to `FastPlotFigure.m` (adding a new method, no changes to existing methods).
+If any existing tests fail, investigate and fix. The new classes should not affect existing behavior since they are additive (new files) with only one modification to `FastSenseFigure.m` (adding a new method, no changes to existing methods).
- [ ] **Step 3: Final commit if fixes were needed**
diff --git a/docs/superpowers/plans/2026-03-13-web-bridge-mvp.md b/docs/superpowers/plans/2026-03-13-web-bridge-mvp.md
index 229b0a8b..527572f2 100644
--- a/docs/superpowers/plans/2026-03-13-web-bridge-mvp.md
+++ b/docs/superpowers/plans/2026-03-13-web-bridge-mvp.md
@@ -29,7 +29,7 @@
| File | Change |
|------|--------|
-| `libs/FastPlot/FastPlotDataStore.m` | Add `enableWAL()` / `disableWAL()` methods |
+| `libs/FastSense/FastSenseDataStore.m` | Add `enableWAL()` / `disableWAL()` methods |
| `setup.m` | Add `libs/WebBridge` to MATLAB path |
| `tests/suite/TestDataStoreWAL.m` | Tests for WAL methods |
@@ -38,12 +38,12 @@
| File | Responsibility |
|------|---------------|
| `bridge/python/pyproject.toml` | Package config, dependencies |
-| `bridge/python/fastplot_bridge/__init__.py` | Package init |
-| `bridge/python/fastplot_bridge/__main__.py` | CLI entry point |
-| `bridge/python/fastplot_bridge/blob_decoder.py` | mksqlite typed BLOB header parser |
-| `bridge/python/fastplot_bridge/sqlite_reader.py` | SQLite queries + BLOB decoding + downsampling |
-| `bridge/python/fastplot_bridge/tcp_client.py` | Async NDJSON-over-TCP client to MATLAB |
-| `bridge/python/fastplot_bridge/server.py` | FastAPI app: REST API + WebSocket + static files |
+| `bridge/python/fastsense_bridge/__init__.py` | Package init |
+| `bridge/python/fastsense_bridge/__main__.py` | CLI entry point |
+| `bridge/python/fastsense_bridge/blob_decoder.py` | mksqlite typed BLOB header parser |
+| `bridge/python/fastsense_bridge/sqlite_reader.py` | SQLite queries + BLOB decoding + downsampling |
+| `bridge/python/fastsense_bridge/tcp_client.py` | Async NDJSON-over-TCP client to MATLAB |
+| `bridge/python/fastsense_bridge/server.py` | FastAPI app: REST API + WebSocket + static files |
| `bridge/python/tests/test_blob_decoder.py` | Unit tests for BLOB parser |
| `bridge/python/tests/test_sqlite_reader.py` | Unit tests for SQLite reader |
| `bridge/python/tests/test_tcp_client.py` | Unit tests for TCP client |
@@ -95,10 +95,10 @@ git commit -m "chore: add WebBridge to MATLAB path in setup.m"
---
-### Task 1: Add WAL Methods to FastPlotDataStore
+### Task 1: Add WAL Methods to FastSenseDataStore
**Files:**
-- Modify: `libs/FastPlot/FastPlotDataStore.m`
+- Modify: `libs/FastSense/FastSenseDataStore.m`
- Test: `tests/suite/TestDataStoreWAL.m`
- [ ] **Step 1: Write the failing test**
@@ -120,7 +120,7 @@ classdef TestDataStoreWAL < matlab.unittest.TestCase
% Create a DataStore with some data
x = 1:1000;
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
% Enable WAL mode
@@ -135,7 +135,7 @@ classdef TestDataStoreWAL < matlab.unittest.TestCase
function testDisableWAL(testCase)
x = 1:1000;
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
ds.enableWAL();
@@ -149,7 +149,7 @@ classdef TestDataStoreWAL < matlab.unittest.TestCase
function testDataAccessAfterWAL(testCase)
x = 1:1000;
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
ds.enableWAL();
@@ -165,12 +165,12 @@ end
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestDataStoreWAL')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestDataStoreWAL')"`
Expected: FAIL — `enableWAL` method not found
- [ ] **Step 3: Implement enableWAL and disableWAL**
-Add to `libs/FastPlot/FastPlotDataStore.m` in the public methods block:
+Add to `libs/FastSense/FastSenseDataStore.m` in the public methods block:
```matlab
function enableWAL(obj)
@@ -192,14 +192,14 @@ end
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestDataStoreWAL')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestDataStoreWAL')"`
Expected: PASS (3/3 tests)
- [ ] **Step 5: Commit**
```bash
-git add libs/FastPlot/FastPlotDataStore.m tests/suite/TestDataStoreWAL.m
-git commit -m "feat: add enableWAL/disableWAL to FastPlotDataStore for concurrent reads"
+git add libs/FastSense/FastSenseDataStore.m tests/suite/TestDataStoreWAL.m
+git commit -m "feat: add enableWAL/disableWAL to FastSenseDataStore for concurrent reads"
```
---
@@ -291,7 +291,7 @@ end
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridgeProtocol')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridgeProtocol')"`
Expected: FAIL — WebBridgeProtocol not found
- [ ] **Step 3: Create libs/WebBridge directory and implement WebBridgeProtocol**
@@ -358,7 +358,7 @@ end
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridgeProtocol')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridgeProtocol')"`
Expected: PASS (7/7 tests)
- [ ] **Step 5: Commit**
@@ -511,7 +511,7 @@ end
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridge')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridge')"`
Expected: FAIL — WebBridge not found
- [ ] **Step 3: Implement WebBridge.m**
@@ -694,7 +694,7 @@ classdef WebBridge < handle
idx = 0;
for i = 1:numel(obj.Dashboard.Widgets)
w = obj.Dashboard.Widgets{i};
- if ~isa(w, 'FastPlotWidget'); continue; end
+ if ~isa(w, 'FastSenseWidget'); continue; end
idx = idx + 1;
if isprop(w, 'Sensor') && ~isempty(w.Sensor) && isprop(w.Sensor, 'Key')
sid = w.Sensor.Key;
@@ -779,7 +779,7 @@ classdef WebBridge < handle
% Find the bridge script relative to this file
bridgeDir = fullfile(fileparts(mfilename('fullpath')), ...
'..', '..', 'bridge', 'python');
- cmd = sprintf('python -m fastplot_bridge --matlab-port %d', obj.TcpPort);
+ cmd = sprintf('python -m fastsense_bridge --matlab-port %d', obj.TcpPort);
if ispc
fullCmd = sprintf('start /B %s', cmd);
else
@@ -798,7 +798,7 @@ classdef WebBridge < handle
end
obj.stop();
error('WebBridge:timeout', ...
- 'Bridge did not start within 10s. Check that fastplot-bridge is installed.');
+ 'Bridge did not start within 10s. Check that fastsense-bridge is installed.');
end
function enableWALOnDataStores(obj)
@@ -822,7 +822,7 @@ classdef WebBridge < handle
end
for i = 1:numel(obj.Dashboard.Widgets)
w = obj.Dashboard.Widgets{i};
- if ~isa(w, 'FastPlotWidget'); continue; end
+ if ~isa(w, 'FastSenseWidget'); continue; end
ds = [];
if isprop(w, 'DataStore') && ~isempty(w.DataStore)
ds = w.DataStore;
@@ -841,7 +841,7 @@ end
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridge')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridge')"`
Expected: PASS (7/7 tests)
- [ ] **Step 5: Commit**
@@ -859,21 +859,21 @@ git commit -m "feat: add WebBridge class with TCP server, action registry, and l
**Files:**
- Create: `bridge/python/pyproject.toml`
-- Create: `bridge/python/fastplot_bridge/__init__.py`
-- Create: `bridge/python/fastplot_bridge/blob_decoder.py`
+- Create: `bridge/python/fastsense_bridge/__init__.py`
+- Create: `bridge/python/fastsense_bridge/blob_decoder.py`
- Test: `bridge/python/tests/test_blob_decoder.py`
- [ ] **Step 1: Create project structure**
```bash
-mkdir -p bridge/python/fastplot_bridge bridge/python/tests
+mkdir -p bridge/python/fastsense_bridge bridge/python/tests
```
Create `bridge/python/pyproject.toml`:
```toml
[project]
-name = "fastplot-bridge"
+name = "fastsense-bridge"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
@@ -888,16 +888,16 @@ dependencies = [
dev = ["pytest>=7.0", "pytest-asyncio>=0.21", "httpx>=0.25"]
[project.scripts]
-fastplot-bridge = "fastplot_bridge.__main__:main"
+fastsense-bridge = "fastsense_bridge.__main__:main"
[tool.pytest.ini_options]
asyncio_mode = "auto"
```
-Create `bridge/python/fastplot_bridge/__init__.py`:
+Create `bridge/python/fastsense_bridge/__init__.py`:
```python
-"""FastPlot Bridge — serves MATLAB dashboard data via REST/WebSocket."""
+"""FastSense Bridge — serves MATLAB dashboard data via REST/WebSocket."""
```
- [ ] **Step 2: Write the failing test for blob_decoder**
@@ -908,7 +908,7 @@ Create `bridge/python/tests/test_blob_decoder.py`:
import struct
import numpy as np
import pytest
-from fastplot_bridge.blob_decoder import decode_typed_blob, MKSQ_MAGIC
+from fastsense_bridge.blob_decoder import decode_typed_blob, MKSQ_MAGIC
MX_DOUBLE = 6
MX_SINGLE = 7
@@ -972,12 +972,12 @@ class TestBlobDecoder:
- [ ] **Step 3: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pip install -e ".[dev]" && pytest tests/test_blob_decoder.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pip install -e ".[dev]" && pytest tests/test_blob_decoder.py -v`
Expected: FAIL — module not found
- [ ] **Step 4: Implement blob_decoder.py**
-Create `bridge/python/fastplot_bridge/blob_decoder.py`:
+Create `bridge/python/fastsense_bridge/blob_decoder.py`:
```python
"""Decoder for mksqlite typed BLOB format (24-byte header + raw data)."""
@@ -1047,7 +1047,7 @@ def decode_typed_blob(data: bytes | memoryview) -> np.ndarray | str | list:
- [ ] **Step 5: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_blob_decoder.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_blob_decoder.py -v`
Expected: PASS (8/8 tests)
- [ ] **Step 6: Commit**
@@ -1062,7 +1062,7 @@ git commit -m "feat: add Python bridge project setup and mksqlite BLOB decoder"
### Task 5: Python SQLite Reader
**Files:**
-- Create: `bridge/python/fastplot_bridge/sqlite_reader.py`
+- Create: `bridge/python/fastsense_bridge/sqlite_reader.py`
- Test: `bridge/python/tests/test_sqlite_reader.py`
**Dependencies:** Task 4 (blob_decoder)
@@ -1078,8 +1078,8 @@ import tempfile
import numpy as np
import pytest
from pathlib import Path
-from fastplot_bridge.blob_decoder import MKSQ_MAGIC
-from fastplot_bridge.sqlite_reader import SqliteReader
+from fastsense_bridge.blob_decoder import MKSQ_MAGIC
+from fastsense_bridge.sqlite_reader import SqliteReader
def _make_double_blob(values: list[float]) -> bytes:
@@ -1090,7 +1090,7 @@ def _make_double_blob(values: list[float]) -> bytes:
@pytest.fixture
def sample_db(tmp_path) -> Path:
- """Create a minimal .fpdb file matching FastPlotDataStore schema."""
+ """Create a minimal .fpdb file matching FastSenseDataStore schema."""
db_path = tmp_path / "test.fpdb"
conn = sqlite3.connect(str(db_path))
@@ -1178,15 +1178,15 @@ class TestSqliteReader:
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_sqlite_reader.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_sqlite_reader.py -v`
Expected: FAIL — SqliteReader not found
- [ ] **Step 3: Implement sqlite_reader.py**
-Create `bridge/python/fastplot_bridge/sqlite_reader.py`:
+Create `bridge/python/fastsense_bridge/sqlite_reader.py`:
```python
-"""Read FastPlotDataStore SQLite files and decode typed BLOBs."""
+"""Read FastSenseDataStore SQLite files and decode typed BLOBs."""
import sqlite3
import numpy as np
@@ -1194,7 +1194,7 @@ from .blob_decoder import decode_typed_blob
class SqliteReader:
- """Synchronous reader for .fpdb files created by FastPlotDataStore."""
+ """Synchronous reader for .fpdb files created by FastSenseDataStore."""
def __init__(self, db_path: str):
self._conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
@@ -1352,13 +1352,13 @@ def _minmax_downsample(
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_sqlite_reader.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_sqlite_reader.py -v`
Expected: PASS (5/5 tests)
- [ ] **Step 5: Commit**
```bash
-git add bridge/python/fastplot_bridge/sqlite_reader.py bridge/python/tests/test_sqlite_reader.py
+git add bridge/python/fastsense_bridge/sqlite_reader.py bridge/python/tests/test_sqlite_reader.py
git commit -m "feat: add SQLite reader with BLOB decoding and minmax downsampling"
```
@@ -1367,7 +1367,7 @@ git commit -m "feat: add SQLite reader with BLOB decoding and minmax downsamplin
### Task 6: Python TCP Client
**Files:**
-- Create: `bridge/python/fastplot_bridge/tcp_client.py`
+- Create: `bridge/python/fastsense_bridge/tcp_client.py`
- Test: `bridge/python/tests/test_tcp_client.py`
- [ ] **Step 1: Write the failing test**
@@ -1379,7 +1379,7 @@ import asyncio
import json
import pytest
import pytest_asyncio
-from fastplot_bridge.tcp_client import MatlabTcpClient
+from fastsense_bridge.tcp_client import MatlabTcpClient
@pytest_asyncio.fixture
@@ -1473,12 +1473,12 @@ class TestMatlabTcpClient:
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_tcp_client.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_tcp_client.py -v`
Expected: FAIL — MatlabTcpClient not found
- [ ] **Step 3: Implement tcp_client.py**
-Create `bridge/python/fastplot_bridge/tcp_client.py`:
+Create `bridge/python/fastsense_bridge/tcp_client.py`:
```python
"""Async NDJSON-over-TCP client for connecting to MATLAB's WebBridge."""
@@ -1559,13 +1559,13 @@ class MatlabTcpClient:
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_tcp_client.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_tcp_client.py -v`
Expected: PASS (4/4 tests)
- [ ] **Step 5: Commit**
```bash
-git add bridge/python/fastplot_bridge/tcp_client.py bridge/python/tests/test_tcp_client.py
+git add bridge/python/fastsense_bridge/tcp_client.py bridge/python/tests/test_tcp_client.py
git commit -m "feat: add async NDJSON TCP client for MATLAB communication"
```
@@ -1574,8 +1574,8 @@ git commit -m "feat: add async NDJSON TCP client for MATLAB communication"
### Task 7: Python FastAPI Server
**Files:**
-- Create: `bridge/python/fastplot_bridge/server.py`
-- Create: `bridge/python/fastplot_bridge/__main__.py`
+- Create: `bridge/python/fastsense_bridge/server.py`
+- Create: `bridge/python/fastsense_bridge/__main__.py`
- Test: `bridge/python/tests/test_server.py`
**Dependencies:** Task 5 (sqlite_reader), Task 6 (tcp_client)
@@ -1593,8 +1593,8 @@ import numpy as np
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
from fastapi.testclient import TestClient
-from fastplot_bridge.blob_decoder import MKSQ_MAGIC
-from fastplot_bridge.server import create_app, AppState
+from fastsense_bridge.blob_decoder import MKSQ_MAGIC
+from fastsense_bridge.server import create_app, AppState
def _make_double_blob(values: list[float]) -> bytes:
@@ -1709,12 +1709,12 @@ class TestServerAPI:
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_server.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_server.py -v`
Expected: FAIL — create_app / AppState not found
- [ ] **Step 3: Implement server.py**
-Create `bridge/python/fastplot_bridge/server.py`:
+Create `bridge/python/fastsense_bridge/server.py`:
```python
"""FastAPI server: REST API + WebSocket + static file serving."""
@@ -1792,7 +1792,7 @@ class AppState:
def create_app(state: AppState) -> FastAPI:
- app = FastAPI(title="FastPlot Bridge")
+ app = FastAPI(title="FastSense Bridge")
# --- REST API ---
@@ -1867,8 +1867,8 @@ def create_app(state: AppState) -> FastAPI:
# --- Static files ---
- # server.py is at bridge/python/fastplot_bridge/server.py
- # Go up to bridge/python/fastplot_bridge → bridge/python → bridge, then /web
+ # server.py is at bridge/python/fastsense_bridge/server.py
+ # Go up to bridge/python/fastsense_bridge → bridge/python → bridge, then /web
web_dir = Path(__file__).resolve().parent.parent.parent / "web"
if web_dir.is_dir():
@app.get("/")
@@ -1882,10 +1882,10 @@ def create_app(state: AppState) -> FastAPI:
- [ ] **Step 4: Implement __main__.py**
-Create `bridge/python/fastplot_bridge/__main__.py`:
+Create `bridge/python/fastsense_bridge/__main__.py`:
```python
-"""CLI entry point for the FastPlot bridge server."""
+"""CLI entry point for the FastSense bridge server."""
import argparse
import asyncio
@@ -1927,7 +1927,7 @@ async def run(matlab_port: int, http_host: str, http_port: int):
def main():
- parser = argparse.ArgumentParser(description="FastPlot Bridge Server")
+ parser = argparse.ArgumentParser(description="FastSense Bridge Server")
parser.add_argument("--matlab-port", type=int, required=True, help="MATLAB TCP port")
parser.add_argument("--host", default="localhost", help="HTTP bind host")
parser.add_argument("--port", type=int, default=8080, help="HTTP port")
@@ -1942,13 +1942,13 @@ if __name__ == "__main__":
- [ ] **Step 5: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot/bridge/python && pytest tests/test_server.py -v`
+Run: `cd /Users/hannessuhr/FastSense/bridge/python && pytest tests/test_server.py -v`
Expected: PASS (9/9 tests)
- [ ] **Step 6: Commit**
```bash
-git add bridge/python/fastplot_bridge/server.py bridge/python/fastplot_bridge/__main__.py bridge/python/tests/test_server.py
+git add bridge/python/fastsense_bridge/server.py bridge/python/fastsense_bridge/__main__.py bridge/python/tests/test_server.py
git commit -m "feat: add FastAPI bridge server with REST API, WebSocket, and CLI entry point"
```
@@ -1979,13 +1979,13 @@ Create `bridge/web/index.html`:
- FastPlot Dashboard
+ FastSense Dashboard
@@ -2109,7 +2109,7 @@ Create `bridge/web/js/app.js`:
```javascript
/**
- * FastPlot Bridge — Main entry point.
+ * FastSense Bridge — Main entry point.
* Connects WebSocket, loads dashboard, handles live updates.
*/
const App = (() => {
@@ -2126,7 +2126,7 @@ const App = (() => {
try {
const resp = await fetch('/api/dashboard');
const config = await resp.json();
- document.getElementById('dashboard-title').textContent = config.name || 'FastPlot Dashboard';
+ document.getElementById('dashboard-title').textContent = config.name || 'FastSense Dashboard';
Dashboard.render(config);
} catch (e) {
showToast('Failed to load dashboard', 'error');
@@ -2219,7 +2219,7 @@ git commit -m "feat: add web frontend shell with HTML, CSS grid layout, and WebS
- [ ] **Step 1: Download uPlot**
```bash
-cd /Users/hannessuhr/FastPlot/bridge/web/vendor
+cd /Users/hannessuhr/FastSense/bridge/web/vendor
curl -L -o uPlot.min.js "https://unpkg.com/uplot@1.6.31/dist/uPlot.iife.min.js"
curl -L -o uPlot.min.css "https://unpkg.com/uplot@1.6.31/dist/uPlot.min.css"
```
@@ -2349,7 +2349,7 @@ const Widgets = (() => {
function render(widgetConfig, bodyEl) {
const type = widgetConfig.type || '';
switch (type) {
- case 'fastplot': return renderFastPlot(widgetConfig, bodyEl);
+ case 'fastsense': return renderFastSense(widgetConfig, bodyEl);
case 'kpi': return renderKpi(widgetConfig, bodyEl);
case 'status': return renderStatus(widgetConfig, bodyEl);
case 'table': return renderTable(widgetConfig, bodyEl);
@@ -2361,7 +2361,7 @@ const Widgets = (() => {
}
}
- function renderFastPlot(config, el) {
+ function renderFastSense(config, el) {
// Determine signal ID from config source
let signalId = '';
if (config.source) {
@@ -2596,9 +2596,9 @@ git commit -m "feat: add action panel with button rendering and invocation"
## Chunk 4: Integration & Wiring
-### Task 12: Wire FastPlotWidget Signal IDs into Dashboard Config
+### Task 12: Wire FastSenseWidget Signal IDs into Dashboard Config
-The web frontend needs to know which signal ID maps to each FastPlotWidget. The `DashboardSerializer.widgetsToConfig` output must include this mapping.
+The web frontend needs to know which signal ID maps to each FastSenseWidget. The `DashboardSerializer.widgetsToConfig` output must include this mapping.
**Files:**
- Modify: `libs/WebBridge/WebBridge.m` (buildDashboardConfig method)
@@ -2621,7 +2621,7 @@ function config = buildDashboardConfig(obj)
sigIdx = 0;
for i = 1:numel(config.widgets)
w = config.widgets{i};
- if strcmp(w.type, 'fastplot') && sigIdx < numel(signals)
+ if strcmp(w.type, 'fastsense') && sigIdx < numel(signals)
sigIdx = sigIdx + 1;
config.widgets{i}.signalId = signals(sigIdx).id;
end
@@ -2631,7 +2631,7 @@ end
- [ ] **Step 2: Run existing WebBridge tests to verify no regressions**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridge')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridge')"`
Expected: PASS
- [ ] **Step 3: Commit**
@@ -2658,7 +2658,7 @@ Create `tests/suite/TestWebBridgeE2E.m`:
classdef TestWebBridgeE2E < matlab.unittest.TestCase
%TESTWEBBRIDGEE2E End-to-end test: MATLAB WebBridge + Python bridge.
%
- % Requires: Python 3.11+ with fastplot-bridge installed.
+ % Requires: Python 3.11+ with fastsense-bridge installed.
% Skip if not available.
methods (TestClassSetup)
@@ -2671,15 +2671,15 @@ classdef TestWebBridgeE2E < matlab.unittest.TestCase
methods (Test)
function testServeAndFetchData(testCase)
% Skip if Python bridge not installed
- [status, ~] = system('python -c "import fastplot_bridge"');
+ [status, ~] = system('python -c "import fastsense_bridge"');
testCase.assumeTrue(status == 0, ...
- 'fastplot-bridge Python package not installed');
+ 'fastsense-bridge Python package not installed');
% Create a dashboard with one signal
x = linspace(0, 100, 10000);
y = sin(x);
engine = DashboardEngine('E2E Test');
- engine.addWidget('fastplot', 'Title', 'Sine Wave', ...
+ engine.addWidget('fastsense', 'Title', 'Sine Wave', ...
'XData', x, 'YData', y, 'Position', [1 1 6 3]);
bridge = WebBridge(engine);
@@ -2710,7 +2710,7 @@ end
- [ ] **Step 2: Run the E2E test (requires Python bridge installed)**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "run_all_tests('TestWebBridgeE2E')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "run_all_tests('TestWebBridgeE2E')"`
Expected: PASS (or SKIP if Python not set up)
- [ ] **Step 3: Commit**
diff --git a/docs/superpowers/plans/2026-03-16-ci-readme-wiki.md b/docs/superpowers/plans/2026-03-16-ci-readme-wiki.md
index 694f48e9..8e1f4235 100644
--- a/docs/superpowers/plans/2026-03-16-ci-readme-wiki.md
+++ b/docs/superpowers/plans/2026-03-16-ci-readme-wiki.md
@@ -142,7 +142,7 @@ jobs:
- name: Package release
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
- DIRNAME="FastPlot-${VERSION}"
+ DIRNAME="FastSense-${VERSION}"
mkdir -p "${DIRNAME}"
# Copy release contents
@@ -173,8 +173,8 @@ jobs:
Download the archive, extract it, and run `setup` in MATLAB/Octave to add libraries to path and compile MEX accelerators.
files: |
- FastPlot-${{ steps.version.outputs.VERSION }}.tar.gz
- FastPlot-${{ steps.version.outputs.VERSION }}.zip
+ FastSense-${{ steps.version.outputs.VERSION }}.tar.gz
+ FastSense-${{ steps.version.outputs.VERSION }}.zip
```
- [ ] **Step 2: Verify YAML syntax**
@@ -205,9 +205,9 @@ git commit -m "ci: add release pipeline with test gate and auto-packaging"
Replace the entire `README.md` with a concise version. Key content:
```markdown
-# FastPlot
+# FastSense
-[](https://github.com/HanSur94/FastPlot/actions/workflows/tests.yml)
+[](https://github.com/HanSur94/FastSense/actions/workflows/tests.yml)
[](LICENSE)
[](https://www.mathworks.com/products/matlab.html)
[](https://octave.org)
@@ -215,7 +215,7 @@ Replace the entire `README.md` with a concise version. Key content:
Ultra-fast time series plotting for MATLAB and GNU Octave. Plot 100M+ data points with fluid zoom and pan — rendering only ~4,000 points at any zoom level.
-
+
## Performance
@@ -253,7 +253,7 @@ setup; % adds libraries to path + compiles MEX
x = linspace(0, 100, 1e7);
y = sin(x) + 0.1 * randn(size(x));
-fp = FastPlot('Theme', 'dark');
+fp = FastSense('Theme', 'dark');
fp.addLine(x, y, 'DisplayName', 'Sensor');
fp.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
@@ -263,8 +263,8 @@ fp.render();
## Installation
```bash
-git clone https://github.com/HanSur94/FastPlot.git
-cd FastPlot
+git clone https://github.com/HanSur94/FastSense.git
+cd FastSense
```
Then in MATLAB or Octave:
@@ -279,26 +279,26 @@ No toolbox dependencies. MEX compilation is optional — pure MATLAB fallbacks a
## Documentation
-Full documentation is available in the [Wiki](https://github.com/HanSur94/FastPlot/wiki):
+Full documentation is available in the [Wiki](https://github.com/HanSur94/FastSense/wiki):
-- [Getting Started](https://github.com/HanSur94/FastPlot/wiki/Getting-Started) — tutorial with examples
-- [API Reference: FastPlot](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-FastPlot) — core plotting class
-- [API Reference: Dashboard](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Dashboard) — layouts, widgets, engine
-- [API Reference: Sensors](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Sensors) — sensor system
-- [API Reference: Event Detection](https://github.com/HanSur94/FastPlot/wiki/API-Reference:-Event-Detection) — event pipeline
-- [Architecture](https://github.com/HanSur94/FastPlot/wiki/Architecture) — render pipeline, data flow
-- [MEX Acceleration](https://github.com/HanSur94/FastPlot/wiki/MEX-Acceleration) — SIMD details
-- [Performance](https://github.com/HanSur94/FastPlot/wiki/Performance) — benchmarks
+- [Getting Started](https://github.com/HanSur94/FastSense/wiki/Getting-Started) — tutorial with examples
+- [API Reference: FastSense](https://github.com/HanSur94/FastSense/wiki/API-Reference:-FastSense) — core plotting class
+- [API Reference: Dashboard](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Dashboard) — layouts, widgets, engine
+- [API Reference: Sensors](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Sensors) — sensor system
+- [API Reference: Event Detection](https://github.com/HanSur94/FastSense/wiki/API-Reference:-Event-Detection) — event pipeline
+- [Architecture](https://github.com/HanSur94/FastSense/wiki/Architecture) — render pipeline, data flow
+- [MEX Acceleration](https://github.com/HanSur94/FastSense/wiki/MEX-Acceleration) — SIMD details
+- [Performance](https://github.com/HanSur94/FastSense/wiki/Performance) — benchmarks
## Examples
-See the [`examples/`](examples/) directory for 40+ runnable scripts covering basic plotting, dashboards, sensors, event detection, live mode, and disk-backed storage. A categorized guide is in the [wiki](https://github.com/HanSur94/FastPlot/wiki/Examples).
+See the [`examples/`](examples/) directory for 40+ runnable scripts covering basic plotting, dashboards, sensors, event detection, live mode, and disk-backed storage. A categorized guide is in the [wiki](https://github.com/HanSur94/FastSense/wiki/Examples).
## Libraries
| Library | Path | Description |
|---------|------|-------------|
-| FastPlot | `libs/FastPlot/` | Core plotting engine, layouts, toolbar, themes, disk storage |
+| FastSense | `libs/FastSense/` | Core plotting engine, layouts, toolbar, themes, disk storage |
| SensorThreshold | `libs/SensorThreshold/` | Sensor containers, state channels, threshold rules |
| EventDetection | `libs/EventDetection/` | Event detection, viewer, live pipeline, notifications |
| Dashboard | `libs/Dashboard/` | Dashboard engine with widgets and JSON persistence |
@@ -306,17 +306,17 @@ See the [`examples/`](examples/) directory for 40+ runnable scripts covering bas
## Contributing
-Contributions are welcome! Please open an issue to discuss your idea before submitting a pull request. See the [wiki](https://github.com/HanSur94/FastPlot/wiki) for architecture details and API references.
+Contributions are welcome! Please open an issue to discuss your idea before submitting a pull request. See the [wiki](https://github.com/HanSur94/FastSense/wiki) for architecture details and API references.
## Citation
-If you use FastPlot in your research, please cite it:
+If you use FastSense in your research, please cite it:
```bibtex
-@software{fastplot,
+@software{fastsense,
author = {Suhr, Hannes},
- title = {FastPlot: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave},
- url = {https://github.com/HanSur94/FastPlot},
+ title = {FastSense: Ultra-Fast Time Series Plotting for MATLAB and GNU Octave},
+ url = {https://github.com/HanSur94/FastSense},
license = {MIT}
}
```
@@ -353,7 +353,7 @@ quick start, feature highlights, and links to detailed docs."
Run:
```bash
-gh repo edit HanSur94/FastPlot \
+gh repo edit HanSur94/FastSense \
--description "Ultra-fast time series plotting for MATLAB & Octave — 10M+ points at 200+ FPS with interactive zoom/pan"
```
@@ -361,7 +361,7 @@ gh repo edit HanSur94/FastPlot \
Run:
```bash
-gh repo edit HanSur94/FastPlot \
+gh repo edit HanSur94/FastSense \
--add-topic matlab \
--add-topic octave \
--add-topic plotting \
@@ -375,7 +375,7 @@ gh repo edit HanSur94/FastPlot \
- [ ] **Step 3: Verify**
-Run: `gh repo view HanSur94/FastPlot --json description,repositoryTopics`
+Run: `gh repo view HanSur94/FastSense --json description,repositoryTopics`
---
@@ -390,7 +390,7 @@ The wiki lives in `wiki/` as a separate git repo. All edits are made to files in
- [ ] **Step 1: Update the libraries table**
-Add the WebBridge row to the libraries table in `wiki/Home.md`. The current table lists 4 libraries (FastPlot, SensorThreshold, EventDetection, Dashboard) — add a 5th row:
+Add the WebBridge row to the libraries table in `wiki/Home.md`. The current table lists 4 libraries (FastSense, SensorThreshold, EventDetection, Dashboard) — add a 5th row:
```markdown
| WebBridge | `libs/WebBridge/` | TCP server for web-based visualization |
@@ -437,7 +437,7 @@ Read the following files to extract current method signatures, properties, and c
- `libs/Dashboard/TextWidget.m`
- `libs/Dashboard/RawAxesWidget.m`
- `libs/Dashboard/EventTimelineWidget.m`
-- `libs/Dashboard/FastPlotWidget.m`
+- `libs/Dashboard/FastSenseWidget.m`
- `libs/Dashboard/DashboardLayout.m`
- `libs/Dashboard/DashboardSerializer.m`
- `libs/Dashboard/DashboardTheme.m`
@@ -532,11 +532,11 @@ cd wiki && git add -A && git commit -m "docs: add IncrementalEventDetector, Data
- Modify: `wiki/Architecture.md`
- Modify: `wiki/Examples.md`
- Modify: `wiki/_Sidebar.md`
-- Verify (read-only): `wiki/Installation.md`, `wiki/Getting-Started.md`, `wiki/API-Reference:-FastPlot.md`, `wiki/API-Reference:-Themes.md`, `wiki/Live-Mode-Guide.md`, `wiki/Datetime-Guide.md`, `wiki/MEX-Acceleration.md`, `wiki/Performance.md`, `wiki/Use-Case:-Multi-Sensor-Shared-Threshold.md`
+- Verify (read-only): `wiki/Installation.md`, `wiki/Getting-Started.md`, `wiki/API-Reference:-FastSense.md`, `wiki/API-Reference:-Themes.md`, `wiki/Live-Mode-Guide.md`, `wiki/Datetime-Guide.md`, `wiki/MEX-Acceleration.md`, `wiki/Performance.md`, `wiki/Use-Case:-Multi-Sensor-Shared-Threshold.md`
- [ ] **Step 1: Update Utilities API reference**
-Read `wiki/API-Reference:-Utilities.md` and `libs/FastPlot/ConsoleProgressBar.m`. Add documentation for hierarchical progress display features (nested bars, `addChild()`, etc.) if missing.
+Read `wiki/API-Reference:-Utilities.md` and `libs/FastSense/ConsoleProgressBar.m`. Add documentation for hierarchical progress display features (nested bars, `addChild()`, etc.) if missing.
- [ ] **Step 2: Update Architecture page**
@@ -568,7 +568,7 @@ Add to `wiki/_Sidebar.md` under Guides:
Read each of these pages and compare key details against current source code. Fix any discrepancies found:
- `wiki/Installation.md` — verify requirements, setup steps
- `wiki/Getting-Started.md` — verify example code runs
-- `wiki/API-Reference:-FastPlot.md` — verify method signatures
+- `wiki/API-Reference:-FastSense.md` — verify method signatures
- `wiki/API-Reference:-Themes.md` — verify theme names and options
- `wiki/Live-Mode-Guide.md` — verify live mode API
- `wiki/Datetime-Guide.md` — verify datetime handling
@@ -601,7 +601,7 @@ Read:
- [ ] **Step 2: Write the guide**
Create `wiki/Dashboard-Engine-Guide.md` covering:
-- Overview of DashboardEngine vs FastPlotFigure (when to use which)
+- Overview of DashboardEngine vs FastSenseFigure (when to use which)
- Building dashboards with DashboardBuilder (fluent API walkthrough)
- Widget types and their options (with small code examples)
- Saving and loading dashboards (JSON serialization)
@@ -646,9 +646,9 @@ Expected: A workflow run in progress or completed
- [ ] **Step 3: Verify repo metadata**
-Run: `gh repo view HanSur94/FastPlot --json description,repositoryTopics`
+Run: `gh repo view HanSur94/FastSense --json description,repositoryTopics`
Expected: Description and topics are set correctly
- [ ] **Step 4: Verify README renders on GitHub**
-Open `https://github.com/HanSur94/FastPlot` and confirm the new README looks correct with badges, image, and formatting.
+Open `https://github.com/HanSur94/FastSense` and confirm the new README looks correct with badges, image, and formatting.
diff --git a/docs/superpowers/plans/2026-03-16-dashboard-widget-rework.md b/docs/superpowers/plans/2026-03-16-dashboard-widget-rework.md
index e00b0ca4..1809a1ad 100644
--- a/docs/superpowers/plans/2026-03-16-dashboard-widget-rework.md
+++ b/docs/superpowers/plans/2026-03-16-dashboard-widget-rework.md
@@ -4,7 +4,7 @@
**Goal:** Rework all dashboard widgets to use Sensor-first data binding, rename KpiWidget→NumberWidget, add 4 gauge styles, rework StatusWidget layout, and add Description tooltip to all widgets.
-**Architecture:** Move `SensorObj` from FastPlotWidget to the `DashboardWidget` base class. Each widget derives its display (value, units, range, colors) from the bound Sensor and its ThresholdRules. Add `Description` property with info icon hover to base class. GaugeWidget gains 4 rendering styles. StatusWidget uses ThresholdRule.Color for dot color.
+**Architecture:** Move `SensorObj` from FastSenseWidget to the `DashboardWidget` base class. Each widget derives its display (value, units, range, colors) from the bound Sensor and its ThresholdRules. Add `Description` property with info icon hover to base class. GaugeWidget gains 4 rendering styles. StatusWidget uses ThresholdRule.Color for dot color.
**Tech Stack:** MATLAB R2020b, figure-based UI (uipanel, uicontrol, axes), no uifigure.
@@ -33,7 +33,7 @@ end
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestSensor', 'ProcedureName', 'testUnitsProperty')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestSensor', 'ProcedureName', 'testUnitsProperty')"`
Expected: FAIL — 'Units' is not a property
- [ ] **Step 3: Add Units property to Sensor.m**
@@ -48,7 +48,7 @@ And in the constructor, add support for the name-value pair (the existing loop `
- [ ] **Step 4: Run test to verify it passes**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestSensor', 'ProcedureName', 'testUnitsProperty')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestSensor', 'ProcedureName', 'testUnitsProperty')"`
Expected: PASS
- [ ] **Step 5: Commit**
@@ -104,7 +104,7 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestDashboardWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestDashboardWidget')"`
Expected: FAIL — Description and SensorObj not recognized
- [ ] **Step 3: Implement base class changes**
@@ -174,7 +174,7 @@ Add a `getTheme` utility method (currently duplicated in every widget — centra
- [ ] **Step 4: Run tests to verify they pass**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestDashboardWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestDashboardWidget')"`
Expected: PASS
- [ ] **Step 5: Commit**
@@ -203,7 +203,7 @@ Each file has a private method block at the end with only `getTheme` in it. Dele
- [ ] **Step 2: Run all existing widget tests to verify nothing breaks**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestKpiWidget'); runtests('tests/suite/TestGaugeWidget'); runtests('tests/suite/TestStatusWidget'); runtests('tests/suite/TestFastPlotWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestKpiWidget'); runtests('tests/suite/TestGaugeWidget'); runtests('tests/suite/TestStatusWidget'); runtests('tests/suite/TestFastSenseWidget')"`
Expected: All PASS
- [ ] **Step 3: Commit**
@@ -273,7 +273,7 @@ In `libs/Dashboard/DashboardSerializer.m`, at the switch block (lines 68-88), re
- [ ] **Step 5: Run TestNumberWidget**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
Expected: All PASS
- [ ] **Step 6: Commit**
@@ -325,7 +325,7 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget', 'ProcedureName', 'testSensorBinding')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget', 'ProcedureName', 'testSensorBinding')"`
Expected: FAIL
- [ ] **Step 3: Implement Sensor binding in NumberWidget**
@@ -471,7 +471,7 @@ Update `fromStruct()` to handle sensor source:
- [ ] **Step 4: Run all NumberWidget tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
Expected: All PASS
- [ ] **Step 5: Commit**
@@ -530,7 +530,7 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestStatusWidget', 'ProcedureName', 'testSensorBindingNoViolation')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestStatusWidget', 'ProcedureName', 'testSensorBindingNoViolation')"`
Expected: FAIL
- [ ] **Step 3: Implement Sensor-bound StatusWidget**
@@ -757,7 +757,7 @@ end
- [ ] **Step 4: Run all StatusWidget tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestStatusWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestStatusWidget')"`
Expected: All PASS
- [ ] **Step 5: Commit**
@@ -803,7 +803,7 @@ end
- [ ] **Step 2: Run test to verify it fails**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget', 'ProcedureName', 'testSensorBinding')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget', 'ProcedureName', 'testSensorBinding')"`
Expected: FAIL
- [ ] **Step 3: Implement Sensor binding**
@@ -928,7 +928,7 @@ Extract the arc rendering into `updateDisplay()` (refactored from existing refre
- [ ] **Step 4: Run all GaugeWidget tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget')"`
Expected: All PASS
- [ ] **Step 5: Commit**
@@ -994,7 +994,7 @@ end
- [ ] **Step 2: Run tests to verify they fail**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget', 'ProcedureName', 'testDonutStyle')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget', 'ProcedureName', 'testDonutStyle')"`
Expected: FAIL — Style property not recognized or donut rendering not implemented
- [ ] **Step 3: Implement the render dispatcher and three new styles**
@@ -1265,7 +1265,7 @@ Update `toStruct()` and `fromStruct()` to serialize `style`:
- [ ] **Step 4: Run all GaugeWidget tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestGaugeWidget')"`
Expected: All PASS
- [ ] **Step 5: Commit**
@@ -1279,18 +1279,18 @@ git commit -m "feat: add donut, bar, thermometer styles to GaugeWidget"
## Chunk 5: Remaining Widget Updates
-### Task 9: Update FastPlotWidget to use base class SensorObj
+### Task 9: Update FastSenseWidget to use base class SensorObj
**Files:**
-- Modify: `libs/Dashboard/FastPlotWidget.m`
-- Test: `tests/suite/TestFastPlotWidget.m`
+- Modify: `libs/Dashboard/FastSenseWidget.m`
+- Test: `tests/suite/TestFastSenseWidget.m`
-- [ ] **Step 1: Remove SensorObj property from FastPlotWidget**
+- [ ] **Step 1: Remove SensorObj property from FastSenseWidget**
-`SensorObj` is now on the base class. Remove it from `libs/Dashboard/FastPlotWidget.m` line 13. Add 'Sensor' shorthand mapping in the constructor. Update constructor to delegate to base class:
+`SensorObj` is now on the base class. Remove it from `libs/Dashboard/FastSenseWidget.m` line 13. Add 'Sensor' shorthand mapping in the constructor. Update constructor to delegate to base class:
```matlab
- function obj = FastPlotWidget(varargin)
+ function obj = FastSenseWidget(varargin)
for k = 1:2:numel(varargin)
if strcmp(varargin{k}, 'Sensor')
varargin{k} = 'SensorObj';
@@ -1318,16 +1318,16 @@ git commit -m "feat: add donut, bar, thermometer styles to GaugeWidget"
Remove the `SensorObj = []` from the public properties block (line 13). The rest of the class already references `obj.SensorObj` which will now resolve to the base class property.
-- [ ] **Step 2: Run existing FastPlotWidget tests**
+- [ ] **Step 2: Run existing FastSenseWidget tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestFastPlotWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestFastSenseWidget')"`
Expected: All PASS
- [ ] **Step 3: Commit**
```bash
-git add libs/Dashboard/FastPlotWidget.m
-git commit -m "refactor: FastPlotWidget uses base class SensorObj"
+git add libs/Dashboard/FastSenseWidget.m
+git commit -m "refactor: FastSenseWidget uses base class SensorObj"
```
---
@@ -1426,7 +1426,7 @@ Add `'Sensor'` shorthand in constructor. Update `refresh()`:
- [ ] **Step 3: Run tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestTableWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestTableWidget')"`
Expected: All PASS
- [ ] **Step 4: Commit**
@@ -1491,7 +1491,7 @@ Add `'Sensor'` shorthand mapping in constructor.
- [ ] **Step 2: Run existing tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite')"`
Expected: All PASS
- [ ] **Step 3: Commit**
@@ -1560,7 +1560,7 @@ This replaces the existing color selection block. When `ColorSource == 'theme'`,
- [ ] **Step 3: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite')"`
Expected: All PASS
- [ ] **Step 4: Commit**
@@ -1626,8 +1626,8 @@ Update `configToWidgets` signature to accept an optional resolver function handl
for i = 1:numel(config.widgets)
ws = config.widgets{i};
switch ws.type
- case 'fastplot'
- widgets{i} = FastPlotWidget.fromStruct(ws);
+ case 'fastsense'
+ widgets{i} = FastSenseWidget.fromStruct(ws);
case {'number', 'kpi'}
widgets{i} = NumberWidget.fromStruct(ws);
case 'status'
@@ -1662,7 +1662,7 @@ Update `configToWidgets` signature to accept an optional resolver function handl
- [ ] **Step 3: Run all tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite')"`
Expected: All PASS
- [ ] **Step 4: Commit**
@@ -1682,7 +1682,7 @@ git commit -m "feat: add SensorResolver to DashboardEngine.load()"
- [ ] **Step 1: Verify NumberWidget works as replacement**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestNumberWidget')"`
Expected: All PASS
- [ ] **Step 2: Delete old files**
@@ -1707,7 +1707,7 @@ Run grep to find all usages, then update each file.
- [ ] **Step 2: Run full test suite**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite')"`
Expected: All PASS
- [ ] **Step 3: Commit**
@@ -1730,7 +1730,7 @@ The palette sidebar creates buttons for each widget type. Update the 'kpi' butto
- [ ] **Step 2: Run builder tests**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); runtests('tests/suite/TestDashboardBuilder')"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); runtests('tests/suite/TestDashboardBuilder')"`
Expected: All PASS
- [ ] **Step 3: Commit**
@@ -1746,7 +1746,7 @@ git commit -m "chore: update DashboardBuilder palette for NumberWidget"
- [ ] **Step 1: Run the full test suite**
-Run: `cd /Users/hannessuhr/FastPlot && matlab -batch "setup(); results = runtests('tests/suite'); disp(table(results))"`
+Run: `cd /Users/hannessuhr/FastSense && matlab -batch "setup(); results = runtests('tests/suite'); disp(table(results))"`
Expected: All PASS, no warnings about deprecated 'kpi' in test code
- [ ] **Step 2: Verify all changes are committed**
diff --git a/docs/superpowers/specs/2026-03-11-sensor-detail-plot-design.md b/docs/superpowers/specs/2026-03-11-sensor-detail-plot-design.md
index 1a3b2008..fc9bf2a4 100644
--- a/docs/superpowers/specs/2026-03-11-sensor-detail-plot-design.md
+++ b/docs/superpowers/specs/2026-03-11-sensor-detail-plot-design.md
@@ -6,21 +6,21 @@ A two-panel composite plot for sensor data. The upper panel shows a zoomable det
## Architecture
-Two new classes in `libs/FastPlot/`:
+Two new classes in `libs/FastSense/`:
-- **`SensorDetailPlot.m`** — Coordinator. Creates two `FastPlot` instances (main + navigator), wires bidirectional zoom synchronization, manages event rendering.
+- **`SensorDetailPlot.m`** — Coordinator. Creates two `FastSense` instances (main + navigator), wires bidirectional zoom synchronization, manages event rendering.
- **`NavigatorOverlay.m`** — Handles the zoom rectangle, dimming patches, and drag interaction on the navigator axes.
## Layout
```
┌──────────────────────────────────────┐
-│ Main Plot (80%) FastPlot │
+│ Main Plot (80%) FastSense │
│ - Sensor data line │
│ - Threshold lines + violations │
│ - Event shading (optional) │
├──────────────────────────────────────┤
-│ Navigator (20%) FastPlot │
+│ Navigator (20%) FastSense │
│ - Full data range line │
│ - Threshold bands (subtle fills) │
│ - Event vertical lines (optional) │
@@ -46,7 +46,7 @@ sdp = SensorDetailPlot(sensor, Name, Value, ...)
| Name | Type | Default | Description |
|------|------|---------|-------------|
-| `Theme` | string or struct | `'default'` | FastPlot theme preset or custom struct |
+| `Theme` | string or struct | `'default'` | FastSense theme preset or custom struct |
| `NavigatorHeight` | double (0–1) | `0.20` | Fraction of total height for navigator |
| `ShowThresholds` | logical | `true` | Show threshold lines + violations in main plot |
| `ShowThresholdBands` | logical | `true` | Show threshold bands in navigator |
@@ -64,13 +64,13 @@ sdp.setZoomRange(xMin, xMax) % Programmatically set visible range
sdp.delete() % Clean up listeners, callbacks, handles
```
-Calling `render()` twice throws an error (same guard as `FastPlot`).
+Calling `render()` twice throws an error (same guard as `FastSense`).
### Properties (read-only)
```matlab
-sdp.MainPlot % FastPlot instance for the upper panel
-sdp.NavigatorPlot % FastPlot instance for the lower panel
+sdp.MainPlot % FastSense instance for the upper panel
+sdp.NavigatorPlot % FastSense instance for the lower panel
```
`MainPlot` is exposed so users can add extra elements (markers, bands, etc.) to the detail view.
@@ -102,8 +102,8 @@ sdp.render();
sdp = SensorDetailPlot(s, 'Events', store, 'Theme', 'dark');
sdp.render();
-% Inside FastPlotFigure (uses new tilePanel method)
-fig = FastPlotFigure(2, 1, 'Theme', 'dark');
+% Inside FastSenseFigure (uses new tilePanel method)
+fig = FastSenseFigure(2, 1, 'Theme', 'dark');
sdp = SensorDetailPlot(s, 'Parent', fig.tilePanel(1), 'Events', store);
sdp.render();
fig.renderAll();
@@ -114,7 +114,7 @@ fig.renderAll();
### Sensor Data + Thresholds
- When `SensorDetailPlot.ShowThresholds = true`, calls `MainPlot.addSensor(sensor, 'ShowThresholds', true)` which renders the data line, threshold lines, and violation markers. When `false`, calls `addSensor(sensor, 'ShowThresholds', false)` (data line only, no thresholds).
-- Inherits all existing FastPlot behavior: downsampling on zoom, pyramid caching, NaN gap handling.
+- Inherits all existing FastSense behavior: downsampling on zoom, pyramid caching, NaN gap handling.
### Event Shading
@@ -128,14 +128,14 @@ When `Events` is provided:
- `Direction = 'low'` — cool colors (blue, alpha 0.12)
- Two-tier escalation: if `ThresholdLabel` contains `'HH'` or `'LL'` (case-insensitive), use stronger color (red / dark blue, alpha 0.15). This matches the `escalateTo()` convention where escalated events get a new `ThresholdLabel`.
- Fallback — theme accent color, alpha 0.10
-5. All Event statistics are attached to the patch `UserData` struct: `ThresholdLabel`, `Direction`, `Duration`, `PeakValue`, `MeanValue`, `MinValue`, `MaxValue`, `RmsValue`, `StdValue`, `NumPoints`. This makes all event data available to `FastPlotToolbar` cursor/crosshair.
+5. All Event statistics are attached to the patch `UserData` struct: `ThresholdLabel`, `Direction`, `Duration`, `PeakValue`, `MeanValue`, `MinValue`, `MaxValue`, `RmsValue`, `StdValue`, `NumPoints`. This makes all event data available to `FastSenseToolbar` cursor/crosshair.
6. No permanent text labels on the plot.
## Lower Plot (Navigator)
### Full Data Range
-- Renders the sensor data line using `FastPlot.addLine()` across the full time range.
+- Renders the sensor data line using `FastSense.addLine()` across the full time range.
- Navigator axes XLim is fixed to `[min(sensor.X), max(sensor.X)]` and does not change.
- Navigator axes YLim is computed from `[min(sensor.Y), max(sensor.Y)]` with 5% padding, set after all elements are drawn, then fixed. This prevents threshold bands and dim patches from affecting the Y scale.
- MATLAB's built-in zoom and pan tools are disabled on the navigator axes (`zoom(hNavAxes, 'off')`, `pan(hNavAxes, 'off')`) to preserve the full-range invariant.
@@ -201,7 +201,7 @@ overlay.setRange(xMin, xMax); % Programmatic update
```
User zooms/pans in main plot
- → FastPlot XLim PostSet listener fires
+ → FastSense XLim PostSet listener fires
→ SensorDetailPlot receives new XLim
→ Calls NavigatorOverlay.setRange(xMin, xMax)
→ Overlay updates rectangle + dim patches
@@ -210,48 +210,48 @@ User drags in navigator
→ NavigatorOverlay fires OnRangeChanged(xMin, xMax)
→ SensorDetailPlot receives callback
→ Sets MainPlot axes XLim
- → FastPlot zoom listener fires, re-downsamples visible data
+ → FastSense zoom listener fires, re-downsamples visible data
```
A guard flag (`IsPropagating`) prevents infinite callback loops (main→navigator→main→...).
-**Design note:** This intentionally does not use FastPlot's `LinkGroup` mechanism. `LinkGroup` propagates XLim changes between peer FastPlot instances that all re-downsample on zoom. The navigator must not re-downsample or change its XLim — it always shows the full range. The bespoke guard flag approach is simpler and avoids `resetplotview` / `XLimMode='auto'` side effects that `LinkGroup` handles for peer plots but that would break navigator invariants.
+**Design note:** This intentionally does not use FastSense's `LinkGroup` mechanism. `LinkGroup` propagates XLim changes between peer FastSense instances that all re-downsample on zoom. The navigator must not re-downsample or change its XLim — it always shows the full range. The bespoke guard flag approach is simpler and avoids `resetplotview` / `XLimMode='auto'` side effects that `LinkGroup` handles for peer plots but that would break navigator invariants.
## Cleanup
-Both classes implement `delete()` methods following the `onCleanup`/`DeleteFcn` pattern used in `FastPlotFigure`:
+Both classes implement `delete()` methods following the `onCleanup`/`DeleteFcn` pattern used in `FastSenseFigure`:
- **`SensorDetailPlot.delete()`** — Removes the XLim PostSet listener on the main axes. Calls `NavigatorOverlay.delete()`. If the figure was self-created (no `Parent`), sets `CloseRequestFcn` to trigger cleanup on figure close.
- **`NavigatorOverlay.delete()`** — Removes `WindowButtonDownFcn`, `WindowButtonMotionFcn`, `WindowButtonUpFcn` callbacks. Removes `SizeChangedFcn` listener. Deletes graphics handles (`hRegion`, `hDimLeft`, `hDimRight`, `hEdgeLeft`, `hEdgeRight`).
This prevents dead listeners and stale figure callbacks when plots are closed and re-opened in the same MATLAB session.
-## Integration with FastPlotFigure
+## Integration with FastSenseFigure
When `Parent` is provided:
-- `SensorDetailPlot` accepts a `uipanel` handle as `Parent`. This handle is NOT passed through to `FastPlot`'s `'Parent'` option.
-- Instead, `SensorDetailPlot` creates two sub-panels inside it, then creates axes within each sub-panel, and passes those axes to the internal `FastPlot` instances via `FastPlot('Parent', hAxes)`.
+- `SensorDetailPlot` accepts a `uipanel` handle as `Parent`. This handle is NOT passed through to `FastSense`'s `'Parent'` option.
+- Instead, `SensorDetailPlot` creates two sub-panels inside it, then creates axes within each sub-panel, and passes those axes to the internal `FastSense` instances via `FastSense('Parent', hAxes)`.
- Does not create its own figure window.
-**New method required on `FastPlotFigure`:** `tilePanel(n)` — returns a `uipanel` handle at the computed position for tile `n`. This is distinct from the existing `tile(n)` (returns a `FastPlot`) and `axes(n)` (returns a raw axes). The `tilePanel(n)` method creates an empty `uipanel` at the tile's grid position, allowing composite widgets like `SensorDetailPlot` to manage their own internal layout within a dashboard tile. Calling `tilePanel(n)` on a tile already occupied by `tile(n)` or `axes(n)` throws a `tileConflict` error, same as the existing `tile(n)` vs `axes(n)` mutual exclusion guard.
+**New method required on `FastSenseFigure`:** `tilePanel(n)` — returns a `uipanel` handle at the computed position for tile `n`. This is distinct from the existing `tile(n)` (returns a `FastSense`) and `axes(n)` (returns a raw axes). The `tilePanel(n)` method creates an empty `uipanel` at the tile's grid position, allowing composite widgets like `SensorDetailPlot` to manage their own internal layout within a dashboard tile. Calling `tilePanel(n)` on a tile already occupied by `tile(n)` or `axes(n)` throws a `tileConflict` error, same as the existing `tile(n)` vs `axes(n)` mutual exclusion guard.
-**Axes creation in Parent path:** `SensorDetailPlot` is responsible for creating the axes within each sub-panel via `axes('Parent', subPanel)`, then passing those axes handles to the internal `FastPlot` instances via `FastPlot('Parent', hAxes)`.
+**Axes creation in Parent path:** `SensorDetailPlot` is responsible for creating the axes within each sub-panel via `axes('Parent', subPanel)`, then passing those axes handles to the internal `FastSense` instances via `FastSense('Parent', hAxes)`.
## File Locations
| File | Location |
|------|----------|
-| `SensorDetailPlot.m` | `libs/FastPlot/SensorDetailPlot.m` |
-| `NavigatorOverlay.m` | `libs/FastPlot/NavigatorOverlay.m` |
+| `SensorDetailPlot.m` | `libs/FastSense/SensorDetailPlot.m` |
+| `NavigatorOverlay.m` | `libs/FastSense/NavigatorOverlay.m` |
| `example_sensor_detail.m` | `examples/example_sensor_detail.m` |
| `test_SensorDetailPlot.m` | `tests/test_SensorDetailPlot.m` |
| `test_NavigatorOverlay.m` | `tests/test_NavigatorOverlay.m` |
## Dependencies
-- `FastPlot` — rendering engine for both panels
+- `FastSense` — rendering engine for both panels
- `Sensor`, `ThresholdRule`, `StateChannel` — sensor data model
- `EventStore`, `Event` — event data (optional)
-- `FastPlotFigure` — for dashboard embedding (optional)
-- `FastPlotTheme` — theme system
+- `FastSenseFigure` — for dashboard embedding (optional)
+- `FastSenseTheme` — theme system
diff --git a/docs/superpowers/specs/2026-03-13-web-bridge-design.md b/docs/superpowers/specs/2026-03-13-web-bridge-design.md
index 76b37ac4..89ee9072 100644
--- a/docs/superpowers/specs/2026-03-13-web-bridge-design.md
+++ b/docs/superpowers/specs/2026-03-13-web-bridge-design.md
@@ -5,7 +5,7 @@
## Overview
-A bidirectional communication layer that makes FastPlot data, metadata, and dashboard state accessible to web frontends in real-time while MATLAB is running. MATLAB runs a minimal TCP server; a separate bridge process (Python or Node.js) serves a REST API, WebSocket, and web UI.
+A bidirectional communication layer that makes FastSense data, metadata, and dashboard state accessible to web frontends in real-time while MATLAB is running. MATLAB runs a minimal TCP server; a separate bridge process (Python or Node.js) serves a REST API, WebSocket, and web UI.
## Goals
@@ -138,10 +138,10 @@ A standalone process (Python or Node) connecting to MATLAB's TCP server.
```bash
# Launched automatically by MATLAB's .serve() via system()
# Or manually:
-fastplot-bridge --matlab-port 5555
+fastsense-bridge --matlab-port 5555
# Node
-npx fastplot-bridge --matlab-port 5555
+npx fastsense-bridge --matlab-port 5555
```
### Components
@@ -210,7 +210,7 @@ For the data endpoint, X/Y chunks are always `mxDOUBLE` (class_id=6). Extra colu
### Server-Side Downsampling
-The data endpoint accepts an optional `maxPoints` query parameter (default: 4000). When the requested range contains more points than `maxPoints`, the bridge applies minmax downsampling (keep min/max per bucket) server-side before returning JSON. This matches FastPlot's existing downsampling strategy and keeps browser payloads manageable.
+The data endpoint accepts an optional `maxPoints` query parameter (default: 4000). When the requested range contains more points than `maxPoints`, the bridge applies minmax downsampling (keep min/max per bucket) server-side before returning JSON. This matches FastSense's existing downsampling strategy and keeps browser payloads manageable.
### Signal Identity
@@ -225,7 +225,7 @@ Vanilla HTML/JS/CSS served by the bridge.
1. **Chart Viewer** — uPlot library for fast rendering of large datasets. Zoom/pan triggers data re-fetch via REST API with `maxPoints` parameter. Threshold lines and violation markers overlaid.
2. **Dashboard Layout** — Reads config from `/api/dashboard`, renders a CSS grid of widgets:
- - FastPlotWidget → Chart Viewer (uPlot)
+ - FastSenseWidget → Chart Viewer (uPlot)
- KpiWidget → Big number display
- StatusWidget → Color-coded badge
- TableWidget → HTML table
@@ -259,7 +259,7 @@ libs/
bridge/
python/
- fastplot_bridge/
+ fastsense_bridge/
__init__.py
server.py — FastAPI app (REST + WebSocket)
tcp_client.py — MATLAB TCP connection
@@ -303,7 +303,7 @@ bridge/
7. Bridge sends `{"type":"bridge_ready","httpPort":8080}` to MATLAB via TCP
8. MATLAB prints: `Dashboard served at http://localhost:`
-**Blocking behavior:** `.serve()` blocks until `bridge_ready` is received or a 10-second timeout fires. If the timeout fires, WebBridge throws: `'Bridge did not start within 10s. Check that fastplot-bridge is installed.'` Actions can be registered before or after `.serve()` — the action list is sent as part of `init` and refreshed via `config_changed` when new actions are added.
+**Blocking behavior:** `.serve()` blocks until `bridge_ready` is received or a 10-second timeout fires. If the timeout fires, WebBridge throws: `'Bridge did not start within 10s. Check that fastsense-bridge is installed.'` Actions can be registered before or after `.serve()` — the action list is sent as part of `init` and refreshed via `config_changed` when new actions are added.
**Config change detection:** A MATLAB timer polls every 1 second, comparing a hash of the serialized dashboard config. Configurable via `WebBridge('ConfigPollInterval', N)`.
@@ -345,7 +345,7 @@ MATLAB is single-threaded. Action callbacks execute on the MATLAB event queue (l
## SQLite Configuration for Concurrent Access
-Each `FastPlotDataStore` gains two methods: `enableWAL()` and `disableWAL()`. These run on the DataStore's own mksqlite connection (ensuring no connection ownership conflicts):
+Each `FastSenseDataStore` gains two methods: `enableWAL()` and `disableWAL()`. These run on the DataStore's own mksqlite connection (ensuring no connection ownership conflicts):
**`enableWAL()`** — called by WebBridge on `.serve()`:
```sql
diff --git a/docs/superpowers/specs/2026-03-16-ci-readme-wiki-design.md b/docs/superpowers/specs/2026-03-16-ci-readme-wiki-design.md
index 1faf40b7..b6b3c789 100644
--- a/docs/superpowers/specs/2026-03-16-ci-readme-wiki-design.md
+++ b/docs/superpowers/specs/2026-03-16-ci-readme-wiki-design.md
@@ -60,7 +60,7 @@ Add GitHub Actions CI/CD pipelines (test + release), replace the 43KB reference-
1. **Gate:** Run Octave tests (same as test pipeline Octave job)
2. **Package:** Create archive containing:
- - `libs/` (all 5 libraries: FastPlot, SensorThreshold, EventDetection, Dashboard, WebBridge)
+ - `libs/` (all 5 libraries: FastSense, SensorThreshold, EventDetection, Dashboard, WebBridge)
- MEX C source files included, compiled `.mex*` binaries **excluded** (users compile via `setup.m`)
- Must explicitly filter `*.mexmaca64`, `*.mexmaci64`, `*.mexa64`, `*.mexw64`, `*.mex` since some are tracked in git despite `.gitignore`
- `setup.m`
@@ -72,18 +72,18 @@ Add GitHub Actions CI/CD pipelines (test + release), replace the 43KB reference-
4. **Release:** Create GitHub Release via `softprops/action-gh-release@v2`
- Title: tag name (e.g., `v1.5.0`)
- Body: auto-generated changelog
- - Assets: `FastPlot-v1.5.0.zip` and `FastPlot-v1.5.0.tar.gz` (version includes `v` prefix)
+ - Assets: `FastSense-v1.5.0.zip` and `FastSense-v1.5.0.tar.gz` (version includes `v` prefix)
### Archive Structure
```
-FastPlot-v1.5.0/
+FastSense-v1.5.0/
├── setup.m
├── LICENSE
├── README.md
├── CITATION.cff
├── libs/
-│ ├── FastPlot/
+│ ├── FastSense/
│ ├── SensorThreshold/
│ ├── EventDetection/
│ ├── Dashboard/
@@ -103,7 +103,7 @@ Replace the current 43KB README with a concise (~150-200 lines) overview.
### Structure
-1. **Title + tagline** — "FastPlot — Ultra-fast time series plotting for MATLAB & Octave"
+1. **Title + tagline** — "FastSense — Ultra-fast time series plotting for MATLAB & Octave"
2. **Badges** — CI status (pointing to `tests.yml` on `main`), license (MIT), MATLAB R2020b+, Octave 7+
3. **One-paragraph description** — what it does, key performance claim
4. **Screenshot** — existing `docs/images/` hero image
@@ -151,7 +151,7 @@ Update all 17 wiki pages to reflect the current project state.
| Home.md | Add Dashboard Engine v2, WebBridge, NumberWidget, new widget types |
| Installation.md | Verify requirements still accurate |
| Getting-Started.md | Ensure examples use current API |
-| API-Reference: FastPlot.md | Verify method signatures match current code |
+| API-Reference: FastSense.md | Verify method signatures match current code |
| API-Reference: Dashboard.md | Add DashboardEngine, DashboardBuilder, new widgets (Gauge, Number, Status, Table, Text, RawAxes, EventTimeline) |
| API-Reference: Sensors.md | Add SensorRegistry, verify ThresholdRule API |
| API-Reference: Event-Detection.md | Add IncrementalEventDetector, DataSourceMap, NotificationRule updates |
diff --git a/docs/superpowers/specs/2026-03-16-dashboard-widget-rework-design.md b/docs/superpowers/specs/2026-03-16-dashboard-widget-rework-design.md
index 603ac238..1572b6dc 100644
--- a/docs/superpowers/specs/2026-03-16-dashboard-widget-rework-design.md
+++ b/docs/superpowers/specs/2026-03-16-dashboard-widget-rework-design.md
@@ -28,7 +28,7 @@ All widgets inherit from `DashboardWidget`. The following properties are added o
|---|---|---|---|
| `Title` | char | `Sensor.Name` or `''` | Display title. Defaults to Sensor name when bound. |
| `Description` | char | `''` | Optional tooltip text, shown via info icon hover on the widget header. |
-| `SensorObj` | Sensor | `[]` | Primary data binding. Moved from FastPlotWidget to base class. |
+| `SensorObj` | Sensor | `[]` | Primary data binding. Moved from FastSenseWidget to base class. |
| `Position` | 1x4 double | widget-specific | `[col, row, width, height]` in grid units (unchanged). |
| `ThemeOverride` | struct | `struct()` | Per-widget theme overrides (unchanged). |
| `UseGlobalTime` | logical | `true` | Follow global time slider (unchanged). |
@@ -45,7 +45,7 @@ When `Description` is non-empty, the widget header renders a small `(i)` icon ne
## Widget Specifications
-### 1. FastPlotWidget
+### 1. FastSenseWidget
**Binding:** Single Sensor (primary), DataStore, File, or inline XData/YData (fallbacks).
@@ -54,7 +54,7 @@ When `Description` is non-empty, the widget header renders a small `(i)` icon ne
- ThresholdRules auto-resolve — violation markers and bands render automatically
- XLabel defaults to `'Time'`, YLabel defaults to `Sensor.Units`
-**Unchanged behavior:** Creates a `FastPlot` instance inside its panel. Full zoom/pan/downsample support. `setTimeRange()` updates xlim when `UseGlobalTime` is true. User zoom sets `UseGlobalTime = false`.
+**Unchanged behavior:** Creates a `FastSense` instance inside its panel. Full zoom/pan/downsample support. `setTimeRange()` updates xlim when `UseGlobalTime` is true. User zoom sets `UseGlobalTime = false`.
**Default size:** 12 cols x 3 rows.
@@ -223,7 +223,7 @@ The `DashboardEngine.addWidget()` method signature remains the same but all widg
```matlab
% Sensor-first (recommended for all sensor-bound widgets)
-d.addWidget('fastplot', 'Sensor', sTemp, 'Position', [1 1 12 3]);
+d.addWidget('fastsense', 'Sensor', sTemp, 'Position', [1 1 12 3]);
d.addWidget('number', 'Sensor', sTemp, 'Position', [13 1 6 1]);
d.addWidget('gauge', 'Sensor', sPressure, 'Style', 'donut', 'Position', [13 2 6 2]);
d.addWidget('status', 'Sensor', sTemp, 'Position', [19 1 6 1]);
@@ -238,7 +238,7 @@ d.addWidget('text', 'Title', 'Section A', 'Content', 'Overview', 'Position', [1
```
**Type string mapping:**
-- `'fastplot'` → FastPlotWidget
+- `'fastsense'` → FastSenseWidget
- `'number'` → NumberWidget (was `'kpi'`)
- `'gauge'` → GaugeWidget
- `'status'` → StatusWidget
@@ -306,7 +306,7 @@ The existing live timer architecture is unchanged. On each tick:
- GaugeWidget: re-evaluates `Sensor.Y(end)`, updates needle/fill
- StatusWidget: re-checks current violations, updates dot color
- TableWidget: re-queries last N data points or events
- - FastPlotWidget: re-renders with latest Sensor data
+ - FastSenseWidget: re-renders with latest Sensor data
- RawAxesWidget: clears and re-calls PlotFcn with updated Sensor
- EventTimelineWidget: re-queries EventStore
- TextWidget: no-op (static)
@@ -322,7 +322,7 @@ The existing live timer architecture is unchanged. On each tick:
- `KpiWidget.m` → `NumberWidget.m`
### Moved Properties
-- `SensorObj` moves from `FastPlotWidget` to `DashboardWidget` base class
+- `SensorObj` moves from `FastSenseWidget` to `DashboardWidget` base class
### API Changes
- `DashboardEngine.load(filepath)` gains an optional name-value parameter: `'SensorResolver'`, a function handle `@(key) -> Sensor`. Existing single-argument calls continue to work (default resolver attempts `SensorRegistry.get(key)` if available, otherwise leaves widget unbound).
diff --git a/examples/demo_all.m b/examples/demo_all.m
index d659a1ed..2eaf788c 100644
--- a/examples/demo_all.m
+++ b/examples/demo_all.m
@@ -1,25 +1,25 @@
-%% FastPlot Interactive Demo
+%% FastSense Interactive Demo
% Opens all example plots and keeps them alive for interactive exploration.
% Zoom and pan on any figure as long as you want.
% Press Enter in the command window to close all figures and exit.
%
% Usage:
% From MATLAB/Octave command window:
-% cd FastPlot/examples
+% cd FastSense/examples
% demo_all
%
% From terminal (Octave — requires GUI for interactive zoom/pan):
-% cd FastPlot
-% octave --gui --eval "run('setup.m'); addpath('libs/FastPlot/private'); addpath('examples'); demo_all;"
+% cd FastSense
+% octave --gui --eval "run('setup.m'); addpath('libs/FastSense/private'); addpath('examples'); demo_all;"
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
-addpath(fullfile(projectRoot, 'libs', 'FastPlot', 'private'));
+addpath(fullfile(projectRoot, 'libs', 'FastSense', 'private'));
addpath(fileparts(mfilename('fullpath')));
fprintf('\n');
fprintf(' =============================================\n');
-fprintf(' FastPlot Interactive Demo\n');
+fprintf(' FastSense Interactive Demo\n');
fprintf(' =============================================\n');
fprintf(' Opening all example plots...\n\n');
diff --git a/examples/example_100M.m b/examples/example_100M.m
index 3ce6de65..3be5aaca 100644
--- a/examples/example_100M.m
+++ b/examples/example_100M.m
@@ -1,4 +1,4 @@
-%% FastPlot Stress Test — 100M points
+%% FastSense Stress Test — 100M points
% Demonstrates performance at maximum scale
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -14,11 +14,11 @@
fprintf('Rendering...\n');
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', '100M Random Walk', 'Color', [0 0.4 0.8]);
fp.addThreshold(3, 'Direction', 'upper', 'ShowViolations', true);
fp.addThreshold(-3, 'Direction', 'lower', 'ShowViolations', true);
fp.render();
fprintf('Rendered in %.3f seconds. Zoom in to see detail!\n', toc);
-title(fp.hAxes, 'FastPlot — 100M Points Stress Test');
+title(fp.hAxes, 'FastSense — 100M Points Stress Test');
diff --git a/examples/example_alarm_bands.m b/examples/example_alarm_bands.m
index 1663098a..bfef3cf8 100644
--- a/examples/example_alarm_bands.m
+++ b/examples/example_alarm_bands.m
@@ -1,4 +1,4 @@
-%% FastPlot Alarm Bands — Industrial sensor with 4 thresholds
+%% FastSense Alarm Bands — Industrial sensor with 4 thresholds
% Demonstrates warning + alarm thresholds in both directions
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -17,7 +17,7 @@
fprintf('Alarm Bands: %d points, 4 thresholds...\n', n);
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Process Variable', 'Color', [0.2 0.4 0.7]);
% Alarm limits (red, dashed) — hard limits
diff --git a/examples/example_basic.m b/examples/example_basic.m
index 83fd8c7e..2a08c31f 100644
--- a/examples/example_basic.m
+++ b/examples/example_basic.m
@@ -1,4 +1,4 @@
-%% FastPlot Basic Example — 10M points single line
+%% FastSense Basic Example — 10M points single line
% Demonstrates basic usage with a large time series
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -8,10 +8,10 @@
x = linspace(0, 100, n);
y = sin(x * 2 * pi / 10) + 0.5 * randn(1, n);
-fprintf('Creating FastPlot with %d points...\n', n);
+fprintf('Creating FastSense with %d points...\n', n);
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Noisy Sine', 'Color', [0 0.4470 0.7410]);
% Alarm thresholds (red, dashed)
@@ -29,5 +29,5 @@
fp.render();
fprintf('Rendered in %.3f seconds. Try zooming and panning!\n', toc);
-title(fp.hAxes, 'FastPlot — 10M Points');
+title(fp.hAxes, 'FastSense — 10M Points');
legend(fp.hAxes, 'show');
diff --git a/examples/example_dashboard.m b/examples/example_dashboard.m
index c63d915b..b9c77045 100644
--- a/examples/example_dashboard.m
+++ b/examples/example_dashboard.m
@@ -1,14 +1,14 @@
-%% FastPlot Dashboard — Tiled layout with themes and visual enhancements
-% Demonstrates FastPlotGrid, theming, bands, shading, and markers.
+%% FastSense Dashboard — Tiled layout with themes and visual enhancements
+% Demonstrates FastSenseGrid, theming, bands, shading, and markers.
%
% Choosing your dashboard approach:
-% FastPlotGrid — Lightweight tiled grid of FastPlot instances.
+% FastSenseGrid — Lightweight tiled grid of FastSense instances.
% Best for: pure time-series dashboards with linked zoom, tile
% spanning, and SensorDetailPlot embedding. No widget types beyond
% plots. See also: example_dashboard_9tile, example_sensor_dashboard.
%
% DashboardEngine — Full widget-based dashboard with toolbar, edit mode,
-% JSON save/load, and 8 widget types (fastplot, number, status,
+% JSON save/load, and 8 widget types (fastsense, number, status,
% gauge, text, table, rawaxes, timeline). Uses a 24-column grid
% with Position = [col row width height].
% See also: example_dashboard_engine, example_dashboard_all_widgets.
@@ -24,8 +24,8 @@
fprintf('Dashboard example: 4 tiles, %d points each, dark theme...\n', n);
tic;
-fig = FastPlotGrid(2, 2, 'Theme', 'light', ...
- 'Name', 'FastPlot Dashboard Demo', 'Position', [50 50 1400 800]);
+fig = FastSenseGrid(2, 2, 'Theme', 'light', ...
+ 'Name', 'FastSense Dashboard Demo', 'Position', [50 50 1400 800]);
% --- Tile 1: Temperature with alarm bands (spans 2 columns) ---
fig.setTileSpan(1, [1 2]);
diff --git a/examples/example_dashboard_9tile.m b/examples/example_dashboard_9tile.m
index 1b223b9a..0345d178 100644
--- a/examples/example_dashboard_9tile.m
+++ b/examples/example_dashboard_9tile.m
@@ -1,4 +1,4 @@
-%% FastPlot 3x3 Dashboard — Industrial Monitoring Console
+%% FastSense 3x3 Dashboard — Industrial Monitoring Console
% 9 tiles with different signals, data sizes, and features.
close all force;
@@ -9,7 +9,7 @@
fprintf('3x3 Dashboard: 9 tiles, mixed data sizes, dark theme...\n');
tic;
-fig = FastPlotGrid(3, 3, 'Theme', 'light', ...
+fig = FastSenseGrid(3, 3, 'Theme', 'light', ...
'Name', 'Industrial Monitoring Console', 'Position', [30 30 1800 1000]);
% =========================================================================
diff --git a/examples/example_dashboard_all_widgets.m b/examples/example_dashboard_all_widgets.m
index 450b1662..5455aaa3 100644
--- a/examples/example_dashboard_all_widgets.m
+++ b/examples/example_dashboard_all_widgets.m
@@ -2,7 +2,7 @@
% Demonstrates every widget type in a single dashboard, wired to Sensor
% objects with dynamic thresholds via StateChannels.
%
-% FastPlot widgets: bound to Sensors with resolved thresholds
+% FastSense widgets: bound to Sensors with resolved thresholds
% Number/Gauge/Status: driven by sensor data (latest value / threshold check)
% Text/Table: static display (no interactivity needed)
% Timeline: derived from threshold violations
@@ -212,17 +212,17 @@
'Position', [20 1 5 2], ...
'Sensor', sPress);
-% --- Row 3-10: Sensor-driven FastPlot widgets with thresholds ---
-d.addWidget('fastplot', ...
+% --- Row 3-10: Sensor-driven FastSense widgets with thresholds ---
+d.addWidget('fastsense', ...
'Position', [1 3 12 8], ...
'Sensor', sTemp);
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [13 3 12 8], ...
'Sensor', sPress);
% --- Row 11-18: Flow plot + Table + Histogram + Gauge ---
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [1 11 12 8], ...
'Sensor', sFlow);
diff --git a/examples/example_dashboard_engine.m b/examples/example_dashboard_engine.m
index dc23fad0..6b6b4c56 100644
--- a/examples/example_dashboard_engine.m
+++ b/examples/example_dashboard_engine.m
@@ -1,5 +1,5 @@
%% Dashboard Engine Example — Sensor-Driven
-% Demonstrates: DashboardEngine with FastPlotWidgets bound to Sensors,
+% Demonstrates: DashboardEngine with FastSenseWidgets bound to Sensors,
% dynamic thresholds via StateChannels, JSON save/load.
%
% DashboardEngine uses a 24-column grid. Widget positions are specified as
@@ -53,15 +53,15 @@
d.Theme = 'light';
d.LiveInterval = 5;
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [1 1 16 8], ...
'Sensor', sTemp);
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [17 1 8 8], ...
'Sensor', sPress);
-d.addWidget('fastplot', 'Title', 'Temperature (full view)', ...
+d.addWidget('fastsense', 'Title', 'Temperature (full view)', ...
'Position', [1 9 24 8], ...
'Sensor', sTemp);
diff --git a/examples/example_dashboard_live.m b/examples/example_dashboard_live.m
index 3f6aa2e6..7a1f9636 100644
--- a/examples/example_dashboard_live.m
+++ b/examples/example_dashboard_live.m
@@ -6,7 +6,7 @@
% text — static header
% number — sensor-bound big number with trend arrow
% status — sensor-bound colored indicator (auto ok/warning/alarm)
-% fastplot — sensor-bound plots with thresholds + violation markers
+% fastsense — sensor-bound plots with thresholds + violation markers
% gauge — sensor-bound arc gauge
% rawaxes — live histogram via PlotFcn
% table — alarm log driven by DataFcn
@@ -124,17 +124,17 @@ function example_dashboard_live_run()
'Position', [20 1 5 2], ...
'Sensor', sPress);
- % --- Row 3-10: Sensor-bound FastPlot widgets (thresholds + violations) ---
- d.addWidget('fastplot', ...
+ % --- Row 3-10: Sensor-bound FastSense widgets (thresholds + violations) ---
+ d.addWidget('fastsense', ...
'Position', [1 3 12 8], ...
'Sensor', sTemp);
- d.addWidget('fastplot', ...
+ d.addWidget('fastsense', ...
'Position', [13 3 12 8], ...
'Sensor', sPress);
% --- Row 11-18: Flow + Gauge + Histogram ---
- d.addWidget('fastplot', ...
+ d.addWidget('fastsense', ...
'Position', [1 11 12 8], ...
'Sensor', sFlow);
diff --git a/examples/example_datetime.m b/examples/example_datetime.m
index c9d69180..44754bdf 100644
--- a/examples/example_datetime.m
+++ b/examples/example_datetime.m
@@ -1,4 +1,4 @@
-%% FastPlot Datetime X-Axis Demo
+%% FastSense Datetime X-Axis Demo
% Demonstrates auto-formatted date/time tick labels that adapt to zoom level.
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -16,27 +16,27 @@
%% Plot 1: With datetime X axis + toolbar
tic;
-fp1 = FastPlot('Theme', 'light');
+fp1 = FastSense('Theme', 'light');
fp1.addLine(x, y, 'DisplayName', 'Temperature', 'XType', 'datenum');
fp1.addThreshold(24, 'Direction', 'upper', 'ShowViolations', true);
fp1.render();
title(fp1.hAxes, 'With datenum + toolbar');
-tb1 = FastPlotToolbar(fp1);
+tb1 = FastSenseToolbar(fp1);
fprintf('Datetime + toolbar rendered in %.3f seconds.\n', toc);
%% Plot 2: Plain numeric X axis + toolbar
tic;
-fp2 = FastPlot('Theme', 'light');
+fp2 = FastSense('Theme', 'light');
fp2.addLine(x, y, 'DisplayName', 'Temperature');
fp2.addThreshold(24, 'Direction', 'upper', 'ShowViolations', true);
fp2.render();
title(fp2.hAxes, 'Without datenum + toolbar');
-tb2 = FastPlotToolbar(fp2);
+tb2 = FastSenseToolbar(fp2);
fprintf('Numeric + toolbar rendered in %.3f seconds.\n', toc);
%% Plot 3: With datetime X axis, no toolbar
tic;
-fp3 = FastPlot('Theme', 'light');
+fp3 = FastSense('Theme', 'light');
fp3.addLine(x, y, 'DisplayName', 'Temperature', 'XType', 'datenum');
fp3.addThreshold(24, 'Direction', 'upper', 'ShowViolations', true);
fp3.render();
@@ -45,7 +45,7 @@
%% Plot 4: Plain numeric X axis, no toolbar
tic;
-fp4 = FastPlot('Theme', 'light');
+fp4 = FastSense('Theme', 'light');
fp4.addLine(x, y, 'DisplayName', 'Temperature');
fp4.addThreshold(24, 'Direction', 'upper', 'ShowViolations', true);
fp4.render();
diff --git a/examples/example_disk_storage.m b/examples/example_disk_storage.m
index 066933a6..7096b97d 100644
--- a/examples/example_disk_storage.m
+++ b/examples/example_disk_storage.m
@@ -1,4 +1,4 @@
-%% FastPlot Disk Storage Example — SQLite-backed large datasets
+%% FastSense Disk Storage Example — SQLite-backed large datasets
% Demonstrates how to use disk-backed storage to plot datasets that
% exceed available RAM. Data is stored in a temporary SQLite database
% and only the visible slice is loaded into memory on zoom/pan.
@@ -7,7 +7,7 @@
run(fullfile(projectRoot, 'setup.m'));
%% 1. Automatic disk offload (default behaviour)
-% In 'auto' mode (the default), FastPlot stores data on disk when it
+% In 'auto' mode (the default), FastSense stores data on disk when it
% exceeds MemoryLimit (default 500 MB = ~31M double-precision points).
fprintf('=== Auto mode: small data stays in memory ===\n');
@@ -15,7 +15,7 @@
x = linspace(0, 100, n_small);
y = sin(x) + 0.3 * randn(1, n_small);
-fp1 = FastPlot(); % StorageMode='auto', MemoryLimit=500e6
+fp1 = FastSense(); % StorageMode='auto', MemoryLimit=500e6
fp1.addLine(x, y, 'DisplayName', '1M pts (in memory)');
fp1.render();
title(fp1.hAxes, 'Auto Mode — 1M Points (in memory)');
@@ -29,7 +29,7 @@
y = sin(x / 20) .* cos(x / 7) + 0.2 * randn(1, n_medium);
tic;
-fp2 = FastPlot('StorageMode', 'disk');
+fp2 = FastSense('StorageMode', 'disk');
fp2.addLine(x, y, 'DisplayName', '5M pts (disk)', 'Color', [0.8 0.2 0.1]);
fp2.addThreshold(1.0, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', 'r', 'LineStyle', '--', 'Label', 'Upper Limit');
@@ -46,7 +46,7 @@
x = linspace(0, 200, n_mid);
y = cumsum(randn(1, n_mid)) / sqrt(n_mid);
-fp3 = FastPlot('MemoryLimit', 10e6); % 10 MB threshold
+fp3 = FastSense('MemoryLimit', 10e6); % 10 MB threshold
fp3.addLine(x, y, 'DisplayName', '2M pts (auto-offloaded)', ...
'Color', [0.1 0.6 0.3]);
fp3.render();
@@ -56,14 +56,14 @@
clear x y;
%% 4. Direct DataStore usage for advanced workflows
-fprintf('\n=== Direct FastPlotDataStore API ===\n');
+fprintf('\n=== Direct FastSenseDataStore API ===\n');
n_large = 10e6;
x = linspace(0, 1000, n_large);
y = sin(x / 50) + 0.1 * randn(1, n_large);
fprintf(' Creating DataStore with %dM points...\n', n_large / 1e6);
tic;
-ds = FastPlotDataStore(x, y);
+ds = FastSenseDataStore(x, y);
fprintf(' Created in %.3f s\n', toc);
clear x y;
@@ -103,7 +103,7 @@
end
tic;
-fp5 = FastPlot('StorageMode', 'disk');
+fp5 = FastSense('StorageMode', 'disk');
fp5.addLine(x, y, 'DisplayName', '50M pts (disk)', 'Color', [0.2 0.3 0.8]);
fp5.render();
tRender = toc;
diff --git a/examples/example_dock.m b/examples/example_dock.m
index 120fd8e7..deb1c28f 100644
--- a/examples/example_dock.m
+++ b/examples/example_dock.m
@@ -1,6 +1,6 @@
-%% FastPlotDock — Tabbed Dashboard Example
+%% FastSenseDock — Tabbed Dashboard Example
% Five dashboards docked in a single window with tab switching.
-% All tabs use datetime X axes (auto-detected by FastPlot).
+% All tabs use datetime X axes (auto-detected by FastSense).
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
@@ -12,7 +12,7 @@
fprintf('Docked Tabs: 5 dashboards in 1 window...\n');
tic;
-dock = FastPlotDock('Theme', 'light', 'Name', 'Control Room', ...
+dock = FastSenseDock('Theme', 'light', 'Name', 'Control Room', ...
'Position', [50 50 1400 800]);
% Common time base: 1 hour of data starting now
@@ -25,7 +25,7 @@
% =========================================================================
% Tab 1: Temperature Monitoring (2x2)
% =========================================================================
-fig1 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig1 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
fp = fig1.tile(1);
n = 2e6; t = linspace(t0, t1, n); s = sec(t);
@@ -60,7 +60,7 @@
% =========================================================================
% Tab 2: Power Systems (1x2)
% =========================================================================
-fig2 = FastPlotGrid(1, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig2 = FastSenseGrid(1, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
fp = fig2.tile(1);
n = 3e6; t = linspace(t0, t1, n); s = sec(t);
@@ -78,7 +78,7 @@
% =========================================================================
% Tab 3: Hydraulics (2x1)
% =========================================================================
-fig3 = FastPlotGrid(2, 1, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig3 = FastSenseGrid(2, 1, 'ParentFigure', dock.hFigure, 'Theme', 'light');
fp = fig3.tile(1);
n = 1.5e6; t = linspace(t0, t1, n); s = sec(t);
@@ -99,7 +99,7 @@
% =========================================================================
% Tab 4: Electrical Grid (1x3)
% =========================================================================
-fig4 = FastPlotGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig4 = FastSenseGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'light');
fp = fig4.tile(1);
n = 2e6; t = linspace(t0, t1, n); s = sec(t);
@@ -124,7 +124,7 @@
% =========================================================================
% Tab 5: Environment (2x2) — 24h span
% =========================================================================
-fig5 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig5 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
te0 = datetime(2026, 3, 8, 0, 0, 0);
te1 = datetime(2026, 3, 8, 23, 59, 59);
diff --git a/examples/example_dock_disk.m b/examples/example_dock_disk.m
index a067e897..6482a268 100644
--- a/examples/example_dock_disk.m
+++ b/examples/example_dock_disk.m
@@ -1,4 +1,4 @@
-%% FastPlotDock — Disk-Backed Dashboard with Dynamic Thresholds
+%% FastSenseDock — Disk-Backed Dashboard with Dynamic Thresholds
%
% Five dashboards in a tabbed dock window, all using disk-backed storage.
% Each sensor has state-dependent (dynamic) thresholds that change with
@@ -22,7 +22,7 @@
fprintf('Generating ~100M data points across 5 tabs (all disk-backed)...\n\n');
tic;
-dock = FastPlotDock('Theme', 'dark', 'Name', 'Plant Control Room — Disk Mode', ...
+dock = FastSenseDock('Theme', 'dark', 'Name', 'Plant Control Room — Disk Mode', ...
'Position', [50 50 1500 900]);
% ---------- Shared time base: 8h shift ----------
@@ -35,7 +35,7 @@
% Tab 1: Turbine Monitoring (2x2) — ~28M points
% =========================================================================
fprintf('Tab 1: Turbine Monitoring...\n');
-fig1 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+fig1 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
% Turbine operates in 3 modes over the shift
scTurbine = StateChannel('turbine');
@@ -162,7 +162,7 @@
% Tab 2: Chemical Process (2x2) — ~22M points
% =========================================================================
fprintf('Tab 2: Chemical Process...\n');
-fig2 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+fig2 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
% Reactor modes: batch phases
scReactor = StateChannel('phase');
@@ -286,7 +286,7 @@
% Tab 3: Compressor Station (1x3) — ~18M points
% =========================================================================
fprintf('Tab 3: Compressor Station...\n');
-fig3 = FastPlotGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+fig3 = FastSenseGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
% Compressor modes
scComp = StateChannel('stage');
@@ -386,7 +386,7 @@
% Tab 4: Power Generation (2x2) — ~24M points
% =========================================================================
fprintf('Tab 4: Power Generation...\n');
-fig4 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+fig4 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
% Generator modes
scGen = StateChannel('gen');
@@ -499,7 +499,7 @@
% Tab 5: Environmental (1x3) — ~11M points
% =========================================================================
fprintf('Tab 5: Environmental...\n');
-fig5 = FastPlotGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+fig5 = FastSenseGrid(1, 3, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
% HVAC modes
scHvac = StateChannel('hvac');
diff --git a/examples/example_dock_many_tabs.m b/examples/example_dock_many_tabs.m
index 5ba0a878..8db97471 100644
--- a/examples/example_dock_many_tabs.m
+++ b/examples/example_dock_many_tabs.m
@@ -1,4 +1,4 @@
-%% FastPlotDock — Many Tabs (Scroll Arrows) Example
+%% FastSenseDock — Many Tabs (Scroll Arrows) Example
% 20 tabs in a single dock window to exercise the scrollable tab bar.
% Each tab gets a simple 1x1 figure with a sine wave variant.
@@ -11,7 +11,7 @@
fprintf('Docked Tabs: 20 tabs — testing scrollable tab bar...\n');
tic;
-dock = FastPlotDock('Theme', 'dark', 'Name', 'Many Tabs Demo', ...
+dock = FastSenseDock('Theme', 'dark', 'Name', 'Many Tabs Demo', ...
'Position', [50 50 1400 800]);
% Common time base
@@ -31,7 +31,7 @@
s = sec(t);
for k = 1:20
- fig = FastPlotGrid(1, 1, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
+ fig = FastSenseGrid(1, 1, 'ParentFigure', dock.hFigure, 'Theme', 'dark');
fp = fig.tile(1);
% Vary the signal per tab
diff --git a/examples/example_dynamic_thresholds_100M.m b/examples/example_dynamic_thresholds_100M.m
index 46e5fb90..eb9713f5 100644
--- a/examples/example_dynamic_thresholds_100M.m
+++ b/examples/example_dynamic_thresholds_100M.m
@@ -173,8 +173,8 @@
fprintf('========================================\n');
%% Plot first sensor as demo
-fprintf('\nPlotting first sensor with FastPlot...\n');
-fp = FastPlot();
+fprintf('\nPlotting first sensor with FastSense...\n');
+fp = FastSense();
fp.addSensor(sensors{1}, 'ShowThresholds', true);
fp.render();
title(fp.hAxes, sprintf('%s — 100M pts, 6 Dynamic Thresholds', ...
diff --git a/examples/example_ecg.m b/examples/example_ecg.m
index ab31e0f3..fb540f54 100644
--- a/examples/example_ecg.m
+++ b/examples/example_ecg.m
@@ -1,4 +1,4 @@
-%% FastPlot ECG — Simulated heart rhythm with arrhythmia detection
+%% FastSense ECG — Simulated heart rhythm with arrhythmia detection
% Demonstrates high sample rate biomedical data with tight thresholds
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -44,7 +44,7 @@
fprintf('ECG: %d points at %d Hz (%.0f min recording)...\n', n, fs, n/fs/60);
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'ECG Lead II', 'Color', [0 0.5 0]);
% Arrhythmia detection thresholds
diff --git a/examples/example_event_detection_live.m b/examples/example_event_detection_live.m
index ce176c28..028716d7 100644
--- a/examples/example_event_detection_live.m
+++ b/examples/example_event_detection_live.m
@@ -2,7 +2,7 @@ function example_event_detection_live()
%EXAMPLE_EVENT_DETECTION_LIVE Live event detection demo with industrial sensors.
% Demonstrates the EventDetection library with 3 mock industrial sensors,
% threshold-based event detection, console logging, EventViewer UI,
-% and a live FastPlot dashboard using startLive for real-time plotting.
+% and a live FastSense dashboard using startLive for real-time plotting.
%
% Run: example_event_detection_live()
% Stop: Close the Event Viewer or Live Plot figure to stop.
@@ -79,7 +79,7 @@ function example_event_detection_live()
liveN = N;
% --- 6. Write initial .mat files for live plotting ---
- liveDir = fullfile(tempdir, 'fastplot_event_live');
+ liveDir = fullfile(tempdir, 'fastsense_event_live');
if ~exist(liveDir, 'dir'); mkdir(liveDir); end
tempFile = fullfile(liveDir, 'temperature.mat');
@@ -90,13 +90,13 @@ function example_event_detection_live()
x = t; y = pressure; save(presFile, 'x', 'y');
x = t; y = vibration; save(vibFile, 'x', 'y');
- % --- 7. Open live FastPlot dashboard ---
+ % --- 7. Open live FastSense dashboard ---
hPlotFig = figure('Name', 'Live Sensor Dashboard', ...
'NumberTitle', 'off', 'Position', [150 50 1200 700]);
% Temperature plot
ax1 = subplot(3,1,1, 'Parent', hPlotFig);
- fpTemp = FastPlot('Parent', ax1, 'LinkGroup', 'live_demo');
+ fpTemp = FastSense('Parent', ax1, 'LinkGroup', 'live_demo');
fpTemp.addLine(t, temp, 'DisplayName', 'Temperature', 'Color', [0.8 0.2 0.1]);
fpTemp.addThreshold(85, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [1 0.8 0], 'LineStyle', '--', 'Label', 'temp warning');
@@ -108,7 +108,7 @@ function example_event_detection_live()
% Pressure plot
ax2 = subplot(3,1,2, 'Parent', hPlotFig);
- fpPres = FastPlot('Parent', ax2, 'LinkGroup', 'live_demo');
+ fpPres = FastSense('Parent', ax2, 'LinkGroup', 'live_demo');
fpPres.addLine(t, pressure, 'DisplayName', 'Pressure', 'Color', [0.2 0.5 1]);
fpPres.addThreshold(4, 'Direction', 'lower', 'ShowViolations', true, ...
'Color', [0.2 0.5 1], 'LineStyle', '--', 'Label', 'pressure low');
@@ -118,7 +118,7 @@ function example_event_detection_live()
% Vibration plot
ax3 = subplot(3,1,3, 'Parent', hPlotFig);
- fpVib = FastPlot('Parent', ax3, 'LinkGroup', 'live_demo');
+ fpVib = FastSense('Parent', ax3, 'LinkGroup', 'live_demo');
fpVib.addLine(t, vibration, 'DisplayName', 'Vibration', 'Color', [0.8 0.3 0.8]);
fpVib.addThreshold(5, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0.3 0.8], 'LineStyle', '--', 'Label', 'vibration high');
@@ -127,7 +127,7 @@ function example_event_detection_live()
ylabel(ax3, 'mm/s');
xlabel(ax3, 'Time (s)');
- % --- 8. Start FastPlot live mode (polls .mat files, auto-scrolls) ---
+ % --- 8. Start FastSense live mode (polls .mat files, auto-scrolls) ---
fpTemp.startLive(tempFile, @(fp, d) fp.updateData(1, d.x, d.y), ...
'Interval', 2, 'ViewMode', 'follow');
fpPres.startLive(presFile, @(fp, d) fp.updateData(1, d.x, d.y), ...
@@ -187,7 +187,7 @@ function generateData()
liveCfg.SensorData(i).y = s.Y;
end
- % Write updated data to .mat files — FastPlot startLive picks them up
+ % Write updated data to .mat files — FastSense startLive picks them up
sT = liveCfg.Sensors{1}; x = sT.X; y = sT.Y; save(tempFile, 'x', 'y');
sP = liveCfg.Sensors{2}; x = sP.X; y = sP.Y; save(presFile, 'x', 'y');
sV = liveCfg.Sensors{3}; x = sV.X; y = sV.Y; save(vibFile, 'x', 'y');
@@ -211,7 +211,7 @@ function stopAll()
stop(dataTimer);
delete(dataTimer);
end
- % Stop FastPlot live timers
+ % Stop FastSense live timers
try fpTemp.stopLive(); catch; end
try fpPres.stopLive(); catch; end
try fpVib.stopLive(); catch; end
diff --git a/examples/example_linked.m b/examples/example_linked.m
index 0f7607b4..6c26af29 100644
--- a/examples/example_linked.m
+++ b/examples/example_linked.m
@@ -1,4 +1,4 @@
-%% FastPlot Linked Axes Example
+%% FastSense Linked Axes Example
% Demonstrates synchronized zoom/pan across subplots
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -7,11 +7,11 @@
n = 5e6;
x = linspace(0, 100, n);
-fig = figure('Name', 'FastPlot Linked Axes', 'Position', [100 100 1200 600]);
+fig = figure('Name', 'FastSense Linked Axes', 'Position', [100 100 1200 600]);
% Top plot
ax1 = subplot(3,1,1, 'Parent', fig);
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'sync');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'sync');
fp1.addLine(x, sin(x * 2 * pi / 5) + 0.2*randn(1,n), ...
'DisplayName', 'Pressure', 'Color', 'b');
fp1.addThreshold(1.2, 'Direction', 'upper', 'ShowViolations', true);
@@ -20,7 +20,7 @@
% Middle plot
ax2 = subplot(3,1,2, 'Parent', fig);
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'sync');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'sync');
fp2.addLine(x, cos(x * 2 * pi / 8) + 0.3*randn(1,n), ...
'DisplayName', 'Temperature', 'Color', [0.8 0.3 0]);
fp2.render();
@@ -28,7 +28,7 @@
% Bottom plot
ax3 = subplot(3,1,3, 'Parent', fig);
-fp3 = FastPlot('Parent', ax3, 'LinkGroup', 'sync');
+fp3 = FastSense('Parent', ax3, 'LinkGroup', 'sync');
fp3.addLine(x, cumsum(randn(1,n))/sqrt(n), ...
'DisplayName', 'Vibration', 'Color', [0 0.6 0]);
fp3.render();
diff --git a/examples/example_live_pipeline.m b/examples/example_live_pipeline.m
index 23a38fd8..d5bbf2ec 100644
--- a/examples/example_live_pipeline.m
+++ b/examples/example_live_pipeline.m
@@ -139,7 +139,7 @@
% 3. EVENT STORE — atomic write with backup rotation
% ========================================================================
-storeFile = fullfile(tempdir, 'fastplot_live_events.mat');
+storeFile = fullfile(tempdir, 'fastsense_live_events.mat');
fprintf('Event store: %s\n', storeFile);
%% ========================================================================
@@ -157,7 +157,7 @@
% 5. NOTIFICATIONS — rule-based with priority matching and snapshots
% ========================================================================
-snapshotDir = fullfile(tempdir, 'fastplot_snapshots');
+snapshotDir = fullfile(tempdir, 'fastsense_snapshots');
fprintf('Snapshot directory: %s\n', snapshotDir);
notif = NotificationService('DryRun', true, 'SnapshotDir', snapshotDir);
@@ -165,7 +165,7 @@
% Default rule: catches all events not matched by specific rules (score=1)
notif.setDefaultRule(NotificationRule( ...
'Recipients', {{'ops-team@company.com'}}, ...
- 'Subject', '[FastPlot] {sensor}: {threshold} violation', ...
+ 'Subject', '[FastSense] {sensor}: {threshold} violation', ...
'Message', ['Sensor {sensor} violated {threshold} ({direction}) ' ...
'from {startTime} to {endTime}.\n' ...
'Peak: {peak}, Mean: {mean}, Std: {std}, Duration: {duration}'], ...
diff --git a/examples/example_lttb_vs_minmax.m b/examples/example_lttb_vs_minmax.m
index 35c00cfb..d41eb927 100644
--- a/examples/example_lttb_vs_minmax.m
+++ b/examples/example_lttb_vs_minmax.m
@@ -1,4 +1,4 @@
-%% FastPlot LTTB vs MinMax — Compare downsampling methods side by side
+%% FastSense LTTB vs MinMax — Compare downsampling methods side by side
% Shows visual difference between MinMax (preserves extremes) and LTTB (preserves shape)
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -15,7 +15,7 @@
% Top: MinMax (default)
ax1 = subplot(2,1,1, 'Parent', fig);
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'compare');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'compare');
fp1.addLine(x, y, 'DisplayName', 'MinMax', 'Color', [0 0.45 0.74], ...
'DownsampleMethod', 'minmax');
fp1.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true, ...
@@ -25,7 +25,7 @@
% Bottom: LTTB
ax2 = subplot(2,1,2, 'Parent', fig);
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'compare');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'compare');
fp2.addLine(x, y, 'DisplayName', 'LTTB', 'Color', [0.85 0.33 0.1], ...
'DownsampleMethod', 'lttb');
fp2.addThreshold(0.8, 'Direction', 'upper', 'ShowViolations', true, ...
diff --git a/examples/example_mixed_tiles.m b/examples/example_mixed_tiles.m
index abee432a..8bf3d0c9 100644
--- a/examples/example_mixed_tiles.m
+++ b/examples/example_mixed_tiles.m
@@ -1,6 +1,6 @@
-%% Mixed Tile Types — FastPlot + raw MATLAB axes in one dashboard
+%% Mixed Tile Types — FastSense + raw MATLAB axes in one dashboard
% Demonstrates using fig.axes(n) alongside fig.tile(n) for plot types
-% that FastPlot doesn't handle (bar, scatter, histogram, stem, etc.)
+% that FastSense doesn't handle (bar, scatter, histogram, stem, etc.)
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
@@ -8,13 +8,13 @@
n = 500000;
x = linspace(0, 120, n);
-fprintf('Mixed tile dashboard: 2x3 grid, FastPlot + raw axes...\n');
+fprintf('Mixed tile dashboard: 2x3 grid, FastSense + raw axes...\n');
tic;
-fig = FastPlotGrid(2, 3, 'Theme', 'light', ...
+fig = FastSenseGrid(2, 3, 'Theme', 'light', ...
'Name', 'Mixed Tile Types Demo', 'Position', [50 50 1500 800]);
-% --- Tile 1: FastPlot time series (temperature) ---
+% --- Tile 1: FastSense time series (temperature) ---
fp1 = fig.tile(1);
y_temp = 70 + 10*sin(x*2*pi/30) + 2*randn(1,n);
fp1.addLine(x, y_temp, 'DisplayName', 'Temperature');
@@ -37,7 +37,7 @@
colormap(ax3, 'parula');
grid(ax3, 'on');
-% --- Tile 4: FastPlot time series (pressure, spans 2 cols) ---
+% --- Tile 4: FastSense time series (pressure, spans 2 cols) ---
fig.setTileSpan(4, [1 2]);
fp4 = fig.tile(4);
y_press = 100 + 15*sin(x*2*pi/60) + 3*randn(1,n);
@@ -55,7 +55,7 @@
% Render all tiles
fig.renderAll();
-% Apply labels (works on both FastPlot and raw axes tiles)
+% Apply labels (works on both FastSense and raw axes tiles)
fig.setTileTitle(1, 'Temperature (C)');
fig.setTileXLabel(1, 'Time (s)');
fig.setTileTitle(2, 'Alarm Events / Day');
diff --git a/examples/example_multi.m b/examples/example_multi.m
index 01945e16..cc358132 100644
--- a/examples/example_multi.m
+++ b/examples/example_multi.m
@@ -1,4 +1,4 @@
-%% FastPlot Multi-Line Example — 5 sensors, 1M points each
+%% FastSense Multi-Line Example — 5 sensors, 1M points each
% Demonstrates multiple lines with thresholds
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -10,7 +10,7 @@
fprintf('Creating 5 lines x %d points = %d total...\n', n, 5*n);
tic;
-fp = FastPlot();
+fp = FastSense();
colors = [0 0.447 0.741; 0.85 0.325 0.098; 0.929 0.694 0.125; 0.494 0.184 0.556; 0.466 0.674 0.188];
for i = 1:5
y = sin(x * 2 * pi * i / 10) + 0.3 * randn(1, n) + i * 2;
@@ -22,5 +22,5 @@
fp.render();
fprintf('Rendered in %.3f seconds.\n', toc);
-title(fp.hAxes, 'FastPlot — 5 Lines x 1M Points');
+title(fp.hAxes, 'FastSense — 5 Lines x 1M Points');
legend(fp.hAxes, 'show');
diff --git a/examples/example_multi_sensor_linked.m b/examples/example_multi_sensor_linked.m
index 7cdc26e9..7efa0f5a 100644
--- a/examples/example_multi_sensor_linked.m
+++ b/examples/example_multi_sensor_linked.m
@@ -1,4 +1,4 @@
-%% FastPlot Multi-Sensor Linked — 4 sensors with independent thresholds, synchronized zoom
+%% FastSense Multi-Sensor Linked — 4 sensors with independent thresholds, synchronized zoom
% Simulates a real monitoring dashboard with different alarm levels per channel
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -15,7 +15,7 @@
% --- Channel 1: Temperature ---
ax1 = subplot(4,1,1, 'Parent', fig);
y_temp = 75 + 8*sin(x*2*pi/120) + 2*randn(1,n);
-fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'dashboard');
+fp1 = FastSense('Parent', ax1, 'LinkGroup', 'dashboard');
fp1.addLine(x, y_temp, 'DisplayName', 'Temperature', 'Color', [0.8 0.2 0.1]);
fp1.addThreshold(90, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0 0], 'LineStyle', '--', 'Label', 'HH');
@@ -31,7 +31,7 @@
% --- Channel 2: Pressure ---
ax2 = subplot(4,1,2, 'Parent', fig);
y_press = 100 + 15*sin(x*2*pi/200) + 5*randn(1,n);
-fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'dashboard');
+fp2 = FastSense('Parent', ax2, 'LinkGroup', 'dashboard');
fp2.addLine(x, y_press, 'DisplayName', 'Pressure', 'Color', [0.1 0.4 0.8]);
fp2.addThreshold(130, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0 0], 'LineStyle', '--', 'Label', 'HH');
@@ -50,7 +50,7 @@
% Add a ramp-up event
ramp_idx = round(n*0.6):round(n*0.65);
y_flow(ramp_idx) = y_flow(ramp_idx) + linspace(0, 25, numel(ramp_idx));
-fp3 = FastPlot('Parent', ax3, 'LinkGroup', 'dashboard');
+fp3 = FastSense('Parent', ax3, 'LinkGroup', 'dashboard');
fp3.addLine(x, y_flow, 'DisplayName', 'Flow Rate', 'Color', [0.2 0.6 0.2]);
fp3.addThreshold(75, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0 0], 'LineStyle', '--');
@@ -69,7 +69,7 @@
idx = round(t_fault*n/600):min(round((t_fault+5)*n/600), n);
y_vib(idx) = y_vib(idx) + 3*randn(1, numel(idx));
end
-fp4 = FastPlot('Parent', ax4, 'LinkGroup', 'dashboard');
+fp4 = FastSense('Parent', ax4, 'LinkGroup', 'dashboard');
fp4.addLine(x, y_vib, 'DisplayName', 'Vibration', 'Color', [0.5 0.2 0.6]);
fp4.addThreshold(4.0, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0 0], 'LineStyle', '--', 'Label', 'Danger');
diff --git a/examples/example_nan_gaps.m b/examples/example_nan_gaps.m
index f8881a99..4411c57c 100644
--- a/examples/example_nan_gaps.m
+++ b/examples/example_nan_gaps.m
@@ -1,5 +1,5 @@
-%% FastPlot NaN Gaps — Sensor dropout simulation
-% Demonstrates how FastPlot handles missing data (NaN gaps)
+%% FastSense NaN Gaps — Sensor dropout simulation
+% Demonstrates how FastSense handles missing data (NaN gaps)
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
@@ -19,7 +19,7 @@
fprintf('NaN Gaps: %d points with %d dropout regions...\n', n, numel(gap_starts));
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Sensor (with dropouts)', 'Color', [0 0.5 0.3]);
fp.addThreshold(1.0, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.9 0 0], 'LineStyle', '--', 'Label', 'Upper Limit');
diff --git a/examples/example_sensor_dashboard.m b/examples/example_sensor_dashboard.m
index ce5dcaba..b8fdaa95 100644
--- a/examples/example_sensor_dashboard.m
+++ b/examples/example_sensor_dashboard.m
@@ -1,6 +1,6 @@
-%% Multi-Sensor Dashboard — FastPlotGrid + SensorRegistry
+%% Multi-Sensor Dashboard — FastSenseGrid + SensorRegistry
% Demonstrates:
-% - FastPlotGrid tiled layout (2x2 grid)
+% - FastSenseGrid tiled layout (2x2 grid)
% - SensorRegistry for predefined sensor definitions
% - Multiple sensors each with different threshold configurations
% - Tile titles, labels, and per-tile theming
@@ -90,9 +90,9 @@
s4.resolve();
% ========================================================
-% Build 2x2 dashboard with FastPlotGrid
+% Build 2x2 dashboard with FastSenseGrid
% ========================================================
-fig = FastPlotGrid(2, 2, 'Name', 'Sensor Dashboard');
+fig = FastSenseGrid(2, 2, 'Name', 'Sensor Dashboard');
% Tile 1: Pressure
fp1 = fig.tile(1);
diff --git a/examples/example_sensor_detail.m b/examples/example_sensor_detail.m
index 4b0324f6..84df2686 100644
--- a/examples/example_sensor_detail.m
+++ b/examples/example_sensor_detail.m
@@ -3,7 +3,7 @@
% Demonstrates:
% 1. Standalone sensor detail plot with thresholds
% 2. Adding events from EventStore
-% 3. Embedding in a FastPlotGrid tile
+% 3. Embedding in a FastSenseGrid tile
%% Setup path
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -83,20 +83,20 @@
fprintf(' Press any key to continue...\n');
pause;
-%% 5. Embedded in FastPlotGrid
-fprintf('=== SensorDetailPlot: Embedded in FastPlotGrid ===\n');
-fig = FastPlotGrid(1, 2, 'Theme', 'light', 'Name', 'Sensor Dashboard');
+%% 5. Embedded in FastSenseGrid
+fprintf('=== SensorDetailPlot: Embedded in FastSenseGrid ===\n');
+fig = FastSenseGrid(1, 2, 'Theme', 'light', 'Name', 'Sensor Dashboard');
sdp3 = SensorDetailPlot(s, 'Parent', fig.tilePanel(1), ...
'Events', events, 'Title', 'Temperature');
sdp3.render();
-% Second tile: plain FastPlot for comparison
+% Second tile: plain FastSense for comparison
fp = fig.tile(2);
fp.addLine(t, data, 'DisplayName', 'Raw Data');
fig.setTileTitle(2, 'Raw Data');
fig.renderAll();
-fprintf(' Two tiles: SensorDetailPlot + plain FastPlot\n');
+fprintf(' Two tiles: SensorDetailPlot + plain FastSense\n');
fprintf(' Press any key to exit...\n');
pause;
diff --git a/examples/example_sensor_detail_dashboard.m b/examples/example_sensor_detail_dashboard.m
index 5fa28171..37e9f8e5 100644
--- a/examples/example_sensor_detail_dashboard.m
+++ b/examples/example_sensor_detail_dashboard.m
@@ -1,5 +1,5 @@
%% Multi-Sensor Detail Dashboard
-% Demonstrates embedding multiple SensorDetailPlots into a FastPlotGrid
+% Demonstrates embedding multiple SensorDetailPlots into a FastSenseGrid
% grid using tilePanel(), each with independent navigators.
close all force;
@@ -52,8 +52,8 @@
s3.Units = 'mm/s';
s3.X = t3; s3.Y = d3;
-%% Build 2x2 dashboard: 3 SensorDetailPlots + 1 plain FastPlot
-fig = FastPlotGrid(2, 2, 'Theme', 'light', 'Name', 'Multi-Sensor Dashboard');
+%% Build 2x2 dashboard: 3 SensorDetailPlots + 1 plain FastSense
+fig = FastSenseGrid(2, 2, 'Theme', 'light', 'Name', 'Multi-Sensor Dashboard');
% Tile 1: Temperature with events
sdp1 = SensorDetailPlot(s1, 'Parent', fig.tilePanel(1), ...
@@ -71,12 +71,12 @@
'NavigatorHeight', 0.15, 'Title', 'Motor Vibration');
sdp3.render();
-% Tile 4: Plain FastPlot comparison overlay
+% Tile 4: Plain FastSense comparison overlay
fp = fig.tile(4);
fp.addLine(t1, (d1 - mean(d1))/std(d1), 'DisplayName', 'Temp (z-score)');
fp.addLine(t2, (d2 - mean(d2))/std(d2), 'DisplayName', 'Pressure (z-score)');
fig.setTileTitle(4, 'Normalized Overlay');
fig.renderAll();
-fprintf('Multi-sensor dashboard with 3 SensorDetailPlots + 1 FastPlot.\n');
+fprintf('Multi-sensor dashboard with 3 SensorDetailPlots + 1 FastSense.\n');
fprintf('Each navigator operates independently.\n');
diff --git a/examples/example_sensor_detail_dock.m b/examples/example_sensor_detail_dock.m
index 4e496e10..f209a27c 100644
--- a/examples/example_sensor_detail_dock.m
+++ b/examples/example_sensor_detail_dock.m
@@ -1,12 +1,12 @@
%% SensorDetailPlot Dock — Multi-Tab Dashboard
%
-% Demonstrates a FastPlotDock with 4 tabs, each containing multiple plots.
-% Tabs mix SensorDetailPlots (with navigators) and plain FastPlot tiles.
+% Demonstrates a FastSenseDock with 4 tabs, each containing multiple plots.
+% Tabs mix SensorDetailPlots (with navigators) and plain FastSense tiles.
%
% Tab 1: Process Overview — 4 SensorDetailPlots (2x2 grid)
-% Tab 2: Correlation — 2 SensorDetailPlots + 2 plain FastPlots
+% Tab 2: Correlation — 2 SensorDetailPlots + 2 plain FastSenses
% Tab 3: Event Analysis — 1 large SensorDetailPlot + event details
-% Tab 4: Trends — 6 plain FastPlots showing z-score overlays
+% Tab 4: Trends — 6 plain FastSenses showing z-score overlays
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
@@ -78,11 +78,11 @@
allEvents = [ev1a, ev1b, ev2, ev3];
%% ===== Create Dock =====
-dock = FastPlotDock('Theme', 'light', 'Name', 'Sensor Detail Dashboard', ...
+dock = FastSenseDock('Theme', 'light', 'Name', 'Sensor Detail Dashboard', ...
'Position', [50 50 1400 800]);
%% ===== Tab 1: Process Overview (2x2 SensorDetailPlots) =====
-fig1 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig1 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
sensors = {s1, s2, s3, s4};
titles = {'Furnace Temperature', 'Chamber Pressure', ...
@@ -100,7 +100,7 @@
dock.addTab(fig1, 'Process Overview');
%% ===== Tab 2: Correlation (2 SensorDetailPlots + 2 plain) =====
-fig2 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig2 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% Top row: SensorDetailPlots for temperature and pressure
sdpCorr1 = SensorDetailPlot(s1, 'Parent', fig2.tilePanel(1), ...
@@ -111,7 +111,7 @@
'Events', ev2, 'XType', 'datenum', 'Title', 'Pressure');
sdpCorr2.render();
-% Bottom row: plain FastPlots
+% Bottom row: plain FastSenses
% Tile 3: Temperature + Pressure overlay (z-score normalized)
fp3 = fig2.tile(3);
fp3.addLine(tNum, (d1-mean(d1))/std(d1), 'DisplayName', 'Temp (z)', 'XType', 'datenum');
@@ -128,7 +128,7 @@
dock.addTab(fig2, 'Correlation');
%% ===== Tab 3: Event Analysis (1 large + event table) =====
-fig3 = FastPlotGrid(1, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig3 = FastSenseGrid(1, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% Left: large SensorDetailPlot of temperature
sdpEvent = SensorDetailPlot(s1, 'Parent', fig3.tilePanel(1), ...
@@ -149,8 +149,8 @@
dock.addTab(fig3, 'Event Analysis');
-%% ===== Tab 4: Trends (3x2 plain FastPlots) =====
-fig4 = FastPlotGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+%% ===== Tab 4: Trends (3x2 plain FastSenses) =====
+fig4 = FastSenseGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% Column 1: Raw signals
rawSensors = {s1, s2, s3};
diff --git a/examples/example_sensor_multi_state.m b/examples/example_sensor_multi_state.m
index c5e594a7..409dc0ba 100644
--- a/examples/example_sensor_multi_state.m
+++ b/examples/example_sensor_multi_state.m
@@ -79,8 +79,8 @@
end
end
-% --- Plot with FastPlot ---
-fp = FastPlot();
+% --- Plot with FastSense ---
+fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
fp.render();
title('Gas Flow — Multi-State Dynamic Thresholds');
diff --git a/examples/example_sensor_registry.m b/examples/example_sensor_registry.m
index 389e9820..42b928b8 100644
--- a/examples/example_sensor_registry.m
+++ b/examples/example_sensor_registry.m
@@ -46,8 +46,8 @@
fprintf(' [%d] key="%s", name="%s"\n', i, sensors{i}.Key, sensors{i}.Name);
end
-% --- Plot the pressure sensor with FastPlot ---
-fp = FastPlot();
+% --- Plot the pressure sensor with FastSense ---
+fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
fp.render();
title(sprintf('%s (from SensorRegistry)', s.Name));
diff --git a/examples/example_sensor_static.m b/examples/example_sensor_static.m
index 72286cfb..4bd61c58 100644
--- a/examples/example_sensor_static.m
+++ b/examples/example_sensor_static.m
@@ -28,7 +28,7 @@
% --- Resolve and plot ---
s.resolve();
-fp = FastPlot();
+fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
fp.render();
title('Motor Vibration — Static Upper & Lower Thresholds');
diff --git a/examples/example_sensor_threshold.m b/examples/example_sensor_threshold.m
index c4a91062..4a03b2ba 100644
--- a/examples/example_sensor_threshold.m
+++ b/examples/example_sensor_threshold.m
@@ -1,4 +1,4 @@
-%EXAMPLE_SENSOR_THRESHOLD Demonstrates the Sensor/Threshold system with FastPlot.
+%EXAMPLE_SENSOR_THRESHOLD Demonstrates the Sensor/Threshold system with FastSense.
% Shows dynamic thresholds that change based on machine state.
% Setup paths
@@ -36,8 +36,8 @@
% --- Precompute everything ---
s.resolve();
-% --- Plot with FastPlot ---
-fp = FastPlot();
+% --- Plot with FastSense ---
+fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
fp.render();
title('Chamber Pressure with Dynamic Thresholds');
diff --git a/examples/example_sensor_todisk.m b/examples/example_sensor_todisk.m
index 2b2403c8..b8d91e6a 100644
--- a/examples/example_sensor_todisk.m
+++ b/examples/example_sensor_todisk.m
@@ -54,11 +54,11 @@
numel(s.ResolvedThresholds), numel(s.ResolvedViolations));
%% 3. Plot the disk-backed sensor
-% addSensor passes the DataStore directly to FastPlot — no copying.
+% addSensor passes the DataStore directly to FastSense — no copying.
fprintf('\n=== 3. Plot disk-backed sensor ===\n');
-fp = FastPlot();
+fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
tic;
fp.render();
@@ -109,7 +109,7 @@
% Query a range
slice = s3.DataStore.getColumnSlice('status', 1, 6);
-labels = FastPlotDataStore.toCategorical(slice);
+labels = FastSenseDataStore.toCategorical(slice);
fprintf(' First 6 status labels: ');
if iscell(labels)
fprintf('%s\n', strjoin(labels, ', '));
@@ -118,7 +118,7 @@
end
% Plot it
-fp2 = FastPlot();
+fp2 = FastSense();
fp2.addSensor(s3);
tic;
fp2.render();
@@ -145,7 +145,7 @@
sensors{i} = si;
end
-fpf = FastPlotGrid(2, 2);
+fpf = FastSenseGrid(2, 2);
for i = 1:4
fpf.tile(i).addSensor(sensors{i}, 'ShowThresholds', true);
end
diff --git a/examples/example_stress_test.m b/examples/example_stress_test.m
index f8b1b554..e6516826 100644
--- a/examples/example_stress_test.m
+++ b/examples/example_stress_test.m
@@ -1,6 +1,6 @@
-%% FastPlot Stress Test — 5-Tab FastPlotDock with Sensors & Thresholds
+%% FastSense Stress Test — 5-Tab FastSenseDock with Sensors & Thresholds
% Demonstrates:
-% - FastPlotDock with 5 tabbed dashboards + FastPlotToolbar
+% - FastSenseDock with 5 tabbed dashboards + FastSenseToolbar
% - 26 sensor tiles, each with 4 dynamic thresholds (Warn HH/LL, Alarm HH/LL)
% - State-dependent thresholds that step at machine state transitions
% - ~86M total data points across all tabs
@@ -9,7 +9,7 @@
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
-fprintf('\n=== FastPlot Stress Test: 5 Tabbed Dashboards ===\n');
+fprintf('\n=== FastSense Stress Test: 5 Tabbed Dashboards ===\n');
totalTic = tic;
% --- Shared state channels (reused across dashboards) ---
@@ -26,13 +26,13 @@
scZone.Y = [0 1 2];
% --- Create dock ---
-dock = FastPlotDock('Theme', 'light', 'Name', 'Stress Test — 26 Sensors, 104 Thresholds', ...
+dock = FastSenseDock('Theme', 'light', 'Name', 'Stress Test — 26 Sensors, 104 Thresholds', ...
'Position', [50 50 1800 1000]);
% =========================================================================
% TAB 1: Vacuum Chamber — 3x2 grid, 6 sensors
% =========================================================================
-fig1 = FastPlotGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig1 = FastSenseGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% 1.1: Chamber Pressure — 5M pts
s = make_sensor('pressure', 'Chamber Pressure', 5e6, 40, 18, 800, 4, {scMachine, scVacuum});
@@ -76,7 +76,7 @@
% =========================================================================
% TAB 2: Motor Diagnostics — 2x3 grid, 6 sensors
% =========================================================================
-fig2 = FastPlotGrid(2, 3, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig2 = FastSenseGrid(2, 3, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% 2.1: Motor Current A — 5M pts
s = make_sensor('motor_A', 'Motor Current A', 5e6, 12, 4, 400, 1.5, {scMachine});
@@ -122,7 +122,7 @@
% =========================================================================
% TAB 3: Environmental — 2x2 grid, 4 sensors
% =========================================================================
-fig3 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig3 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% 3.1: Cleanroom Temp — 5M pts
s = make_sensor('room_temp', 'Cleanroom Temp', 5e6, 22, 1.5, 1800, 0.3, {scMachine});
@@ -155,7 +155,7 @@
% =========================================================================
% TAB 4: Gas Delivery — 3x2 grid, 6 sensors
% =========================================================================
-fig4 = FastPlotGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig4 = FastSenseGrid(3, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
gasNames = {'Argon', 'Nitrogen', 'Oxygen', 'CF4', 'CHF3', 'Helium'};
gasNominal = [200 150 80 50 30 500];
@@ -185,7 +185,7 @@
% =========================================================================
% TAB 5: Power & Cooling — 2x2 grid, 4 sensors
% =========================================================================
-fig5 = FastPlotGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
+fig5 = FastSenseGrid(2, 2, 'ParentFigure', dock.hFigure, 'Theme', 'light');
% 5.1: Chiller Supply — 3M pts
s = make_sensor('chiller_supply', 'Chiller Supply', 3e6, 18, 2, 1200, 0.5, {scMachine});
diff --git a/examples/example_themes.m b/examples/example_themes.m
index 4bc2939d..952fe8dd 100644
--- a/examples/example_themes.m
+++ b/examples/example_themes.m
@@ -1,4 +1,4 @@
-%% FastPlot Theme Comparison — All 5 built-in themes side by side
+%% FastSense Theme Comparison — All 5 built-in themes side by side
% Opens one figure per theme to compare visual styles
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -14,7 +14,7 @@
for i = 1:numel(themes)
themeName = themes{i};
- fp = FastPlot('Theme', themeName);
+ fp = FastSense('Theme', themeName);
fp.addLine(x, y1, 'DisplayName', 'Signal A');
fp.addLine(x, y2, 'DisplayName', 'Signal B');
fp.addLine(x, y3, 'DisplayName', 'Signal C');
diff --git a/examples/example_toolbar.m b/examples/example_toolbar.m
index 8f3416a9..801b8496 100644
--- a/examples/example_toolbar.m
+++ b/examples/example_toolbar.m
@@ -1,4 +1,4 @@
-%% FastPlot Toolbar Demo
+%% FastSense Toolbar Demo
% Demonstrates the interactive toolbar: data cursor, crosshair,
% grid toggle, legend toggle, autoscale Y, and PNG export.
@@ -13,19 +13,19 @@
fprintf('Toolbar example: %d points, 2 lines...\n', n);
tic;
-fp = FastPlot('Theme', 'light');
+fp = FastSense('Theme', 'light');
fp.addLine(x, y1, 'DisplayName', 'Sine');
fp.addLine(x, y2, 'DisplayName', 'Cosine');
fp.addThreshold(1.2, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
-tb = FastPlotToolbar(fp);
+tb = FastSenseToolbar(fp);
fprintf('Rendered with toolbar in %.3f seconds.\n', toc);
fprintf('Try: Data Cursor (click), Crosshair (hover), Grid, Legend, Autoscale Y, Export PNG\n');
%% Dashboard with toolbar
-fig = FastPlotGrid(1, 2, 'Theme', 'industrial');
+fig = FastSenseGrid(1, 2, 'Theme', 'industrial');
fp1 = fig.tile(1);
fp1.addLine(x, y1, 'DisplayName', 'Pressure');
fp1.addThreshold(1.0, 'Direction', 'upper', 'ShowViolations', true);
@@ -35,17 +35,17 @@
fig.setTileTitle(1, 'Pressure');
fig.setTileTitle(2, 'Temperature');
-tb2 = FastPlotToolbar(fig);
+tb2 = FastSenseToolbar(fig);
fprintf('Dashboard with toolbar ready.\n');
%% Datetime X-Axis
x = datenum(2024,1,1) + (0:99999)/86400; % ~1 day at 1-second resolution
y = sin((1:100000) * 2*pi/3600) + 0.2*randn(1,100000);
-fp3 = FastPlot('Theme', 'light');
+fp3 = FastSense('Theme', 'light');
fp3.addLine(x, y, 'DisplayName', 'Sensor', 'XType', 'datenum');
fp3.render();
title(fp3.hAxes, 'Datetime Axis — zoom to see format change');
-tb3 = FastPlotToolbar(fp3);
+tb3 = FastSenseToolbar(fp3);
fprintf('Datetime axis with toolbar ready. Zoom to see tick format adapt.\n');
diff --git a/examples/example_uneven_sampling.m b/examples/example_uneven_sampling.m
index eb389128..65c97985 100644
--- a/examples/example_uneven_sampling.m
+++ b/examples/example_uneven_sampling.m
@@ -1,5 +1,5 @@
-%% FastPlot Unevenly Sampled Data — Event-driven acquisition
-% Demonstrates that FastPlot handles non-uniform X spacing correctly
+%% FastSense Unevenly Sampled Data — Event-driven acquisition
+% Demonstrates that FastSense handles non-uniform X spacing correctly
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
@@ -38,7 +38,7 @@
fprintf('Uneven sampling: %d points, rate varies 10 Hz to 10 kHz...\n', numel(x));
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Event-Driven Sensor', 'Color', [0.2 0.5 0.7]);
fp.addThreshold(4.0, 'Direction', 'upper', 'ShowViolations', true, ...
'Color', [0.8 0 0], 'LineStyle', '--', 'Label', 'High');
diff --git a/examples/example_vibration.m b/examples/example_vibration.m
index b14c1ac7..e39a3c2d 100644
--- a/examples/example_vibration.m
+++ b/examples/example_vibration.m
@@ -1,4 +1,4 @@
-%% FastPlot Vibration Analysis — High-frequency data with envelope thresholds
+%% FastSense Vibration Analysis — High-frequency data with envelope thresholds
% Simulates accelerometer data from a rotating machine
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -27,7 +27,7 @@
fprintf('Vibration: %d points at %d kHz...\n', n, fs/1000);
tic;
-fp = FastPlot();
+fp = FastSense();
fp.addLine(x, y, 'DisplayName', 'Accelerometer', 'Color', [0.1 0.3 0.6]);
% ISO 10816 style velocity thresholds (simplified for displacement)
diff --git a/examples/example_visual_features.m b/examples/example_visual_features.m
index 943c21ca..1d8b12eb 100644
--- a/examples/example_visual_features.m
+++ b/examples/example_visual_features.m
@@ -1,4 +1,4 @@
-%% FastPlot Visual Features — Bands, Shading, Fill, and Markers
+%% FastSense Visual Features — Bands, Shading, Fill, and Markers
% Demonstrates all new visual enhancement methods in a 2x2 dashboard
projectRoot = fileparts(fileparts(mfilename('fullpath')));
@@ -10,7 +10,7 @@
fprintf('Visual features example: 4 tiles, %d points...\n', n);
tic;
-fig = FastPlotGrid(2, 2, 'Theme', 'default', ...
+fig = FastSenseGrid(2, 2, 'Theme', 'default', ...
'Name', 'Visual Features Demo', 'Position', [50 50 1200 800]);
% --- Tile 1: addBand — Alarm bands with thresholds ---
diff --git a/examples/example_widget_fastplot.m b/examples/example_widget_fastsense.m
similarity index 86%
rename from examples/example_widget_fastplot.m
rename to examples/example_widget_fastsense.m
index 43992d7e..8e46016f 100644
--- a/examples/example_widget_fastplot.m
+++ b/examples/example_widget_fastsense.m
@@ -1,10 +1,10 @@
-%% FastPlotWidget — All Configuration Modes
-% Demonstrates every data-binding mode of FastPlotWidget inside
+%% FastSenseWidget — All Configuration Modes
+% Demonstrates every data-binding mode of FastSenseWidget inside
% DashboardEngine on a 24-column grid.
%
% Supported properties:
% SensorObj (alias 'Sensor') — Sensor object for data binding
-% DataStoreObj (alias 'DataStore') — FastPlotDataStore for disk-backed data
+% DataStoreObj (alias 'DataStore') — FastSenseDataStore for disk-backed data
% XData, YData — inline numeric arrays
% File, XVar, YVar — load from .mat file
% Thresholds — 'auto' (default, from Sensor) | false
@@ -68,23 +68,23 @@
x = linspace(0, 10, N);
y = 2.5*sin(2*pi*3*x) .* exp(-0.15*x) + 0.3*randn(1,N);
-%% 3. Build dashboard — 2x2 grid of FastPlotWidgets
-d = DashboardEngine('FastPlotWidget — Configuration Showcase');
+%% 3. Build dashboard — 2x2 grid of FastSenseWidgets
+d = DashboardEngine('FastSenseWidget — Configuration Showcase');
d.Theme = 'light';
% Top-left: sensor-bound, auto thresholds + violations
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [1 1 12 10], ...
'Sensor', sTemp);
% Top-right: sensor-bound, thresholds disabled
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [13 1 12 10], ...
'Sensor', sPress, ...
'Thresholds', false);
% Bottom-left: inline XData/YData with manual labels
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [1 11 12 10], ...
'XData', x, 'YData', y, ...
'Title', 'Vibration Decay', ...
@@ -92,7 +92,7 @@
'YLabel', 'Amplitude [g]');
% Bottom-right: sensor-bound with custom axis labels
-d.addWidget('fastplot', ...
+d.addWidget('fastsense', ...
'Position', [13 11 12 10], ...
'Sensor', sTemp, ...
'YLabel', ['Temperature [' char(176) 'F]'], ...
@@ -101,6 +101,6 @@
%% 4. Render and print summary
d.render();
-fprintf('Dashboard rendered with %d FastPlotWidgets.\n', numel(d.Widgets));
+fprintf('Dashboard rendered with %d FastSenseWidgets.\n', numel(d.Widgets));
fprintf('Temperature violations: %d\n', sTemp.countViolations());
fprintf('Pressure violations: %d\n', sPress.countViolations());
diff --git a/examples/example_widget_number.m b/examples/example_widget_number.m
index a4ba2a1d..378b0a2b 100644
--- a/examples/example_widget_number.m
+++ b/examples/example_widget_number.m
@@ -73,8 +73,8 @@
'Units', 'items', ...
'Format', '%d');
-% --- FastPlot for visual context ---
-d.addWidget('fastplot', ...
+% --- FastSense for visual context ---
+d.addWidget('fastsense', ...
'Position', [1 3 24 10], ...
'SensorObj', sTemp);
diff --git a/examples/example_widget_status.m b/examples/example_widget_status.m
index 4b0fe9bd..7a057015 100644
--- a/examples/example_widget_status.m
+++ b/examples/example_widget_status.m
@@ -63,10 +63,10 @@
d.addWidget('status', 'Position', [21 1 4 1], ...
'Title', 'Manual Override', 'StaticStatus', 'ok');
-% --- Row 3+: FastPlot widgets showing the underlying sensor data ---
-d.addWidget('fastplot', 'Position', [1 3 8 6], 'SensorObj', sTemp);
-d.addWidget('fastplot', 'Position', [9 3 8 6], 'SensorObj', sPress);
-d.addWidget('fastplot', 'Position', [17 3 8 6], 'SensorObj', sFlow);
+% --- Row 3+: FastSense widgets showing the underlying sensor data ---
+d.addWidget('fastsense', 'Position', [1 3 8 6], 'SensorObj', sTemp);
+d.addWidget('fastsense', 'Position', [9 3 8 6], 'SensorObj', sPress);
+d.addWidget('fastsense', 'Position', [17 3 8 6], 'SensorObj', sFlow);
%% 3. Render
d.render();
diff --git a/examples/run_all_examples.m b/examples/run_all_examples.m
index 252f5e69..026c47a1 100644
--- a/examples/run_all_examples.m
+++ b/examples/run_all_examples.m
@@ -1,5 +1,5 @@
function run_all_examples(mode)
-%RUN_ALL_EXAMPLES Run each FastPlot example.
+%RUN_ALL_EXAMPLES Run each FastSense example.
% run_all_examples() — interactive: press ENTER between examples
% run_all_examples('auto') — non-interactive: 5s pause between examples
%
@@ -11,7 +11,7 @@ function run_all_examples(mode)
projectRoot = fileparts(fileparts(mfilename('fullpath')));
run(fullfile(projectRoot, 'setup.m'));
- addpath(fullfile(projectRoot, 'libs', 'FastPlot', 'private'));
+ addpath(fullfile(projectRoot, 'libs', 'FastSense', 'private'));
addpath(fileparts(mfilename('fullpath')));
examples = {
@@ -33,12 +33,12 @@ function run_all_examples(mode)
'example_sensor_multi_state', 'Multi-state sensor, combined conditions, getThresholdsAt'
'example_sensor_registry', 'SensorRegistry API (list, get, getMultiple)'
'example_sensor_dashboard', 'Multi-sensor 2x2 dashboard with SensorRegistry'
- 'example_mixed_tiles', 'Mixed tile types: FastPlot + bar/scatter/histogram'
+ 'example_mixed_tiles', 'Mixed tile types: FastSense + bar/scatter/histogram'
};
fprintf('\n');
fprintf('========================================\n');
- fprintf(' FastPlot Examples (%d total)\n', size(examples, 1));
+ fprintf(' FastSense Examples (%d total)\n', size(examples, 1));
if strcmp(mode, 'auto')
fprintf(' Auto mode: 5s pause between examples\n');
else
diff --git a/libs/Dashboard/DashboardBuilder.m b/libs/Dashboard/DashboardBuilder.m
index 907ad3f9..336f7471 100644
--- a/libs/Dashboard/DashboardBuilder.m
+++ b/libs/Dashboard/DashboardBuilder.m
@@ -52,7 +52,7 @@
hPropDelete = []
hPropLabel = []
- % Axis label controls (fastplot only)
+ % Axis label controls (fastsense only)
hPropXLabel = []
hPropYLabel = []
@@ -249,7 +249,7 @@ function applyProperties(obj)
function pos = findNextSlot(obj, type)
switch type
- case 'fastplot', defW = 12; defH = 3;
+ case 'fastsense', defW = 12; defH = 3;
case 'number', defW = 6; defH = 1;
case 'status', defW = 4; defH = 1;
case 'text', defW = 6; defH = 1;
@@ -307,7 +307,7 @@ function createPalette(obj, hFig, theme)
'BackgroundColor', theme.ToolbarBackground, ...
'HorizontalAlignment', 'center');
- types = {'fastplot','number','status','text', ...
+ types = {'fastsense','number','status','text', ...
'gauge','table','rawaxes','timeline'};
labels = {'Plot','Number','Status','Text', ...
'Gauge','Table','Axes','Events'};
@@ -433,7 +433,7 @@ function createPropertiesPanel(obj, hFig, theme)
'String', '', 'Visible', 'off');
y = y - fh - gap*2;
- % --- Axis Labels (shown for fastplot) ---
+ % --- Axis Labels (shown for fastsense) ---
uicontrol('Parent', obj.hPropsPanel, 'Style', 'text', ...
'Units', 'normalized', 'Position', [0.04 y 0.44 lh], ...
'String', 'X:', 'FontSize', fs, ...
@@ -785,7 +785,7 @@ function updatePropertiesDisplay(obj)
set(obj.hPropWidth, 'String', num2str(w.Position(3)));
set(obj.hPropHeight, 'String', num2str(w.Position(4)));
- % Populate axis label fields (fastplot only)
+ % Populate axis label fields (fastsense only)
if isprop(w, 'XLabel')
set(obj.hPropXLabel, 'String', w.XLabel, 'Enable', 'on');
set(obj.hPropYLabel, 'String', w.YLabel, 'Enable', 'on');
@@ -935,7 +935,7 @@ function showProps(obj, vis)
function populateSourceControls(obj, w)
switch w.Type
- case 'fastplot'
+ case 'fastsense'
if ~isempty(w.Sensor)
set(obj.hSourceType, 'Value', 2); % Sensor
set(obj.hSourceKey, 'String', w.Sensor.Key);
@@ -1022,7 +1022,7 @@ function onSourceBrowse(obj)
function t = defaultTitleForType(~, type)
switch type
- case 'fastplot', t = 'New Plot';
+ case 'fastsense', t = 'New Plot';
case 'number', t = 'New Number';
case 'status', t = 'New Status';
case 'text', t = 'New Text';
diff --git a/libs/Dashboard/DashboardEngine.m b/libs/Dashboard/DashboardEngine.m
index df3b5bc3..ba01a1bd 100644
--- a/libs/Dashboard/DashboardEngine.m
+++ b/libs/Dashboard/DashboardEngine.m
@@ -5,7 +5,7 @@
% d = DashboardEngine('My Dashboard');
% d.Theme = 'light';
% d.LiveInterval = 5;
-% d.addWidget('fastplot', 'Title', 'Temp', 'Position', [1 1 6 3], ...
+% d.addWidget('fastsense', 'Title', 'Temp', 'Position', [1 1 6 3], ...
% 'Sensor', SensorRegistry.get('temperature'));
% d.render();
%
@@ -16,8 +16,8 @@
% d = DashboardEngine.load('path/to/dashboard.json');
% d.render();
%
-% For a lightweight tiled grid of FastPlot charts without widgets,
-% see FastPlotGrid.
+% For a lightweight tiled grid of FastSense charts without widgets,
+% see FastSenseGrid.
properties (Access = public)
Name = ''
@@ -63,8 +63,8 @@
function addWidget(obj, type, varargin)
switch type
- case 'fastplot'
- w = FastPlotWidget(varargin{:});
+ case 'fastsense'
+ w = FastSenseWidget(varargin{:});
case 'number'
w = NumberWidget(varargin{:});
case 'kpi'
@@ -432,7 +432,7 @@ function onLiveTick(obj)
function types = widgetTypes()
%WIDGETTYPES List supported widget type strings.
types = {
- 'fastplot', 'Time-series plot (FastPlotWidget)'
+ 'fastsense', 'Time-series plot (FastSenseWidget)'
'number', 'Single numeric value with trend (NumberWidget)'
'status', 'Status indicator with dot and label (StatusWidget)'
'gauge', 'Gauge display in arc/donut/bar/thermometer style (GaugeWidget)'
diff --git a/libs/Dashboard/DashboardSerializer.m b/libs/Dashboard/DashboardSerializer.m
index d2d570ed..4af9501b 100644
--- a/libs/Dashboard/DashboardSerializer.m
+++ b/libs/Dashboard/DashboardSerializer.m
@@ -71,8 +71,8 @@ function save(config, filepath)
ws = config.widgets{i};
w = [];
switch ws.type
- case 'fastplot'
- widgets{i} = FastPlotWidget.fromStruct(ws);
+ case 'fastsense'
+ widgets{i} = FastSenseWidget.fromStruct(ws);
case 'number'
widgets{i} = NumberWidget.fromStruct(ws);
case 'kpi'
@@ -127,28 +127,28 @@ function exportScript(config, filepath)
ws.position.width, ws.position.height);
switch ws.type
- case 'fastplot'
+ case 'fastsense'
if isfield(ws, 'source')
switch ws.source.type
case 'sensor'
- lines{end+1} = sprintf('d.addWidget(''fastplot'', ''Title'', ''%s'', ...', ws.title);
+ lines{end+1} = sprintf('d.addWidget(''fastsense'', ''Title'', ''%s'', ...', ws.title);
lines{end+1} = sprintf(' ''Position'', %s, ...', pos);
lines{end+1} = sprintf(' ''Sensor'', SensorRegistry.get(''%s''));', ws.source.name);
case 'file'
- lines{end+1} = sprintf('d.addWidget(''fastplot'', ''Title'', ''%s'', ...', ws.title);
+ lines{end+1} = sprintf('d.addWidget(''fastsense'', ''Title'', ''%s'', ...', ws.title);
lines{end+1} = sprintf(' ''Position'', %s, ...', pos);
lines{end+1} = sprintf(' ''File'', ''%s'', ''XVar'', ''%s'', ''YVar'', ''%s'');', ...
ws.source.path, ws.source.xVar, ws.source.yVar);
case 'data'
- lines{end+1} = sprintf('d.addWidget(''fastplot'', ''Title'', ''%s'', ...', ws.title);
+ lines{end+1} = sprintf('d.addWidget(''fastsense'', ''Title'', ''%s'', ...', ws.title);
lines{end+1} = sprintf(' ''Position'', %s, ...', pos);
lines{end+1} = sprintf(' ''XData'', %s, ''YData'', %s);', ...
mat2str(ws.source.x), mat2str(ws.source.y));
otherwise
- lines{end+1} = sprintf('d.addWidget(''fastplot'', ''Title'', ''%s'', ''Position'', %s);', ws.title, pos);
+ lines{end+1} = sprintf('d.addWidget(''fastsense'', ''Title'', ''%s'', ''Position'', %s);', ws.title, pos);
end
else
- lines{end+1} = sprintf('d.addWidget(''fastplot'', ''Title'', ''%s'', ''Position'', %s);', ws.title, pos);
+ lines{end+1} = sprintf('d.addWidget(''fastsense'', ''Title'', ''%s'', ''Position'', %s);', ws.title, pos);
end
case 'number'
line = sprintf('d.addWidget(''number'', ''Title'', ''%s'', ''Position'', %s', ws.title, pos);
diff --git a/libs/Dashboard/DashboardTheme.m b/libs/Dashboard/DashboardTheme.m
index f9e113bb..a1dda74f 100644
--- a/libs/Dashboard/DashboardTheme.m
+++ b/libs/Dashboard/DashboardTheme.m
@@ -1,11 +1,11 @@
function theme = DashboardTheme(preset, varargin)
-%DASHBOARDTHEME Returns a theme struct with FastPlotTheme + dashboard fields.
+%DASHBOARDTHEME Returns a theme struct with FastSenseTheme + dashboard fields.
%
% theme = DashboardTheme() % default preset
% theme = DashboardTheme('dark') % named preset
% theme = DashboardTheme('dark', 'DashboardBackground', [0.1 0.1 0.2])
%
-% Returns a struct containing all FastPlotTheme fields plus dashboard-specific
+% Returns a struct containing all FastSenseTheme fields plus dashboard-specific
% fields: DashboardBackground, WidgetBackground, WidgetBorderColor,
% WidgetBorderWidth, DragHandleColor, DropZoneColor, GridLineColor,
% ToolbarBackground, ToolbarFontColor, HeaderFontSize,
@@ -16,8 +16,8 @@
preset = 'default';
end
- % Get base FastPlotTheme
- base = FastPlotTheme(preset);
+ % Get base FastSenseTheme
+ base = FastSenseTheme(preset);
% Append dashboard-specific fields
dash = getDashboardDefaults(preset);
diff --git a/libs/Dashboard/DashboardWidget.m b/libs/Dashboard/DashboardWidget.m
index 8f6ffabf..cc29cd2b 100644
--- a/libs/Dashboard/DashboardWidget.m
+++ b/libs/Dashboard/DashboardWidget.m
@@ -5,7 +5,7 @@
% render(parentPanel) — create graphics objects inside the panel
% refresh() — update data/display (called by live timer)
% configure() — open properties UI for edit mode
-% getType() — return widget type string (e.g. 'fastplot')
+% getType() — return widget type string (e.g. 'fastsense')
%
% Subclasses must also provide a static fromStruct(s) method.
diff --git a/libs/Dashboard/FastPlotWidget.m b/libs/Dashboard/FastSenseWidget.m
similarity index 86%
rename from libs/Dashboard/FastPlotWidget.m
rename to libs/Dashboard/FastSenseWidget.m
index fff2eb46..5880d1fb 100644
--- a/libs/Dashboard/FastPlotWidget.m
+++ b/libs/Dashboard/FastSenseWidget.m
@@ -1,11 +1,11 @@
-classdef FastPlotWidget < DashboardWidget
-%FASTPLOTWIDGET Dashboard widget wrapping a FastPlot instance.
+classdef FastSenseWidget < DashboardWidget
+%FASTSENSEWIDGET Dashboard widget wrapping a FastSense instance.
%
% Supports three data binding modes:
-% Sensor: w = FastPlotWidget('Sensor', sensorObj)
-% DataStore: w = FastPlotWidget('DataStore', dsObj)
-% Inline: w = FastPlotWidget('XData', x, 'YData', y)
-% File: w = FastPlotWidget('File', 'path.mat', 'XVar', 'x', 'YVar', 'y')
+% Sensor: w = FastSenseWidget('Sensor', sensorObj)
+% DataStore: w = FastSenseWidget('DataStore', dsObj)
+% Inline: w = FastSenseWidget('XData', x, 'YData', y)
+% File: w = FastSenseWidget('File', 'path.mat', 'XVar', 'x', 'YVar', 'y')
%
% When bound to a Sensor, ThresholdRules apply automatically.
@@ -22,12 +22,12 @@
end
properties (SetAccess = private)
- FastPlotObj = []
+ FastSenseObj = []
IsSettingTime = false % guard to distinguish programmatic vs user xlim change
end
methods
- function obj = FastPlotWidget(varargin)
+ function obj = FastSenseWidget(varargin)
obj = obj@DashboardWidget(varargin{:});
if isequal(obj.Position, [1 1 6 2])
obj.Position = [1 1 12 3];
@@ -54,9 +54,9 @@ function render(obj, parentPanel)
'Units', 'normalized', ...
'Position', [0.08 0.12 0.88 0.78]);
- % Create FastPlot on this axes
- fp = FastPlot('Parent', ax);
- obj.FastPlotObj = fp;
+ % Create FastSense on this axes
+ fp = FastSense('Parent', ax);
+ obj.FastSenseObj = fp;
% Bind data
if ~isempty(obj.Sensor)
@@ -100,15 +100,15 @@ function refresh(obj)
% Save zoom state before teardown
savedXLim = [];
- if ~isempty(obj.FastPlotObj) && ~isempty(obj.FastPlotObj.hAxes) ...
- && ishandle(obj.FastPlotObj.hAxes)
- savedXLim = get(obj.FastPlotObj.hAxes, 'XLim');
+ if ~isempty(obj.FastSenseObj) && ~isempty(obj.FastSenseObj.hAxes) ...
+ && ishandle(obj.FastSenseObj.hAxes)
+ savedXLim = get(obj.FastSenseObj.hAxes, 'XLim');
end
- % Delete old axes and FastPlot, then rebuild
- if ~isempty(obj.FastPlotObj)
- try delete(obj.FastPlotObj); catch, end
- obj.FastPlotObj = [];
+ % Delete old axes and FastSense, then rebuild
+ if ~isempty(obj.FastSenseObj)
+ try delete(obj.FastSenseObj); catch, end
+ obj.FastSenseObj = [];
end
% Delete any leftover axes in the panel
ch = findobj(obj.hPanel, 'Type', 'axes');
@@ -118,8 +118,8 @@ function refresh(obj)
'Units', 'normalized', ...
'Position', [0.08 0.12 0.88 0.78]);
- fp = FastPlot('Parent', ax);
- obj.FastPlotObj = fp;
+ fp = FastSense('Parent', ax);
+ obj.FastSenseObj = fp;
fp.addSensor(obj.Sensor);
if ~isempty(obj.Title)
@@ -155,9 +155,9 @@ function setTimeRange(obj, tStart, tEnd)
if ~obj.UseGlobalTime
return; % widget has its own zoom, skip global time
end
- if ~isempty(obj.FastPlotObj)
+ if ~isempty(obj.FastSenseObj)
try
- ax = obj.FastPlotObj.hAxes;
+ ax = obj.FastSenseObj.hAxes;
if ~isempty(ax) && ishandle(ax)
obj.IsSettingTime = true;
xlim(ax, [tStart tEnd]);
@@ -191,7 +191,7 @@ function onXLimChanged(obj)
end
function t = getType(~)
- t = 'fastplot';
+ t = 'fastsense';
end
function s = toStruct(obj)
@@ -213,7 +213,7 @@ function onXLimChanged(obj)
methods (Static)
function obj = fromStruct(s)
- obj = FastPlotWidget();
+ obj = FastSenseWidget();
obj.Title = s.title;
obj.Position = [s.position.col, s.position.row, ...
s.position.width, s.position.height];
diff --git a/libs/EventDetection/EventViewer.m b/libs/EventDetection/EventViewer.m
index 3680397f..f864475c 100644
--- a/libs/EventDetection/EventViewer.m
+++ b/libs/EventDetection/EventViewer.m
@@ -639,7 +639,7 @@ function openEventPlot(obj, row)
minWidth = 1 / 1440;
% --- Dashboard: 2 rows, 1 column (light theme) ---
- dashboard = FastPlotGrid(2, 1, 'Theme', 'light', ...
+ dashboard = FastSenseGrid(2, 1, 'Theme', 'light', ...
'Name', sprintf('Event: %s — %s', ev.SensorName, ev.ThresholdLabel));
% Get selected event's threshold color
@@ -703,7 +703,7 @@ function openEventPlot(obj, row)
'EdgeColor', evColor, 'LineWidth', 2, 'LineStyle', '-', ...
'HandleVisibility', 'off');
- FastPlotToolbar(fp1);
+ FastSenseToolbar(fp1);
end
function c = getThresholdColor(obj, label)
diff --git a/libs/EventDetection/NotificationService.m b/libs/EventDetection/NotificationService.m
index c4e864e9..9bcfb88a 100644
--- a/libs/EventDetection/NotificationService.m
+++ b/libs/EventDetection/NotificationService.m
@@ -12,7 +12,7 @@
SmtpPort = 25
SmtpUser = ''
SmtpPassword = ''
- FromAddress = 'fastplot@noreply.com'
+ FromAddress = 'fastsense@noreply.com'
NotificationCount = 0
end
@@ -23,7 +23,7 @@
p.addParameter('DryRun', false, @islogical);
p.addParameter('SnapshotDir', '', @ischar);
p.addParameter('SmtpServer', '', @ischar);
- p.addParameter('FromAddress', 'fastplot@noreply.com', @ischar);
+ p.addParameter('FromAddress', 'fastsense@noreply.com', @ischar);
p.parse(varargin{:});
obj.Enabled = p.Results.Enabled;
obj.DryRun = p.Results.DryRun;
@@ -31,7 +31,7 @@
obj.SmtpServer = p.Results.SmtpServer;
obj.FromAddress = p.Results.FromAddress;
if isempty(obj.SnapshotDir)
- obj.SnapshotDir = fullfile(tempdir, 'fastplot_snapshots');
+ obj.SnapshotDir = fullfile(tempdir, 'fastsense_snapshots');
end
end
diff --git a/libs/EventDetection/generateEventSnapshot.m b/libs/EventDetection/generateEventSnapshot.m
index 0b69704f..42ff226e 100644
--- a/libs/EventDetection/generateEventSnapshot.m
+++ b/libs/EventDetection/generateEventSnapshot.m
@@ -1,5 +1,5 @@
function files = generateEventSnapshot(event, sensorData, varargin)
- % generateEventSnapshot Create two FastPlot PNG snapshots for an event.
+ % generateEventSnapshot Create two FastSense PNG snapshots for an event.
%
% files = generateEventSnapshot(event, sensorData, ...)
%
diff --git a/libs/EventDetection/private/parseOpts.m b/libs/EventDetection/private/parseOpts.m
index 2db738ee..242f3c9e 100644
--- a/libs/EventDetection/private/parseOpts.m
+++ b/libs/EventDetection/private/parseOpts.m
@@ -9,7 +9,7 @@
% [opts, unmatched] = PARSEOPTS(defaults, args, verbose) additionally
% emits a warning for every unrecognized option when verbose is true.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% defaults — scalar struct whose field names define valid option keys
@@ -32,7 +32,7 @@
% [opts, extra] = parseOpts(defs, {'color', 'b', 'Name', 'foo'});
% % opts.Color == 'b', opts.Width == 1, extra.Name == 'foo'
%
-% See also FastPlot, FastPlotGrid, struct2nvpairs.
+% See also FastSense, FastSenseGrid, struct2nvpairs.
if nargin < 3; verbose = false; end
@@ -58,7 +58,7 @@
% Unmatched — collect for pass-through
unmatched.(key) = val;
if verbose
- warning('FastPlot:unknownOption', ...
+ warning('FastSense:unknownOption', ...
'Unknown option ''%s''. Valid options: %s', ...
key, strjoin(fnames, ', '));
end
diff --git a/libs/FastPlot/ConsoleProgressBar.m b/libs/FastSense/ConsoleProgressBar.m
similarity index 99%
rename from libs/FastPlot/ConsoleProgressBar.m
rename to libs/FastSense/ConsoleProgressBar.m
index 878c5f5e..a63c3b5d 100644
--- a/libs/FastPlot/ConsoleProgressBar.m
+++ b/libs/FastSense/ConsoleProgressBar.m
@@ -40,7 +40,7 @@
% end
% pb.freeze(); % becomes permanent line
%
-% See also FastPlot, FastPlotGrid, FastPlotDock.
+% See also FastSense, FastSenseGrid, FastSenseDock.
properties (Access = private)
Label = ''
diff --git a/libs/FastPlot/FastPlot.m b/libs/FastSense/FastSense.m
similarity index 94%
rename from libs/FastPlot/FastPlot.m
rename to libs/FastSense/FastSense.m
index 1b491824..b7e9ae6d 100644
--- a/libs/FastPlot/FastPlot.m
+++ b/libs/FastSense/FastSense.m
@@ -1,6 +1,6 @@
-classdef FastPlot < handle
- %FASTPLOT Ultra-fast time series plotting with dynamic downsampling.
- % FastPlot renders 1K to 100M data points with fluid zoom/pan by
+classdef FastSense < handle
+ %FASTSENSE Ultra-fast time series plotting with dynamic downsampling.
+ % FastSense renders 1K to 100M data points with fluid zoom/pan by
% dynamically downsampling data to screen resolution using MinMax or
% LTTB algorithms. A multi-level pyramid cache provides instant
% re-downsample on zoom without touching raw data.
@@ -15,10 +15,10 @@
% - Metadata attachment and forward-fill lookup by X value
% - Datetime X-axis support with auto-formatting
% - Logarithmic axis support (X, Y, or both)
- % - Theme-based styling via FastPlotTheme
+ % - Theme-based styling via FastSenseTheme
%
% Usage:
- % fp = FastPlot();
+ % fp = FastSense();
% fp.addLine(x, y, 'DisplayName', 'Sensor1');
% fp.addThreshold(4.5, 'Direction', 'upper', 'ShowViolations', true);
% fp.render();
@@ -26,7 +26,7 @@
% Constructor options (name-value):
% 'Parent' — axes handle (default: create new figure)
% 'LinkGroup' — string ID for linked zoom/pan across plots
- % 'Theme' — theme preset name, struct, or FastPlotTheme
+ % 'Theme' — theme preset name, struct, or FastSenseTheme
% 'Verbose' — logical, print diagnostics (default: false)
% 'MinPointsForDownsample' — threshold for raw vs downsampled
% 'DownsampleFactor' — points per pixel (default: 2)
@@ -37,40 +37,40 @@
% 'LiveInterval' — poll interval in seconds (default: 2.0)
%
% Example — linked zoom across two plots:
- % fp1 = FastPlot('LinkGroup', 'group1');
+ % fp1 = FastSense('LinkGroup', 'group1');
% fp1.addLine(x, y1, 'DisplayName', 'Temp');
% fp1.render();
- % fp2 = FastPlot('LinkGroup', 'group1');
+ % fp2 = FastSense('LinkGroup', 'group1');
% fp2.addLine(x, y2, 'DisplayName', 'Pressure');
% fp2.render();
%
% Example — logarithmic Y axis:
- % fp = FastPlot('YScale', 'log');
+ % fp = FastSense('YScale', 'log');
% fp.addLine(1:1000, logspace(-1, 3, 1000));
% fp.render();
%
% Example — live mode:
- % fp = FastPlot(); fp.addLine(x, y); fp.render();
+ % fp = FastSense(); fp.addLine(x, y); fp.render();
% fp.startLive('data.mat', @(fp, s) fp.updateData(1, s.x, s.y));
%
% Example — distribute figures on screen (bundled in vendor/):
- % FastPlot.distFig() % auto-arrange all figures
- % FastPlot.distFig('Rows', 2, 'Cols', 3) % 2x3 grid
+ % FastSense.distFig() % auto-arrange all figures
+ % FastSense.distFig('Rows', 2, 'Cols', 3) % 2x3 grid
%
% Notes:
% addLine, addThreshold, addBand, addShaded, and addMarker must be
% called BEFORE render(). After render(), use updateData(lineIndex,
% newX, newY) to replace existing line data. To add a new series
- % after render(), create a new FastPlot instance.
+ % after render(), create a new FastSense instance.
%
- % See also FastPlotGrid, FastPlotDock, FastPlotTheme, FastPlotToolbar.
+ % See also FastSenseGrid, FastSenseDock, FastSenseTheme, FastSenseToolbar.
% ========================= PUBLIC PROPERTIES =========================
% User-configurable settings. Set before calling render().
properties (Access = public)
ParentAxes = [] % axes handle, empty = create new
LinkGroup = '' % string ID for linked zoom/pan
- Theme = [] % theme struct (from FastPlotTheme)
+ Theme = [] % theme struct (from FastSenseTheme)
Verbose = false % print diagnostics to console
LiveViewMode = '' % 'preserve' | 'follow' | 'reset' (empty = no view mode applied)
LiveFile = '' % path to .mat file for live mode
@@ -151,22 +151,22 @@
end
methods (Access = public)
- function obj = FastPlot(varargin)
- %FASTPLOT Construct a FastPlot instance.
- % fp = FASTPLOT() creates a new FastPlot with default settings.
- % fp = FASTPLOT('Parent', ax, 'Theme', 'dark') creates a plot
+ function obj = FastSense(varargin)
+ %FASTSENSE Construct a FastSense instance.
+ % fp = FASTSENSE() creates a new FastSense with default settings.
+ % fp = FASTSENSE('Parent', ax, 'Theme', 'dark') creates a plot
% inside existing axes ax with the 'dark' theme.
- % fp = FASTPLOT('LinkGroup', 'g1', 'Verbose', true) creates a
+ % fp = FASTSENSE('LinkGroup', 'g1', 'Verbose', true) creates a
% plot that shares zoom/pan with other plots in group 'g1'.
%
% All options are name-value pairs. Defaults are loaded from
- % FastPlotDefaults (via getDefaults) and can be overridden
+ % FastSenseDefaults (via getDefaults) and can be overridden
% per-instance.
%
% Inputs (name-value pairs):
% 'Parent' — axes handle; empty = create new figure
% 'LinkGroup' — string ID for linked zoom/pan
- % 'Theme' — theme name, struct, or FastPlotTheme object
+ % 'Theme' — theme name, struct, or FastSenseTheme object
% 'Verbose' — logical, print diagnostics (default: false)
% 'MinPointsForDownsample' — skip downsampling below this count
% 'DownsampleFactor' — points per pixel (default: 2)
@@ -177,14 +177,14 @@
% 'YScale' — 'linear' or 'log' (default: 'linear')
%
% Output:
- % obj — new FastPlot handle object
+ % obj — new FastSense handle object
%
% Example:
- % fp = FastPlot('Theme', 'dark', 'Verbose', true);
+ % fp = FastSense('Theme', 'dark', 'Verbose', true);
% fp.addLine(1:1e6, randn(1,1e6));
% fp.render();
%
- % See also addLine, render, FastPlotTheme, FastPlotDefaults.
+ % See also addLine, render, FastSenseTheme, FastSenseDefaults.
cfg = getDefaults();
defaults.Parent = [];
defaults.LinkGroup = '';
@@ -243,10 +243,10 @@ function reapplyTheme(obj)
% Has no effect before render() has been called.
%
% Example:
- % fp.Theme = FastPlotTheme('dark');
+ % fp.Theme = FastSenseTheme('dark');
% fp.reapplyTheme();
%
- % See also applyTheme, FastPlotTheme.
+ % See also applyTheme, FastSenseTheme.
if ~obj.IsRendered; return; end
obj.applyTheme();
% Update existing line widths
@@ -288,10 +288,10 @@ function setScale(obj, varargin)
% Validate
validScales = {'linear', 'log'};
if ~ismember(opts.XScale, validScales)
- error('FastPlot:invalidScale', 'XScale must be ''linear'' or ''log''.');
+ error('FastSense:invalidScale', 'XScale must be ''linear'' or ''log''.');
end
if ~ismember(opts.YScale, validScales)
- error('FastPlot:invalidScale', 'YScale must be ''linear'' or ''log''.');
+ error('FastSense:invalidScale', 'YScale must be ''linear'' or ''log''.');
end
xChanged = ~strcmp(opts.XScale, obj.XScale);
@@ -359,17 +359,17 @@ function addLine(obj, x, y, varargin)
% 'Color','LineStyle','DisplayName',... — passed to line()
%
% Note: addLine must be called before render(). After rendering, use
- % updateData() to modify existing lines, or create a new FastPlot.
+ % updateData() to modify existing lines, or create a new FastSense.
%
% Example:
- % fp = FastPlot();
+ % fp = FastSense();
% fp.addLine(1:1e6, cumsum(randn(1,1e6)), 'DisplayName', 'Walk');
% fp.render();
%
% See also addThreshold, addShaded, render, updateData.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add lines after render() has been called.');
end
@@ -390,7 +390,7 @@ function addLine(obj, x, y, varargin)
% Validate sizes match
if numel(x) ~= numel(y)
- error('FastPlot:sizeMismatch', ...
+ error('FastSense:sizeMismatch', ...
'X and Y must have the same number of elements.');
end
@@ -440,7 +440,7 @@ function addLine(obj, x, y, varargin)
lineStruct.Y = [];
if obj.Verbose
- fprintf('[FastPlot] addLine: %d pts -> pre-built DataStore\n', nPts);
+ fprintf('[FastSense] addLine: %d pts -> pre-built DataStore\n', nPts);
end
if isempty(obj.Lines)
@@ -459,7 +459,7 @@ function addLine(obj, x, y, varargin)
ce = min(ci + chunkSize, nX);
dx = diff(x(ci:ce));
if any(dx(~isnan(dx)) < 0)
- error('FastPlot:nonMonotonicX', ...
+ error('FastSense:nonMonotonicX', ...
'X must be monotonically increasing.');
end
end
@@ -491,11 +491,11 @@ function addLine(obj, x, y, varargin)
% Decide storage: disk-backed for large datasets to avoid OOM
useDisk = obj.shouldUseDisk(nPts);
if useDisk
- lineStruct.DataStore = FastPlotDataStore(x, y);
+ lineStruct.DataStore = FastSenseDataStore(x, y);
lineStruct.X = [];
lineStruct.Y = [];
if obj.Verbose
- fprintf('[FastPlot] addLine: %d pts (%.1f MB) -> disk-backed storage\n', ...
+ fprintf('[FastSense] addLine: %d pts (%.1f MB) -> disk-backed storage\n', ...
nPts, nPts * 16 / 1e6);
end
else
@@ -540,7 +540,7 @@ function addSensor(obj, sensor, varargin)
% See also addLine, addThreshold.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add sensors after render() has been called.');
end
@@ -613,7 +613,7 @@ function addThreshold(obj, varargin)
% 'Label' — text label for threshold
%
% Note: addThreshold must be called before render(). After
- % rendering, create a new FastPlot to add new thresholds.
+ % rendering, create a new FastSense to add new thresholds.
%
% Example:
% fp.addThreshold(4.5, 'Direction', 'upper', ...
@@ -622,7 +622,7 @@ function addThreshold(obj, varargin)
% See also addLine, addBand, updateViolations.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add thresholds after render() has been called.');
end
@@ -697,7 +697,7 @@ function addBand(obj, yLow, yHigh, varargin)
% 'Label' — text label for the band
%
% Note: addBand must be called before render(). After rendering,
- % create a new FastPlot to add new bands.
+ % create a new FastSense to add new bands.
%
% Example:
% fp.addBand(3.5, 4.5, 'FaceColor', [1 0.9 0.9], ...
@@ -706,7 +706,7 @@ function addBand(obj, yLow, yHigh, varargin)
% See also addThreshold, addShaded.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add bands after render() has been called.');
end
@@ -754,7 +754,7 @@ function addMarker(obj, x, y, varargin)
% 'Label' — text label for the marker group
%
% Note: addMarker must be called before render(). After rendering,
- % create a new FastPlot to add new markers.
+ % create a new FastSense to add new markers.
%
% Example:
% events_x = [100 500 900];
@@ -765,7 +765,7 @@ function addMarker(obj, x, y, varargin)
% See also addLine, addThreshold.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add markers after render() has been called.');
end
@@ -821,7 +821,7 @@ function addShaded(obj, x, y1, y2, varargin)
% 'DisplayName' — legend entry text
%
% Note: addShaded must be called before render(). After rendering,
- % create a new FastPlot to add new shaded regions.
+ % create a new FastSense to add new shaded regions.
%
% Example:
% x = linspace(0, 10, 1e5);
@@ -831,7 +831,7 @@ function addShaded(obj, x, y1, y2, varargin)
% See also addFill, addBand.
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
+ error('FastSense:alreadyRendered', ...
'Cannot add shaded regions after render() has been called.');
end
@@ -840,7 +840,7 @@ function addShaded(obj, x, y1, y2, varargin)
if ~isrow(y2); y2 = y2(:)'; end
if numel(x) ~= numel(y1) || numel(x) ~= numel(y2)
- error('FastPlot:sizeMismatch', ...
+ error('FastSense:sizeMismatch', ...
'X, Y1, and Y2 must have the same number of elements.');
end
@@ -850,7 +850,7 @@ function addShaded(obj, x, y1, y2, varargin)
ce = min(ci + chunkSize, nX);
dx = diff(x(ci:ce));
if any(dx(~isnan(dx)) < 0)
- error('FastPlot:nonMonotonicX', ...
+ error('FastSense:nonMonotonicX', ...
'X must be monotonically increasing.');
end
end
@@ -943,10 +943,10 @@ function render(obj, progressBar)
% 10. Registers in LinkGroup for synchronized zoom/pan
%
% fp.RENDER(progressBar) uses an existing ConsoleProgressBar
- % for progress reporting (used by FastPlotGrid for batch
+ % for progress reporting (used by FastSenseGrid for batch
% rendering of multiple tiles).
%
- % Can only be called once per FastPlot instance. After render(),
+ % Can only be called once per FastSense instance. After render(),
% addLine()/addThreshold()/addBand() will error. Use
% updateData() for live data updates.
%
@@ -955,12 +955,12 @@ function render(obj, progressBar)
% empty and ShowProgress is true, creates one
%
% Example:
- % fp = FastPlot();
+ % fp = FastSense();
% fp.addLine(x, y, 'DisplayName', 'Signal');
% fp.addThreshold(4.5, 'ShowViolations', true);
% fp.render();
%
- % See also addLine, updateData, startLive, FastPlotGrid.
+ % See also addLine, updateData, startLive, FastSenseGrid.
if nargin < 2; progressBar = []; end
@@ -976,11 +976,11 @@ function render(obj, progressBar)
if obj.Verbose; renderTic = tic; end
if obj.IsRendered
- error('FastPlot:alreadyRendered', ...
- 'render() has already been called on this FastPlot.');
+ error('FastSense:alreadyRendered', ...
+ 'render() has already been called on this FastSense.');
end
if isempty(obj.Lines)
- error('FastPlot:noLines', 'Add at least one line before render().');
+ error('FastSense:noLines', 'Add at least one line before render().');
end
% Create or use axes
@@ -1024,7 +1024,7 @@ function render(obj, progressBar)
'FaceAlpha', B.FaceAlpha, ...
'EdgeColor', B.EdgeColor, ...
'HandleVisibility', 'off');
- udB.FastPlot = struct( ...
+ udB.FastSense = struct( ...
'Type', 'band', ...
'Name', B.Label, ...
'LineIndex', [], ...
@@ -1063,7 +1063,7 @@ function render(obj, progressBar)
'FaceAlpha', S.FaceAlpha, ...
'EdgeColor', S.EdgeColor, ...
'HandleVisibility', 'off');
- udS.FastPlot = struct( ...
+ udS.FastSense = struct( ...
'Type', 'shaded', ...
'Name', S.DisplayName, ...
'LineIndex', [], ...
@@ -1132,18 +1132,18 @@ function render(obj, progressBar)
if isfield(L.Options, 'DisplayName')
displayName = L.Options.DisplayName;
end
- ud.FastPlot = struct( ...
+ ud.FastSense = struct( ...
'Type', 'data_line', ...
'Name', displayName, ...
'LineIndex', i, ...
'ThresholdValue', []);
- ud.FastPlotInstance = obj;
+ ud.FastSenseInstance = obj;
set(h, 'UserData', ud);
obj.Lines(i).hLine = h;
if obj.Verbose
- fprintf('[FastPlot] render: line %d: %d pts -> %d displayed (pw=%d)\n', ...
+ fprintf('[FastSense] render: line %d: %d pts -> %d displayed (pw=%d)\n', ...
i, nPtsLine, numel(xd), obj.PixelWidth);
end
if ~isempty(progressBar)
@@ -1156,7 +1156,7 @@ function render(obj, progressBar)
if ~obj.lineOnDisk(i)
nNonPos = sum(obj.Lines(i).Y <= 0);
if nNonPos > 0
- fprintf('[FastPlot] warning: line %d has %d non-positive values (clipped on log scale)\n', i, nNonPos);
+ fprintf('[FastSense] warning: line %d has %d non-positive values (clipped on log scale)\n', i, nNonPos);
end
end
end
@@ -1182,7 +1182,7 @@ function render(obj, progressBar)
'LineWidth', 1.5, ...
'HandleVisibility', 'off');
end
- udT.FastPlot = struct( ...
+ udT.FastSense = struct( ...
'Type', 'threshold', ...
'Name', T.Label, ...
'LineIndex', [], ...
@@ -1230,7 +1230,7 @@ function render(obj, progressBar)
'LineStyle', 'none', 'Marker', '.', ...
'MarkerSize', 6, 'Color', T.Color, ...
'HandleVisibility', 'off');
- udM.FastPlot = struct( ...
+ udM.FastSense = struct( ...
'Type', 'violation_marker', ...
'Name', T.Label, ...
'LineIndex', [], ...
@@ -1240,10 +1240,10 @@ function render(obj, progressBar)
if obj.Verbose
if isempty(T.X)
- fprintf('[FastPlot] render: threshold %.4g: %d violation markers\n', ...
+ fprintf('[FastSense] render: threshold %.4g: %d violation markers\n', ...
T.Value, numel(vxAll));
else
- fprintf('[FastPlot] render: time-varying threshold "%s": %d violation markers\n', ...
+ fprintf('[FastSense] render: time-varying threshold "%s": %d violation markers\n', ...
T.Label, numel(vxAll));
end
end
@@ -1259,7 +1259,7 @@ function render(obj, progressBar)
'MarkerSize', M.MarkerSize, ...
'Color', M.Color, ...
'HandleVisibility', 'off');
- udM.FastPlot = struct( ...
+ udM.FastSense = struct( ...
'Type', 'marker', ...
'Name', M.Label, ...
'LineIndex', [], ...
@@ -1336,7 +1336,7 @@ function render(obj, progressBar)
% when visible lines are downsampled to a zoomed sub-range.
line(obj.hAxes, [xmin xmax], [NaN NaN], ...
'HandleVisibility', 'off', 'Visible', 'off', ...
- 'Tag', 'FastPlotAnchor', ...
+ 'Tag', 'FastSenseAnchor', ...
'XLimInclude', 'on', 'YLimInclude', 'off');
% --- Install listeners ---
@@ -1415,13 +1415,13 @@ function render(obj, progressBar)
if obj.Verbose
totalPts = 0;
for i = 1:numel(obj.Lines); totalPts = totalPts + obj.lineNumPoints(i); end
- fprintf('[FastPlot] render complete: %d total pts, pw=%d, %.3fs\n', ...
+ fprintf('[FastSense] render complete: %d total pts, pw=%d, %.3fs\n', ...
totalPts, obj.PixelWidth, toc(renderTic));
end
% Register in link group
if ~isempty(obj.LinkGroup)
- FastPlot.getLinkRegistry('register', obj.LinkGroup, obj);
+ FastSense.getLinkRegistry('register', obj.LinkGroup, obj);
end
hold(obj.hAxes, 'off');
@@ -1545,11 +1545,11 @@ function updateData(obj, lineIdx, newX, newY, varargin)
% See also startLive, render, addLine.
if ~obj.IsRendered
- error('FastPlot:notRendered', ...
+ error('FastSense:notRendered', ...
'Cannot update data before render() has been called.');
end
if lineIdx < 1 || lineIdx > numel(obj.Lines)
- error('FastPlot:indexOutOfRange', ...
+ error('FastSense:indexOutOfRange', ...
'Line index %d is out of range (1-%d).', lineIdx, numel(obj.Lines));
end
@@ -1558,7 +1558,7 @@ function updateData(obj, lineIdx, newX, newY, varargin)
if ~isrow(newY); newY = newY(:)'; end
if numel(newX) ~= numel(newY)
- error('FastPlot:sizeMismatch', ...
+ error('FastSense:sizeMismatch', ...
'X and Y must have the same number of elements.');
end
@@ -1587,7 +1587,7 @@ function updateData(obj, lineIdx, newX, newY, varargin)
% Replace raw data (decide storage mode)
nPtsNew = numel(newX);
if obj.shouldUseDisk(nPtsNew)
- obj.Lines(lineIdx).DataStore = FastPlotDataStore(newX, newY);
+ obj.Lines(lineIdx).DataStore = FastSenseDataStore(newX, newY);
obj.Lines(lineIdx).X = [];
obj.Lines(lineIdx).Y = [];
else
@@ -1661,7 +1661,7 @@ function startLive(obj, filepath, updateFcn, varargin)
obj.stopRefineTimer();
if ~obj.IsRendered
- error('FastPlot:notRendered', ...
+ error('FastSense:notRendered', ...
'Cannot start live mode before render() has been called.');
end
@@ -1724,7 +1724,7 @@ function startLive(obj, filepath, updateFcn, varargin)
set(obj.hFigure, 'DeleteFcn', @(s,e) obj.onFigureCloseLive(existingDeleteFcn, s, e));
if obj.Verbose
- fprintf('[FastPlot] live mode started: %s (%.1fs interval, %s mode)\n', ...
+ fprintf('[FastSense] live mode started: %s (%.1fs interval, %s mode)\n', ...
filepath, obj.LiveInterval, obj.LiveViewMode);
end
end
@@ -1755,13 +1755,13 @@ function stopLive(obj)
end
if obj.Verbose
- fprintf('[FastPlot] live mode stopped\n');
+ fprintf('[FastSense] live mode stopped\n');
end
end
function delete(obj)
%DELETE Clean up timers and release resources.
- % Called automatically when the FastPlot object is destroyed
+ % Called automatically when the FastSense object is destroyed
% (e.g., cleared from workspace or figure closed). Stops the
% refinement timer and live polling timer to prevent dangling
% timer callbacks referencing deleted objects.
@@ -1793,11 +1793,11 @@ function refresh(obj)
%
% See also startLive, onLiveTimer.
if isempty(obj.LiveFile) || isempty(obj.LiveUpdateFcn)
- error('FastPlot:noLiveSource', ...
+ error('FastSense:noLiveSource', ...
'No live source configured. Call startLive() first or set LiveFile and LiveUpdateFcn.');
end
if ~exist(obj.LiveFile, 'file')
- warning('FastPlot:fileNotFound', 'Live file not found: %s', obj.LiveFile);
+ warning('FastSense:fileNotFound', 'Live file not found: %s', obj.LiveFile);
return;
end
@@ -1806,7 +1806,7 @@ function refresh(obj)
obj.LiveUpdateFcn(obj, data);
catch e
if obj.Verbose
- fprintf('[FastPlot] refresh error: %s\n', e.message);
+ fprintf('[FastSense] refresh error: %s\n', e.message);
end
end
@@ -1869,7 +1869,7 @@ function runLive(obj)
cleanupObj = onCleanup(@() obj.stopLive());
if obj.Verbose
- fprintf('[FastPlot] runLive: entering poll loop (%.1fs interval)\n', obj.LiveInterval);
+ fprintf('[FastSense] runLive: entering poll loop (%.1fs interval)\n', obj.LiveInterval);
end
while obj.LiveIsActive && ishandle(obj.hFigure)
@@ -1882,13 +1882,13 @@ function runLive(obj)
data = load(obj.LiveFile);
obj.LiveUpdateFcn(obj, data);
if obj.Verbose
- fprintf('[FastPlot] live update: %s\n', datestr(now, 'HH:MM:SS'));
+ fprintf('[FastSense] live update: %s\n', datestr(now, 'HH:MM:SS'));
end
end
end
catch e
if obj.Verbose
- fprintf('[FastPlot] runLive error: %s\n', e.message);
+ fprintf('[FastSense] runLive error: %s\n', e.message);
end
end
drawnow;
@@ -1896,7 +1896,7 @@ function runLive(obj)
end
if obj.Verbose
- fprintf('[FastPlot] runLive: exited poll loop\n');
+ fprintf('[FastSense] runLive: exited poll loop\n');
end
end
@@ -1914,7 +1914,7 @@ function setLineMetadata(obj, lineIdx, meta)
%SETLINEMETADATA Set metadata on a line after construction.
% fp.SETLINEMETADATA(lineIdx, meta) attaches or replaces the
% metadata struct on the specified line. Primarily used by
- % FastPlotGrid to attach metadata loaded from a separate
+ % FastSenseGrid to attach metadata loaded from a separate
% file after the plot has been rendered.
%
% The metadata struct should contain a .datenum field with
@@ -1928,7 +1928,7 @@ function setLineMetadata(obj, lineIdx, meta)
% meta = struct('datenum', [1 5], 'batch', {{'A','B'}});
% fp.setLineMetadata(1, meta);
%
- % See also lookupMetadata, addLine, FastPlotGrid.
+ % See also lookupMetadata, addLine, FastSenseGrid.
if lineIdx >= 1 && lineIdx <= numel(obj.Lines)
obj.Lines(lineIdx).Metadata = meta;
end
@@ -1953,7 +1953,7 @@ function setViolationsVisible(obj, on)
% fp.setViolationsVisible(false); % hide all markers
% fp.setViolationsVisible(true); % show and recompute
%
- % See also updateViolations, addThreshold, FastPlotToolbar.
+ % See also updateViolations, addThreshold, FastSenseToolbar.
obj.ViolationsVisible = on;
if on
obj.CachedViolationLim = []; % force recompute
@@ -1978,12 +1978,12 @@ function setViolationsVisible(obj, on)
function openLoupe(obj)
%OPENLOUPE Open a standalone enlarged copy of this tile.
- % fp.OPENLOUPE() creates a new FastPlot in a separate figure
+ % fp.OPENLOUPE() creates a new FastSense in a separate figure
% containing deep copies of all lines, thresholds, bands,
% shadings, and markers from the current plot. The new figure
% preserves the current zoom state (XLim/YLim), is offset
% by [+30, -30] pixels from the source figure, and receives
- % its own FastPlotToolbar.
+ % its own FastSenseToolbar.
%
% The loupe uses DeferDraw=true during render so the figure
% appears once with correct zoom rather than flashing at
@@ -1996,13 +1996,13 @@ function openLoupe(obj)
% Example:
% fp.openLoupe(); % or double-click on the axes
%
- % See also onAxesDoubleClick, loupeButtonFilter, FastPlotToolbar.
+ % See also onAxesDoubleClick, loupeButtonFilter, FastSenseToolbar.
% Use the source tile's title as the loupe figure name
title_str = get(get(obj.hAxes, 'Title'), 'String');
- if isempty(title_str); title_str = 'FastPlot'; end
+ if isempty(title_str); title_str = 'FastSense'; end
- % Deep-copy all data into a fresh FastPlot instance
- fp = FastPlot();
+ % Deep-copy all data into a fresh FastSense instance
+ fp = FastSense();
fp.Theme = obj.Theme;
% Copy lines (converting datenum back to datetime if needed)
@@ -2078,8 +2078,8 @@ function openLoupe(obj)
srcPos = get(ancestor(obj.hAxes, 'figure'), 'Position');
set(fp.hFigure, 'Position', srcPos + [30 -30 0 0]);
- tb = FastPlotToolbar(fp);
- setappdata(fp.hFigure, 'FastPlotToolbar', tb);
+ tb = FastSenseToolbar(fp);
+ setappdata(fp.hFigure, 'FastSenseToolbar', tb);
set(fp.hFigure, 'Visible', 'on');
drawnow;
@@ -2156,12 +2156,12 @@ function onLiveTimer(obj)
obj.LiveUpdateFcn(obj, data);
obj.drawnowLimitRate();
if obj.Verbose
- fprintf('[FastPlot] live update: %s\n', datestr(now, 'HH:MM:SS'));
+ fprintf('[FastSense] live update: %s\n', datestr(now, 'HH:MM:SS'));
end
end
catch e
if obj.Verbose
- fprintf('[FastPlot] live timer error: %s\n', e.message);
+ fprintf('[FastSense] live timer error: %s\n', e.message);
end
end
@@ -2262,11 +2262,11 @@ function applyViewMode(obj, newX)
function applyTheme(obj)
%APPLYTHEME Apply the current Theme struct to axes and figure.
% APPLYTHEME(obj) configures the figure background (only when
- % FastPlot owns the figure), axes background, foreground
+ % FastSense owns the figure), axes background, foreground
% colors, font name/size, and grid style from the Theme
% struct. Called during render() and by reapplyTheme().
%
- % See also reapplyTheme, render, FastPlotTheme.
+ % See also reapplyTheme, render, FastSenseTheme.
t = obj.Theme;
% Figure background (only if we own the figure)
@@ -2341,7 +2341,7 @@ function refineLines(obj)
set(L.hLine, 'XData', xd, 'YData', yd);
if obj.Verbose
- fprintf('[FastPlot] refine: line %d: %d pts -> %d displayed\n', ...
+ fprintf('[FastSense] refine: line %d: %d pts -> %d displayed\n', ...
i, nPtsI, numel(xd));
end
end
@@ -2439,7 +2439,7 @@ function onXLimChanged(obj, ~, ~)
obj.CachedXLim = newXLim;
if obj.Verbose
- fprintf('[FastPlot] onXLimChanged: range=[%.4g, %.4g]\n', newXLim(1), newXLim(2));
+ fprintf('[FastSense] onXLimChanged: range=[%.4g, %.4g]\n', newXLim(1), newXLim(2));
end
obj.updateLines();
@@ -2547,7 +2547,7 @@ function deferredXLimCheck(obj)
function onResize(obj, ~, ~)
%ONRESIZE Re-downsample all data when the figure is resized.
% ONRESIZE(obj, src, evt) is the figure ResizeFcn callback
- % installed during render() (only when FastPlot owns the
+ % installed during render() (only when FastSense owns the
% figure). Reads the new axes pixel width; if it changed,
% re-downsamples all lines, shadings, and violations at the
% new resolution and flushes the display.
@@ -2560,7 +2560,7 @@ function onResize(obj, ~, ~)
newPW = obj.getAxesPixelWidth();
if newPW ~= obj.PixelWidth
if obj.Verbose
- fprintf('[FastPlot] onResize: pw %d -> %d\n', obj.PixelWidth, newPW);
+ fprintf('[FastSense] onResize: pw %d -> %d\n', obj.PixelWidth, newPW);
end
obj.PixelWidth = newPW;
obj.updateLines();
@@ -2752,7 +2752,7 @@ function updateLines(obj)
else
pyrStr = 'raw';
end
- fprintf('[FastPlot] line %d: %d visible -> %d displayed (%s, pw=%d)\n', ...
+ fprintf('[FastSense] line %d: %d visible -> %d displayed (%s, pw=%d)\n', ...
i, nVis, numel(xd), pyrStr, pw);
end
end
@@ -2953,7 +2953,7 @@ function updateViolations(obj)
'LineStyle', 'none', 'Marker', '.', ...
'MarkerSize', 6, 'Color', T.Color, ...
'HandleVisibility', 'off');
- udM.FastPlot = struct( ...
+ udM.FastSense = struct( ...
'Type', 'violation_marker', ...
'Name', T.Label, ...
'LineIndex', [], ...
@@ -2998,13 +2998,13 @@ function updateViolations(obj)
vyAll = [vyCell{1:nViols}];
set(obj.Thresholds(t).hMarkers, 'XData', vxAll, 'YData', vyAll);
if obj.Verbose
- fprintf('[FastPlot] violations T%d: %d markers\n', ...
+ fprintf('[FastSense] violations T%d: %d markers\n', ...
t, numel(vxAll));
end
else
set(obj.Thresholds(t).hMarkers, 'XData', NaN, 'YData', NaN);
if obj.Verbose
- fprintf('[FastPlot] violations T%d: 0 markers\n', t);
+ fprintf('[FastSense] violations T%d: 0 markers\n', t);
end
end
end
@@ -3090,7 +3090,7 @@ function drawnowLimitRate(obj)
function propagateXLim(obj, newXLim)
%PROPAGATEXLIM Sync XLim to all members of the link group.
- % PROPAGATEXLIM(obj, newXLim) retrieves all FastPlot instances
+ % PROPAGATEXLIM(obj, newXLim) retrieves all FastSense instances
% registered in the same LinkGroup, then sets each one's XLim
% to newXLim and re-downsamples its lines, shadings, and
% violations. Each member's IsPropagating flag is set to true
@@ -3100,7 +3100,7 @@ function propagateXLim(obj, newXLim)
% newXLim — 1-by-2 vector [xmin xmax] to apply
%
% See also onXLimChanged, getLinkRegistry.
- members = FastPlot.getLinkRegistry('get', obj.LinkGroup, []);
+ members = FastSense.getLinkRegistry('get', obj.LinkGroup, []);
for i = 1:numel(members)
other = members{i};
if other.hAxes ~= obj.hAxes && ishandle(other.hAxes)
@@ -3117,13 +3117,13 @@ function propagateXLim(obj, newXLim)
end
% ======================== STATIC HELPERS =============================
- % Persistent registry for linked FastPlot groups.
+ % Persistent registry for linked FastSense groups.
methods (Static, Access = private)
function registry = getLinkRegistry(action, group, obj)
- %GETLINKREGISTRY Persistent registry for linked FastPlot instances.
+ %GETLINKREGISTRY Persistent registry for linked FastSense instances.
% registry = GETLINKREGISTRY(action, group, obj) manages a
% persistent struct that maps group names to cell arrays of
- % FastPlot handles. Group names are sanitized via
+ % FastSense handles. Group names are sanitized via
% matlab.lang.makeValidName.
%
% Actions:
@@ -3134,10 +3134,10 @@ function propagateXLim(obj, newXLim)
% Inputs:
% action — 'register', 'get', or 'cleanup'
% group — string group name (from LinkGroup property)
- % obj — FastPlot instance (used for 'register' only)
+ % obj — FastSense instance (used for 'register' only)
%
% Output:
- % registry — cell array of FastPlot handles (for 'get'),
+ % registry — cell array of FastSense handles (for 'get'),
% or [] for other actions
%
% See also propagateXLim, render.
@@ -3178,19 +3178,19 @@ function propagateXLim(obj, newXLim)
methods (Static)
function fp = plot(x, y, varargin)
%PLOT One-liner convenience for quick plotting.
- % FastPlot.plot(x, y)
- % FastPlot.plot(x, y, 'DisplayName', 'Signal', 'Theme', 'dark')
+ % FastSense.plot(x, y)
+ % FastSense.plot(x, y, 'DisplayName', 'Signal', 'Theme', 'dark')
%
- % Creates a FastPlot, adds a single line, and renders immediately.
- % Returns the FastPlot handle for further customization.
+ % Creates a FastSense, adds a single line, and renders immediately.
+ % Returns the FastSense handle for further customization.
%
% For multi-line plots or advanced features, use the builder pattern:
- % fp = FastPlot();
+ % fp = FastSense();
% fp.addLine(x1, y1);
% fp.addLine(x2, y2);
% fp.render();
- % Separate FastPlot constructor args from addLine args
+ % Separate FastSense constructor args from addLine args
fpArgs = {};
lineArgs = {};
fpProps = {'Parent', 'LinkGroup', 'Theme', 'Verbose', ...
@@ -3208,32 +3208,32 @@ function propagateXLim(obj, newXLim)
end
end
- fp = FastPlot(fpArgs{:});
+ fp = FastSense(fpArgs{:});
fp.addLine(x, y, lineArgs{:});
fp.render();
end
function resetDefaults()
- %RESETDEFAULTS Force reload of FastPlotDefaults on next use.
- % FastPlot.RESETDEFAULTS() clears the cached defaults struct
- % so the next FastPlot constructor will re-read
- % FastPlotDefaults.m. Useful after editing the defaults file
+ %RESETDEFAULTS Force reload of FastSenseDefaults on next use.
+ % FastSense.RESETDEFAULTS() clears the cached defaults struct
+ % so the next FastSense constructor will re-read
+ % FastSenseDefaults.m. Useful after editing the defaults file
% in a running session.
%
% Example:
- % FastPlot.resetDefaults();
- % fp = FastPlot(); % picks up new defaults
+ % FastSense.resetDefaults();
+ % fp = FastSense(); % picks up new defaults
%
- % See also FastPlot, getDefaults, clearDefaultsCache.
+ % See also FastSense, getDefaults, clearDefaultsCache.
clearDefaultsCache();
end
function distFig(varargin)
%DISTFIG Distribute figure windows across the screen.
- % FastPlot.DISTFIG() auto-arranges all open figure windows
+ % FastSense.DISTFIG() auto-arranges all open figure windows
% in a grid that fills the screen. Figures are sorted by
% number and tiled left-to-right, top-to-bottom.
- % FastPlot.DISTFIG('Rows', 2, 'Cols', 3) uses a 2-by-3 grid.
+ % FastSense.DISTFIG('Rows', 2, 'Cols', 3) uses a 2-by-3 grid.
%
% Delegates to the vendored distFig function (in vendor/).
% Adds the vendor path automatically if not already on path.
@@ -3244,10 +3244,10 @@ function distFig(varargin)
% 'Cols' — number of grid columns
%
% Example:
- % FastPlot.distFig();
- % FastPlot.distFig('Rows', 2, 'Cols', 3);
+ % FastSense.distFig();
+ % FastSense.distFig('Rows', 2, 'Cols', 3);
%
- % See also FastPlotDock.
+ % See also FastSenseDock.
vendorDir = fullfile(fileparts(mfilename('fullpath')), 'vendor', 'distFig');
if ~exist('distFig', 'file')
addpath(vendorDir);
diff --git a/libs/FastPlot/FastPlotDataStore.m b/libs/FastSense/FastSenseDataStore.m
similarity index 97%
rename from libs/FastPlot/FastPlotDataStore.m
rename to libs/FastSense/FastSenseDataStore.m
index 96b82327..eb280b46 100644
--- a/libs/FastPlot/FastPlotDataStore.m
+++ b/libs/FastSense/FastSenseDataStore.m
@@ -1,5 +1,5 @@
-classdef FastPlotDataStore < handle
- %FASTPLOTDATASTORE SQLite-backed data storage for large time series.
+classdef FastSenseDataStore < handle
+ %FASTSENSEDATASTORE SQLite-backed data storage for large time series.
% Stores X/Y data in a temporary SQLite database via mksqlite using
% chunked typed BLOBs for fast bulk insert and range-based retrieval.
% This avoids loading full datasets into MATLAB memory, preventing
@@ -18,7 +18,7 @@
% storage (extra columns require mksqlite).
%
% Usage:
- % ds = FastPlotDataStore(x, y);
+ % ds = FastSenseDataStore(x, y);
% [xVis, yVis] = ds.getRange(xMin, xMax);
% [xSlice, ySlice] = ds.readSlice(1000, 2000);
%
@@ -28,7 +28,7 @@
% vals = ds.getColumnSlice('labels', 1, 100);
% names = ds.listColumns();
%
- % See also FastPlot, FastPlotDefaults, mksqlite.
+ % See also FastSense, FastSenseDefaults, mksqlite.
properties (SetAccess = private)
NumPoints = 0
@@ -52,8 +52,8 @@
end
methods (Access = public)
- function obj = FastPlotDataStore(x, y)
- %FASTPLOTDATASTORE Create a disk-backed store from X/Y arrays.
+ function obj = FastSenseDataStore(x, y)
+ %FASTSENSEDATASTORE Create a disk-backed store from X/Y arrays.
if nargin < 2; return; end
obj.NumPoints = numel(x);
@@ -75,7 +75,7 @@
% Pre-compute L1 minmax pyramid while data is in memory.
% This avoids re-reading the full dataset from disk on first
- % render. Reduction factor 100 matches FastPlot.PyramidReduction.
+ % render. Reduction factor 100 matches FastSense.PyramidReduction.
obj.buildPyramidFromMemory(x, y, 100);
end
@@ -118,18 +118,18 @@ function addColumn(obj, name, data)
% Categorical arrays auto-convert to codes+categories struct.
% String arrays auto-convert to cell of char.
if ~obj.UseSqlite
- error('FastPlotDataStore:noSqlite', ...
+ error('FastSenseDataStore:noSqlite', ...
'addColumn requires mksqlite (SQLite backend).');
end
obj.ensureOpen();
if ~obj.IsValid
- error('FastPlotDataStore:notValid', ...
+ error('FastSenseDataStore:notValid', ...
'DataStore is not initialized.');
end
% Auto-convert types
if isa(data, 'categorical')
- data = FastPlotDataStore.fromCategorical(data);
+ data = FastSenseDataStore.fromCategorical(data);
end
if isa(data, 'string')
data = cellstr(data);
@@ -138,7 +138,7 @@ function addColumn(obj, name, data)
% Validate length
nData = columnLength(data);
if nData ~= obj.NumPoints
- error('FastPlotDataStore:sizeMismatch', ...
+ error('FastSenseDataStore:sizeMismatch', ...
'Column data length (%d) must match NumPoints (%d).', ...
nData, obj.NumPoints);
end
@@ -157,7 +157,7 @@ function addColumn(obj, name, data)
end
if any(strcmp(name, obj.ColumnNames))
- error('FastPlotDataStore:duplicateColumn', ...
+ error('FastSenseDataStore:duplicateColumn', ...
'Column ''%s'' already exists.', name);
end
@@ -381,7 +381,7 @@ function disableWAL(obj)
function c = toCategorical(s)
%TOCATEGORICAL Convert a codes+categories struct back to categorical.
if ~isCategoricalStruct(s)
- error('FastPlotDataStore:badInput', ...
+ error('FastSenseDataStore:badInput', ...
'Input must be a struct with ''codes'' and ''categories'' fields.');
end
catNames = s.categories(:)';
@@ -395,7 +395,7 @@ function disableWAL(obj)
function c = fromCategorical(data)
%FROMCATEGORICAL Convert a MATLAB categorical to codes+categories struct.
if ~isa(data, 'categorical')
- error('FastPlotDataStore:badInput', ...
+ error('FastSenseDataStore:badInput', ...
'Input must be a categorical array.');
end
catNames = categories(data);
@@ -545,7 +545,7 @@ function initSqlite(obj, x, y)
obj.IsValid = true;
return;
catch me
- warning('FastPlot:build_store_mex:fallback', ...
+ warning('FastSense:build_store_mex:fallback', ...
'build_store_mex failed (%s), falling back to MATLAB path.', me.message);
if exist(obj.DbPath, 'file'); delete(obj.DbPath); end
end
@@ -750,7 +750,7 @@ function initBinaryFallback(obj, x, y)
obj.BinPath = [tempname, '.fpdat'];
fid = fopen(obj.BinPath, 'wb');
if fid == -1
- error('FastPlotDataStore:fileError', ...
+ error('FastSenseDataStore:fileError', ...
'Cannot create temp file: %s', obj.BinPath);
end
try
@@ -790,7 +790,7 @@ function initBinaryFallback(obj, x, y)
function [xOut, yOut] = readSliceBinary(obj, startIdx, endIdx)
fid = fopen(obj.BinPath, 'rb');
if fid == -1
- error('FastPlotDataStore:fileError', ...
+ error('FastSenseDataStore:fileError', ...
'Cannot read temp file: %s', obj.BinPath);
end
count = endIdx - startIdx + 1;
diff --git a/libs/FastPlot/FastPlotDefaults.m b/libs/FastSense/FastSenseDefaults.m
similarity index 93%
rename from libs/FastPlot/FastPlotDefaults.m
rename to libs/FastSense/FastSenseDefaults.m
index 06c62294..43b076e6 100644
--- a/libs/FastPlot/FastPlotDefaults.m
+++ b/libs/FastSense/FastSenseDefaults.m
@@ -1,7 +1,7 @@
-function cfg = FastPlotDefaults()
-%FASTPLOTDEFAULTS User-editable default settings for FastPlot.
-% cfg = FASTPLOTDEFAULTS() returns a struct of global defaults used by
-% FastPlot, FastPlotGrid, and FastPlotDock. Edit this file to
+function cfg = FastSenseDefaults()
+%FASTSENSEDEFAULTS User-editable default settings for FastSense.
+% cfg = FASTSENSEDEFAULTS() returns a struct of global defaults used by
+% FastSense, FastSenseGrid, and FastSenseDock. Edit this file to
% customize behavior project-wide.
%
% Values are loaded once per MATLAB session via getDefaults() and cached
@@ -77,16 +77,16 @@
% SensorDetailPlot (default: 0.20)
%
% Example — switch to dark theme with LTTB downsampling:
-% cfg = FastPlotDefaults();
+% cfg = FastSenseDefaults();
% cfg.Theme = 'dark';
% cfg.DefaultDownsampleMethod = 'lttb';
%
% Example — widen tile gaps for a spacious dashboard:
-% cfg = FastPlotDefaults();
+% cfg = FastSenseDefaults();
% cfg.DashboardGapH = 0.06;
% cfg.DashboardGapV = 0.10;
%
-% See also getDefaults, clearDefaultsCache, FastPlotTheme.
+% See also getDefaults, clearDefaultsCache, FastSenseTheme.
% --- Theme ---
cfg.Theme = 'default'; % preset name or struct
diff --git a/libs/FastPlot/FastPlotDock.m b/libs/FastSense/FastSenseDock.m
similarity index 93%
rename from libs/FastPlot/FastPlotDock.m
rename to libs/FastSense/FastSenseDock.m
index 946ccf00..2560565e 100644
--- a/libs/FastPlot/FastPlotDock.m
+++ b/libs/FastSense/FastSenseDock.m
@@ -1,27 +1,27 @@
-classdef FastPlotDock < handle
- %FASTPLOTDOCK Tabbed container for multiple FastPlotGrid dashboards.
- % Manages multiple FastPlotGrid instances as switchable tabs in a
+classdef FastSenseDock < handle
+ %FASTSENSEDOCK Tabbed container for multiple FastSenseGrid dashboards.
+ % Manages multiple FastSenseGrid instances as switchable tabs in a
% single window. Each tab has its own panel, toolbar, close button,
% and undock button. Tabs can be dynamically added, removed, or
% popped out into standalone figures.
%
- % dock = FastPlotDock()
- % dock = FastPlotDock('Theme', 'dark')
- % dock = FastPlotDock('Theme', 'dark', 'Name', 'My Dock')
+ % dock = FastSenseDock()
+ % dock = FastSenseDock('Theme', 'dark')
+ % dock = FastSenseDock('Theme', 'dark', 'Name', 'My Dock')
%
% Constructor options (name-value):
- % 'Theme' — theme preset name, struct, or FastPlotTheme
+ % 'Theme' — theme preset name, struct, or FastSenseTheme
% Any additional name-value pairs are passed to figure().
%
- % FastPlotDock Properties:
- % Theme — FastPlotTheme struct applied to all tabs
+ % FastSenseDock Properties:
+ % Theme — FastSenseTheme struct applied to all tabs
% hFigure — shared figure handle for the dock window
% ShowProgress — show console progress bar during renderAll
% TabBarHeight — normalized height of the tab bar (default 0.03)
%
- % FastPlotDock Methods:
- % FastPlotDock — construct a tabbed dock container
- % addTab — register a FastPlotGrid as a tab
+ % FastSenseDock Methods:
+ % FastSenseDock — construct a tabbed dock container
+ % addTab — register a FastSenseGrid as a tab
% render — render active tab, create tab bar, show first tab
% renderAll — eagerly render all tabs with hierarchical progress
% selectTab — switch to tab n, rendering lazily if needed
@@ -32,20 +32,20 @@
% delete — clean up dock: stop all live timers and close figure
%
% Example:
- % dock = FastPlotDock('Theme', 'dark', 'Name', 'Dashboard');
- % fig1 = FastPlotGrid(2, 1, 'ParentFigure', dock.hFigure);
+ % dock = FastSenseDock('Theme', 'dark', 'Name', 'Dashboard');
+ % fig1 = FastSenseGrid(2, 1, 'ParentFigure', dock.hFigure);
% fig1.tile(1).addLine(x, y1); fig1.tile(2).addLine(x, y2);
% dock.addTab(fig1, 'Temperature');
- % fig2 = FastPlotGrid(1, 1, 'ParentFigure', dock.hFigure);
+ % fig2 = FastSenseGrid(1, 1, 'ParentFigure', dock.hFigure);
% fig2.tile(1).addLine(x, y3);
% dock.addTab(fig2, 'Pressure');
% dock.render();
%
- % See also FastPlotGrid, FastPlot, FastPlotToolbar, FastPlotTheme.
+ % See also FastSenseGrid, FastSense, FastSenseToolbar, FastSenseTheme.
% ========================= PUBLIC PROPERTIES =========================
properties (Access = public)
- Theme = [] % FastPlotTheme struct
+ Theme = [] % FastSenseTheme struct
hFigure = [] % shared figure handle
ShowProgress = true % show console progress bar during renderAll
end
@@ -53,7 +53,7 @@
% ====================== INTERNAL STATE ===============================
properties (SetAccess = private)
Tabs = struct('Name', {}, 'Figure', {}, 'Panel', {}, 'IsRendered', {})
- Toolbar = [] % shared FastPlotToolbar instance
+ Toolbar = [] % shared FastSenseToolbar instance
ActiveTab = 0 % index of currently visible tab
hTabButtons = {} % cell array of uicontrol handles
hCloseButtons = {} % cell array of close button handles
@@ -73,13 +73,13 @@
end
methods (Access = public)
- function obj = FastPlotDock(varargin)
- %FASTPLOTDOCK Construct a tabbed dock container.
- % dock = FastPlotDock()
- % dock = FastPlotDock('Theme', 'dark', 'Name', 'My Dock')
+ function obj = FastSenseDock(varargin)
+ %FASTSENSEDOCK Construct a tabbed dock container.
+ % dock = FastSenseDock()
+ % dock = FastSenseDock('Theme', 'dark', 'Name', 'My Dock')
%
% Creates a figure with a tab bar. Use addTab() to register
- % FastPlotGrid instances, then call render().
+ % FastSenseGrid instances, then call render().
cfg = getDefaults();
obj.TabBarHeight = cfg.TabBarHeight;
obj.MinTabWidth = cfg.MinTabWidth;
@@ -93,12 +93,12 @@
'Color', obj.Theme.Background, figOptsCell{:});
set(obj.hFigure, 'SizeChangedFcn', @(s,e) obj.recomputeLayout());
set(obj.hFigure, 'CloseRequestFcn', @(s,e) obj.onClose());
- setappdata(obj.hFigure, 'FastPlotDock', obj);
+ setappdata(obj.hFigure, 'FastSenseDock', obj);
end
function addTab(obj, fig, name)
- %ADDTAB Register a FastPlotGrid as a tab.
- % dock.addTab(fig, name) adds a FastPlotGrid as a new tab
+ %ADDTAB Register a FastSenseGrid as a tab.
+ % dock.addTab(fig, name) adds a FastSenseGrid as a new tab
% in the dock. The figure's ParentFigure and hFigure are
% redirected to the dock's shared figure. A uipanel is created
% for the tab's content, offset below the tab bar.
@@ -107,7 +107,7 @@ function addTab(obj, fig, name)
% the new tab is rendered immediately and its button is added.
%
% Inputs:
- % fig — FastPlotGrid instance to dock
+ % fig — FastSenseGrid instance to dock
% name — display name for the tab button
%
% See also removeTab, undockTab, selectTab.
@@ -147,7 +147,7 @@ function render(obj)
%RENDER Render active tab, create tab bar, show first tab.
% dock.render() renders only the first tab (lazy rendering),
% creates tab bar buttons for all tabs, attaches a shared
- % FastPlotToolbar, selects tab 1, and makes the figure visible.
+ % FastSenseToolbar, selects tab 1, and makes the figure visible.
% Subsequent tabs are rendered on-demand when selectTab is called.
%
% See also renderAll, selectTab.
@@ -173,7 +173,7 @@ function render(obj)
obj.createTabBar();
% Create shared toolbar for first tab
- obj.Toolbar = FastPlotToolbar(obj.Tabs(1).Figure);
+ obj.Toolbar = FastSenseToolbar(obj.Tabs(1).Figure);
% Show the first tab
obj.selectTab(1);
@@ -225,7 +225,7 @@ function renderAll(obj)
obj.createTabBar();
% Create shared toolbar, then show tab 1
- obj.Toolbar = FastPlotToolbar(obj.Tabs(1).Figure);
+ obj.Toolbar = FastSenseToolbar(obj.Tabs(1).Figure);
obj.selectTab(1);
set(obj.hFigure, 'Visible', 'on');
@@ -236,14 +236,14 @@ function selectTab(obj, n)
%SELECTTAB Switch to tab n, rendering it lazily if needed.
% dock.selectTab(n) hides the currently active tab, renders
% tab n if it hasn't been rendered yet, rebinds the shared
- % toolbar to the new tab's FastPlotGrid, and shows tab n.
+ % toolbar to the new tab's FastSenseGrid, and shows tab n.
%
% Input:
% n — tab index (1 to numel(Tabs))
%
% See also addTab, removeTab, render.
if n < 1 || n > numel(obj.Tabs)
- error('FastPlotDock:outOfBounds', ...
+ error('FastSenseDock:outOfBounds', ...
'Tab %d is out of range (1-%d).', n, numel(obj.Tabs));
end
@@ -261,7 +261,7 @@ function selectTab(obj, n)
if ~isempty(obj.Toolbar)
obj.Toolbar.rebind(obj.Tabs(n).Figure);
else
- obj.Toolbar = FastPlotToolbar(obj.Tabs(n).Figure);
+ obj.Toolbar = FastSenseToolbar(obj.Tabs(n).Figure);
end
% Hide current tab
@@ -349,7 +349,7 @@ function undockTab(obj, n)
% dock.undockTab(n) creates a new standalone figure, stops
% live mode, reparents all tile axes from the dock panel to
% the new figure, recomputes tile positions for standalone
- % layout, creates a fresh FastPlotToolbar, and removes the
+ % layout, creates a fresh FastSenseToolbar, and removes the
% tab from the dock. The remaining dock tabs are reindexed
% and the tab bar is rebuilt.
%
@@ -416,7 +416,7 @@ function undockTab(obj, n)
obj.hUndockButtons(n) = [];
% Create toolbar on the new standalone figure
- FastPlotToolbar(fig);
+ FastSenseToolbar(fig);
% Show the new figure (suppress MATLAB R2025b reparenting warnings)
set(newFig, 'Visible', 'on');
@@ -549,10 +549,10 @@ function reapplyTheme(obj)
%REAPPLYTHEME Re-apply theme to dock, tab bar, panels, and all tabs.
% dock.reapplyTheme() updates the figure background, re-styles
% all tab/undock/close buttons, updates panel backgrounds, and
- % propagates the theme to every tab's FastPlotGrid (calling
+ % propagates the theme to every tab's FastSenseGrid (calling
% reapplyTheme on rendered figures).
%
- % See also FastPlotGrid.reapplyTheme.
+ % See also FastSenseGrid.reapplyTheme.
set(obj.hFigure, 'Color', obj.Theme.Background);
for i = 1:numel(obj.hTabButtons)
if ishandle(obj.hTabButtons{i})
@@ -619,7 +619,7 @@ function delete(obj)
function reparentAxes(obj, idx)
%REPARENTAXES Move all tile axes into the tab's panel.
% reparentAxes(obj, idx) sets the Parent of every tile axes
- % in tab idx's FastPlotGrid to the tab's uipanel. This
+ % in tab idx's FastSenseGrid to the tab's uipanel. This
% ensures axes are clipped to the panel and hidden/shown
% with it during tab switching.
%
@@ -637,7 +637,7 @@ function reparentAxes(obj, idx)
function renderTab(obj, idx)
%RENDERTAB Render a single tab: figure and axes reparenting.
% renderTab(obj, idx) calls renderAll on the tab's
- % FastPlotGrid, reparents the axes into the tab's panel,
+ % FastSenseGrid, reparents the axes into the tab's panel,
% and marks the tab as rendered.
%
% Input:
diff --git a/libs/FastPlot/FastPlotGrid.m b/libs/FastSense/FastSenseGrid.m
similarity index 91%
rename from libs/FastPlot/FastPlotGrid.m
rename to libs/FastSense/FastSenseGrid.m
index 835a15a8..164a3b7b 100644
--- a/libs/FastPlot/FastPlotGrid.m
+++ b/libs/FastSense/FastSenseGrid.m
@@ -1,24 +1,24 @@
-classdef FastPlotGrid < handle
- %FASTPLOTGRID Tiled layout manager for FastPlot dashboards.
- % Creates a grid of FastPlot tiles in a single figure window with
+classdef FastSenseGrid < handle
+ %FASTSENSEGRID Tiled layout manager for FastSense dashboards.
+ % Creates a grid of FastSense tiles in a single figure window with
% configurable spacing, per-tile theme overrides, and tile spanning.
% Supports live mode that synchronizes file polling across all tiles.
%
% For widget-based dashboards with gauges, numbers, status indicators,
% and edit mode, see DashboardEngine.
%
- % fig = FastPlotGrid(rows, cols)
- % fig = FastPlotGrid(rows, cols, 'Theme', 'dark')
- % fig = FastPlotGrid(rows, cols, 'ParentFigure', hFig)
+ % fig = FastSenseGrid(rows, cols)
+ % fig = FastSenseGrid(rows, cols, 'Theme', 'dark')
+ % fig = FastSenseGrid(rows, cols, 'ParentFigure', hFig)
%
% Constructor options (name-value):
- % 'Theme' — theme preset name, struct, or FastPlotTheme
+ % 'Theme' — theme preset name, struct, or FastSenseTheme
% 'ParentFigure' — existing figure handle (skip figure creation)
% Any additional name-value pairs are passed to figure().
%
- % FastPlotGrid Properties:
+ % FastSenseGrid Properties:
% Grid — [rows, cols] grid dimensions
- % Theme — FastPlotTheme struct for all tiles
+ % Theme — FastSenseTheme struct for all tiles
% hFigure — figure handle
% ParentFigure — external figure handle (skip figure creation)
% ContentOffset — [left bottom width height] normalized content area
@@ -36,9 +36,9 @@
% GapH — horizontal gap between tiles (normalized)
% GapV — vertical gap between tiles (normalized)
%
- % FastPlotGrid Methods:
- % FastPlotGrid — construct a tiled dashboard
- % tile — get or create the FastPlot instance for tile n
+ % FastSenseGrid Methods:
+ % FastSenseGrid — construct a tiled dashboard
+ % tile — get or create the FastSense instance for tile n
% axes — get or create a raw MATLAB axes for tile n
% setTileSpan — set the row/column span for tile n
% setTileTheme — set per-tile theme overrides
@@ -56,27 +56,27 @@
% computeTilePosition — calculate normalized [x y w h] for tile n
%
% Example — 2x2 dashboard:
- % fig = FastPlotGrid(2, 2, 'Theme', 'dark');
+ % fig = FastSenseGrid(2, 2, 'Theme', 'dark');
% fig.tile(1).addLine(x1, y1); fig.tile(2).addLine(x2, y2);
% fig.tile(3).addLine(x3, y3); fig.tile(4).addLine(x4, y4);
% fig.renderAll();
%
% Example — tile spanning:
- % fig = FastPlotGrid(2, 2);
+ % fig = FastSenseGrid(2, 2);
% fig.setTileSpan(1, [1, 2]); % tile 1 spans full width
% fig.tile(1).addLine(x, y);
% fig.renderAll();
%
% Example — mixed tile types:
- % fig = FastPlotGrid(2, 2, 'Theme', 'dark');
- % fig.tile(1).addLine(t, y1); % FastPlot (optimized)
+ % fig = FastSenseGrid(2, 2, 'Theme', 'dark');
+ % fig.tile(1).addLine(t, y1); % FastSense (optimized)
% ax = fig.axes(2); bar(ax, x, y2); % raw axes (bar chart)
% ax = fig.axes(3); scatter(ax, x, y3); % raw axes (scatter)
- % fig.tile(4).addLine(t, y4); % FastPlot (optimized)
+ % fig.tile(4).addLine(t, y4); % FastSense (optimized)
% fig.renderAll();
%
% Example — embedding custom content in a tile:
- % fig = FastPlotGrid(2, 2);
+ % fig = FastSenseGrid(2, 2);
% fig.tile(1).addLine(x, y1);
% hp = fig.tilePanel(2); % raw uipanel for custom content
% uicontrol(hp, 'Style', 'text', 'String', 'KPI: 42.5', ...
@@ -85,12 +85,12 @@
% fig.tile(3).addLine(x, y2);
% fig.renderAll();
%
- % See also FastPlot, FastPlotDock, FastPlotTheme, FastPlotToolbar, DashboardEngine.
+ % See also FastSense, FastSenseDock, FastSenseTheme, FastSenseToolbar, DashboardEngine.
% ========================= PUBLIC PROPERTIES =========================
properties (Access = public)
Grid = [1 1] % [rows, cols]
- Theme = [] % FastPlotTheme struct
+ Theme = [] % FastSenseTheme struct
hFigure = [] % figure handle
ParentFigure = [] % external figure handle (skip figure creation)
ContentOffset = [0 0 1 1] % [left bottom width height] normalized content area
@@ -108,14 +108,14 @@
% ====================== INTERNAL STATE ===============================
properties (SetAccess = private)
- Tiles = {} % cell array of FastPlot instances
+ Tiles = {} % cell array of FastSense instances
TileAxes = {} % cell array of axes handles
TileSpans = {} % cell array of [rowSpan, colSpan]
TileThemes = {} % cell array of theme override structs
TileTitles = {} % cell array of buffered title strings
TileXLabels = {} % cell array of buffered xlabel strings
TileYLabels = {} % cell array of buffered ylabel strings
- RawAxesTiles = [] % logical array: true = raw axes, false = FastPlot
+ RawAxesTiles = [] % logical array: true = raw axes, false = FastSense
IsRendered = false
LiveTimer = [] % timer object
LiveFileDate = 0 % last known file datenum
@@ -131,10 +131,10 @@
end
methods (Access = public)
- function obj = FastPlotGrid(rows, cols, varargin)
- %FASTPLOTGRID Construct a tiled dashboard.
- % fig = FastPlotGrid(rows, cols)
- % fig = FastPlotGrid(rows, cols, 'Theme', 'dark')
+ function obj = FastSenseGrid(rows, cols, varargin)
+ %FASTSENSEGRID Construct a tiled dashboard.
+ % fig = FastSenseGrid(rows, cols)
+ % fig = FastSenseGrid(rows, cols, 'Theme', 'dark')
%
% rows, cols — grid dimensions
% Remaining name-value pairs: 'Theme', 'ParentFigure', or
@@ -181,8 +181,8 @@
end
function fp = tile(obj, n)
- %TILE Get or create the FastPlot instance for tile n.
- % fp = fig.tile(n) returns the FastPlot for tile n, creating
+ %TILE Get or create the FastSense instance for tile n.
+ % fp = fig.tile(n) returns the FastSense for tile n, creating
% it (and its axes) on first access. Tile themes are merged
% from the figure theme and any per-tile overrides.
%
@@ -190,17 +190,17 @@
% n — tile index (1 to rows*cols, row-major order)
%
% Output:
- % fp — FastPlot instance for the requested tile
+ % fp — FastSense instance for the requested tile
%
% See also setTileSpan, setTileTheme.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotGrid:outOfBounds', ...
+ error('FastSenseGrid:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
if obj.RawAxesTiles(n)
- error('FastPlotGrid:tileConflict', ...
+ error('FastSenseGrid:tileConflict', ...
'Tile %d is a raw axes tile. Use axes(%d) to access it.', n, n);
end
@@ -214,7 +214,7 @@
tileTheme = mergeTheme(tileTheme, obj.TileThemes{n});
end
- fp = FastPlot('Parent', ax, 'Theme', tileTheme);
+ fp = FastSense('Parent', ax, 'Theme', tileTheme);
obj.Tiles{n} = fp;
else
fp = obj.Tiles{n};
@@ -224,12 +224,12 @@
function ax = axes(obj, n)
%AXES Get or create a raw MATLAB axes for tile n.
% ax = fig.axes(n) returns a themed MATLAB axes handle at the
- % position for tile n. Use for non-FastPlot plot types (bar,
+ % position for tile n. Use for non-FastSense plot types (bar,
% scatter, histogram, stem, etc.). The axes gets theme colors
- % applied but no FastPlot optimization.
+ % applied but no FastSense optimization.
%
% Mutually exclusive with tile(n) — a tile cannot be both a
- % FastPlot and a raw axes.
+ % FastSense and a raw axes.
%
% Input:
% n — tile index (1 to rows*cols, row-major order)
@@ -244,13 +244,13 @@
% See also tile, setTileSpan.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotGrid:outOfBounds', ...
+ error('FastSenseGrid:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
if ~isempty(obj.Tiles{n})
- error('FastPlotGrid:tileConflict', ...
- 'Tile %d is a FastPlot tile. Use tile(%d) to access it.', n, n);
+ error('FastSenseGrid:tileConflict', ...
+ 'Tile %d is a FastSense tile. Use tile(%d) to access it.', n, n);
end
if isempty(obj.TileAxes{n})
@@ -270,11 +270,11 @@
% composite widgets (e.g. SensorDetailPlot) into a tile.
%
% Throws an error if tile n is already occupied by a
- % FastPlot (via tile()) or raw axes (via axes()).
+ % FastSense (via tile()) or raw axes (via axes()).
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotGrid:invalidTile', ...
+ error('FastSenseGrid:invalidTile', ...
'Tile index %d is out of range [1, %d].', n, nTiles);
end
@@ -284,15 +284,15 @@
return;
end
- % Conflict check: occupied by FastPlot?
+ % Conflict check: occupied by FastSense?
if ~isempty(obj.Tiles{n})
- error('FastPlotGrid:tileConflict', ...
- 'Tile %d is a FastPlot tile. Use tile(%d) to access it.', n, n);
+ error('FastSenseGrid:tileConflict', ...
+ 'Tile %d is a FastSense tile. Use tile(%d) to access it.', n, n);
end
% Conflict check: occupied by raw axes?
if obj.RawAxesTiles(n)
- error('FastPlotGrid:tileConflict', ...
+ error('FastSenseGrid:tileConflict', ...
'Tile %d is a raw axes tile. Use axes(%d) to access it.', n, n);
end
@@ -305,7 +305,7 @@
% Attach theme so embedded widgets (e.g. SensorDetailPlot) can
% auto-inherit the figure's theme without explicit Theme arg.
- hp.UserData = struct('FastPlotTheme', obj.Theme);
+ hp.UserData = struct('FastSenseTheme', obj.Theme);
% Store panel handle (reuses TileAxes cell for storage)
obj.TileAxes{n} = hp;
@@ -331,7 +331,7 @@ function setTileSpan(obj, n, span)
% See also tile, computeTilePosition.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotGrid:outOfBounds', ...
+ error('FastSenseGrid:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
obj.TileSpans{n} = span;
@@ -359,7 +359,7 @@ function setTileTheme(obj, n, themeOverrides)
% See also tile, reapplyTheme.
nTiles = obj.Grid(1) * obj.Grid(2);
if n < 1 || n > nTiles
- error('FastPlotGrid:outOfBounds', ...
+ error('FastSenseGrid:outOfBounds', ...
'Tile %d is out of range (1-%d).', n, nTiles);
end
obj.TileThemes{n} = themeOverrides;
@@ -436,7 +436,7 @@ function renderAll(obj, parentProgressBar)
% See also render, tile.
if nargin < 2; parentProgressBar = []; end
- % Collect FastPlot tiles that need rendering (skip raw axes tiles)
+ % Collect FastSense tiles that need rendering (skip raw axes tiles)
tilesToRender = [];
for i = 1:numel(obj.Tiles)
if obj.RawAxesTiles(i)
@@ -531,7 +531,7 @@ function reapplyTheme(obj)
%
% Use after changing fig.Theme to update all visuals.
%
- % See also setTileTheme, FastPlot.reapplyTheme.
+ % See also setTileTheme, FastSense.reapplyTheme.
set(obj.hFigure, 'Color', obj.Theme.Background);
for i = 1:numel(obj.Tiles)
if obj.RawAxesTiles(i)
@@ -592,7 +592,7 @@ function startLive(obj, filepath, updateFcn, varargin)
obj.LiveViewMode = 'preserve';
end
- % Set view mode on FastPlot tiles only (raw axes tiles are unmanaged)
+ % Set view mode on FastSense tiles only (raw axes tiles are unmanaged)
for i = 1:numel(obj.Tiles)
if ~obj.RawAxesTiles(i) && ~isempty(obj.Tiles{i})
obj.Tiles{i}.LiveViewMode = obj.LiveViewMode;
@@ -653,11 +653,11 @@ function refresh(obj)
%
% See also startLive, stopLive.
if isempty(obj.LiveFile) || isempty(obj.LiveUpdateFcn)
- error('FastPlotGrid:noLiveSource', ...
+ error('FastSenseGrid:noLiveSource', ...
'No live source configured.');
end
if ~exist(obj.LiveFile, 'file')
- warning('FastPlotGrid:fileNotFound', 'File not found: %s', obj.LiveFile);
+ warning('FastSenseGrid:fileNotFound', 'File not found: %s', obj.LiveFile);
return;
end
try
@@ -818,7 +818,7 @@ function onFigureCloseLive(obj, existingDeleteFcn, src, evt)
end
function ax = getTileAxesHandle(obj, n)
- %GETTILEAXESHANDLE Get the axes handle for tile n (FastPlot or raw).
+ %GETTILEAXESHANDLE Get the axes handle for tile n (FastSense or raw).
if obj.RawAxesTiles(n)
ax = obj.TileAxes{n};
if ~isempty(ax) && ~ishandle(ax); ax = []; end
diff --git a/libs/FastPlot/FastPlotTheme.m b/libs/FastSense/FastSenseTheme.m
similarity index 92%
rename from libs/FastPlot/FastPlotTheme.m
rename to libs/FastSense/FastSenseTheme.m
index 2fba60a3..413d2114 100644
--- a/libs/FastPlot/FastPlotTheme.m
+++ b/libs/FastSense/FastSenseTheme.m
@@ -1,15 +1,15 @@
-function theme = FastPlotTheme(preset, varargin)
-%FASTPLOTTHEME Return a theme struct for FastPlot styling.
-% theme = FASTPLOTTHEME() returns the 'default' theme preset.
+function theme = FastSenseTheme(preset, varargin)
+%FASTSENSETHEME Return a theme struct for FastSense styling.
+% theme = FASTSENSETHEME() returns the 'default' theme preset.
%
-% theme = FASTPLOTTHEME(preset) returns the named preset. Valid preset
+% theme = FASTSENSETHEME(preset) returns the named preset. Valid preset
% names are 'default', 'dark', 'light', 'industrial', 'scientific',
% and 'ocean'.
%
-% theme = FASTPLOTTHEME(preset, Name, Value) returns the named preset
+% theme = FASTSENSETHEME(preset, Name, Value) returns the named preset
% with individual fields overridden by the supplied name-value pairs.
%
-% theme = FASTPLOTTHEME(S) where S is a struct uses S as a set of
+% theme = FASTSENSETHEME(S) where S is a struct uses S as a set of
% overrides on top of the 'default' preset. Missing fields are filled
% from 'default'.
%
@@ -44,14 +44,14 @@
% BandAlpha — double in [0,1]; transparency of shaded bands
%
% Example:
-% theme = FastPlotTheme('dark', 'FontSize', 14, 'LineWidth', 1.5);
+% theme = FastSenseTheme('dark', 'FontSize', 14, 'LineWidth', 1.5);
%
% Example — struct override:
% overrides.FontSize = 14;
% overrides.GridAlpha = 0.5;
-% theme = FastPlotTheme(overrides);
+% theme = FastSenseTheme(overrides);
%
-% See also FastPlotDefaults, getDefaults.
+% See also FastSenseDefaults, getDefaults.
if nargin == 0
preset = 'default';
@@ -85,9 +85,9 @@
% 'scientific', 'ocean' (case-insensitive)
%
% Output:
-% t — struct; fully populated theme (see FastPlotTheme for fields)
+% t — struct; fully populated theme (see FastSenseTheme for fields)
%
-% Throws FastPlotTheme:unknownPreset if the name is not recognized.
+% Throws FastSenseTheme:unknownPreset if the name is not recognized.
switch lower(name)
case 'default'
t = struct( ...
@@ -204,7 +204,7 @@
'BandAlpha', 0.15 ...
);
otherwise
- error('FastPlotTheme:unknownPreset', ...
+ error('FastSenseTheme:unknownPreset', ...
'Unknown theme preset: ''%s''. Use ''default'', ''dark'', ''light'', ''industrial'', ''scientific'', or ''ocean''.', name);
end
end
@@ -223,7 +223,7 @@
% Output:
% colors — 8x3 double; each row is an [R G B] triplet in [0,1]
%
-% Throws FastPlotTheme:unknownPalette if the name is not recognized.
+% Throws FastSenseTheme:unknownPalette if the name is not recognized.
switch lower(name)
case 'vibrant'
colors = [ ...
@@ -272,7 +272,7 @@
0.16 0.62 0.24; ... % forest green
];
otherwise
- error('FastPlotTheme:unknownPalette', ...
+ error('FastSenseTheme:unknownPalette', ...
'Unknown palette: ''%s''. Use ''vibrant'', ''muted'', ''colorblind'', or ''ocean''.', name);
end
end
diff --git a/libs/FastPlot/FastPlotToolbar.m b/libs/FastSense/FastSenseToolbar.m
similarity index 89%
rename from libs/FastPlot/FastPlotToolbar.m
rename to libs/FastSense/FastSenseToolbar.m
index 0ae44910..dbae7acc 100644
--- a/libs/FastPlot/FastPlotToolbar.m
+++ b/libs/FastSense/FastSenseToolbar.m
@@ -1,12 +1,12 @@
-classdef FastPlotToolbar < handle
- %FASTPLOTTOOLBAR Interactive toolbar for FastPlot and FastPlotGrid.
+classdef FastSenseToolbar < handle
+ %FASTSENSETOOLBAR Interactive toolbar for FastSense and FastSenseGrid.
% Adds a uitoolbar with data cursor, crosshair, grid/legend toggles,
% Y-axis autoscale, PNG export, live mode controls, and metadata
% display. Integrates with MATLAB's built-in datacursormode for
% enhanced tooltips.
%
- % tb = FastPlotToolbar(fp) — attach to a FastPlot instance
- % tb = FastPlotToolbar(fig) — attach to a FastPlotGrid instance
+ % tb = FastSenseToolbar(fp) — attach to a FastSense instance
+ % tb = FastSenseToolbar(fig) — attach to a FastSenseGrid instance
%
% Toolbar buttons:
% Data Cursor — click to snap to nearest data point, shows value
@@ -20,11 +20,11 @@
% Metadata — show/hide metadata in data cursor tooltips
% Violations — toggle violation marker visibility
%
- % FastPlotToolbar Properties:
+ % FastSenseToolbar Properties:
% MetadataEnabled — whether metadata fields are shown in tooltips
%
- % FastPlotToolbar Methods:
- % FastPlotToolbar — construct and attach toolbar to a plot target
+ % FastSenseToolbar Methods:
+ % FastSenseToolbar — construct and attach toolbar to a plot target
% toggleGrid — toggle grid visibility on all managed axes
% toggleLegend — toggle legend visibility on all managed axes
% autoscaleY — fit Y-axis limits to visible data on all axes
@@ -44,12 +44,12 @@
% formatX — format an X value based on XType
%
% Example:
- % fp = FastPlot('Parent', ax);
+ % fp = FastSense('Parent', ax);
% fp.addLine(x, y);
% fp.render();
- % tb = FastPlotToolbar(fp);
+ % tb = FastSenseToolbar(fp);
%
- % See also FastPlot, FastPlotGrid, FastPlotDock.
+ % See also FastSense, FastSenseGrid, FastSenseDock.
% ========================= PUBLIC STATE ==============================
properties (SetAccess = private, GetAccess = public)
@@ -59,10 +59,10 @@
% ====================== INTERNAL STATE ===============================
% Graphics handles, mode tracking, and saved callbacks.
properties (SetAccess = private)
- Target = [] % FastPlot or FastPlotGrid
+ Target = [] % FastSense or FastSenseGrid
hFigure = [] % figure handle
hToolbar = [] % uitoolbar handle
- FastPlots = {} % cell array of all FastPlot instances
+ FastSenses = {} % cell array of all FastSense instances
Mode = 'none' % 'none' | 'cursor' | 'crosshair'
hCursorBtn = [] % uitoggletool handle
hCrosshairBtn = [] % uitoggletool handle
@@ -80,30 +80,30 @@
end
methods (Access = public)
- function obj = FastPlotToolbar(target)
- %FASTPLOTTOOLBAR Construct and attach a toolbar to a plot target.
- % tb = FastPlotToolbar(fp) — FastPlot instance
- % tb = FastPlotToolbar(fig) — FastPlotGrid instance
+ function obj = FastSenseToolbar(target)
+ %FASTSENSETOOLBAR Construct and attach a toolbar to a plot target.
+ % tb = FastSenseToolbar(fp) — FastSense instance
+ % tb = FastSenseToolbar(fig) — FastSenseGrid instance
%
- % Resolves the figure handle, collects all FastPlot instances,
+ % Resolves the figure handle, collects all FastSense instances,
% creates the uitoolbar, and installs the datacursor callback.
obj.Target = target;
- % Resolve figure handle and FastPlot instances
- if isa(target, 'FastPlotGrid')
+ % Resolve figure handle and FastSense instances
+ if isa(target, 'FastSenseGrid')
obj.hFigure = target.hFigure;
- obj.FastPlots = {};
+ obj.FastSenses = {};
for i = 1:numel(target.Tiles)
if ~isempty(target.Tiles{i})
- obj.FastPlots{end+1} = target.Tiles{i};
+ obj.FastSenses{end+1} = target.Tiles{i};
end
end
- elseif isa(target, 'FastPlot')
+ elseif isa(target, 'FastSense')
obj.hFigure = target.hFigure;
- obj.FastPlots = {target};
+ obj.FastSenses = {target};
else
- error('FastPlotToolbar:invalidTarget', ...
- 'Target must be a FastPlot or FastPlotGrid instance.');
+ error('FastSenseToolbar:invalidTarget', ...
+ 'Target must be a FastSense or FastSenseGrid instance.');
end
obj.createToolbar();
@@ -112,22 +112,22 @@
function toggleGrid(obj)
%TOGGLEGRID Toggle grid visibility on all managed axes.
- for i = 1:numel(obj.FastPlots)
- obj.toggleGridOnAxes(obj.FastPlots{i}.hAxes);
+ for i = 1:numel(obj.FastSenses)
+ obj.toggleGridOnAxes(obj.FastSenses{i}.hAxes);
end
end
function toggleLegend(obj)
%TOGGLELEGEND Toggle legend visibility on all managed axes.
- for i = 1:numel(obj.FastPlots)
- obj.toggleLegendOnAxes(obj.FastPlots{i}.hAxes);
+ for i = 1:numel(obj.FastSenses)
+ obj.toggleLegendOnAxes(obj.FastSenses{i}.hAxes);
end
end
function autoscaleY(obj)
%AUTOSCALEY Fit Y-axis limits to visible data on all axes.
- for i = 1:numel(obj.FastPlots)
- obj.autoscaleYOnAxes(obj.FastPlots{i});
+ for i = 1:numel(obj.FastSenses)
+ obj.autoscaleYOnAxes(obj.FastSenses{i});
end
end
@@ -213,7 +213,7 @@ function toggleLive(obj)
if isprop(target, 'MetadataLineIndex')
args = [args, 'MetadataLineIndex', target.MetadataLineIndex];
end
- if isprop(target, 'MetadataTileIndex') && isa(target, 'FastPlotGrid')
+ if isprop(target, 'MetadataTileIndex') && isa(target, 'FastSenseGrid')
args = [args, 'MetadataTileIndex', target.MetadataTileIndex];
end
target.startLive(target.LiveFile, target.LiveUpdateFcn, args{:});
@@ -227,7 +227,7 @@ function setMetadata(obj, on)
% tb.setMetadata(true) — show metadata fields in cursor
% tb.setMetadata(false) — hide metadata
obj.MetadataEnabled = on;
- setappdata(obj.hFigure, 'FastPlotMetadataEnabled', on);
+ setappdata(obj.hFigure, 'FastSenseMetadataEnabled', on);
if on
set(obj.hMetadataBtn, 'State', 'on');
else
@@ -239,15 +239,15 @@ function setMetadata(obj, on)
function setViolationsVisible(obj, on)
%SETVIOLATIONSVISIBLE Toggle violation markers on all tiles.
% setViolationsVisible(obj, on) iterates over all managed
- % FastPlot instances and calls setViolationsVisible(on) on
+ % FastSense instances and calls setViolationsVisible(on) on
% each, then syncs the toolbar toggle button state.
%
% Input:
% on — logical, true to show markers, false to hide
%
- % See also FastPlot.setViolationsVisible.
- for i = 1:numel(obj.FastPlots)
- obj.FastPlots{i}.setViolationsVisible(on);
+ % See also FastSense.setViolationsVisible.
+ for i = 1:numel(obj.FastSenses)
+ obj.FastSenses{i}.setViolationsVisible(on);
end
if on
set(obj.hViolationsBtn, 'State', 'on');
@@ -275,17 +275,17 @@ function rebind(obj, target)
% Update target references
obj.Target = target;
- if isa(target, 'FastPlotGrid')
+ if isa(target, 'FastSenseGrid')
obj.hFigure = target.hFigure;
- obj.FastPlots = {};
+ obj.FastSenses = {};
for i = 1:numel(target.Tiles)
if ~isempty(target.Tiles{i})
- obj.FastPlots{end+1} = target.Tiles{i};
+ obj.FastSenses{end+1} = target.Tiles{i};
end
end
- elseif isa(target, 'FastPlot')
+ elseif isa(target, 'FastSense')
obj.hFigure = target.hFigure;
- obj.FastPlots = {target};
+ obj.FastSenses = {target};
end
% Sync toggle states to new target
@@ -294,12 +294,12 @@ function rebind(obj, target)
else
set(obj.hLiveBtn, 'State', 'off');
end
- setappdata(obj.hFigure, 'FastPlotMetadataEnabled', obj.MetadataEnabled);
+ setappdata(obj.hFigure, 'FastSenseMetadataEnabled', obj.MetadataEnabled);
% Sync violations toggle to first tile's state (all tiles
% share the same ViolationsVisible after any toolbar action)
- if ~isempty(obj.FastPlots)
- if obj.FastPlots{1}.ViolationsVisible
+ if ~isempty(obj.FastSenses)
+ if obj.FastSenses{1}.ViolationsVisible
set(obj.hViolationsBtn, 'State', 'on');
else
set(obj.hViolationsBtn, 'State', 'off');
@@ -377,68 +377,68 @@ function createToolbar(obj)
% Creates toggle and push tools for cursor, crosshair, grid,
% legend, autoscale, export, refresh, live mode, metadata,
% violations, and theme selection. Pre-warms the icon cache.
- FastPlotToolbar.initIcons();
+ FastSenseToolbar.initIcons();
obj.hToolbar = uitoolbar(obj.hFigure);
% Buttons: cursor, crosshair, grid, legend, autoscale, export
obj.hCursorBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('cursor'), ...
+ 'CData', FastSenseToolbar.makeIcon('cursor'), ...
'TooltipString', 'Data Cursor', ...
'OnCallback', @(s,e) obj.onCursorOn(), ...
'OffCallback', @(s,e) obj.onCursorOff());
obj.hCrosshairBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('crosshair'), ...
+ 'CData', FastSenseToolbar.makeIcon('crosshair'), ...
'TooltipString', 'Crosshair', ...
'OnCallback', @(s,e) obj.onCrosshairOn(), ...
'OffCallback', @(s,e) obj.onCrosshairOff());
uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('grid'), ...
+ 'CData', FastSenseToolbar.makeIcon('grid'), ...
'TooltipString', 'Toggle Grid', ...
'ClickedCallback', @(s,e) obj.onToggleGrid());
uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('legend'), ...
+ 'CData', FastSenseToolbar.makeIcon('legend'), ...
'TooltipString', 'Toggle Legend', ...
'ClickedCallback', @(s,e) obj.onToggleLegend());
uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('autoscale'), ...
+ 'CData', FastSenseToolbar.makeIcon('autoscale'), ...
'TooltipString', 'Autoscale Y', ...
'ClickedCallback', @(s,e) obj.onAutoscaleY());
uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('export'), ...
+ 'CData', FastSenseToolbar.makeIcon('export'), ...
'TooltipString', 'Export PNG', ...
'ClickedCallback', @(s,e) obj.onExportPNG());
obj.hRefreshBtn = uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('refresh'), ...
+ 'CData', FastSenseToolbar.makeIcon('refresh'), ...
'TooltipString', 'Refresh Data', ...
'ClickedCallback', @(s,e) obj.onRefresh());
obj.hLiveBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('live'), ...
+ 'CData', FastSenseToolbar.makeIcon('live'), ...
'TooltipString', 'Live Mode', ...
'OnCallback', @(s,e) obj.onLiveOn(), ...
'OffCallback', @(s,e) obj.onLiveOff());
obj.hMetadataBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('metadata'), ...
+ 'CData', FastSenseToolbar.makeIcon('metadata'), ...
'TooltipString', 'Metadata', ...
'OnCallback', @(s,e) obj.onMetadataOn(), ...
'OffCallback', @(s,e) obj.onMetadataOff());
obj.hViolationsBtn = uitoggletool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('violations'), ...
+ 'CData', FastSenseToolbar.makeIcon('violations'), ...
'TooltipString', 'Toggle Violations', ...
'State', 'on', ...
'OnCallback', @(s,e) obj.onViolationsOn(), ...
'OffCallback', @(s,e) obj.onViolationsOff());
obj.hThemeBtn = uipushtool(obj.hToolbar, ...
- 'CData', FastPlotToolbar.makeIcon('theme'), ...
+ 'CData', FastSenseToolbar.makeIcon('theme'), ...
'TooltipString', 'Change Theme', ...
'ClickedCallback', @(s,e) obj.onThemeClick());
end
@@ -564,7 +564,7 @@ function onSelect(src)
% name — theme name string (e.g. 'dark') or ''
name = '';
target = obj.Target;
- if isa(target, 'FastPlotGrid') || isa(target, 'FastPlot')
+ if isa(target, 'FastSenseGrid') || isa(target, 'FastSense')
currentTheme = target.Theme;
else
return;
@@ -574,7 +574,7 @@ function onSelect(src)
% Check built-in presets
presets = {'default', 'dark', 'light', 'industrial', 'scientific'};
for i = 1:numel(presets)
- ref = FastPlotTheme(presets{i});
+ ref = FastSenseTheme(presets{i});
if obj.themesEqual(currentTheme, ref)
name = presets{i};
return;
@@ -586,7 +586,7 @@ function onSelect(src)
if isfield(cfg, 'CustomThemes')
customs = fieldnames(cfg.CustomThemes);
for i = 1:numel(customs)
- ref = mergeTheme(FastPlotTheme('default'), cfg.CustomThemes.(customs{i}));
+ ref = mergeTheme(FastSenseTheme('default'), cfg.CustomThemes.(customs{i}));
if obj.themesEqual(currentTheme, ref)
name = customs{i};
return;
@@ -629,9 +629,9 @@ function applyThemeByName(obj, name)
%APPLYTHEMEBYNAME Resolve theme by name and apply to hierarchy.
% applyThemeByName(obj, name) resolves a theme by name
% (checking custom themes from getDefaults first, then
- % built-in FastPlotTheme presets). The resolved theme is
+ % built-in FastSenseTheme presets). The resolved theme is
% applied to the target and, if the target belongs to a
- % FastPlotDock (via AppData), to the entire dock hierarchy.
+ % FastSenseDock (via AppData), to the entire dock hierarchy.
%
% Input:
% name — theme name string (e.g. 'dark', 'scientific')
@@ -639,23 +639,23 @@ function applyThemeByName(obj, name)
% Resolve: check custom themes first, then built-in
if isfield(cfg, 'CustomThemes') && isfield(cfg.CustomThemes, name)
- newTheme = mergeTheme(FastPlotTheme('default'), cfg.CustomThemes.(name));
+ newTheme = mergeTheme(FastSenseTheme('default'), cfg.CustomThemes.(name));
else
- newTheme = FastPlotTheme(name);
+ newTheme = FastSenseTheme(name);
end
target = obj.Target;
- if isa(target, 'FastPlotGrid')
+ if isa(target, 'FastSenseGrid')
% Check if the figure belongs to a dock (via AppData)
- dock = getappdata(obj.hFigure, 'FastPlotDock');
- if ~isempty(dock) && isa(dock, 'FastPlotDock')
+ dock = getappdata(obj.hFigure, 'FastSenseDock');
+ if ~isempty(dock) && isa(dock, 'FastSenseDock')
dock.Theme = newTheme;
dock.reapplyTheme();
else
target.Theme = newTheme;
target.reapplyTheme();
end
- elseif isa(target, 'FastPlot')
+ elseif isa(target, 'FastSense')
target.Theme = newTheme;
target.reapplyTheme();
end
@@ -812,11 +812,11 @@ function cleanupCursor(obj)
function onToggleGrid(obj)
%ONTOGGLEGRID Callback: toggle grid on active axes or all tiles.
% If the mouse is over an axes, toggles that axes only;
- % otherwise toggles grid on every managed FastPlot axes.
+ % otherwise toggles grid on every managed FastSense axes.
[~, ax] = obj.getActiveTarget();
if isempty(ax)
- for i = 1:numel(obj.FastPlots)
- obj.toggleGridOnAxes(obj.FastPlots{i}.hAxes);
+ for i = 1:numel(obj.FastSenses)
+ obj.toggleGridOnAxes(obj.FastSenses{i}.hAxes);
end
else
obj.toggleGridOnAxes(ax);
@@ -840,11 +840,11 @@ function toggleGridOnAxes(~, ax)
function onToggleLegend(obj)
%ONTOGGLELEGEND Callback: toggle legend on active axes or all tiles.
% If the mouse is over an axes, toggles that legend only;
- % otherwise toggles legend on every managed FastPlot axes.
+ % otherwise toggles legend on every managed FastSense axes.
[~, ax] = obj.getActiveTarget();
if isempty(ax)
- for i = 1:numel(obj.FastPlots)
- obj.toggleLegendOnAxes(obj.FastPlots{i}.hAxes);
+ for i = 1:numel(obj.FastSenses)
+ obj.toggleLegendOnAxes(obj.FastSenses{i}.hAxes);
end
else
obj.toggleLegendOnAxes(ax);
@@ -869,11 +869,11 @@ function toggleLegendOnAxes(~, ax)
function onAutoscaleY(obj)
%ONAUTOSCALEY Callback: autoscale Y on active axes or all tiles.
% If the mouse is over an axes, autoscales that axes only;
- % otherwise autoscales every managed FastPlot axes.
+ % otherwise autoscales every managed FastSense axes.
[fp, ~] = obj.getActiveTarget();
if isempty(fp)
- for i = 1:numel(obj.FastPlots)
- obj.autoscaleYOnAxes(obj.FastPlots{i});
+ for i = 1:numel(obj.FastSenses)
+ obj.autoscaleYOnAxes(obj.FastSenses{i});
end
else
obj.autoscaleYOnAxes(fp);
@@ -881,13 +881,13 @@ function onAutoscaleY(obj)
end
function autoscaleYOnAxes(~, fp)
- %AUTOSCALEYONAXES Fit Y-axis limits to visible data on one FastPlot.
+ %AUTOSCALEYONAXES Fit Y-axis limits to visible data on one FastSense.
% autoscaleYOnAxes(obj, fp) examines all lines in fp, finds the
% min/max Y values within the current X-axis limits using binary
% search, and sets YLim with 5% padding.
%
% Input:
- % fp — FastPlot instance whose axes to autoscale
+ % fp — FastSense instance whose axes to autoscale
ax = fp.hAxes;
xlims = get(ax, 'XLim');
ymin = Inf; ymax = -Inf;
@@ -925,20 +925,20 @@ function onExportPNG(obj)
end
function [fp, ax] = getActiveTarget(obj)
- %GETACTIVETARGET Find the FastPlot instance under the mouse.
+ %GETACTIVETARGET Find the FastSense instance under the mouse.
% [fp, ax] = getActiveTarget(obj) checks the current mouse
- % position against all managed FastPlot axes (in pixel units).
- % Returns the FastPlot instance and axes handle if the mouse
+ % position against all managed FastSense axes (in pixel units).
+ % Returns the FastSense instance and axes handle if the mouse
% is inside an axes, or empty arrays if outside all axes.
%
% Outputs:
- % fp — FastPlot instance under cursor, or []
+ % fp — FastSense instance under cursor, or []
% ax — axes handle under cursor, or []
fp = [];
ax = [];
cp = get(obj.hFigure, 'CurrentPoint');
- for i = 1:numel(obj.FastPlots)
- a = obj.FastPlots{i}.hAxes;
+ for i = 1:numel(obj.FastSenses)
+ a = obj.FastSenses{i}.hAxes;
if ~ishandle(a); continue; end
oldUnits = get(a, 'Units');
set(a, 'Units', 'pixels');
@@ -946,7 +946,7 @@ function onExportPNG(obj)
set(a, 'Units', oldUnits);
if cp(1) >= pos(1) && cp(1) <= pos(1)+pos(3) && ...
cp(2) >= pos(2) && cp(2) <= pos(2)+pos(4)
- fp = obj.FastPlots{i};
+ fp = obj.FastSenses{i};
ax = a;
return;
end
@@ -1004,15 +1004,15 @@ function refreshDataCursors(obj)
hTarget = evt.Target;
end
- % Look up which FastPlot and line index from the line's UserData
+ % Look up which FastSense and line index from the line's UserData
fp = [];
lineIdx = [];
ud = get(hTarget, 'UserData');
- if isstruct(ud) && isfield(ud, 'FastPlot') && isfield(ud.FastPlot, 'LineIndex')
- lineIdx = ud.FastPlot.LineIndex;
+ if isstruct(ud) && isfield(ud, 'FastSense') && isfield(ud.FastSense, 'LineIndex')
+ lineIdx = ud.FastSense.LineIndex;
end
- if isstruct(ud) && isfield(ud, 'FastPlotInstance')
- fp = ud.FastPlotInstance;
+ if isstruct(ud) && isfield(ud, 'FastSenseInstance')
+ fp = ud.FastSenseInstance;
end
% Format X value (datetime-aware)
@@ -1040,7 +1040,7 @@ function refreshDataCursors(obj)
metaOn = false;
try
hFig = ancestor(hTarget, 'figure');
- metaOn = getappdata(hFig, 'FastPlotMetadataEnabled');
+ metaOn = getappdata(hFig, 'FastSenseMetadataEnabled');
catch
end
if isempty(metaOn); metaOn = false; end
@@ -1069,7 +1069,7 @@ function refreshDataCursors(obj)
methods (Static)
function icon = makeIcon(name)
%MAKEICON Generate a 16x16x3 RGB icon for toolbar buttons.
- % icon = FastPlotToolbar.makeIcon(name)
+ % icon = FastSenseToolbar.makeIcon(name)
%
% Draws simple pixel-art icons on a light gray background.
% Available names: 'cursor', 'crosshair', 'grid', 'legend',
@@ -1248,14 +1248,14 @@ function initIcons()
names = {'cursor', 'crosshair', 'grid', 'legend', 'autoscale', ...
'export', 'refresh', 'live', 'metadata', 'violations', 'theme'};
for i = 1:numel(names)
- FastPlotToolbar.makeIcon(names{i});
+ FastSenseToolbar.makeIcon(names{i});
end
end
function s = formatX(xVal, xType)
%FORMATX Format an X value based on XType.
- % s = FastPlotToolbar.formatX(xVal, 'datenum')
- % s = FastPlotToolbar.formatX(xVal, 'numeric')
+ % s = FastSenseToolbar.formatX(xVal, 'datenum')
+ % s = FastSenseToolbar.formatX(xVal, 'numeric')
if strcmp(xType, 'datenum')
try
s = datestr(xVal, 'mmm dd HH:MM:SS');
diff --git a/libs/FastPlot/NavigatorOverlay.m b/libs/FastSense/NavigatorOverlay.m
similarity index 100%
rename from libs/FastPlot/NavigatorOverlay.m
rename to libs/FastSense/NavigatorOverlay.m
diff --git a/libs/FastPlot/SensorDetailPlot.m b/libs/FastSense/SensorDetailPlot.m
similarity index 95%
rename from libs/FastPlot/SensorDetailPlot.m
rename to libs/FastSense/SensorDetailPlot.m
index eef150cc..ad90ec1c 100644
--- a/libs/FastPlot/SensorDetailPlot.m
+++ b/libs/FastSense/SensorDetailPlot.m
@@ -5,7 +5,7 @@
% sdp = SensorDetailPlot(sensor, Name, Value, ...)
%
% Name-Value Options:
- % 'Theme' - FastPlot theme (default: 'default')
+ % 'Theme' - FastSense theme (default: 'default')
% 'NavigatorHeight' - Fraction 0-1 for navigator (default: 0.20)
% 'ShowThresholds' - Show thresholds in main plot (default: true)
% 'ShowThresholdBands' - Show threshold bands in navigator (default: true)
@@ -17,8 +17,8 @@
properties (SetAccess = private)
Sensor % Sensor object
- MainPlot % FastPlot instance for upper panel
- NavigatorPlot % FastPlot instance for lower panel
+ MainPlot % FastSense instance for upper panel
+ NavigatorPlot % FastSense instance for lower panel
NavigatorOverlayObj % NavigatorOverlay instance
end
@@ -55,7 +55,7 @@
obj.IsPropagating = false;
obj.OwnsFigure = false;
- % Load cached defaults (same pattern as FastPlot / FastPlotGrid)
+ % Load cached defaults (same pattern as FastSense / FastSenseGrid)
cfg = getDefaults();
% Parse options via standard parseOpts
@@ -70,13 +70,13 @@
conDefaults.XType = 'numeric';
[opts, ~] = parseOpts(conDefaults, varargin);
- % Inherit theme from parent panel (set by FastPlotGrid.tilePanel)
+ % Inherit theme from parent panel (set by FastSenseGrid.tilePanel)
% when no explicit Theme was given.
if isempty(opts.Theme) && ~isempty(opts.Parent)
try
ud = get(opts.Parent, 'UserData');
- if isstruct(ud) && isfield(ud, 'FastPlotTheme')
- opts.Theme = ud.FastPlotTheme;
+ if isstruct(ud) && isfield(ud, 'FastSenseTheme')
+ opts.Theme = ud.FastSenseTheme;
end
catch
end
@@ -101,7 +101,7 @@ function render(obj)
end
% Auto-resolve sensor if not yet resolved (avoids struct()
- % default in ResolvedThresholds crashing FastPlot.addSensor)
+ % default in ResolvedThresholds crashing FastSense.addSensor)
if isstruct(obj.Sensor.ResolvedThresholds) && isempty(fieldnames(obj.Sensor.ResolvedThresholds))
obj.Sensor.resolve();
end
@@ -109,8 +109,8 @@ function render(obj)
% Create layout
obj.createLayout();
- % Create main FastPlot
- obj.MainPlot = FastPlot('Parent', obj.hMainAxes, 'Theme', obj.Theme);
+ % Create main FastSense
+ obj.MainPlot = FastSense('Parent', obj.hMainAxes, 'Theme', obj.Theme);
displayName = obj.Sensor.Name;
if isempty(displayName); displayName = obj.Sensor.Key; end
obj.MainPlot.addLine(obj.Sensor.X, obj.Sensor.Y, ...
@@ -141,15 +141,15 @@ function render(obj)
set(obj.hMainAxes, 'XTickLabel', []);
xlabel(obj.hMainAxes, '');
- % Set title with theme formatting (matches FastPlotGrid.setTileTitle)
+ % Set title with theme formatting (matches FastSenseGrid.setTileTitle)
if ~isempty(obj.Title)
title(obj.hMainAxes, obj.Title, ...
'FontSize', obj.Theme.TitleFontSize, ...
'Color', obj.Theme.ForegroundColor);
end
- % Create navigator FastPlot
- obj.NavigatorPlot = FastPlot('Parent', obj.hNavAxes, 'Theme', obj.Theme);
+ % Create navigator FastSense
+ obj.NavigatorPlot = FastSense('Parent', obj.hNavAxes, 'Theme', obj.Theme);
obj.NavigatorPlot.addLine(obj.Sensor.X, obj.Sensor.Y, ...
'DisplayName', obj.Sensor.Name, 'XType', obj.XType);
@@ -183,7 +183,7 @@ function render(obj)
rotate3d(obj.hNavAxes, 'off');
% Re-apply datetime tick formatting after all nav axes
- % modifications to guarantee it matches normal FastPlot tiles.
+ % modifications to guarantee it matches normal FastSense tiles.
% Sync main axes XTick to match, keeping labels suppressed.
if strcmp(obj.XType, 'datenum')
obj.formatDatetimeTicks(obj.hNavAxes);
@@ -315,7 +315,7 @@ function createLayout(obj)
end
% Use Position + innerposition for both modes so the plot
- % area width matches normal FastPlot tiles exactly.
+ % area width matches normal FastSense tiles exactly.
% In embedded mode add vertical margins inside the panel for
% the title (top) and navigator X-tick labels (bottom).
navFrac = obj.NavigatorHeight;
@@ -537,7 +537,7 @@ function onMainXLimChanged(obj)
end
% Re-apply correct tick density and suppress labels after
- % FastPlot's onXLimChanged calls datetick (which re-sets
+ % FastSense's onXLimChanged calls datetick (which re-sets
% XTick and XTickLabel with wrong density).
if strcmp(obj.XType, 'datenum')
obj.formatDatetimeTicks(obj.hMainAxes);
@@ -572,9 +572,9 @@ function refreshDatetimeTicks(obj)
end
function formatDatetimeTicks(~, ax)
- %FORMATEDATETIMETICKS Apply datetime tick formatting matching FastPlot.
+ %FORMATEDATETIMETICKS Apply datetime tick formatting matching FastSense.
% Computes nice datetime tick positions and labels directly,
- % matching the format selection in FastPlot.updateDatetimeTicks.
+ % matching the format selection in FastSense.updateDatetimeTicks.
% Avoids datetick() which produces inconsistent tick density
% for axes embedded in uipanels.
if ~ishandle(ax); return; end
@@ -583,7 +583,7 @@ function formatDatetimeTicks(~, ax)
span = diff(xl); % in days (datenum units)
% Choose interval and format based on span (same thresholds
- % as FastPlot.updateDatetimeTicks)
+ % as FastSense.updateDatetimeTicks)
if span > 365
fmt = 'yyyy mmm dd HH:MM';
% Round to months
diff --git a/libs/FastPlot/binary_search.m b/libs/FastSense/binary_search.m
similarity index 100%
rename from libs/FastPlot/binary_search.m
rename to libs/FastSense/binary_search.m
diff --git a/libs/FastPlot/build_mex.m b/libs/FastSense/build_mex.m
similarity index 99%
rename from libs/FastPlot/build_mex.m
rename to libs/FastSense/build_mex.m
index 339d3282..6c1e3756 100644
--- a/libs/FastPlot/build_mex.m
+++ b/libs/FastSense/build_mex.m
@@ -1,5 +1,5 @@
function build_mex()
-%BUILD_MEX Compile all FastPlot MEX files with platform-appropriate SIMD flags.
+%BUILD_MEX Compile all FastSense MEX files with platform-appropriate SIMD flags.
% BUILD_MEX() detects the CPU architecture (x86_64 or ARM64) and the
% best available C compiler, then compiles every MEX source file found
% in private/mex_src/ into the private/ directory.
diff --git a/libs/FastPlot/mksqlite.c b/libs/FastSense/mksqlite.c
similarity index 100%
rename from libs/FastPlot/mksqlite.c
rename to libs/FastSense/mksqlite.c
diff --git a/libs/FastPlot/private/binary_search.m b/libs/FastSense/private/binary_search.m
similarity index 97%
rename from libs/FastPlot/private/binary_search.m
rename to libs/FastSense/private/binary_search.m
index bc1f419f..7d1236ce 100644
--- a/libs/FastPlot/private/binary_search.m
+++ b/libs/FastSense/private/binary_search.m
@@ -6,7 +6,7 @@
% idx = BINARY_SEARCH(x, val, 'right') returns the last (rightmost)
% index where x(idx) <= val (upper bound).
%
-% This function is a private helper for FastPlot, used extensively by
+% This function is a private helper for FastSense, used extensively by
% the downsampling and viewport-clipping routines.
%
% Inputs:
diff --git a/libs/FastPlot/private/clearDefaultsCache.m b/libs/FastSense/private/clearDefaultsCache.m
similarity index 58%
rename from libs/FastPlot/private/clearDefaultsCache.m
rename to libs/FastSense/private/clearDefaultsCache.m
index 028429cd..38f0095d 100644
--- a/libs/FastPlot/private/clearDefaultsCache.m
+++ b/libs/FastSense/private/clearDefaultsCache.m
@@ -1,13 +1,13 @@
function clearDefaultsCache()
-%CLEARDEFAULTSCACHE Force getDefaults to reload FastPlotDefaults on next call.
+%CLEARDEFAULTSCACHE Force getDefaults to reload FastSenseDefaults on next call.
% CLEARDEFAULTSCACHE() invalidates the persistent cache held by
% getDefaults() so that the next call to getDefaults() re-executes
-% FastPlotDefaults() and rebuilds the configuration from scratch.
+% FastSenseDefaults() and rebuilds the configuration from scratch.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
-% Use this after editing FastPlotDefaults.m or any custom theme file
-% during a MATLAB session, so that subsequent FastPlot constructions
+% Use this after editing FastSenseDefaults.m or any custom theme file
+% during a MATLAB session, so that subsequent FastSense constructions
% pick up the new settings without restarting MATLAB.
%
% Inputs:
@@ -20,7 +20,7 @@ function clearDefaultsCache()
% CLEAR clears the persistent variables inside that
% function, effectively resetting its cached state.
%
-% See also getDefaults, FastPlotDefaults.
+% See also getDefaults, FastSenseDefaults.
% Clear the persistent variable inside getDefaults
clear getDefaults;
diff --git a/libs/FastPlot/private/compute_violations.m b/libs/FastSense/private/compute_violations.m
similarity index 94%
rename from libs/FastPlot/private/compute_violations.m
rename to libs/FastSense/private/compute_violations.m
index 2b6d3e86..0a0a7322 100644
--- a/libs/FastPlot/private/compute_violations.m
+++ b/libs/FastSense/private/compute_violations.m
@@ -4,7 +4,7 @@
% returns the X and Y coordinates of all points where the data strictly
% exceeds (or falls below) the given scalar threshold value.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% x — numeric vector of X coordinates
@@ -29,7 +29,7 @@
% compute_violations_dynamic instead.
%
% See also compute_violations_dynamic, downsample_violations,
-% violation_cull, FastPlot.addThreshold.
+% violation_cull, FastSense.addThreshold.
% Build logical mask of violating points
if strcmp(direction, 'upper')
diff --git a/libs/FastPlot/private/compute_violations_dynamic.m b/libs/FastSense/private/compute_violations_dynamic.m
similarity index 97%
rename from libs/FastPlot/private/compute_violations_dynamic.m
rename to libs/FastSense/private/compute_violations_dynamic.m
index 5abdde4d..ce3234d9 100644
--- a/libs/FastPlot/private/compute_violations_dynamic.m
+++ b/libs/FastSense/private/compute_violations_dynamic.m
@@ -7,7 +7,7 @@
% corresponding thX is at or before x(i) — i.e., zero-order hold
% (previous-value) interpolation.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% x — numeric vector of data X coordinates
@@ -36,7 +36,7 @@
% automatically excluded (IEEE 754: NaN comparisons return false).
%
% See also compute_violations, downsample_violations, violation_cull,
-% FastPlot.addThreshold.
+% FastSense.addThreshold.
% Guard: empty data
if isempty(x)
diff --git a/libs/FastPlot/private/downsample_violations.m b/libs/FastSense/private/downsample_violations.m
similarity index 97%
rename from libs/FastPlot/private/downsample_violations.m
rename to libs/FastSense/private/downsample_violations.m
index e8124410..db01e706 100644
--- a/libs/FastPlot/private/downsample_violations.m
+++ b/libs/FastSense/private/downsample_violations.m
@@ -7,7 +7,7 @@
% violations while eliminating sub-pixel overlap that would waste GPU
% marker-rendering budget.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% xViol — numeric vector of violation X coordinates (from
@@ -34,7 +34,7 @@
% 3. For each unique bucket, keep the point with max |y - threshold|.
%
% See also compute_violations, compute_violations_dynamic, violation_cull,
-% FastPlot.updateViolations.
+% FastSense.updateViolations.
% Guard: empty input or degenerate pixel width
if isempty(xViol) || pixelWidth <= 0
diff --git a/libs/FastPlot/private/getDefaults.m b/libs/FastSense/private/getDefaults.m
similarity index 73%
rename from libs/FastPlot/private/getDefaults.m
rename to libs/FastSense/private/getDefaults.m
index 5a483fa2..0d0e93d9 100644
--- a/libs/FastPlot/private/getDefaults.m
+++ b/libs/FastSense/private/getDefaults.m
@@ -1,32 +1,32 @@
function cfg = getDefaults()
-%GETDEFAULTS Return cached FastPlotDefaults struct.
-% cfg = GETDEFAULTS() returns the FastPlot configuration struct produced
-% by FastPlotDefaults(). The result is cached in a persistent variable so
-% that FastPlotDefaults() is called only once per MATLAB session, avoiding
-% repeated file parsing on every FastPlot construction.
+%GETDEFAULTS Return cached FastSenseDefaults struct.
+% cfg = GETDEFAULTS() returns the FastSense configuration struct produced
+% by FastSenseDefaults(). The result is cached in a persistent variable so
+% that FastSenseDefaults() is called only once per MATLAB session, avoiding
+% repeated file parsing on every FastSense construction.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% On the first call the cache is populated by:
-% 1. Calling FastPlotDefaults() to obtain the base configuration.
+% 1. Calling FastSenseDefaults() to obtain the base configuration.
% 2. Calling loadCustomThemes() to scan cfg.ThemeDir for user themes.
%
% Inputs:
% (none)
%
% Outputs:
-% cfg — scalar struct of FastPlot default settings, including a
+% cfg — scalar struct of FastSense default settings, including a
% CustomThemes field populated from the user's theme directory
%
% Call clearDefaultsCache() to invalidate the cache and force a fresh
-% reload on the next invocation (e.g., after editing FastPlotDefaults.m).
+% reload on the next invocation (e.g., after editing FastSenseDefaults.m).
%
-% See also FastPlotDefaults, clearDefaultsCache, loadCustomThemes.
+% See also FastSenseDefaults, clearDefaultsCache, loadCustomThemes.
persistent cachedCfg;
if isempty(cachedCfg)
% First call: build and cache the configuration
- cachedCfg = FastPlotDefaults();
+ cachedCfg = FastSenseDefaults();
cachedCfg.CustomThemes = loadCustomThemes(cachedCfg);
end
cfg = cachedCfg;
@@ -41,7 +41,7 @@
% This function is a local helper for getDefaults.
%
% Inputs:
-% cfg — FastPlotDefaults struct (must contain field ThemeDir)
+% cfg — FastSenseDefaults struct (must contain field ThemeDir)
%
% Outputs:
% themes — struct whose field names are theme file basenames and whose
@@ -50,7 +50,7 @@
%
% Path resolution:
% If cfg.ThemeDir is not an absolute folder, it is resolved relative to
-% the FastPlot library root (one level above this private/ directory).
+% the FastSense library root (one level above this private/ directory).
%
% Error handling:
% Broken or non-struct-returning theme files are silently skipped.
@@ -64,7 +64,7 @@
return;
end
- % Resolve relative paths against FastPlot root
+ % Resolve relative paths against FastSense root
themeDir = cfg.ThemeDir;
if ~isfolder(themeDir)
root = fileparts(mfilename('fullpath'));
diff --git a/libs/FastPlot/private/loadMetaStruct.m b/libs/FastSense/private/loadMetaStruct.m
similarity index 92%
rename from libs/FastPlot/private/loadMetaStruct.m
rename to libs/FastSense/private/loadMetaStruct.m
index b4ecfcba..9b1a928a 100644
--- a/libs/FastPlot/private/loadMetaStruct.m
+++ b/libs/FastSense/private/loadMetaStruct.m
@@ -3,9 +3,9 @@
% meta = LOADMETASTRUCT(filepath, vars) loads the specified .mat file,
% extracts a timestamp vector (from a field named 'datenum' or
% 'datetime') and the requested variable names, and returns them in a
-% flat struct suitable for FastPlot metadata lookup and live-data feeds.
+% flat struct suitable for FastSense metadata lookup and live-data feeds.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% filepath — char, path to a .mat file. The file must contain at least
@@ -26,7 +26,7 @@
% Variables listed in vars that are absent from the file are silently
% skipped (no error or warning).
%
-% See also FastPlot.lookupMetadata, FastPlot.startLive.
+% See also FastSense.lookupMetadata, FastSense.startLive.
meta = [];
diff --git a/libs/FastPlot/private/lttb_downsample.m b/libs/FastSense/private/lttb_downsample.m
similarity index 99%
rename from libs/FastPlot/private/lttb_downsample.m
rename to libs/FastSense/private/lttb_downsample.m
index 5970681b..89a64d0b 100644
--- a/libs/FastPlot/private/lttb_downsample.m
+++ b/libs/FastSense/private/lttb_downsample.m
@@ -11,7 +11,7 @@
% is true, yielding visually accurate point selection on logarithmic
% axes. Output values remain in original (linear) space.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% x — sorted numeric row vector of X coordinates (ascending)
diff --git a/libs/FastPlot/private/mergeTheme.m b/libs/FastSense/private/mergeTheme.m
similarity index 88%
rename from libs/FastPlot/private/mergeTheme.m
rename to libs/FastSense/private/mergeTheme.m
index cd1d317e..87f17105 100644
--- a/libs/FastPlot/private/mergeTheme.m
+++ b/libs/FastSense/private/mergeTheme.m
@@ -6,11 +6,11 @@
% is a shallow (non-recursive) merge — nested structs are replaced
% wholesale, not recursively merged.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% base — scalar struct, the complete theme with all fields present
-% (typically produced by FastPlotTheme)
+% (typically produced by FastSenseTheme)
% overrides — scalar struct, partial set of fields whose values should
% replace those in base. May contain any subset of fields
% from base, or even new fields.
@@ -25,7 +25,7 @@
% result = mergeTheme(base, ov);
% % result.Color == 'w', result.FontSize == 12, result.Grid == true
%
-% See also FastPlotTheme, resolveTheme, getDefaults.
+% See also FastSenseTheme, resolveTheme, getDefaults.
result = base;
fnames = fieldnames(overrides);
diff --git a/libs/FastPlot/private/mex_src/binary_search_mex.c b/libs/FastSense/private/mex_src/binary_search_mex.c
similarity index 90%
rename from libs/FastPlot/private/mex_src/binary_search_mex.c
rename to libs/FastSense/private/mex_src/binary_search_mex.c
index 29d42797..bd96966d 100644
--- a/libs/FastPlot/private/mex_src/binary_search_mex.c
+++ b/libs/FastSense/private/mex_src/binary_search_mex.c
@@ -24,19 +24,19 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:nrhs",
"Three inputs required: x, val, direction.");
}
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notDouble",
"x must be a real double array.");
}
if (!mxIsDouble(prhs[1]) || mxGetNumberOfElements(prhs[1]) != 1) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notScalar",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notScalar",
"val must be a scalar double.");
}
if (!mxIsChar(prhs[2])) {
- mexErrMsgIdAndTxt("FastPlot:binary_search_mex:notChar",
+ mexErrMsgIdAndTxt("FastSense:binary_search_mex:notChar",
"direction must be a char array.");
}
diff --git a/libs/FastPlot/private/mex_src/build_store_mex.c b/libs/FastSense/private/mex_src/build_store_mex.c
similarity index 92%
rename from libs/FastPlot/private/mex_src/build_store_mex.c
rename to libs/FastSense/private/mex_src/build_store_mex.c
index 2d15795c..8efe0158 100644
--- a/libs/FastPlot/private/mex_src/build_store_mex.c
+++ b/libs/FastSense/private/mex_src/build_store_mex.c
@@ -1,5 +1,5 @@
/*
- * build_store_mex.c — MEX-based bulk SQLite writer for FastPlotDataStore.
+ * build_store_mex.c — MEX-based bulk SQLite writer for FastSenseDataStore.
*
* numChunks = build_store_mex(dbPath, X, Y, chunkSize)
*
@@ -15,7 +15,7 @@
* resolved_violations tables. Writes all data as typed BLOBs (mksqlite-
* compatible 24-byte header) with SIMD-accelerated Y min/max metadata.
*
- * Replaces the MATLAB loop in FastPlotDataStore.initSqlite, eliminating
+ * Replaces the MATLAB loop in FastSenseDataStore.initSqlite, eliminating
* ~20K mksqlite round-trips and saving ~3-4s on 100M+ point datasets.
*/
@@ -133,26 +133,26 @@ void mexFunction(int nlhs, mxArray *plhs[],
/* Sanity check: typed BLOB class constant must match MATLAB's mxDOUBLE_CLASS */
if (TYPED_BLOB_CLASS_DBL != mxDOUBLE_CLASS) {
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:classSync",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:classSync",
"TYPED_BLOB_CLASS_DBL (%d) != mxDOUBLE_CLASS (%d)",
TYPED_BLOB_CLASS_DBL, (int)mxDOUBLE_CLASS);
}
/* ---- Validate inputs ---- */
if (nrhs != 4) {
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:nrhs",
"Four inputs required: dbPath, X, Y, chunkSize.");
}
if (!mxIsChar(prhs[0])) {
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:badPath",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:badPath",
"First input must be a char array (database path).");
}
if (!mxIsDouble(prhs[1]) || mxIsComplex(prhs[1])) {
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:notDouble",
"X must be a real double array.");
}
if (!mxIsDouble(prhs[2]) || mxIsComplex(prhs[2])) {
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:notDouble",
"Y must be a real double array.");
}
@@ -177,7 +177,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
snprintf(errbuf, sizeof(errbuf), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:dbOpen",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:dbOpen",
"Cannot open database: %s", errbuf);
}
@@ -191,7 +191,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
sqlite3_exec(db, "PRAGMA mmap_size = 268435456", NULL, NULL, NULL);
/* ---- Create tables ---- */
- /* KEEP IN SYNC with FastPlotDataStore.initSqlite MATLAB fallback */
+ /* KEEP IN SYNC with FastSenseDataStore.initSqlite MATLAB fallback */
rc = sqlite3_exec(db,
"CREATE TABLE chunks ("
" chunk_id INTEGER PRIMARY KEY,"
@@ -209,11 +209,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
snprintf(errbuf, sizeof(errbuf), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:createTable",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:createTable",
"CREATE TABLE chunks failed: %s", errbuf);
}
- /* KEEP IN SYNC with FastPlotDataStore.initSqlite MATLAB fallback */
+ /* KEEP IN SYNC with FastSenseDataStore.initSqlite MATLAB fallback */
sqlite3_exec(db,
"CREATE TABLE resolved_thresholds ("
" idx INTEGER PRIMARY KEY,"
@@ -226,7 +226,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
" value REAL NOT NULL"
")", NULL, NULL, NULL);
- /* KEEP IN SYNC with FastPlotDataStore.initSqlite MATLAB fallback */
+ /* KEEP IN SYNC with FastSenseDataStore.initSqlite MATLAB fallback */
sqlite3_exec(db,
"CREATE TABLE resolved_violations ("
" idx INTEGER PRIMARY KEY,"
@@ -245,7 +245,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
snprintf(errbuf, sizeof(errbuf), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:prepare",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:prepare",
"Prepare failed: %s", errbuf);
}
@@ -306,7 +306,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
mxFree(xBlobBuf);
mxFree(yBlobBuf);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:build_store_mex:insert",
+ mexErrMsgIdAndTxt("FastSense:build_store_mex:insert",
"Insert failed at chunk %d: %s", (int)chunkId, errbuf);
}
}
diff --git a/libs/FastPlot/private/mex_src/compute_violations_mex.c b/libs/FastSense/private/mex_src/compute_violations_mex.c
similarity index 99%
rename from libs/FastPlot/private/mex_src/compute_violations_mex.c
rename to libs/FastSense/private/mex_src/compute_violations_mex.c
index 232e8c4f..6882f5d8 100644
--- a/libs/FastPlot/private/mex_src/compute_violations_mex.c
+++ b/libs/FastSense/private/mex_src/compute_violations_mex.c
@@ -66,7 +66,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
dirD = mxGetPr(prhs[4]);
nTh = mxGetNumberOfElements(prhs[3]);
} else {
- mexErrMsgIdAndTxt("FastPlot:compute_violations_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:compute_violations_mex:nrhs",
"Five or six inputs required.");
}
diff --git a/libs/FastPlot/private/mex_src/lttb_core_mex.c b/libs/FastSense/private/mex_src/lttb_core_mex.c
similarity index 97%
rename from libs/FastPlot/private/mex_src/lttb_core_mex.c
rename to libs/FastSense/private/mex_src/lttb_core_mex.c
index a7370e26..8031ed45 100644
--- a/libs/FastPlot/private/mex_src/lttb_core_mex.c
+++ b/libs/FastSense/private/mex_src/lttb_core_mex.c
@@ -24,11 +24,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:lttb_core_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:lttb_core_mex:nrhs",
"Three inputs required: x, y, numOut.");
}
if (!mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1])) {
- mexErrMsgIdAndTxt("FastPlot:lttb_core_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:lttb_core_mex:notDouble",
"x and y must be real double arrays.");
}
diff --git a/libs/FastPlot/private/mex_src/minmax_core_mex.c b/libs/FastSense/private/mex_src/minmax_core_mex.c
similarity index 96%
rename from libs/FastPlot/private/mex_src/minmax_core_mex.c
rename to libs/FastSense/private/mex_src/minmax_core_mex.c
index 136a9a89..f63009c9 100644
--- a/libs/FastPlot/private/mex_src/minmax_core_mex.c
+++ b/libs/FastSense/private/mex_src/minmax_core_mex.c
@@ -25,11 +25,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
{
/* Validate inputs */
if (nrhs != 3) {
- mexErrMsgIdAndTxt("FastPlot:minmax_core_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:minmax_core_mex:nrhs",
"Three inputs required: x, y, numBuckets.");
}
if (!mxIsDouble(prhs[0]) || !mxIsDouble(prhs[1])) {
- mexErrMsgIdAndTxt("FastPlot:minmax_core_mex:notDouble",
+ mexErrMsgIdAndTxt("FastSense:minmax_core_mex:notDouble",
"x and y must be real double arrays.");
}
diff --git a/libs/FastPlot/private/mex_src/resolve_disk_mex.c b/libs/FastSense/private/mex_src/resolve_disk_mex.c
similarity index 97%
rename from libs/FastPlot/private/mex_src/resolve_disk_mex.c
rename to libs/FastSense/private/mex_src/resolve_disk_mex.c
index d906fd05..e5919514 100644
--- a/libs/FastPlot/private/mex_src/resolve_disk_mex.c
+++ b/libs/FastSense/private/mex_src/resolve_disk_mex.c
@@ -95,11 +95,11 @@ void mexFunction(int nlhs, mxArray *plhs[],
/* ---- Validate inputs ---- */
if (nrhs != 5) {
- mexErrMsgIdAndTxt("FastPlot:resolve_disk_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:resolve_disk_mex:nrhs",
"Five inputs required: dbPath, segLo, segHi, thresholdValues, directions.");
}
if (!mxIsChar(prhs[0])) {
- mexErrMsgIdAndTxt("FastPlot:resolve_disk_mex:badPath",
+ mexErrMsgIdAndTxt("FastSense:resolve_disk_mex:badPath",
"First input must be a char array (database path).");
}
@@ -145,7 +145,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
const char *errmsg = sqlite3_errmsg(db);
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:resolve_disk_mex:dbOpen",
+ mexErrMsgIdAndTxt("FastSense:resolve_disk_mex:dbOpen",
"Cannot open database: %s", errmsg);
}
@@ -167,7 +167,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
if (rc != SQLITE_OK) {
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:resolve_disk_mex:prepare",
+ mexErrMsgIdAndTxt("FastSense:resolve_disk_mex:prepare",
"SQL prepare failed: %s", sqlite3_errmsg(db));
}
@@ -176,7 +176,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
sqlite3_finalize(stmtUpper);
sqlite3_close(db);
mxFree(dbPath);
- mexErrMsgIdAndTxt("FastPlot:resolve_disk_mex:prepare",
+ mexErrMsgIdAndTxt("FastSense:resolve_disk_mex:prepare",
"SQL prepare failed: %s", sqlite3_errmsg(db));
}
diff --git a/libs/FastPlot/private/mex_src/simd_utils.h b/libs/FastSense/private/mex_src/simd_utils.h
similarity index 98%
rename from libs/FastPlot/private/mex_src/simd_utils.h
rename to libs/FastSense/private/mex_src/simd_utils.h
index 559c53db..5907e72c 100644
--- a/libs/FastPlot/private/mex_src/simd_utils.h
+++ b/libs/FastSense/private/mex_src/simd_utils.h
@@ -5,7 +5,7 @@
#include
/*
- * simd_utils.h — Compile-time SIMD abstraction for FastPlot MEX files.
+ * simd_utils.h — Compile-time SIMD abstraction for FastSense MEX files.
*
* Provides unified operations on packed doubles:
* - AVX2: 4 doubles per vector (__m256d)
diff --git a/libs/FastPlot/private/mex_src/sqlite3.c b/libs/FastSense/private/mex_src/sqlite3.c
similarity index 100%
rename from libs/FastPlot/private/mex_src/sqlite3.c
rename to libs/FastSense/private/mex_src/sqlite3.c
diff --git a/libs/FastPlot/private/mex_src/sqlite3.h b/libs/FastSense/private/mex_src/sqlite3.h
similarity index 100%
rename from libs/FastPlot/private/mex_src/sqlite3.h
rename to libs/FastSense/private/mex_src/sqlite3.h
diff --git a/libs/FastPlot/private/mex_src/violation_cull_mex.c b/libs/FastSense/private/mex_src/violation_cull_mex.c
similarity index 99%
rename from libs/FastPlot/private/mex_src/violation_cull_mex.c
rename to libs/FastSense/private/mex_src/violation_cull_mex.c
index 8b5892f1..ea2000ac 100644
--- a/libs/FastPlot/private/mex_src/violation_cull_mex.c
+++ b/libs/FastSense/private/mex_src/violation_cull_mex.c
@@ -49,7 +49,7 @@ void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
if (nrhs != 7) {
- mexErrMsgIdAndTxt("FastPlot:violation_cull_mex:nrhs",
+ mexErrMsgIdAndTxt("FastSense:violation_cull_mex:nrhs",
"Seven inputs required: x, y, thX, thY, direction, pixelWidth, xmin.");
}
diff --git a/libs/FastPlot/private/minmax_downsample.m b/libs/FastSense/private/minmax_downsample.m
similarity index 99%
rename from libs/FastPlot/private/minmax_downsample.m
rename to libs/FastSense/private/minmax_downsample.m
index 3f0b4577..2c489f0e 100644
--- a/libs/FastPlot/private/minmax_downsample.m
+++ b/libs/FastSense/private/minmax_downsample.m
@@ -13,7 +13,7 @@
% logarithmically-spaced bucket edges when logX is true, producing
% visually uniform bin widths on a log-scale X axis.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% x — sorted numeric row vector of X coordinates (ascending)
diff --git a/libs/FastPlot/private/parseOpts.m b/libs/FastSense/private/parseOpts.m
similarity index 94%
rename from libs/FastPlot/private/parseOpts.m
rename to libs/FastSense/private/parseOpts.m
index 2db738ee..242f3c9e 100644
--- a/libs/FastPlot/private/parseOpts.m
+++ b/libs/FastSense/private/parseOpts.m
@@ -9,7 +9,7 @@
% [opts, unmatched] = PARSEOPTS(defaults, args, verbose) additionally
% emits a warning for every unrecognized option when verbose is true.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% defaults — scalar struct whose field names define valid option keys
@@ -32,7 +32,7 @@
% [opts, extra] = parseOpts(defs, {'color', 'b', 'Name', 'foo'});
% % opts.Color == 'b', opts.Width == 1, extra.Name == 'foo'
%
-% See also FastPlot, FastPlotGrid, struct2nvpairs.
+% See also FastSense, FastSenseGrid, struct2nvpairs.
if nargin < 3; verbose = false; end
@@ -58,7 +58,7 @@
% Unmatched — collect for pass-through
unmatched.(key) = val;
if verbose
- warning('FastPlot:unknownOption', ...
+ warning('FastSense:unknownOption', ...
'Unknown option ''%s''. Valid options: %s', ...
key, strjoin(fnames, ', '));
end
diff --git a/libs/FastPlot/private/resolveTheme.m b/libs/FastSense/private/resolveTheme.m
similarity index 65%
rename from libs/FastPlot/private/resolveTheme.m
rename to libs/FastSense/private/resolveTheme.m
index 5ea9a240..df937e86 100644
--- a/libs/FastPlot/private/resolveTheme.m
+++ b/libs/FastSense/private/resolveTheme.m
@@ -2,17 +2,17 @@
%RESOLVETHEME Normalize a theme specification to a complete theme struct.
% theme = RESOLVETHEME(val, fallbackName) accepts a theme specification
% in one of several flexible formats and returns a fully populated theme
-% struct suitable for FastPlot rendering.
+% struct suitable for FastSense rendering.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Supported input formats for val:
-% [] — empty: uses FastPlotTheme(fallbackName) to load the named
+% [] — empty: uses FastSenseTheme(fallbackName) to load the named
% preset specified by fallbackName
% char — character vector: treated as a preset name and passed to
-% FastPlotTheme(val) (e.g., 'dark', 'light')
+% FastSenseTheme(val) (e.g., 'dark', 'light')
% struct — partial struct of theme overrides: passed to
-% FastPlotTheme(val) which merges them onto the base theme
+% FastSenseTheme(val) which merges them onto the base theme
% other — any other type is assumed to be a pre-built, complete
% theme struct and is returned as-is
%
@@ -22,16 +22,16 @@
%
% Outputs:
% theme — complete theme struct with all required fields populated,
-% ready for use in FastPlot rendering
+% ready for use in FastSense rendering
%
-% See also FastPlotTheme, mergeTheme, getDefaults.
+% See also FastSenseTheme, mergeTheme, getDefaults.
if isempty(val)
% No theme specified — load the fallback preset
- theme = FastPlotTheme(fallbackName);
+ theme = FastSenseTheme(fallbackName);
elseif ischar(val) || isstruct(val)
- % Preset name or partial overrides — delegate to FastPlotTheme
- theme = FastPlotTheme(val);
+ % Preset name or partial overrides — delegate to FastSenseTheme
+ theme = FastSenseTheme(val);
else
% Pre-built theme object — pass through unchanged
theme = val;
diff --git a/libs/FastPlot/private/struct2nvpairs.m b/libs/FastSense/private/struct2nvpairs.m
similarity index 94%
rename from libs/FastPlot/private/struct2nvpairs.m
rename to libs/FastSense/private/struct2nvpairs.m
index abe94f98..41d17718 100644
--- a/libs/FastPlot/private/struct2nvpairs.m
+++ b/libs/FastSense/private/struct2nvpairs.m
@@ -5,7 +5,7 @@
% passing to MATLAB functions that accept name-value syntax such as
% figure(), set(), or uicontrol().
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% s — scalar struct with N fields (any field value types)
diff --git a/libs/FastPlot/private/violation_cull.m b/libs/FastSense/private/violation_cull.m
similarity index 98%
rename from libs/FastPlot/private/violation_cull.m
rename to libs/FastSense/private/violation_cull.m
index 37707f1c..7de8b1f8 100644
--- a/libs/FastPlot/private/violation_cull.m
+++ b/libs/FastSense/private/violation_cull.m
@@ -6,7 +6,7 @@
% compute_violations (or compute_violations_dynamic) and
% downsample_violations in a single call.
%
-% This function is a private helper for FastPlot.
+% This function is a private helper for FastSense.
%
% Inputs:
% x — numeric vector of data X coordinates
diff --git a/libs/SensorThreshold/Sensor.m b/libs/SensorThreshold/Sensor.m
index 3680fd4b..be1a64dc 100644
--- a/libs/SensorThreshold/Sensor.m
+++ b/libs/SensorThreshold/Sensor.m
@@ -6,7 +6,7 @@
% limit values). The resolve() method evaluates all rules against
% the state channels to produce pre-computed threshold time series,
% violation indices, and state-band regions that can be rendered by
- % a plotting layer such as FastPlot.
+ % a plotting layer such as FastSense.
%
% Typical workflow:
% 1. Create a Sensor and set X/Y data (or call load()).
@@ -63,7 +63,7 @@
X % 1xN double: datenum time stamps
Y % 1xN (or MxN) double: sensor values
Units % char: measurement unit (e.g., 'degC', 'bar', 'rpm')
- DataStore % FastPlotDataStore: disk-backed storage (set by toDisk)
+ DataStore % FastSenseDataStore: disk-backed storage (set by toDisk)
StateChannels % cell array of StateChannel objects
ThresholdRules % cell array of ThresholdRule objects
ResolvedThresholds % struct array: precomputed threshold step-function lines
@@ -214,11 +214,11 @@ function addThresholdRule(obj, condition, value, varargin)
function toDisk(obj)
%TODISK Move sensor X/Y data to disk-backed DataStore.
- % s.toDisk() creates a FastPlotDataStore from the sensor's
+ % s.toDisk() creates a FastSenseDataStore from the sensor's
% X and Y arrays, then clears X and Y from memory. The data
% remains accessible via s.DataStore.getRange() and
% s.DataStore.readSlice(). Subsequent calls to resolve(),
- % addSensor(), and FastPlot rendering all work transparently.
+ % addSensor(), and FastSense rendering all work transparently.
%
% Call toDisk() after setting X and Y but before or after
% resolve(). resolve() automatically reads from the DataStore
@@ -233,7 +233,7 @@ function toDisk(obj)
% fp.addSensor(s);
% fp.render();
%
- % See also toMemory, isOnDisk, FastPlotDataStore.
+ % See also toMemory, isOnDisk, FastSenseDataStore.
if isempty(obj.X) && ~isempty(obj.DataStore)
return; % already on disk
@@ -241,7 +241,7 @@ function toDisk(obj)
if isempty(obj.X)
error('Sensor:noData', 'No X/Y data to move to disk.');
end
- obj.DataStore = FastPlotDataStore(obj.X, obj.Y);
+ obj.DataStore = FastSenseDataStore(obj.X, obj.Y);
% Pre-compute resolve() while X/Y are still in memory (fastest
% path). Results are stored in the SQLite database so that
diff --git a/libs/SensorThreshold/private/compute_violations_disk.m b/libs/SensorThreshold/private/compute_violations_disk.m
index 9cfcbc85..b242a157 100644
--- a/libs/SensorThreshold/private/compute_violations_disk.m
+++ b/libs/SensorThreshold/private/compute_violations_disk.m
@@ -8,7 +8,7 @@
% single MEX call (direct SQLite + SIMD), eliminating MATLAB<->MEX overhead.
%
% Inputs:
-% ds — FastPlotDataStore, disk-backed data source
+% ds — FastSenseDataStore, disk-backed data source
% segLo — 1xS integer, start indices of active segments
% segHi — 1xS integer, end indices of active segments
% thresholdValues — 1xT double, threshold value for each rule
@@ -18,7 +18,7 @@
% batchViolX — 1xT cell array of violation X coordinates
% batchViolY — 1xT cell array of violation Y coordinates
%
-% See also compute_violations_batch, Sensor.resolve, FastPlotDataStore.
+% See also compute_violations_batch, Sensor.resolve, FastSenseDataStore.
persistent hasMex
if isempty(hasMex)
diff --git a/libs/WebBridge/WebBridge.m b/libs/WebBridge/WebBridge.m
index 82a91478..363a17df 100644
--- a/libs/WebBridge/WebBridge.m
+++ b/libs/WebBridge/WebBridge.m
@@ -144,7 +144,7 @@ function sendInit(obj)
idx = 0;
for i = 1:numel(obj.Dashboard.Widgets)
w = obj.Dashboard.Widgets{i};
- if ~isa(w, 'FastPlotWidget'); continue; end
+ if ~isa(w, 'FastSenseWidget'); continue; end
idx = idx + 1;
if isprop(w, 'Sensor') && ~isempty(w.Sensor) && isprop(w.Sensor, 'Key')
sid = w.Sensor.Key;
@@ -225,7 +225,7 @@ function checkConfigChanged(obj)
end
function launchBridge(obj)
bridgeDir = fullfile(fileparts(mfilename('fullpath')), '..', '..', 'bridge', 'python');
- cmd = sprintf('python -m fastplot_bridge --matlab-port %d', obj.TcpPort);
+ cmd = sprintf('python -m fastsense_bridge --matlab-port %d', obj.TcpPort);
if ispc
fullCmd = sprintf('start /B %s', cmd);
else
@@ -239,7 +239,7 @@ function launchBridge(obj)
pause(0.1);
end
obj.stop();
- error('WebBridge:timeout', 'Bridge did not start within 10s. Check that fastplot-bridge is installed.');
+ error('WebBridge:timeout', 'Bridge did not start within 10s. Check that fastsense-bridge is installed.');
end
function enableWALOnDataStores(obj)
stores = obj.collectDataStores();
@@ -254,7 +254,7 @@ function disableWALOnDataStores(obj)
if isempty(obj.Dashboard) || isempty(obj.Dashboard.Widgets); return; end
for i = 1:numel(obj.Dashboard.Widgets)
w = obj.Dashboard.Widgets{i};
- if ~isa(w, 'FastPlotWidget'); continue; end
+ if ~isa(w, 'FastSenseWidget'); continue; end
ds = [];
if isprop(w, 'DataStore') && ~isempty(w.DataStore)
ds = w.DataStore;
diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py
index e80246cf..6d1c8f87 100644
--- a/scripts/generate_api_docs.py
+++ b/scripts/generate_api_docs.py
@@ -640,16 +640,16 @@ def _escape_md_table(text: str) -> str:
# Each page: (output filename, page title, library dir, class order)
PAGES = [
(
- "API-Reference:-FastPlot.md",
- "API Reference: FastPlot",
- "FastPlot",
+ "API-Reference:-FastSense.md",
+ "API Reference: FastSense",
+ "FastSense",
[
- "FastPlot",
- "FastPlotFigure",
- "FastPlotDock",
- "FastPlotToolbar",
- "FastPlotTheme",
- "FastPlotDataStore",
+ "FastSense",
+ "FastSenseFigure",
+ "FastSenseDock",
+ "FastSenseToolbar",
+ "FastSenseTheme",
+ "FastSenseDataStore",
"NavigatorOverlay",
"SensorDetailPlot",
],
@@ -662,7 +662,7 @@ def _escape_md_table(text: str) -> str:
"DashboardEngine",
"DashboardBuilder",
"DashboardWidget",
- "FastPlotWidget",
+ "FastSenseWidget",
"GaugeWidget",
"NumberWidget",
"StatusWidget",
@@ -705,7 +705,7 @@ def _escape_md_table(text: str) -> str:
"API-Reference:-Utilities.md",
"API Reference: Utilities",
None, # special: pulls from multiple dirs
- ["ConsoleProgressBar", "FastPlotDefaults"],
+ ["ConsoleProgressBar", "FastSenseDefaults"],
),
]
@@ -762,7 +762,7 @@ def generate_page(filename, title, classes_by_name, class_order):
# ---------------------------------------------------------------------------
def main():
- print(f"FastPlot API Doc Generator")
+ print(f"FastSense API Doc Generator")
print(f"Project root: {PROJECT_ROOT}")
print(f"Libs dir: {LIBS_DIR}")
print(f"Wiki dir: {WIKI_DIR}")
@@ -778,7 +778,7 @@ def main():
all_classes = {} # name -> MatlabClass
lib_classes = {} # lib_name -> {name: MatlabClass}
- for lib_name in ["FastPlot", "Dashboard", "SensorThreshold", "EventDetection", "WebBridge"]:
+ for lib_name in ["FastSense", "Dashboard", "SensorThreshold", "EventDetection", "WebBridge"]:
lib_dir = LIBS_DIR / lib_name
print(f"[{lib_name}]")
parsed = collect_classes(lib_dir)
diff --git a/scripts/run_tests_with_coverage.m b/scripts/run_tests_with_coverage.m
index 5eb2419f..d2a0a19e 100644
--- a/scripts/run_tests_with_coverage.m
+++ b/scripts/run_tests_with_coverage.m
@@ -18,7 +18,7 @@ function run_tests_with_coverage()
% Add code coverage for all library source files
sourceFiles = {};
- libDirs = {'FastPlot', 'SensorThreshold', 'EventDetection', 'Dashboard', 'WebBridge'};
+ libDirs = {'FastSense', 'SensorThreshold', 'EventDetection', 'Dashboard', 'WebBridge'};
for i = 1:numel(libDirs)
libPath = fullfile(repo_root, 'libs', libDirs{i});
files = dir(fullfile(libPath, '*.m'));
diff --git a/setup.m b/setup.m
index f43bdace..615c091b 100644
--- a/setup.m
+++ b/setup.m
@@ -1,7 +1,7 @@
function setup()
%SETUP Add libraries to path and compile MEX files (including mksqlite/SQLite).
% SETUP() locates the project root (the directory containing this
-% file), then adds the FastPlot, SensorThreshold, and EventDetection
+% file), then adds the FastSense, SensorThreshold, and EventDetection
% library folders to the MATLAB search path using addpath. It then
% compiles all MEX files, including mksqlite for SQLite-backed
% DataStore support.
@@ -10,7 +10,7 @@ function setup()
% for automatic initialization.
%
% The following directories are added:
-% /libs/FastPlot
+% /libs/FastSense
% /libs/SensorThreshold
% /libs/EventDetection
% /libs/Dashboard
@@ -20,32 +20,32 @@ function setup()
% - mksqlite (SQLite3 MEX interface for large-dataset disk storage)
%
% SQLite3 is bundled as the amalgamation (sqlite3.c + sqlite3.h) in
-% libs/FastPlot/private/mex_src/, so no system SQLite installation is
+% libs/FastSense/private/mex_src/, so no system SQLite installation is
% required. It compiles directly into the MEX files on all platforms
% (Linux, macOS, Windows).
%
% Example:
% setup(); % adds libraries to path, compiles MEX; prints status
%
-% See also addpath, FastPlotDefaults, build_mex, FastPlotDataStore.
+% See also addpath, FastSenseDefaults, build_mex, FastSenseDataStore.
% Determine the project root from this file's location
root = fileparts(mfilename('fullpath'));
% Add library directories to the MATLAB search path
- addpath(fullfile(root, 'libs', 'FastPlot'));
+ addpath(fullfile(root, 'libs', 'FastSense'));
addpath(fullfile(root, 'libs', 'SensorThreshold'));
addpath(fullfile(root, 'libs', 'EventDetection'));
addpath(fullfile(root, 'libs', 'Dashboard'));
addpath(fullfile(root, 'libs', 'WebBridge'));
- fprintf('FastPlot + SensorThreshold + EventDetection + Dashboard + WebBridge libraries added to path.\n');
+ fprintf('FastSense + SensorThreshold + EventDetection + Dashboard + WebBridge libraries added to path.\n');
% Compile all MEX files (SIMD kernels + bundled SQLite3)
- % Set FASTPLOT_SKIP_BUILD=1 to skip (e.g., CI with pre-cached MEX)
- if isempty(getenv('FASTPLOT_SKIP_BUILD'))
+ % Set FASTSENSE_SKIP_BUILD=1 to skip (e.g., CI with pre-cached MEX)
+ if isempty(getenv('FASTSENSE_SKIP_BUILD'))
fprintf('\n--- Compiling MEX files ---\n');
build_mex();
else
- fprintf('MEX compilation skipped (FASTPLOT_SKIP_BUILD set).\n');
+ fprintf('MEX compilation skipped (FASTSENSE_SKIP_BUILD set).\n');
end
end
diff --git a/tests/add_fastplot_private_path.m b/tests/add_fastsense_private_path.m
similarity index 79%
rename from tests/add_fastplot_private_path.m
rename to tests/add_fastsense_private_path.m
index 54af0a5e..172fa16d 100644
--- a/tests/add_fastplot_private_path.m
+++ b/tests/add_fastsense_private_path.m
@@ -1,11 +1,11 @@
-function add_fastplot_private_path()
-%ADD_FASTPLOT_PRIVATE_PATH Make libs/FastPlot/private/ functions accessible from tests.
+function add_fastsense_private_path()
+%ADD_FASTSENSE_PRIVATE_PATH Make libs/FastSense/private/ functions accessible from tests.
% On R2025b+, addpath('private') is rejected, so we copy files to a
% temp directory proxy.
test_dir = fileparts(mfilename('fullpath'));
repo_root = fileparts(test_dir);
- privDir = fullfile(repo_root, 'libs', 'FastPlot', 'private');
+ privDir = fullfile(repo_root, 'libs', 'FastSense', 'private');
w = warning('off', 'all');
addpath(privDir);
@@ -16,7 +16,7 @@ function add_fastplot_private_path()
if ~any(strcmp(dirs, privDir))
% R2025b+: addpath('private') was rejected.
% Make private functions available via a temp directory with copies.
- tmpDir = fullfile(tempdir, 'fastplot_private_proxy');
+ tmpDir = fullfile(tempdir, 'fastsense_private_proxy');
if ~exist(tmpDir, 'dir')
mkdir(tmpDir);
end
diff --git a/tests/run_all_tests.m b/tests/run_all_tests.m
index a8190372..5fcfee3a 100644
--- a/tests/run_all_tests.m
+++ b/tests/run_all_tests.m
@@ -1,5 +1,5 @@
function results = run_all_tests()
-%RUN_ALL_TESTS Execute all FastPlot unit tests.
+%RUN_ALL_TESTS Execute all FastSense unit tests.
% On MATLAB: runs the class-based test suite in tests/suite/ using
% matlab.unittest. On Octave: runs function-based test_*.m files.
%
@@ -29,7 +29,7 @@
suite_dir = fullfile(test_dir, 'suite');
addpath(suite_dir);
- fprintf('=== FastPlot Test Suite (MATLAB) ===\n\n');
+ fprintf('=== FastSense Test Suite (MATLAB) ===\n\n');
suite = TestSuite.fromFolder(suite_dir);
@@ -72,7 +72,7 @@
function results = run_octave_tests(test_dir)
%RUN_OCTAVE_TESTS Run function-based tests for Octave compatibility.
- add_fastplot_private_path();
+ add_fastsense_private_path();
files = dir(fullfile(test_dir, 'test_*.m'));
total = 0;
@@ -94,7 +94,7 @@
end
total = total + 1;
% Write results incrementally so they survive Octave crashes
- resultsFile = getenv('FASTPLOT_RESULTS_FILE');
+ resultsFile = getenv('FASTSENSE_RESULTS_FILE');
if ~isempty(resultsFile)
fid = fopen(resultsFile, 'w');
fprintf(fid, '%d %d\n', passed, failed);
diff --git a/tests/suite/TestAddBand.m b/tests/suite/TestAddBand.m
index d7544578..dd3894ac 100644
--- a/tests/suite/TestAddBand.m
+++ b/tests/suite/TestAddBand.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testAddBand(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-1, 1, 'FaceColor', [1 0.9 0.9], 'FaceAlpha', 0.3, 'Label', 'Safe');
testCase.verifyEqual(numel(fp.Bands), 1, 'testAddBand: count');
testCase.verifyEqual(fp.Bands(1).YLow, -1, 'testAddBand: YLow');
@@ -18,14 +18,14 @@ function testAddBand(testCase)
end
function testAddMultipleBands(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-2, -1);
fp.addBand(1, 2);
testCase.verifyEqual(numel(fp.Bands), 2, 'testAddMultipleBands');
end
function testBandRendered(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addBand(0.2, 0.8, 'FaceColor', [0 1 0], 'FaceAlpha', 0.2);
fp.render();
@@ -33,11 +33,11 @@ function testBandRendered(testCase)
testCase.verifyNotEmpty(fp.Bands(1).hPatch, 'testBandRendered: hPatch created');
testCase.verifyTrue(ishandle(fp.Bands(1).hPatch), 'testBandRendered: hPatch valid');
ud = get(fp.Bands(1).hPatch, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'band', 'testBandRendered: UserData type');
+ testCase.verifyEqual(ud.FastSense.Type, 'band', 'testBandRendered: UserData type');
end
function testBandRejectsAfterRender(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -51,7 +51,7 @@ function testBandRejectsAfterRender(testCase)
end
function testBandDefaults(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(0, 1);
testCase.verifyTrue(fp.Bands(1).FaceAlpha > 0, 'testBandDefaults: FaceAlpha');
testCase.verifyEqual(numel(fp.Bands(1).FaceColor), 3, 'testBandDefaults: FaceColor');
diff --git a/tests/suite/TestAddLine.m b/tests/suite/TestAddLine.m
index 9dc830bf..0fbc26cd 100644
--- a/tests/suite/TestAddLine.m
+++ b/tests/suite/TestAddLine.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testAddSingleLine(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = 1:100;
y = rand(1, 100);
fp.addLine(x, y);
@@ -19,7 +19,7 @@ function testAddSingleLine(testCase)
end
function testAddMultipleLines(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:20, rand(1,20));
fp.addLine(1:5, rand(1,5));
@@ -27,26 +27,26 @@ function testAddMultipleLines(testCase)
end
function testLineOptions(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', 'r', 'DisplayName', 'S1');
testCase.verifyEqual(fp.Lines(1).Options.Color, 'r', 'testLineOptions: Color');
testCase.verifyEqual(fp.Lines(1).Options.DisplayName, 'S1', 'testLineOptions: DisplayName');
end
function testDownsampleMethodDefault(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
testCase.verifyEqual(fp.Lines(1).DownsampleMethod, 'minmax', 'testDownsampleMethodDefault');
end
function testDownsampleMethodOverride(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'DownsampleMethod', 'lttb');
testCase.verifyEqual(fp.Lines(1).DownsampleMethod, 'lttb', 'testDownsampleMethodOverride');
end
function testRejectsNonMonotonicX(testCase)
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addLine([1 3 2 4], rand(1,4));
@@ -58,7 +58,7 @@ function testRejectsNonMonotonicX(testCase)
end
function testRejectsMismatchedLengths(testCase)
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addLine(1:10, rand(1,5));
@@ -70,7 +70,7 @@ function testRejectsMismatchedLengths(testCase)
end
function testColumnVectorsAccepted(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine((1:10)', rand(10,1));
testCase.verifyEqual(numel(fp.Lines(1).X), 10, 'testColumnVectors: numel');
testCase.verifyTrue(isrow(fp.Lines(1).X), 'testColumnVectors: must be row');
diff --git a/tests/suite/TestAddMarker.m b/tests/suite/TestAddMarker.m
index 248e55d7..a3620a02 100644
--- a/tests/suite/TestAddMarker.m
+++ b/tests/suite/TestAddMarker.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testAddMarker(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([10 20 30], [1 2 3], 'Marker', 'v', 'Color', [1 0 0], 'Label', 'Faults');
testCase.verifyEqual(numel(fp.Markers), 1, 'testAddMarker: count');
testCase.verifyEqual(fp.Markers(1).X, [10 20 30], 'testAddMarker: X');
@@ -17,7 +17,7 @@ function testAddMarker(testCase)
end
function testMarkerRendered(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addMarker([10 50], [0.5 0.8], 'Marker', 'd', 'MarkerSize', 10);
fp.render();
@@ -25,18 +25,18 @@ function testMarkerRendered(testCase)
testCase.verifyNotEmpty(fp.Markers(1).hLine, 'testMarkerRendered: hLine');
testCase.verifyTrue(ishandle(fp.Markers(1).hLine), 'testMarkerRendered: valid handle');
ud = get(fp.Markers(1).hLine, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'marker', 'testMarkerRendered: UserData type');
+ testCase.verifyEqual(ud.FastSense.Type, 'marker', 'testMarkerRendered: UserData type');
end
function testMarkerDefaults(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([5], [1]);
testCase.verifyNotEmpty(fp.Markers(1).Marker, 'testMarkerDefaults: Marker shape');
testCase.verifyTrue(fp.Markers(1).MarkerSize > 0, 'testMarkerDefaults: MarkerSize');
end
function testMarkerRejectsAfterRender(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
diff --git a/tests/suite/TestAddSensor.m b/tests/suite/TestAddSensor.m
index 97a3e96a..002202c6 100644
--- a/tests/suite/TestAddSensor.m
+++ b/tests/suite/TestAddSensor.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
@@ -14,7 +14,7 @@ function testAddSensorBasic(testCase)
s.Y = rand(1, 100) * 10;
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s);
testCase.verifyEqual(numel(fp.Lines), 1, 'testBasic: one line added');
testCase.verifyEqual(fp.Lines(1).Options.DisplayName, 'Chamber Pressure', 'testBasic: display name');
@@ -31,7 +31,7 @@ function testAddSensorWithThresholds(testCase)
s.addThresholdRule(struct('machine', 1), 10, 'Direction', 'upper', 'Label', 'HH');
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
testCase.verifyEqual(numel(fp.Lines), 1, 'testWithThresholds: only data line');
testCase.verifyTrue(numel(fp.Thresholds) >= 1, 'testWithThresholds: threshold(s) added');
@@ -46,7 +46,7 @@ function testAddSensorNoThresholds(testCase)
s.addThresholdRule(struct(), 5, 'Direction', 'upper');
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', false);
testCase.verifyEqual(numel(fp.Lines), 1, 'testNoThresholds: only data line');
testCase.verifyEqual(numel(fp.Thresholds), 0, 'testNoThresholds: no thresholds');
@@ -58,7 +58,7 @@ function testAddSensorUsesKeyAsFallbackName(testCase)
s.Y = rand(1, 10);
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s);
testCase.verifyEqual(fp.Lines(1).Options.DisplayName, 'flow_rate', 'testFallbackName: uses Key');
end
diff --git a/tests/suite/TestAddShaded.m b/tests/suite/TestAddShaded.m
index 4550c36f..c86c7693 100644
--- a/tests/suite/TestAddShaded.m
+++ b/tests/suite/TestAddShaded.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
@@ -12,7 +12,7 @@ function testAddShaded(testCase)
x = 1:100;
y1 = ones(1,100) * 2;
y2 = ones(1,100) * -2;
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded(x, y1, y2, 'FaceColor', [0 0 1], 'FaceAlpha', 0.2);
testCase.verifyEqual(numel(fp.Shadings), 1, 'testAddShaded: count');
testCase.verifyEqual(fp.Shadings(1).X, x, 'testAddShaded: X');
@@ -21,7 +21,7 @@ function testAddShaded(testCase)
end
function testShadedRendered(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addShaded(1:100, ones(1,100), zeros(1,100), 'FaceColor', [1 0 0]);
fp.render();
@@ -29,11 +29,11 @@ function testShadedRendered(testCase)
testCase.verifyNotEmpty(fp.Shadings(1).hPatch, 'testShadedRendered: hPatch');
testCase.verifyTrue(ishandle(fp.Shadings(1).hPatch), 'testShadedRendered: valid');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'shaded', 'testShadedRendered: type');
+ testCase.verifyEqual(ud.FastSense.Type, 'shaded', 'testShadedRendered: type');
end
function testShadedValidation(testCase)
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded(1:10, 1:10, 1:5); % mismatched lengths
@@ -44,7 +44,7 @@ function testShadedValidation(testCase)
end
function testShadedMonotonicX(testCase)
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded([3 1 2], [1 1 1], [0 0 0]);
@@ -55,7 +55,7 @@ function testShadedMonotonicX(testCase)
end
function testShadedRejectsAfterRender(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -69,7 +69,7 @@ function testShadedRejectsAfterRender(testCase)
end
function testShadedColumnVectors(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded((1:10)', (1:10)', zeros(10,1));
testCase.verifyTrue(isrow(fp.Shadings(1).X), 'testShadedColumnVectors: X row');
testCase.verifyTrue(isrow(fp.Shadings(1).Y1), 'testShadedColumnVectors: Y1 row');
@@ -77,7 +77,7 @@ function testShadedColumnVectors(testCase)
end
function testAddFill(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = 1:50;
y = rand(1,50);
fp.addFill(x, y, 'FaceColor', [0 0.5 1], 'FaceAlpha', 0.2);
@@ -86,20 +86,20 @@ function testAddFill(testCase)
end
function testAddFillCustomBaseline(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addFill(1:10, rand(1,10), 'Baseline', -1);
testCase.verifyTrue(all(fp.Shadings(1).Y2 == -1), 'testAddFillCustomBaseline');
end
function testAddFillRendered(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addFill(1:100, rand(1,100), 'FaceColor', [0 1 0]);
fp.render();
testCase.addTeardown(@close, fp.hFigure);
testCase.verifyTrue(ishandle(fp.Shadings(1).hPatch), 'testAddFillRendered: valid patch');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'shaded', 'testAddFillRendered: type is shaded');
+ testCase.verifyEqual(ud.FastSense.Type, 'shaded', 'testAddFillRendered: type is shaded');
end
end
end
diff --git a/tests/suite/TestAddThreshold.m b/tests/suite/TestAddThreshold.m
index 510f8e85..2172d6ab 100644
--- a/tests/suite/TestAddThreshold.m
+++ b/tests/suite/TestAddThreshold.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testAddUpperThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5, 'Direction', 'upper');
testCase.verifyEqual(numel(fp.Thresholds), 1, 'testAddUpperThreshold: count');
testCase.verifyEqual(fp.Thresholds(1).Value, 4.5, 'testAddUpperThreshold: value');
@@ -17,13 +17,13 @@ function testAddUpperThreshold(testCase)
end
function testAddLowerThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(-2.0, 'Direction', 'lower');
testCase.verifyEqual(fp.Thresholds(1).Direction, 'lower', 'testAddLowerThreshold');
end
function testDefaults(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(5.0);
testCase.verifyEqual(fp.Thresholds(1).Direction, 'upper', 'testDefaults: direction');
testCase.verifyEqual(fp.Thresholds(1).ShowViolations, false, 'testDefaults: ShowViolations');
@@ -32,7 +32,7 @@ function testDefaults(testCase)
end
function testCustomOptions(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(3.0, 'Direction', 'lower', ...
'ShowViolations', true, 'Color', [1 0 0], ...
'LineStyle', ':', 'Label', 'LowerBound');
@@ -44,7 +44,7 @@ function testCustomOptions(testCase)
end
function testMultipleThresholds(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(1.0);
fp.addThreshold(2.0);
fp.addThreshold(3.0);
@@ -52,7 +52,7 @@ function testMultipleThresholds(testCase)
end
function testTimeVaryingThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
thX = [0 10 20 30];
thY = [5.0 5.0 7.0 7.0];
fp.addThreshold(thX, thY, 'Direction', 'upper', 'ShowViolations', true, 'Label', 'StepTh');
@@ -65,7 +65,7 @@ function testTimeVaryingThreshold(testCase)
end
function testMixedThresholds(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5);
fp.addThreshold([0 10], [3.0 5.0], 'Direction', 'lower');
testCase.verifyEqual(numel(fp.Thresholds), 2, 'testMixed: count');
diff --git a/tests/suite/TestBinarySearch.m b/tests/suite/TestBinarySearch.m
index c93b6028..f22e5344 100644
--- a/tests/suite/TestBinarySearch.m
+++ b/tests/suite/TestBinarySearch.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestComputeViolations.m b/tests/suite/TestComputeViolations.m
index 8d1fb5c7..82ae22f7 100644
--- a/tests/suite/TestComputeViolations.m
+++ b/tests/suite/TestComputeViolations.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestComputeViolationsDynamic.m b/tests/suite/TestComputeViolationsDynamic.m
index c3be25ef..a6641f24 100644
--- a/tests/suite/TestComputeViolationsDynamic.m
+++ b/tests/suite/TestComputeViolationsDynamic.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestDashboardEngine.m b/tests/suite/TestDashboardEngine.m
index d695cd0e..8a09f6f3 100644
--- a/tests/suite/TestDashboardEngine.m
+++ b/tests/suite/TestDashboardEngine.m
@@ -22,34 +22,34 @@ function testSetTheme(testCase)
function testAddWidget(testCase)
d = DashboardEngine('Test');
- d.addWidget('fastplot', 'Title', 'Plot 1', ...
+ d.addWidget('fastsense', 'Title', 'Plot 1', ...
'Position', [1 1 12 3], ...
'XData', 1:10, 'YData', rand(1,10));
testCase.verifyEqual(numel(d.Widgets), 1);
- testCase.verifyTrue(isa(d.Widgets{1}, 'FastPlotWidget'));
+ testCase.verifyTrue(isa(d.Widgets{1}, 'FastSenseWidget'));
end
function testAddMultipleWidgets(testCase)
d = DashboardEngine('Test');
- d.addWidget('fastplot', 'Title', 'Plot 1', ...
+ d.addWidget('fastsense', 'Title', 'Plot 1', ...
'Position', [1 1 12 3], 'XData', 1:10, 'YData', rand(1,10));
- d.addWidget('fastplot', 'Title', 'Plot 2', ...
+ d.addWidget('fastsense', 'Title', 'Plot 2', ...
'Position', [13 1 12 3], 'XData', 1:10, 'YData', rand(1,10));
testCase.verifyEqual(numel(d.Widgets), 2);
end
function testOverlapResolution(testCase)
d = DashboardEngine('Test');
- d.addWidget('fastplot', 'Title', 'Plot 1', ...
+ d.addWidget('fastsense', 'Title', 'Plot 1', ...
'Position', [1 1 12 3], 'XData', 1:10, 'YData', rand(1,10));
- d.addWidget('fastplot', 'Title', 'Plot 2', ...
+ d.addWidget('fastsense', 'Title', 'Plot 2', ...
'Position', [5 1 12 3], 'XData', 1:10, 'YData', rand(1,10));
testCase.verifyEqual(d.Widgets{2}.Position(2), 4);
end
function testRender(testCase)
d = DashboardEngine('Render Test');
- d.addWidget('fastplot', 'Title', 'Plot 1', ...
+ d.addWidget('fastsense', 'Title', 'Plot 1', ...
'Position', [1 1 24 3], 'XData', 1:100, 'YData', rand(1,100));
d.render();
testCase.addTeardown(@() close(d.hFigure));
@@ -62,7 +62,7 @@ function testSaveAndLoad(testCase)
d = DashboardEngine('Save Test');
d.Theme = 'dark';
d.LiveInterval = 3;
- d.addWidget('fastplot', 'Title', 'Temp', ...
+ d.addWidget('fastsense', 'Title', 'Temp', ...
'Position', [1 1 12 3], 'XData', 1:10, 'YData', [1:10]);
filepath = fullfile(tempdir, 'test_save_dashboard.json');
@@ -79,7 +79,7 @@ function testSaveAndLoad(testCase)
function testExportScript(testCase)
d = DashboardEngine('Export Test');
- d.addWidget('fastplot', 'Title', 'Pressure', ...
+ d.addWidget('fastsense', 'Title', 'Pressure', ...
'Position', [1 1 12 3], 'XData', 1:5, 'YData', [5 4 3 2 1]);
filepath = fullfile(tempdir, 'test_export_dashboard.m');
@@ -94,7 +94,7 @@ function testExportScript(testCase)
function testLiveStartStop(testCase)
d = DashboardEngine('Live Test');
d.LiveInterval = 1;
- d.addWidget('fastplot', 'Title', 'Plot', ...
+ d.addWidget('fastsense', 'Title', 'Plot', ...
'Position', [1 1 24 3], 'XData', 1:10, 'YData', rand(1,10));
d.render();
testCase.addTeardown(@() close(d.hFigure));
@@ -115,7 +115,7 @@ function testAddWidgetWithSensor(testCase)
s.resolve();
d = DashboardEngine('Sensor Test');
- d.addWidget('fastplot', 'Sensor', s, 'Position', [1 1 16 3]);
+ d.addWidget('fastsense', 'Sensor', s, 'Position', [1 1 16 3]);
testCase.verifyEqual(d.Widgets{1}.Title, 'Temperature');
testCase.verifyEqual(d.Widgets{1}.Sensor, s);
end
@@ -123,7 +123,7 @@ function testAddWidgetWithSensor(testCase)
function testCloseDeletesTimer(testCase)
d = DashboardEngine('Timer Cleanup');
d.LiveInterval = 1;
- d.addWidget('fastplot', 'Title', 'P', ...
+ d.addWidget('fastsense', 'Title', 'P', ...
'Position', [1 1 24 3], 'XData', 1:10, 'YData', rand(1,10));
d.render();
d.startLive();
diff --git a/tests/suite/TestDashboardSerializer.m b/tests/suite/TestDashboardSerializer.m
index e7098e17..b25bef6a 100644
--- a/tests/suite/TestDashboardSerializer.m
+++ b/tests/suite/TestDashboardSerializer.m
@@ -26,7 +26,7 @@ function testSaveAndLoadRoundTrip(testCase)
config.liveInterval = 5;
config.grid = struct('columns', 24);
config.widgets = {};
- config.widgets{1} = struct('type', 'fastplot', ...
+ config.widgets{1} = struct('type', 'fastsense', ...
'title', 'Temperature', ...
'position', struct('col', 1, 'row', 1, 'width', 12, 'height', 3), ...
'source', struct('type', 'data', 'x', 1:10, 'y', rand(1,10)));
@@ -45,10 +45,10 @@ function testSaveAndLoadRoundTrip(testCase)
end
function testWidgetsToConfig(testCase)
- w1 = FastPlotWidget('Title', 'Plot 1', 'Position', [1 1 12 3]);
+ w1 = FastSenseWidget('Title', 'Plot 1', 'Position', [1 1 12 3]);
w1.XData = 1:10;
w1.YData = rand(1,10);
- w2 = FastPlotWidget('Title', 'Plot 2', 'Position', [13 1 12 3]);
+ w2 = FastSenseWidget('Title', 'Plot 2', 'Position', [13 1 12 3]);
w2.XData = 1:10;
w2.YData = rand(1,10);
@@ -67,7 +67,7 @@ function testConfigToWidgets(testCase)
config.grid = struct('columns', 24);
ws = struct();
- ws.type = 'fastplot';
+ ws.type = 'fastsense';
ws.title = 'Temp';
ws.position = struct('col', 1, 'row', 1, 'width', 12, 'height', 3);
ws.source = struct('type', 'data', 'x', 1:5, 'y', [1 2 3 4 5]);
@@ -75,7 +75,7 @@ function testConfigToWidgets(testCase)
widgets = DashboardSerializer.configToWidgets(config);
testCase.verifyEqual(numel(widgets), 1);
- testCase.verifyTrue(isa(widgets{1}, 'FastPlotWidget'));
+ testCase.verifyTrue(isa(widgets{1}, 'FastSenseWidget'));
testCase.verifyEqual(widgets{1}.Title, 'Temp');
end
@@ -87,7 +87,7 @@ function testExportScript(testCase)
config.grid = struct('columns', 24);
ws = struct();
- ws.type = 'fastplot';
+ ws.type = 'fastsense';
ws.title = 'Temperature';
ws.position = struct('col', 1, 'row', 1, 'width', 12, 'height', 3);
ws.source = struct('type', 'data', 'x', 1:10, 'y', rand(1,10));
diff --git a/tests/suite/TestDashboardTheme.m b/tests/suite/TestDashboardTheme.m
index 1e5c6083..0119e6a6 100644
--- a/tests/suite/TestDashboardTheme.m
+++ b/tests/suite/TestDashboardTheme.m
@@ -13,12 +13,12 @@ function testDefaultReturnsStruct(testCase)
'DashboardTheme should return a struct');
end
- function testContainsFastPlotFields(testCase)
+ function testContainsFastSenseFields(testCase)
theme = DashboardTheme();
testCase.verifyTrue(isfield(theme, 'Background'), ...
- 'Should contain FastPlotTheme fields');
+ 'Should contain FastSenseTheme fields');
testCase.verifyTrue(isfield(theme, 'FontSize'), ...
- 'Should contain FastPlotTheme FontSize field');
+ 'Should contain FastSenseTheme FontSize field');
end
function testContainsDashboardFields(testCase)
@@ -57,11 +57,11 @@ function testContainsDashboardFields(testCase)
function testPresetInheritance(testCase)
theme = DashboardTheme('dark');
- baseDark = FastPlotTheme('dark');
+ baseDark = FastSenseTheme('dark');
testCase.verifyEqual(theme.Background, baseDark.Background, ...
- 'Should inherit FastPlotTheme dark preset Background');
+ 'Should inherit FastSenseTheme dark preset Background');
testCase.verifyEqual(theme.FontSize, baseDark.FontSize, ...
- 'Should inherit FastPlotTheme dark preset FontSize');
+ 'Should inherit FastSenseTheme dark preset FontSize');
end
function testNameValueOverrides(testCase)
diff --git a/tests/suite/TestDataStoreWAL.m b/tests/suite/TestDataStoreWAL.m
index 8530d036..8515c3f6 100644
--- a/tests/suite/TestDataStoreWAL.m
+++ b/tests/suite/TestDataStoreWAL.m
@@ -8,7 +8,7 @@ function addPaths(testCase)
methods (Test)
function testEnableWAL(testCase)
x = 1:1000; y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
ds.enableWAL();
ds.ensureOpen();
@@ -17,7 +17,7 @@ function testEnableWAL(testCase)
end
function testDisableWAL(testCase)
x = 1:1000; y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
ds.enableWAL();
ds.disableWAL();
@@ -27,7 +27,7 @@ function testDisableWAL(testCase)
end
function testDataAccessAfterWAL(testCase)
x = 1:1000; y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() delete(ds));
ds.enableWAL();
[xOut, yOut] = ds.getRange(1, 1000);
diff --git a/tests/suite/TestDatastore.m b/tests/suite/TestDatastore.m
index 976c3c08..2418e81c 100644
--- a/tests/suite/TestDatastore.m
+++ b/tests/suite/TestDatastore.m
@@ -1,6 +1,6 @@
classdef TestDatastore < matlab.unittest.TestCase
-%TestDatastore Unit tests for FastPlotDataStore class.
-% Tests the SQLite/binary-backed data storage used by FastPlot to handle
+%TestDatastore Unit tests for FastSenseDataStore class.
+% Tests the SQLite/binary-backed data storage used by FastSense to handle
% large datasets without running out of memory. Covers creation, range
% queries, slice reads, edge cases, and cleanup.
@@ -8,7 +8,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
@@ -17,7 +17,7 @@ function testCreateStore(testCase)
% basic construction stores metadata correctly
x = linspace(0, 100, 10000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.NumPoints, 10000, 'testCreateStore: NumPoints');
testCase.verifyEqual(ds.XMin, x(1), 'testCreateStore: XMin');
@@ -30,14 +30,14 @@ function testCreateStoreWithNaN(testCase)
x = linspace(0, 100, 10000);
y = sin(x);
y(500) = NaN;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.HasNaN, true, 'testCreateStoreWithNaN: HasNaN should be true');
end
function testEmptyConstruction(testCase)
% empty construction returns valid zero-state
- ds = FastPlotDataStore();
+ ds = FastSenseDataStore();
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.NumPoints, 0, 'testEmptyConstruction: NumPoints');
testCase.verifyTrue(isnan(ds.XMin), 'testEmptyConstruction: XMin should be NaN');
@@ -45,7 +45,7 @@ function testEmptyConstruction(testCase)
function testColumnVectorInput(testCase)
% accepts column vectors
- ds = FastPlotDataStore((1:100)', rand(100,1));
+ ds = FastSenseDataStore((1:100)', rand(100,1));
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.NumPoints, 100, 'testColumnVectorInput: NumPoints');
end
@@ -54,7 +54,7 @@ function testGetRangeMiddle(testCase)
% query a middle range returns correct data
x = linspace(0, 100, 50000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, yr] = ds.getRange(20, 40);
testCase.verifyNotEmpty(xr, 'testGetRangeMiddle: should return data');
@@ -70,7 +70,7 @@ function testGetRangeFullSpan(testCase)
% range covering entire dataset returns all points
x = 1:1000;
y = rand(1, 1000);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, yr] = ds.getRange(1, 1000);
testCase.verifyEqual(numel(xr), 1000, 'testGetRangeFullSpan: should get all points');
@@ -84,7 +84,7 @@ function testGetRangeSmall(testCase)
n = 200000;
x = linspace(0, 1000, n);
y = cumsum(randn(1, n));
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, yr] = ds.getRange(500, 501);
% Should get a reasonable number of points (not all 200K)
@@ -99,7 +99,7 @@ function testGetRangeOutside(testCase)
% range outside data returns empty or edge points
x = 1:100;
y = rand(1, 100);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, ~] = ds.getRange(200, 300);
% Should either be empty or contain only the last data point
@@ -110,7 +110,7 @@ function testReadSliceExact(testCase)
% reading a specific index range returns correct data
x = 1:5000;
y = (1:5000) * 2;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xs, ys] = ds.readSlice(100, 200);
testCase.verifyEqual(numel(xs), 101, 'testReadSliceExact: count');
@@ -124,7 +124,7 @@ function testReadSliceFullRange(testCase)
% reading entire range matches original data
x = linspace(0, 10, 1000);
y = cos(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xs, ys] = ds.readSlice(1, 1000);
tol = 1e-12;
@@ -134,7 +134,7 @@ function testReadSliceFullRange(testCase)
function testReadSliceClamped(testCase)
% out-of-bounds indices are clamped
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
testCase.addTeardown(@() ds.cleanup());
[xs, ~] = ds.readSlice(-5, 200);
testCase.verifyEqual(numel(xs), 100, 'testReadSliceClamped: should clamp to full range');
@@ -148,7 +148,7 @@ function testDataIntegrity(testCase)
n = 150000;
x = sort(rand(1, n)) * 1000;
y = randn(1, n);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xAll, yAll] = ds.readSlice(1, n);
tol = 1e-12;
@@ -161,7 +161,7 @@ function testDataIntegrityNaN(testCase)
x = 1:100;
y = rand(1, 100);
y([10, 50, 90]) = NaN;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[~, yr] = ds.readSlice(1, 100);
testCase.verifyTrue(isnan(yr(10)), 'testDataIntegrityNaN: NaN at 10');
@@ -171,7 +171,7 @@ function testDataIntegrityNaN(testCase)
function testOutputShape(testCase)
% getRange and readSlice return row vectors
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
testCase.addTeardown(@() ds.cleanup());
[xr, yr] = ds.getRange(100, 200);
testCase.verifyTrue(isrow(xr), 'testOutputShape: getRange X must be row');
@@ -183,7 +183,7 @@ function testOutputShape(testCase)
function testCleanupDeletesFile(testCase)
% cleanup removes temp files from disk
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
% Store the path(s) before cleanup
hasDb = ~isempty(ds.DbPath) && exist(ds.DbPath, 'file');
hasBin = ~isempty(ds.BinPath) && exist(ds.BinPath, 'file');
@@ -199,7 +199,7 @@ function testCleanupDeletesFile(testCase)
function testDestructorCleanup(testCase)
% deleting the object cleans up temp files
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
if ~isempty(ds.DbPath) && exist(ds.DbPath, 'file')
fpath = ds.DbPath;
else
@@ -214,7 +214,7 @@ function testLargeDataset(testCase)
n = 500000;
x = linspace(0, 10000, n);
y = sin(x / 100) + randn(1, n) * 0.1;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.NumPoints, n, 'testLargeDataset: NumPoints');
diff --git a/tests/suite/TestDatastoreEdgeCases.m b/tests/suite/TestDatastoreEdgeCases.m
index f0d72d91..0f0833cf 100644
--- a/tests/suite/TestDatastoreEdgeCases.m
+++ b/tests/suite/TestDatastoreEdgeCases.m
@@ -1,5 +1,5 @@
classdef TestDatastoreEdgeCases < matlab.unittest.TestCase
-%TestDatastoreEdgeCases Edge-case and stress tests for FastPlotDataStore.
+%TestDatastoreEdgeCases Edge-case and stress tests for FastSenseDataStore.
% Covers: boundary conditions, special values (Inf, NaN), single-point
% datasets, repeated X values, multi-chunk queries, and binary fallback.
@@ -7,13 +7,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testSinglePointDataset(testCase)
- ds = FastPlotDataStore(5, 10);
+ ds = FastSenseDataStore(5, 10);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.NumPoints, 1, 'singlePoint: NumPoints');
testCase.verifyEqual(ds.XMin, 5, 'singlePoint: XMin');
@@ -26,7 +26,7 @@ function testSinglePointDataset(testCase)
end
function testTwoPointDataset(testCase)
- ds = FastPlotDataStore([1, 100], [10, 20]);
+ ds = FastSenseDataStore([1, 100], [10, 20]);
testCase.addTeardown(@() ds.cleanup());
[xr, yr] = ds.getRange(1, 100);
testCase.verifyEqual(numel(xr), 2, 'twoPoint: getRange count');
@@ -37,7 +37,7 @@ function testInfValuesInY(testCase)
x = 1:100;
y = rand(1, 100);
y(25) = Inf; y(75) = -Inf;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[~, yr] = ds.readSlice(1, 100);
testCase.verifyTrue(isinf(yr(25)) && yr(25) > 0, 'infValues: +Inf preserved');
@@ -47,7 +47,7 @@ function testInfValuesInY(testCase)
function testAllNaNYData(testCase)
x = 1:50;
y = nan(1, 50);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyEqual(ds.HasNaN, true, 'allNaN: HasNaN');
[~, yr] = ds.readSlice(1, 50);
@@ -57,7 +57,7 @@ function testAllNaNYData(testCase)
function testConstantX(testCase)
x = ones(1, 100) * 42;
y = rand(1, 100);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyTrue(ds.XMin == 42 && ds.XMax == 42, 'constantX: XMin==XMax');
[xr, yr] = ds.getRange(41, 43);
@@ -67,14 +67,14 @@ function testConstantX(testCase)
function testRepeatedXValues(testCase)
x = sort(repmat(1:50, 1, 3)); % [1 1 1 2 2 2 ... 50 50 50]
y = rand(1, 150);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, ~] = ds.getRange(10, 20);
testCase.verifyTrue(all(xr >= 9 & xr <= 21), 'duplicateX: range respected');
end
function testInvertedRange(testCase)
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
testCase.addTeardown(@() ds.cleanup());
[xr, ~] = ds.getRange(500, 100);
testCase.verifyEmpty(xr, 'invertedRange: should return empty');
@@ -83,7 +83,7 @@ function testInvertedRange(testCase)
function testExactBoundaryQueries(testCase)
x = linspace(0, 100, 10000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, ~] = ds.getRange(0, 0); % exact start
testCase.verifyTrue(numel(xr) >= 1, 'exactBoundary: at start');
@@ -92,7 +92,7 @@ function testExactBoundaryQueries(testCase)
end
function testSinglePointSlice(testCase)
- ds = FastPlotDataStore(1:1000, (1:1000)*3);
+ ds = FastSenseDataStore(1:1000, (1:1000)*3);
testCase.addTeardown(@() ds.cleanup());
[xs, ys] = ds.readSlice(500, 500);
testCase.verifyEqual(numel(xs), 1, 'singleSlice: count');
@@ -103,7 +103,7 @@ function testEndSlice(testCase)
n = 5000;
x = 1:n;
y = x * 2;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xs, ys] = ds.readSlice(n-2, n);
testCase.verifyEqual(numel(xs), 3, 'endSlice: count');
@@ -112,7 +112,7 @@ function testEndSlice(testCase)
end
function testStartSlice(testCase)
- ds = FastPlotDataStore(1:5000, (1:5000)*2);
+ ds = FastSenseDataStore(1:5000, (1:5000)*2);
testCase.addTeardown(@() ds.cleanup());
[xs, ys] = ds.readSlice(1, 3);
testCase.verifyEqual(numel(xs), 3, 'startSlice: count');
@@ -122,7 +122,7 @@ function testStartSlice(testCase)
function testRepeatedQueriesConsistent(testCase)
x = linspace(0, 100, 50000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr1, ~] = ds.getRange(10, 20);
[xr2, ~] = ds.getRange(50, 60);
@@ -134,7 +134,7 @@ function testRepeatedQueriesConsistent(testCase)
function testStressQueries(testCase)
x = linspace(0, 1000, 100000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
tic;
for i = 1:100
@@ -146,14 +146,14 @@ function testStressQueries(testCase)
end
function testIdempotentCleanup(testCase)
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
ds.cleanup();
ds.cleanup(); % should not throw
testCase.verifyTrue(true, 'idempotent cleanup: no error on double cleanup');
end
function testPostCleanupState(testCase)
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
if ~isempty(ds.DbPath); fpath = ds.DbPath; else; fpath = ds.BinPath; end
ds.cleanup();
testCase.verifyTrue(~exist(fpath, 'file'), 'afterCleanup: file should be gone');
@@ -162,7 +162,7 @@ function testPostCleanupState(testCase)
function testVeryLargeYValues(testCase)
x = 1:100;
y = ones(1, 100) * 1e300;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[~, yr] = ds.readSlice(1, 100);
testCase.verifyTrue(all(yr == 1e300), 'largeValues: preserved');
@@ -171,7 +171,7 @@ function testVeryLargeYValues(testCase)
function testVerySmallYValues(testCase)
x = 1:100;
y = ones(1, 100) * 1e-300;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[~, yr] = ds.readSlice(1, 100);
testCase.verifyTrue(all(abs(yr - 1e-300) < 1e-312), 'smallValues: preserved');
@@ -180,7 +180,7 @@ function testVerySmallYValues(testCase)
function testNegativeXValues(testCase)
x = linspace(-100, -1, 500);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
testCase.verifyTrue(ds.XMin == -100 && ds.XMax == -1, 'negativeX: range');
[xr, ~] = ds.getRange(-60, -40);
@@ -192,7 +192,7 @@ function testCrossChunkBoundaryQuery(testCase)
n = 200000;
x = linspace(0, 1000, n);
y = x .* 3; % simple linear for verification
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
% Query range that spans chunk boundaries
[xr, yr] = ds.getRange(400, 600);
@@ -205,7 +205,7 @@ function testXMonotonicity(testCase)
n = 100000;
x = linspace(0, 1000, n);
y = randn(1, n);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
[xr, ~] = ds.getRange(200, 800);
testCase.verifyTrue(all(diff(xr) >= 0), 'monotonicity: X must be non-decreasing');
diff --git a/tests/suite/TestDatetime.m b/tests/suite/TestDatetime.m
index e23e38dc..aad0f9dc 100644
--- a/tests/suite/TestDatetime.m
+++ b/tests/suite/TestDatetime.m
@@ -3,19 +3,19 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testXTypeDefaultIsNumeric(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
testCase.verifyEqual(fp.XType, 'numeric', 'testXTypeDefault: should be numeric');
end
function testXTypeDatenum(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24;
fp.addLine(x, rand(1,100), 'XType', 'datenum');
testCase.verifyEqual(fp.XType, 'datenum', 'testXTypeDatenum: should be datenum');
@@ -23,7 +23,7 @@ function testXTypeDatenum(testCase)
function testDatetimeAutoConvert(testCase)
if exist('datetime', 'class')
- fp = FastPlot();
+ fp = FastSense();
dt = datetime(2024,1,1) + hours(0:99);
fp.addLine(dt, rand(1,100));
testCase.verifyEqual(fp.XType, 'datenum', 'testDatetimeAutoConvert: should be datenum');
@@ -32,7 +32,7 @@ function testDatetimeAutoConvert(testCase)
end
function testTickLabelsAreDateStrings(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24; % ~4 days of hourly data
fp.addLine(x, rand(1,100), 'XType', 'datenum');
fp.render();
@@ -50,7 +50,7 @@ function testTickLabelsAreDateStrings(testCase)
end
function testTickFormatChangesOnZoom(testCase)
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:9999)/86400; % ~0.1s resolution
fp.addLine(x, rand(1,10000), 'XType', 'datenum');
fp.render();
@@ -73,9 +73,9 @@ function testTickFormatChangesOnZoom(testCase)
function testToolbarFormatX(testCase)
% Verify the static helper returns date string for datenum XType
xVal = datenum(2024, 3, 15, 10, 30, 45);
- result = FastPlotToolbar.formatX(xVal, 'datenum');
+ result = FastSenseToolbar.formatX(xVal, 'datenum');
testCase.verifyTrue(any(result == ':'), 'testToolbarFormatX: should contain colon');
- resultNum = FastPlotToolbar.formatX(42.5, 'numeric');
+ resultNum = FastSenseToolbar.formatX(42.5, 'numeric');
testCase.verifyTrue(~any(resultNum == ':'), 'testToolbarFormatXNum: should not contain colon');
end
end
diff --git a/tests/suite/TestDiskAdvanced.m b/tests/suite/TestDiskAdvanced.m
index 1f460f63..efb22bef 100644
--- a/tests/suite/TestDiskAdvanced.m
+++ b/tests/suite/TestDiskAdvanced.m
@@ -1,5 +1,5 @@
classdef TestDiskAdvanced < matlab.unittest.TestCase
-%TestDiskAdvanced Advanced integration tests for FastPlot disk storage.
+%TestDiskAdvanced Advanced integration tests for FastSense disk storage.
% Covers: storage mode transitions, multiple disk lines, pyramid building,
% updateData edge cases, re-render after update, and stress scenarios.
@@ -7,13 +7,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testMultipleDiskLines(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
for i = 1:5
x = linspace(0, 100, 10000);
y = sin(x + i);
@@ -34,7 +34,7 @@ function testMultipleDiskLines(testCase)
end
function testMemoryToDiskTransition(testCase)
- fp = FastPlot('MemoryLimit', 10000);
+ fp = FastSense('MemoryLimit', 10000);
fp.addLine(1:50, rand(1, 50)); % memory (800 bytes < 10000)
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -46,7 +46,7 @@ function testMemoryToDiskTransition(testCase)
end
function testDiskToMemoryTransition(testCase)
- fp = FastPlot('MemoryLimit', 10000);
+ fp = FastSense('MemoryLimit', 10000);
fp.addLine(linspace(0, 100, 5000), rand(1, 5000)); % disk
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -67,7 +67,7 @@ function testDiskToMemoryTransition(testCase)
end
function testUpdateDataPreservesCleanup(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -82,7 +82,7 @@ function testUpdateDataPreservesCleanup(testCase)
end
function testRenderUpdateReRenderCycle(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 20000);
fp.addLine(x, sin(x));
fp.render();
@@ -97,7 +97,7 @@ function testRenderUpdateReRenderCycle(testCase)
end
function testVeryNarrowZoomOnDisk(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 100000;
x = linspace(0, 1000, n);
y = sin(x);
@@ -112,7 +112,7 @@ function testVeryNarrowZoomOnDisk(testCase)
end
function testZoomInThenOut(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
@@ -132,7 +132,7 @@ function testZoomInThenOut(testCase)
end
function testMixedMemDiskDataFidelity(testCase)
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
x1 = 1:50; y1 = x1 * 2; % memory
x2 = linspace(0, 100, 5000); y2 = x2 * 3; % disk
fp.addLine(x1, y1, 'DisplayName', 'Mem');
@@ -150,7 +150,7 @@ function testMixedMemDiskDataFidelity(testCase)
end
function testDeleteCleansAllDiskFiles(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
paths = {};
for i = 1:3
fp.addLine(1:5000, rand(1, 5000));
@@ -165,7 +165,7 @@ function testDeleteCleansAllDiskFiles(testCase)
end
function testDiskLineWithNaN(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 10000;
x = linspace(0, 100, n);
y = sin(x);
@@ -177,7 +177,7 @@ function testDiskLineWithNaN(testCase)
end
function testThresholdDiskLineWithNaN(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 10000);
y = sin(x); y(500:600) = NaN;
fp.addLine(x, y);
@@ -188,7 +188,7 @@ function testThresholdDiskLineWithNaN(testCase)
end
function testLowerThresholdOnDiskLine(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 10000);
y = sin(x);
fp.addLine(x, y);
@@ -199,7 +199,7 @@ function testLowerThresholdOnDiskLine(testCase)
end
function testMultipleThresholdsOnDiskLine(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 20000);
y = sin(x);
fp.addLine(x, y);
@@ -212,7 +212,7 @@ function testMultipleThresholdsOnDiskLine(testCase)
end
function testMemoryLimitExactBoundary(testCase)
- fp = FastPlot('MemoryLimit', 1600); % 100 points * 8 * 2 = 1600
+ fp = FastSense('MemoryLimit', 1600); % 100 points * 8 * 2 = 1600
fp.addLine(1:100, rand(1, 100));
% 1600 bytes == 1600 limit -> not strictly greater, stays in memory
testCase.verifyEmpty(fp.Lines(1).DataStore, 'boundary: at limit stays memory');
@@ -222,7 +222,7 @@ function testMemoryLimitExactBoundary(testCase)
end
function testRapidSequentialUpdates(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
diff --git a/tests/suite/TestDiskStorage.m b/tests/suite/TestDiskStorage.m
index c61b56b1..bd09a421 100644
--- a/tests/suite/TestDiskStorage.m
+++ b/tests/suite/TestDiskStorage.m
@@ -1,43 +1,43 @@
classdef TestDiskStorage < matlab.unittest.TestCase
-%TestDiskStorage Integration tests for FastPlot disk-backed storage.
-% Tests that FastPlot correctly stores large datasets on disk via
-% FastPlotDataStore and that render, zoom/pan, updateData, and cleanup
+%TestDiskStorage Integration tests for FastSense disk-backed storage.
+% Tests that FastSense correctly stores large datasets on disk via
+% FastSenseDataStore and that render, zoom/pan, updateData, and cleanup
% all work transparently with disk-backed lines.
methods (TestClassSetup)
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testDefaultStorageMode(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
testCase.verifyEqual(fp.StorageMode, 'auto', 'testDefaultStorageMode');
end
function testStorageModeConstructor(testCase)
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
testCase.verifyEqual(fp.StorageMode, 'disk', 'testStorageModeConstructor');
end
function testMemoryLimitDefault(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
testCase.verifyEqual(fp.MemoryLimit, 500e6, 'testMemoryLimitDefault');
end
function testMemoryLimitConstructor(testCase)
- fp = FastPlot('MemoryLimit', 100e6);
+ fp = FastSense('MemoryLimit', 100e6);
testCase.verifyEqual(fp.MemoryLimit, 100e6, 'testMemoryLimitConstructor');
end
function testAutoModeDiskTrigger(testCase)
% data exceeding MemoryLimit goes to disk
- fp = FastPlot('MemoryLimit', 1000); % very low threshold: 1000 bytes
+ fp = FastSense('MemoryLimit', 1000); % very low threshold: 1000 bytes
n = 1000; % 1000 points * 8 bytes * 2 = 16000 bytes > 1000
x = linspace(0, 10, n);
y = sin(x);
@@ -54,7 +54,7 @@ function testAutoModeDiskTrigger(testCase)
function testAutoModeMemoryForSmall(testCase)
% small data stays in memory
- fp = FastPlot('MemoryLimit', 1e9); % 1 GB threshold
+ fp = FastSense('MemoryLimit', 1e9); % 1 GB threshold
fp.addLine(1:100, rand(1, 100));
testCase.verifyEmpty(fp.Lines(1).DataStore, ...
'testAutoModeMemoryForSmall: should NOT have DataStore');
@@ -64,7 +64,7 @@ function testAutoModeMemoryForSmall(testCase)
function testForceDiskMode(testCase)
% StorageMode='disk' forces all data to disk
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:50, rand(1, 50));
testCase.verifyNotEmpty(fp.Lines(1).DataStore, ...
'testForceDiskMode: small data should still go to disk');
@@ -74,7 +74,7 @@ function testForceDiskMode(testCase)
function testForceMemoryMode(testCase)
% StorageMode='memory' keeps all data in RAM
- fp = FastPlot('StorageMode', 'memory', 'MemoryLimit', 100);
+ fp = FastSense('StorageMode', 'memory', 'MemoryLimit', 100);
fp.addLine(1:10000, rand(1, 10000));
testCase.verifyEmpty(fp.Lines(1).DataStore, ...
'testForceMemoryMode: should NOT use disk even if above limit');
@@ -82,7 +82,7 @@ function testForceMemoryMode(testCase)
function testRenderDiskLine(testCase)
% disk-backed line renders without error
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 20000;
x = linspace(0, 100, n);
y = sin(x);
@@ -102,7 +102,7 @@ function testRenderDiskLine(testCase)
function testRenderMixedLines(testCase)
% mix of memory and disk lines renders
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(1:10, rand(1, 10), 'DisplayName', 'Small'); % memory
fp.addLine(linspace(0,100,5000), rand(1,5000), 'DisplayName', 'Large'); % disk
fp.render();
@@ -114,7 +114,7 @@ function testRenderMixedLines(testCase)
function testZoomDiskLine(testCase)
% zooming re-downsamples from disk correctly
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
@@ -136,7 +136,7 @@ function testZoomDiskLine(testCase)
function testZoomDiskLineDataFidelity(testCase)
% zoomed data preserves signal shape
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 100000;
x = linspace(0, 100, n);
y = x * 2; % simple linear — easy to verify
@@ -158,7 +158,7 @@ function testZoomDiskLineDataFidelity(testCase)
function testUpdateDataDisk(testCase)
% updateData replaces disk-backed data
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 10, 10000);
y = sin(x);
fp.addLine(x, y);
@@ -180,7 +180,7 @@ function testUpdateDataDisk(testCase)
function testThresholdsDiskLine(testCase)
% violations render correctly on disk lines
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 10000;
x = linspace(0, 100, n);
y = sin(x); % values between -1 and 1
@@ -193,8 +193,8 @@ function testThresholdsDiskLine(testCase)
end
function testDeleteCleansDiskFiles(testCase)
- % deleting FastPlot cleans up DataStore files
- fp = FastPlot('StorageMode', 'disk');
+ % deleting FastSense cleans up DataStore files
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
ds = fp.Lines(1).DataStore;
% Get the file path before deletion
@@ -212,7 +212,7 @@ function testDeleteCleansDiskFiles(testCase)
function testLineNumPoints(testCase)
% works for both memory and disk lines
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(1:50, rand(1, 50)); % memory
fp.addLine(1:5000, rand(1, 5000)); % disk
testCase.verifyEqual(fp.lineNumPoints(1), 50, 'testLineNumPoints: memory line');
@@ -221,7 +221,7 @@ function testLineNumPoints(testCase)
function testLineXRange(testCase)
% returns correct endpoints for both storage types
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(5:100, rand(1, 96)); % memory
fp.addLine(linspace(10,200,5000), rand(1,5000)); % disk
[mn1, mx1] = fp.lineXRange(1);
diff --git a/tests/suite/TestDownsampleViolations.m b/tests/suite/TestDownsampleViolations.m
index b8d47b97..ee63ba72 100644
--- a/tests/suite/TestDownsampleViolations.m
+++ b/tests/suite/TestDownsampleViolations.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestEventSnapshot.m b/tests/suite/TestEventSnapshot.m
index 6a4129cb..22a527ce 100644
--- a/tests/suite/TestEventSnapshot.m
+++ b/tests/suite/TestEventSnapshot.m
@@ -4,7 +4,7 @@ function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'EventDetection'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'SensorThreshold'));
- addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastSense'));
setup();
end
end
diff --git a/tests/suite/TestFastplotTheme.m b/tests/suite/TestFastSenseTheme.m
similarity index 86%
rename from tests/suite/TestFastplotTheme.m
rename to tests/suite/TestFastSenseTheme.m
index 899ae762..ae451215 100644
--- a/tests/suite/TestFastplotTheme.m
+++ b/tests/suite/TestFastSenseTheme.m
@@ -1,34 +1,34 @@
-classdef TestFastplotTheme < matlab.unittest.TestCase
+classdef TestFastSenseTheme < matlab.unittest.TestCase
methods (TestClassSetup)
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testThemeConstructorString(testCase)
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
testCase.verifyTrue(isstruct(fp.Theme), 'testThemeConstructorString: Theme must be struct');
testCase.verifyTrue(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testThemeConstructorString: dark bg');
end
function testThemeConstructorStruct(testCase)
custom = struct('Background', [0.5 0.5 0.5]);
- fp = FastPlot('Theme', custom);
+ fp = FastSense('Theme', custom);
testCase.verifyEqual(fp.Theme.Background, [0.5 0.5 0.5], 'testThemeConstructorStruct');
testCase.verifyTrue(isfield(fp.Theme, 'FontSize'), 'testThemeConstructorStruct: inherits defaults');
end
function testDefaultThemeWhenNoneSpecified(testCase)
- fp = FastPlot();
+ fp = FastSense();
testCase.verifyTrue(isstruct(fp.Theme), 'testDefaultTheme: must have theme');
testCase.verifyEqual(fp.Theme.Background, [1 1 1], 'testDefaultTheme: default bg');
end
function testThemeAppliedOnRender(testCase)
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -39,7 +39,7 @@ function testThemeAppliedOnRender(testCase)
end
function testThemeFontApplied(testCase)
- fp = FastPlot('Theme', 'scientific');
+ fp = FastSense('Theme', 'scientific');
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -50,7 +50,7 @@ function testThemeWithParentAxes(testCase)
fig = figure('Visible', 'off');
testCase.addTeardown(@close, fig);
ax = axes('Parent', fig);
- fp = FastPlot('Parent', ax, 'Theme', 'dark');
+ fp = FastSense('Parent', ax, 'Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
axColor = get(ax, 'Color');
@@ -58,7 +58,7 @@ function testThemeWithParentAxes(testCase)
end
function testBackwardCompatNoTheme(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -66,7 +66,7 @@ function testBackwardCompatNoTheme(testCase)
end
function testAutoColorCycling(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
@@ -78,7 +78,7 @@ function testAutoColorCycling(testCase)
end
function testExplicitColorSkipsCycle(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', [1 0 0]);
fp.addLine(1:10, rand(1,10));
testCase.verifyEqual(fp.Lines(1).Options.Color, [1 0 0], 'testExplicitColorSkipsCycle: explicit');
@@ -87,14 +87,14 @@ function testExplicitColorSkipsCycle(testCase)
end
function testThresholdUsesThemeDefaults(testCase)
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
fp.addThreshold(5.0);
testCase.verifyEqual(fp.Thresholds(1).Color, [0 1 0], 'testThresholdThemeDefaults: Color');
testCase.verifyEqual(fp.Thresholds(1).LineStyle, ':', 'testThresholdThemeDefaults: Style');
end
function testThresholdExplicitOverridesTheme(testCase)
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0]));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0]));
fp.addThreshold(5.0, 'Color', [1 0 0]);
testCase.verifyEqual(fp.Thresholds(1).Color, [1 0 0], 'testThresholdOverride: Color');
end
diff --git a/tests/suite/TestFastPlotWidget.m b/tests/suite/TestFastSenseWidget.m
similarity index 72%
rename from tests/suite/TestFastPlotWidget.m
rename to tests/suite/TestFastSenseWidget.m
index 0bfeadc7..2d10befb 100644
--- a/tests/suite/TestFastPlotWidget.m
+++ b/tests/suite/TestFastSenseWidget.m
@@ -1,4 +1,4 @@
-classdef TestFastPlotWidget < matlab.unittest.TestCase
+classdef TestFastSenseWidget < matlab.unittest.TestCase
methods (TestClassSetup)
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
@@ -7,15 +7,15 @@ function addPaths(testCase)
end
methods (Test)
- function testTypeIsFastplot(testCase)
- w = FastPlotWidget();
- testCase.verifyEqual(w.Type, 'fastplot');
+ function testTypeIsFastSense(testCase)
+ w = FastSenseWidget();
+ testCase.verifyEqual(w.Type, 'fastsense');
end
function testDefaultPosition(testCase)
- w = FastPlotWidget();
+ w = FastSenseWidget();
testCase.verifyEqual(w.Position, [1 1 12 3], ...
- 'Default FastPlotWidget size should be 12x3');
+ 'Default FastSenseWidget size should be 12x3');
end
function testSensorBinding(testCase)
@@ -23,7 +23,7 @@ function testSensorBinding(testCase)
s.X = 1:100;
s.Y = rand(1,100);
- w = FastPlotWidget('Sensor', s);
+ w = FastSenseWidget('Sensor', s);
testCase.verifyEqual(w.Sensor, s);
testCase.verifyEqual(w.Title, 'Temperature', ...
'Title should default to Sensor.Name');
@@ -32,9 +32,9 @@ function testSensorBinding(testCase)
function testDataStoreBinding(testCase)
x = 1:1000;
y = rand(1,1000);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
- w = FastPlotWidget('DataStoreObj', ds);
+ w = FastSenseWidget('DataStoreObj', ds);
testCase.verifyEqual(w.DataStoreObj, ds);
end
@@ -45,14 +45,14 @@ function testRenderCreatesAxes(testCase)
hp = uipanel('Parent', hFig, 'Units', 'normalized', ...
'Position', [0 0 1 1]);
- w = FastPlotWidget();
+ w = FastSenseWidget();
w.XData = 1:100;
w.YData = rand(1,100);
w.render(hp);
- testCase.verifyNotEmpty(w.FastPlotObj, ...
- 'Should create a FastPlot instance');
- testCase.verifyTrue(isa(w.FastPlotObj, 'FastPlot'));
+ testCase.verifyNotEmpty(w.FastSenseObj, ...
+ 'Should create a FastSense instance');
+ testCase.verifyTrue(isa(w.FastSenseObj, 'FastSense'));
end
function testRenderWithSensor(testCase)
@@ -68,20 +68,20 @@ function testRenderWithSensor(testCase)
s.addThresholdRule(struct(), 80, 'Direction', 'upper', 'Label', 'Hi Alarm');
s.resolve();
- w = FastPlotWidget('Sensor', s);
+ w = FastSenseWidget('Sensor', s);
w.render(hp);
- testCase.verifyNotEmpty(w.FastPlotObj);
- testCase.verifyGreaterThanOrEqual(numel(w.FastPlotObj.Lines), 1);
+ testCase.verifyNotEmpty(w.FastSenseObj);
+ testCase.verifyGreaterThanOrEqual(numel(w.FastSenseObj.Lines), 1);
end
function testToStructRoundTrip(testCase)
- w = FastPlotWidget('Title', 'My Plot', 'Position', [5 2 16 3]);
+ w = FastSenseWidget('Title', 'My Plot', 'Position', [5 2 16 3]);
w.XData = 1:10;
w.YData = rand(1,10);
s = w.toStruct();
- testCase.verifyEqual(s.type, 'fastplot');
+ testCase.verifyEqual(s.type, 'fastsense');
testCase.verifyEqual(s.title, 'My Plot');
testCase.verifyEqual(s.position.col, 5);
end
@@ -90,7 +90,7 @@ function testToStructWithSensor(testCase)
sensor = Sensor('P-201', 'Name', 'Pressure');
sensor.X = 1:100;
sensor.Y = rand(1,100);
- w = FastPlotWidget('Sensor', sensor);
+ w = FastSenseWidget('Sensor', sensor);
s = w.toStruct();
testCase.verifyEqual(s.source.type, 'sensor');
@@ -99,12 +99,12 @@ function testToStructWithSensor(testCase)
function testFromStructWithData(testCase)
s = struct();
- s.type = 'fastplot';
+ s.type = 'fastsense';
s.title = 'Restored Plot';
s.position = struct('col', 1, 'row', 1, 'width', 12, 'height', 3);
s.source = struct('type', 'data', 'x', 1:10, 'y', rand(1,10));
- w = FastPlotWidget.fromStruct(s);
+ w = FastSenseWidget.fromStruct(s);
testCase.verifyEqual(w.Title, 'Restored Plot');
testCase.verifyEqual(w.Position, [1 1 12 3]);
testCase.verifyLength(w.XData, 10);
diff --git a/tests/suite/TestFigureLayout.m b/tests/suite/TestFigureLayout.m
index fe7b91f0..d4ea89c6 100644
--- a/tests/suite/TestFigureLayout.m
+++ b/tests/suite/TestFigureLayout.m
@@ -3,28 +3,28 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testConstruction(testCase)
- fig = FastPlotGrid(2, 3);
+ fig = FastSenseGrid(2, 3);
testCase.addTeardown(@close, fig.hFigure);
testCase.verifyEqual(fig.Grid, [2 3], 'testConstruction: Grid');
testCase.verifyNotEmpty(fig.hFigure, 'testConstruction: hFigure');
testCase.verifyTrue(ishandle(fig.hFigure), 'testConstruction: hFigure valid');
end
- function testTileReturnsFastPlot(testCase)
- fig = FastPlotGrid(2, 1);
+ function testTileReturnsFastSense(testCase)
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fp = fig.tile(1);
- testCase.verifyTrue(isa(fp, 'FastPlot'), 'testTileReturnsFastPlot');
+ testCase.verifyTrue(isa(fp, 'FastSense'), 'testTileReturnsFastSense');
end
function testTileLazy(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fp1a = fig.tile(1);
fp1b = fig.tile(1);
@@ -34,7 +34,7 @@ function testTileLazy(testCase)
end
function testTileCreatesAxes(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fp = fig.tile(1);
fp.addLine(1:100, rand(1,100));
@@ -44,7 +44,7 @@ function testTileCreatesAxes(testCase)
end
function testMultipleTiles(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
for i = 1:4
fp = fig.tile(i);
@@ -58,7 +58,7 @@ function testMultipleTiles(testCase)
end
function testRenderAllSkipsRendered(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fp1 = fig.tile(1);
fp1.addLine(1:10, rand(1,10));
@@ -70,7 +70,7 @@ function testRenderAllSkipsRendered(testCase)
end
function testOutOfBoundsTileErrors(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
threw = false;
try
@@ -82,7 +82,7 @@ function testOutOfBoundsTileErrors(testCase)
end
function testTileSpanning(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
fig.setTileSpan(1, [1 2]); % tile 1 spans both columns
fp1 = fig.tile(1);
@@ -94,14 +94,14 @@ function testTileSpanning(testCase)
end
function testFigureThemePassedToTiles(testCase)
- fig = FastPlotGrid(2, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(2, 1, 'Theme', 'dark');
testCase.addTeardown(@close, fig.hFigure);
fp = fig.tile(1);
testCase.verifyTrue(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testFigureThemePassedToTiles');
end
function testTileThemeOverride(testCase)
- fig = FastPlotGrid(2, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(2, 1, 'Theme', 'dark');
testCase.addTeardown(@close, fig.hFigure);
fig.setTileTheme(1, struct('AxesColor', [0.3 0 0]));
fp = fig.tile(1);
@@ -110,14 +110,14 @@ function testTileThemeOverride(testCase)
end
function testFigureProperties(testCase)
- fig = FastPlotGrid(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
+ fig = FastSenseGrid(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
testCase.addTeardown(@close, fig.hFigure);
name = get(fig.hFigure, 'Name');
testCase.verifyEqual(name, 'MyDash', 'testFigureProperties: Name');
end
function testTileLabels(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fp = fig.tile(1);
fp.addLine(1:50, rand(1,50));
@@ -129,7 +129,7 @@ function testTileLabels(testCase)
end
function testAxesReturnsRawAxes(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
ax = fig.axes(1);
testCase.verifyTrue(ishandle(ax), 'testAxesReturnsRawAxes: valid handle');
@@ -137,7 +137,7 @@ function testAxesReturnsRawAxes(testCase)
end
function testAxesLazy(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
ax1 = fig.axes(1);
ax2 = fig.axes(1);
@@ -145,7 +145,7 @@ function testAxesLazy(testCase)
end
function testTileThenAxesErrors(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fig.tile(1);
threw = false;
@@ -158,7 +158,7 @@ function testTileThenAxesErrors(testCase)
end
function testAxesThenTileErrors(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
fig.axes(1);
threw = false;
@@ -171,7 +171,7 @@ function testAxesThenTileErrors(testCase)
end
function testMixedRenderAll(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
fig.tile(1).addLine(1:50, rand(1,50));
ax2 = fig.axes(2); bar(ax2, [1 2 3], [10 20 15]);
@@ -186,7 +186,7 @@ function testMixedRenderAll(testCase)
end
function testAxesThemeApplied(testCase)
- fig = FastPlotGrid(1, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(1, 1, 'Theme', 'dark');
testCase.addTeardown(@close, fig.hFigure);
ax = fig.axes(1);
bgColor = get(ax, 'Color');
@@ -194,7 +194,7 @@ function testAxesThemeApplied(testCase)
end
function testLabelsOnRawAxes(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
testCase.addTeardown(@close, fig.hFigure);
ax = fig.axes(1);
bar(ax, [1 2 3], [10 20 15]);
@@ -207,7 +207,7 @@ function testLabelsOnRawAxes(testCase)
end
function testAxesOutOfBounds(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
threw = false;
try
@@ -219,7 +219,7 @@ function testAxesOutOfBounds(testCase)
end
function testAxesTileSpanning(testCase)
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
testCase.addTeardown(@close, fig.hFigure);
fig.setTileSpan(1, [1 2]);
ax = fig.axes(1);
diff --git a/tests/suite/TestLinkedAxes.m b/tests/suite/TestLinkedAxes.m
index a07eb03f..e7d353bf 100644
--- a/tests/suite/TestLinkedAxes.m
+++ b/tests/suite/TestLinkedAxes.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
@@ -14,11 +14,11 @@ function testLinkedZoomPropagates(testCase)
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'testgroup');
+ fp1 = FastSense('Parent', ax1, 'LinkGroup', 'testgroup');
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'testgroup');
+ fp2 = FastSense('Parent', ax2, 'LinkGroup', 'testgroup');
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
@@ -39,11 +39,11 @@ function testUnlinkedDoesNotPropagate(testCase)
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1);
+ fp1 = FastSense('Parent', ax1);
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2);
+ fp2 = FastSense('Parent', ax2);
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
diff --git a/tests/suite/TestLivePipeline.m b/tests/suite/TestLivePipeline.m
index dd4204c3..4a492849 100644
--- a/tests/suite/TestLivePipeline.m
+++ b/tests/suite/TestLivePipeline.m
@@ -4,7 +4,7 @@ function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'EventDetection'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'SensorThreshold'));
- addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastSense'));
setup();
end
end
diff --git a/tests/suite/TestLttbDownsample.m b/tests/suite/TestLttbDownsample.m
index 4826c73e..7bf2ad99 100644
--- a/tests/suite/TestLttbDownsample.m
+++ b/tests/suite/TestLttbDownsample.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestMexEdgeCases.m b/tests/suite/TestMexEdgeCases.m
index 9334bb4e..94cd7799 100644
--- a/tests/suite/TestMexEdgeCases.m
+++ b/tests/suite/TestMexEdgeCases.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestMexParity.m b/tests/suite/TestMexParity.m
index 2fa035bd..db605c45 100644
--- a/tests/suite/TestMexParity.m
+++ b/tests/suite/TestMexParity.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestMinmaxDownsample.m b/tests/suite/TestMinmaxDownsample.m
index a8ab8f22..30e6ceb0 100644
--- a/tests/suite/TestMinmaxDownsample.m
+++ b/tests/suite/TestMinmaxDownsample.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestMksqliteEdgeCases.m b/tests/suite/TestMksqliteEdgeCases.m
index 0df938e1..4ea014c1 100644
--- a/tests/suite/TestMksqliteEdgeCases.m
+++ b/tests/suite/TestMksqliteEdgeCases.m
@@ -14,7 +14,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestMksqliteTypes.m b/tests/suite/TestMksqliteTypes.m
index 5e414689..eb081e17 100644
--- a/tests/suite/TestMksqliteTypes.m
+++ b/tests/suite/TestMksqliteTypes.m
@@ -13,7 +13,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
@@ -135,7 +135,7 @@ function testAddColumnCellStrings(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -151,7 +151,7 @@ function testAddColumnLogical(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -169,7 +169,7 @@ function testAddColumnCategoricalStruct(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -188,7 +188,7 @@ function testAddColumnChar(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
charData = char(mod(0:n-1, 26) + 65); % A-Z repeating
@@ -201,7 +201,7 @@ function testGetColumnSliceLabels(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -219,7 +219,7 @@ function testGetColumnSliceLogical(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
flags = logical(mod(1:n, 2));
@@ -236,7 +236,7 @@ function testGetColumnSliceCategorical(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -260,7 +260,7 @@ function testGetColumnSliceChar(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
charData = char(mod(0:n-1, 26) + 65);
@@ -276,7 +276,7 @@ function testGetColumnRangeLabels(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -292,7 +292,7 @@ function testGetColumnRangeFlags(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
flags = logical(mod(1:n, 2));
@@ -306,7 +306,7 @@ function testListColumns(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -330,7 +330,7 @@ function testAddColumnDuplicateRejection(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
labels = cell(1, n);
@@ -350,7 +350,7 @@ function testAddColumnSizeMismatchRejection(testCase)
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
testCase.addTeardown(@() ds.cleanup());
threw = false;
@@ -368,14 +368,14 @@ function testToCategoricalRoundTrip(testCase)
n2 = 1000;
x2 = linspace(0, 100, n2);
y2 = sin(x2);
- ds2 = FastPlotDataStore(x2, y2);
+ ds2 = FastSenseDataStore(x2, y2);
testCase.addTeardown(@() ds2.cleanup());
catData2.codes = uint32(mod(0:n2-1, 3) + 1);
catData2.categories = {'low', 'medium', 'high'};
ds2.addColumn('cat_struct', catData2);
slice = ds2.getColumnSlice('cat_struct', 1, 6);
- labels_back = FastPlotDataStore.toCategorical(slice);
+ labels_back = FastSenseDataStore.toCategorical(slice);
if exist('categorical', 'class')
testCase.verifyTrue(isa(labels_back, 'categorical'), ...
'toCategorical: should return categorical in MATLAB');
@@ -395,7 +395,7 @@ function testToCategoricalRoundTrip(testCase)
function testToCategoricalBadInput(testCase)
threw = false;
try
- FastPlotDataStore.toCategorical('not_a_struct');
+ FastSenseDataStore.toCategorical('not_a_struct');
catch
threw = true;
end
@@ -409,7 +409,7 @@ function testAutoConvertCategorical(testCase)
n2 = 1000;
x2 = linspace(0, 100, n2);
y2 = sin(x2);
- ds2 = FastPlotDataStore(x2, y2);
+ ds2 = FastSenseDataStore(x2, y2);
testCase.addTeardown(@() ds2.cleanup());
c_native = categorical({'a','b','c','a','b'}, {'a','b','c'});
@@ -418,7 +418,7 @@ function testAutoConvertCategorical(testCase)
sliceN = ds2.getColumnSlice('cat_native', 1, 5);
testCase.verifyTrue(isstruct(sliceN) && isfield(sliceN, 'codes'), ...
'auto-convert categorical: should be stored as struct');
- labelsN = FastPlotDataStore.toCategorical(sliceN);
+ labelsN = FastSenseDataStore.toCategorical(sliceN);
testCase.verifyTrue(isa(labelsN, 'categorical'), ...
'auto-convert categorical: toCategorical should return categorical');
end
@@ -428,7 +428,7 @@ function testFromCategorical(testCase)
return;
end
c_test = categorical({'x','y','z','x'}, {'x','y','z'});
- s_test = FastPlotDataStore.fromCategorical(c_test);
+ s_test = FastSenseDataStore.fromCategorical(c_test);
testCase.verifyEqual(s_test.codes, uint32([1 2 3 1]), ...
'fromCategorical: codes mismatch');
testCase.verifyEqual(s_test.categories, {'x','y','z'}, ...
@@ -442,7 +442,7 @@ function testAutoConvertStringArray(testCase)
n2 = 1000;
x2 = linspace(0, 100, n2);
y2 = sin(x2);
- ds2 = FastPlotDataStore(x2, y2);
+ ds2 = FastSenseDataStore(x2, y2);
testCase.addTeardown(@() ds2.cleanup());
labels = cell(1, n2);
diff --git a/tests/suite/TestMultiThreshold.m b/tests/suite/TestMultiThreshold.m
index d43524b7..70a652fb 100644
--- a/tests/suite/TestMultiThreshold.m
+++ b/tests/suite/TestMultiThreshold.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testEachThresholdGetsOwnLine(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, randn(1,100));
fp.addThreshold(2.0, 'Direction', 'upper', 'Color', 'r', 'LineStyle', '--');
fp.addThreshold(1.0, 'Direction', 'upper', 'Color', [1 0.6 0], 'LineStyle', ':');
@@ -36,7 +36,7 @@ function testEachThresholdGetsOwnLine(testCase)
end
function testEachThresholdGetsOwnViolationMarkers(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [0 0 0 1.5 1.5 0 0 0 2.5 2.5 0 0];
fp.addLine(1:12, y);
fp.addThreshold(2.0, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
@@ -63,7 +63,7 @@ function testEachThresholdGetsOwnViolationMarkers(testCase)
end
function testThresholdWithoutViolationsGetsNoMarkers(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, zeros(1,10));
fp.addThreshold(5.0, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.render();
@@ -77,7 +77,7 @@ function testThresholdWithoutViolationsGetsNoMarkers(testCase)
end
function testShowViolationsFalseGetsNoMarkerHandle(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, 5*ones(1,10));
fp.addThreshold(2.0, 'Direction', 'upper', 'ShowViolations', false, 'Color', 'r');
fp.render();
@@ -87,7 +87,7 @@ function testShowViolationsFalseGetsNoMarkerHandle(testCase)
end
function testViolationsUpdateOnZoomPerThreshold(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,100), 1.5*ones(1,100), zeros(1,100), 2.5*ones(1,100), zeros(1,100)];
x = 1:500;
fp.addLine(x, y);
@@ -111,16 +111,16 @@ function testViolationsUpdateOnZoomPerThreshold(testCase)
end
function testUserDataTagging(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, randn(1,100));
fp.addThreshold(1.0, 'Direction', 'upper', 'Label', 'AlarmHi', 'Color', 'r');
fp.render();
testCase.addTeardown(@close, fp.hFigure);
ud = get(fp.Thresholds(1).hLine, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'threshold', 'UserData Type');
- testCase.verifyEqual(ud.FastPlot.Name, 'AlarmHi', 'UserData Name');
- testCase.verifyEqual(ud.FastPlot.ThresholdValue, 1.0, 'UserData ThresholdValue');
+ testCase.verifyEqual(ud.FastSense.Type, 'threshold', 'UserData Type');
+ testCase.verifyEqual(ud.FastSense.Name, 'AlarmHi', 'UserData Name');
+ testCase.verifyEqual(ud.FastSense.ThresholdValue, 1.0, 'UserData ThresholdValue');
end
end
end
diff --git a/tests/suite/TestNotificationService.m b/tests/suite/TestNotificationService.m
index f46ade9c..6b2f39df 100644
--- a/tests/suite/TestNotificationService.m
+++ b/tests/suite/TestNotificationService.m
@@ -4,7 +4,7 @@ function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'EventDetection'));
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'SensorThreshold'));
- addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastSense'));
setup();
end
end
diff --git a/tests/suite/TestRender.m b/tests/suite/TestRender.m
index 77e15edf..83eb894e 100644
--- a/tests/suite/TestRender.m
+++ b/tests/suite/TestRender.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testCreatesNewFigure(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Test');
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -21,14 +21,14 @@ function testUsesExistingAxes(testCase)
fig = figure('Visible', 'off');
testCase.addTeardown(@close, fig);
ax = axes('Parent', fig);
- fp = FastPlot('Parent', ax);
+ fp = FastSense('Parent', ax);
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.verifyEqual(fp.hAxes, ax, 'testUsesExistingAxes');
end
function testCreatesLineObjects(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L1');
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L2');
fp.render();
@@ -39,30 +39,30 @@ function testCreatesLineObjects(testCase)
end
function testUserDataTagging(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Sensor1');
fp.addThreshold(0.5, 'Label', 'UpperLim');
fp.render();
testCase.addTeardown(@close, fp.hFigure);
ud = get(fp.Lines(1).hLine, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'data_line', 'testUserDataTagging: Type');
- testCase.verifyEqual(ud.FastPlot.Name, 'Sensor1', 'testUserDataTagging: Name');
- testCase.verifyEqual(ud.FastPlot.LineIndex, 1, 'testUserDataTagging: LineIndex');
+ testCase.verifyEqual(ud.FastSense.Type, 'data_line', 'testUserDataTagging: Type');
+ testCase.verifyEqual(ud.FastSense.Name, 'Sensor1', 'testUserDataTagging: Name');
+ testCase.verifyEqual(ud.FastSense.LineIndex, 1, 'testUserDataTagging: LineIndex');
end
function testThresholdLineCreated(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addThreshold(0.5, 'Direction', 'upper', 'Label', 'UL');
fp.render();
testCase.addTeardown(@close, fp.hFigure);
testCase.verifyTrue(isgraphics(fp.Thresholds(1).hLine, 'line'), 'testThresholdLineCreated');
ud = get(fp.Thresholds(1).hLine, 'UserData');
- testCase.verifyEqual(ud.FastPlot.Type, 'threshold', 'testThresholdLineCreated: Type');
+ testCase.verifyEqual(ud.FastSense.Type, 'threshold', 'testThresholdLineCreated: Type');
end
function testViolationMarkersCreated(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [0.1 0.2 0.8 0.9 0.3 0.1];
fp.addLine(1:6, y);
fp.addThreshold(0.5, 'Direction', 'upper', 'ShowViolations', true);
@@ -76,7 +76,7 @@ function testViolationMarkersCreated(testCase)
end
function testDoubleRenderError(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -90,7 +90,7 @@ function testDoubleRenderError(testCase)
end
function testStaticAxisLimits(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
diff --git a/tests/suite/TestSensorDetailPlot.m b/tests/suite/TestSensorDetailPlot.m
index f4d99411..d3b0f3b7 100644
--- a/tests/suite/TestSensorDetailPlot.m
+++ b/tests/suite/TestSensorDetailPlot.m
@@ -50,12 +50,12 @@ function testConstructorCustomOptions(testCase)
delete(sdp);
end
- %% Render creates two FastPlot instances
+ %% Render creates two FastSense instances
function testRenderCreatesMainAndNavigator(testCase)
sdp = SensorDetailPlot(testCase.TestData.sensor);
sdp.render();
- testCase.verifyClass(sdp.MainPlot, ?FastPlot);
- testCase.verifyClass(sdp.NavigatorPlot, ?FastPlot);
+ testCase.verifyClass(sdp.MainPlot, ?FastSense);
+ testCase.verifyClass(sdp.NavigatorPlot, ?FastSense);
delete(sdp);
end
@@ -285,30 +285,30 @@ function testEventPatchUserdataFields(testCase)
delete(sdp);
end
- %% FastPlotGrid tilePanel integration
+ %% FastSenseGrid tilePanel integration
function testTilePanelReturnsUipanel(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
hp = fig.tilePanel(1);
testCase.verifyTrue(isa(hp, 'matlab.ui.container.Panel'));
delete(fig);
end
function testTilePanelConflictWithTile(testCase)
- fig = FastPlotGrid(2, 1);
- fig.tile(1); % Occupy tile 1 as FastPlot
- testCase.verifyError(@() fig.tilePanel(1), 'FastPlotGrid:tileConflict');
+ fig = FastSenseGrid(2, 1);
+ fig.tile(1); % Occupy tile 1 as FastSense
+ testCase.verifyError(@() fig.tilePanel(1), 'FastSenseGrid:tileConflict');
delete(fig);
end
- %% Embedded in FastPlotGrid
+ %% Embedded in FastSenseGrid
function testEmbeddedInFigureTile(testCase)
s = testCase.TestData.sensor;
- fig = FastPlotGrid(1, 1);
+ fig = FastSenseGrid(1, 1);
hp = fig.tilePanel(1);
sdp = SensorDetailPlot(s, 'Parent', hp);
sdp.render();
testCase.verifyTrue(sdp.IsRendered);
- testCase.verifyClass(sdp.MainPlot, ?FastPlot);
+ testCase.verifyClass(sdp.MainPlot, ?FastSense);
delete(sdp);
delete(fig);
end
diff --git a/tests/suite/TestSensorTodisk.m b/tests/suite/TestSensorTodisk.m
index 8d74a238..1d9f085c 100644
--- a/tests/suite/TestSensorTodisk.m
+++ b/tests/suite/TestSensorTodisk.m
@@ -80,7 +80,7 @@ function testAddSensorWithDiskBacked(testCase)
testCase.addTeardown(@() s2.DataStore.cleanup());
s2.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s2, 'ShowThresholds', true);
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -94,7 +94,7 @@ function testAddSensorNoThresholds(testCase)
s3.Y = rand(1, 10000);
s3.toDisk();
testCase.addTeardown(@() s3.DataStore.cleanup());
- fp2 = FastPlot();
+ fp2 = FastSense();
fp2.addSensor(s3);
fp2.render();
testCase.addTeardown(@close, fp2.hFigure);
diff --git a/tests/suite/TestTheme.m b/tests/suite/TestTheme.m
index c83863c1..3d5dc030 100644
--- a/tests/suite/TestTheme.m
+++ b/tests/suite/TestTheme.m
@@ -8,7 +8,7 @@ function addPaths(testCase)
methods (Test)
function testDefaultPreset(testCase)
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
testCase.verifyTrue(isstruct(t), 'testDefaultPreset: must return struct');
testCase.verifyEqual(t.Background, [1 1 1], 'testDefaultPreset: Background');
testCase.verifyTrue(isfield(t, 'AxesColor'), 'testDefaultPreset: AxesColor field');
@@ -30,13 +30,13 @@ function testDefaultPreset(testCase)
end
function testNoArgsReturnsDefault(testCase)
- t0 = FastPlotTheme();
- t1 = FastPlotTheme('default');
+ t0 = FastSenseTheme();
+ t1 = FastSenseTheme('default');
testCase.verifyEqual(t0, t1, 'testNoArgsReturnsDefault');
end
function testMergeOverrides(testCase)
- t = FastPlotTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
+ t = FastSenseTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
testCase.verifyEqual(t.FontSize, 14, 'testMergeOverrides: FontSize');
testCase.verifyEqual(t.LineWidth, 2.0, 'testMergeOverrides: LineWidth');
testCase.verifyEqual(t.Background, [1 1 1], 'testMergeOverrides: Background unchanged');
@@ -45,7 +45,7 @@ function testMergeOverrides(testCase)
function testInvalidPresetErrors(testCase)
threw = false;
try
- FastPlotTheme('nonexistent');
+ FastSenseTheme('nonexistent');
catch
threw = true;
end
@@ -53,26 +53,26 @@ function testInvalidPresetErrors(testCase)
end
function testDarkPreset(testCase)
- t = FastPlotTheme('dark');
+ t = FastSenseTheme('dark');
testCase.verifyTrue(all(t.Background < [0.2 0.2 0.2]), 'testDarkPreset: Background should be dark');
testCase.verifyTrue(all(t.ForegroundColor > [0.7 0.7 0.7]), 'testDarkPreset: ForegroundColor should be light');
testCase.verifyEqual(size(t.LineColorOrder, 2), 3, 'testDarkPreset: LineColorOrder Nx3');
end
function testLightPreset(testCase)
- t = FastPlotTheme('light');
+ t = FastSenseTheme('light');
testCase.verifyTrue(all(t.Background > [0.9 0.9 0.9]), 'testLightPreset: Background');
testCase.verifyEqual(size(t.LineColorOrder, 2), 3, 'testLightPreset: LineColorOrder Nx3');
end
function testIndustrialPreset(testCase)
- t = FastPlotTheme('industrial');
+ t = FastSenseTheme('industrial');
testCase.verifyTrue(t.LineWidth >= 1.0, 'testIndustrialPreset: LineWidth');
testCase.verifyEqual(size(t.LineColorOrder, 2), 3, 'testIndustrialPreset: LineColorOrder Nx3');
end
function testScientificPreset(testCase)
- t = FastPlotTheme('scientific');
+ t = FastSenseTheme('scientific');
testCase.verifyEqual(t.FontName, 'Times New Roman', 'testScientificPreset: FontName');
testCase.verifyEqual(t.GridAlpha, 0, 'testScientificPreset: no grid');
testCase.verifyTrue(t.LineWidth < 1.0, 'testScientificPreset: thin lines');
@@ -80,7 +80,7 @@ function testScientificPreset(testCase)
end
function testOceanPreset(testCase)
- t = FastPlotTheme('ocean');
+ t = FastSenseTheme('ocean');
testCase.verifyEqual(t.Background, [1 1 1], 'testOceanPreset: Background should be white');
testCase.verifyEqual(t.AxesColor, [1 1 1], 'testOceanPreset: AxesColor should be white');
testCase.verifyEqual(size(t.LineColorOrder, 2), 3, 'testOceanPreset: LineColorOrder Nx3');
@@ -89,20 +89,20 @@ function testOceanPreset(testCase)
function testStructAsPreset(testCase)
custom = struct('Background', [0 0 0], 'FontSize', 16);
- t = FastPlotTheme(custom);
+ t = FastSenseTheme(custom);
testCase.verifyEqual(t.Background, [0 0 0], 'testStructAsPreset: Background');
testCase.verifyEqual(t.FontSize, 16, 'testStructAsPreset: FontSize');
testCase.verifyTrue(isfield(t, 'GridColor'), 'testStructAsPreset: inherits defaults');
end
function testPaletteResolution(testCase)
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
testCase.verifyTrue(size(t.LineColorOrder, 1) >= 6, 'testPaletteResolution: at least 6 colors');
end
function testCustomPaletteMatrix(testCase)
customColors = [1 0 0; 0 1 0; 0 0 1];
- t = FastPlotTheme('default', 'LineColorOrder', customColors);
+ t = FastSenseTheme('default', 'LineColorOrder', customColors);
testCase.verifyEqual(t.LineColorOrder, customColors, 'testCustomPaletteMatrix');
end
end
diff --git a/tests/suite/TestToolbar.m b/tests/suite/TestToolbar.m
index 30352f1c..aa88e322 100644
--- a/tests/suite/TestToolbar.m
+++ b/tests/suite/TestToolbar.m
@@ -3,62 +3,62 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
- function testConstructorWithFastPlot(testCase)
- fp = FastPlot();
+ function testConstructorWithFastSense(testCase)
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
- testCase.verifyNotEmpty(tb.hToolbar, 'testConstructorWithFastPlot: hToolbar');
- testCase.verifyTrue(ishandle(tb.hToolbar), 'testConstructorWithFastPlot: ishandle');
+ tb = FastSenseToolbar(fp);
+ testCase.verifyNotEmpty(tb.hToolbar, 'testConstructorWithFastSense: hToolbar');
+ testCase.verifyTrue(ishandle(tb.hToolbar), 'testConstructorWithFastSense: ishandle');
end
- function testConstructorWithFastPlotGrid(testCase)
- fig = FastPlotGrid(1, 2);
+ function testConstructorWithFastSenseGrid(testCase)
+ fig = FastSenseGrid(1, 2);
fp1 = fig.tile(1); fp1.addLine(1:100, rand(1,100));
fp2 = fig.tile(2); fp2.addLine(1:100, rand(1,100));
fig.renderAll();
testCase.addTeardown(@close, fig.hFigure);
- tb = FastPlotToolbar(fig);
+ tb = FastSenseToolbar(fig);
testCase.verifyNotEmpty(tb.hToolbar, 'testConstructorWithFPFigure: hToolbar');
end
function testToolbarHasAllButtons(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
children = get(tb.hToolbar, 'Children');
testCase.verifyEqual(numel(children), 11, ...
sprintf('testToolbarHasAllButtons: got %d', numel(children)));
end
function testIconsAre16x16x3(testCase)
- icons = FastPlotToolbar.makeIcon('grid');
+ icons = FastSenseToolbar.makeIcon('grid');
testCase.verifyEqual(size(icons), [16 16 3], 'testIconsAre16x16x3');
end
function testAllIconNames(testCase)
names = {'cursor', 'crosshair', 'grid', 'legend', 'autoscale', 'export', 'violations'};
for i = 1:numel(names)
- icon = FastPlotToolbar.makeIcon(names{i});
+ icon = FastSenseToolbar.makeIcon(names{i});
testCase.verifyEqual(size(icon), [16 16 3], ...
sprintf('testAllIconNames: %s', names{i}));
end
end
function testToggleGrid(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
gridBefore = get(fp.hAxes, 'XGrid');
tb.toggleGrid();
gridAfter = get(fp.hAxes, 'XGrid');
@@ -66,11 +66,11 @@ function testToggleGrid(testCase)
end
function testToggleLegend(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'TestLine');
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.toggleLegend();
hLeg = findobj(fp.hFigure, 'Type', 'axes', 'Tag', 'legend');
if isempty(hLeg)
@@ -83,12 +83,12 @@ function testToggleLegend(testCase)
end
function testAutoscaleY(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,50), 10*ones(1,50)];
fp.addLine(1:100, y);
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
% Zoom into first half (all zeros)
set(fp.hAxes, 'XLim', [1 50]);
drawnow;
@@ -100,11 +100,11 @@ function testAutoscaleY(testCase)
end
function testExportPNG(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tmpFile = [tempname, '.png'];
testCase.addTeardown(@() TestToolbar.deleteIfExists(tmpFile));
tb.exportPNG(tmpFile);
@@ -112,11 +112,11 @@ function testExportPNG(testCase)
end
function testCrosshairMode(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
testCase.verifyEqual(tb.Mode, 'none', 'testCrosshairMode: initial mode');
tb.setCrosshair(true);
testCase.verifyEqual(tb.Mode, 'crosshair', 'testCrosshairMode: on');
@@ -125,11 +125,11 @@ function testCrosshairMode(testCase)
end
function testCrosshairMutualExclusion(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.setCursor(true);
testCase.verifyEqual(tb.Mode, 'cursor', 'testMutualExcl: cursor on');
tb.setCrosshair(true);
@@ -138,11 +138,11 @@ function testCrosshairMutualExclusion(testCase)
end
function testCursorMode(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.setCursor(true);
testCase.verifyEqual(tb.Mode, 'cursor', 'testCursorMode: on');
tb.setCursor(false);
@@ -150,23 +150,23 @@ function testCursorMode(testCase)
end
function testSnapToNearest(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine([1 2 3 4 5], [10 20 30 40 50]);
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
[sx, sy, ~] = tb.snapToNearest(fp, 2.8, 25);
testCase.verifyEqual(sx, 3, sprintf('testSnapToNearest: x should be 3, got %g', sx));
testCase.verifyEqual(sy, 30, sprintf('testSnapToNearest: y should be 30, got %g', sy));
end
function testViolationsToggle(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, [ones(1,50)*2, ones(1,50)*8]);
fp.addThreshold(5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
testCase.addTeardown(@close, fp.hFigure);
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
% Violations should be visible initially
testCase.verifyTrue(fp.ViolationsVisible, 'testViolationsToggle: default true');
hM = fp.Thresholds(1).hMarkers;
diff --git a/tests/suite/TestViolationCullMex.m b/tests/suite/TestViolationCullMex.m
index fcae3864..f2fd0649 100644
--- a/tests/suite/TestViolationCullMex.m
+++ b/tests/suite/TestViolationCullMex.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
diff --git a/tests/suite/TestViolationsMexParity.m b/tests/suite/TestViolationsMexParity.m
index b4be0f5a..738fffda 100644
--- a/tests/suite/TestViolationsMexParity.m
+++ b/tests/suite/TestViolationsMexParity.m
@@ -3,7 +3,7 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastPlot', 'private'));
+ addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', 'libs', 'FastSense', 'private'));
end
end
diff --git a/tests/suite/TestWebBridgeE2E.m b/tests/suite/TestWebBridgeE2E.m
index 79c34d24..077b9f96 100644
--- a/tests/suite/TestWebBridgeE2E.m
+++ b/tests/suite/TestWebBridgeE2E.m
@@ -7,12 +7,12 @@ function addPaths(testCase)
end
methods (Test)
function testServeAndFetchData(testCase)
- [status, ~] = system('python -c "import fastplot_bridge"');
- testCase.assumeTrue(status == 0, 'fastplot-bridge Python package not installed');
+ [status, ~] = system('python -c "import fastsense_bridge"');
+ testCase.assumeTrue(status == 0, 'fastsense-bridge Python package not installed');
x = linspace(0, 100, 10000);
y = sin(x);
engine = DashboardEngine('E2E Test');
- engine.addWidget('fastplot', 'Title', 'Sine Wave', 'XData', x, 'YData', y, 'Position', [1 1 6 3]);
+ engine.addWidget('fastsense', 'Title', 'Sine Wave', 'XData', x, 'YData', y, 'Position', [1 1 6 3]);
bridge = WebBridge(engine);
testCase.addTeardown(@() bridge.stop());
bridge.serve();
diff --git a/tests/suite/TestZoomPan.m b/tests/suite/TestZoomPan.m
index 9bd5ce45..36a2243d 100644
--- a/tests/suite/TestZoomPan.m
+++ b/tests/suite/TestZoomPan.m
@@ -3,13 +3,13 @@
function addPaths(testCase)
addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..'));
setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
end
end
methods (Test)
function testZoomUpdatesPlottedData(testCase)
- fp = FastPlot();
+ fp = FastSense();
n = 100000;
x = linspace(0, 100, n);
y = sin(x);
@@ -29,7 +29,7 @@ function testZoomUpdatesPlottedData(testCase)
end
function testLazySkipsRedundantUpdate(testCase)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:1000, rand(1,1000));
fp.render();
testCase.addTeardown(@close, fp.hFigure);
@@ -43,7 +43,7 @@ function testLazySkipsRedundantUpdate(testCase)
end
function testViolationsUpdateOnZoom(testCase)
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,500), ones(1,500)*10, zeros(1,500)];
x = 1:1500;
fp.addLine(x, y);
diff --git a/tests/test_NavigatorOverlay.m b/tests/test_NavigatorOverlay.m
index 0dffb42b..48d1cd8e 100644
--- a/tests/test_NavigatorOverlay.m
+++ b/tests/test_NavigatorOverlay.m
@@ -8,7 +8,7 @@
end
function setup(testCase)
- addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastSense'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'SensorThreshold'));
testCase.TestData.hFig = figure('Visible', 'off');
testCase.TestData.hAxes = axes('Parent', testCase.TestData.hFig);
diff --git a/tests/test_SensorDetailPlot.m b/tests/test_SensorDetailPlot.m
index d62f0a5d..39b942e3 100644
--- a/tests/test_SensorDetailPlot.m
+++ b/tests/test_SensorDetailPlot.m
@@ -8,7 +8,7 @@
end
function setup(testCase)
- addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastPlot'));
+ addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'FastSense'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'SensorThreshold'));
addpath(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'libs', 'EventDetection'));
@@ -52,12 +52,12 @@ function test_constructor_custom_options(testCase)
delete(sdp);
end
-%% Render creates two FastPlot instances
+%% Render creates two FastSense instances
function test_render_creates_main_and_navigator(testCase)
sdp = SensorDetailPlot(testCase.TestData.sensor);
sdp.render();
- verifyClass(testCase, sdp.MainPlot, ?FastPlot);
- verifyClass(testCase, sdp.NavigatorPlot, ?FastPlot);
+ verifyClass(testCase, sdp.MainPlot, ?FastSense);
+ verifyClass(testCase, sdp.NavigatorPlot, ?FastSense);
delete(sdp);
end
@@ -302,30 +302,30 @@ function test_event_patch_userdata_fields(testCase)
delete(sdp);
end
-%% FastPlotGrid tilePanel integration
+%% FastSenseGrid tilePanel integration
function test_tilePanel_returns_uipanel(testCase)
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
hp = fig.tilePanel(1);
verifyTrue(testCase, isa(hp, 'matlab.ui.container.Panel'));
delete(fig);
end
function test_tilePanel_conflict_with_tile(testCase)
- fig = FastPlotGrid(2, 1);
- fig.tile(1); % Occupy tile 1 as FastPlot
- verifyError(testCase, @() fig.tilePanel(1), 'FastPlotGrid:tileConflict');
+ fig = FastSenseGrid(2, 1);
+ fig.tile(1); % Occupy tile 1 as FastSense
+ verifyError(testCase, @() fig.tilePanel(1), 'FastSenseGrid:tileConflict');
delete(fig);
end
-%% Embedded in FastPlotGrid
+%% Embedded in FastSenseGrid
function test_embedded_in_figure_tile(testCase)
s = testCase.TestData.sensor;
- fig = FastPlotGrid(1, 1);
+ fig = FastSenseGrid(1, 1);
hp = fig.tilePanel(1);
sdp = SensorDetailPlot(s, 'Parent', hp);
sdp.render();
verifyTrue(testCase, sdp.IsRendered);
- verifyClass(testCase, sdp.MainPlot, ?FastPlot);
+ verifyClass(testCase, sdp.MainPlot, ?FastSense);
delete(sdp);
delete(fig);
end
diff --git a/tests/test_add_band.m b/tests/test_add_band.m
index fa78e72f..54ad4ac5 100644
--- a/tests/test_add_band.m
+++ b/tests/test_add_band.m
@@ -1,11 +1,11 @@
function test_add_band()
-%TEST_ADD_BAND Tests for FastPlot.addBand method.
+%TEST_ADD_BAND Tests for FastSense.addBand method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testAddBand
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-1, 1, 'FaceColor', [1 0.9 0.9], 'FaceAlpha', 0.3, 'Label', 'Safe');
assert(numel(fp.Bands) == 1, 'testAddBand: count');
assert(fp.Bands(1).YLow == -1, 'testAddBand: YLow');
@@ -13,24 +13,24 @@ function test_add_band()
assert(strcmp(fp.Bands(1).Label, 'Safe'), 'testAddBand: Label');
% testAddMultipleBands
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(-2, -1);
fp.addBand(1, 2);
assert(numel(fp.Bands) == 2, 'testAddMultipleBands');
% testBandRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addBand(0.2, 0.8, 'FaceColor', [0 1 0], 'FaceAlpha', 0.2);
fp.render();
assert(~isempty(fp.Bands(1).hPatch), 'testBandRendered: hPatch created');
assert(ishandle(fp.Bands(1).hPatch), 'testBandRendered: hPatch valid');
ud = get(fp.Bands(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'band'), 'testBandRendered: UserData type');
+ assert(strcmp(ud.FastSense.Type, 'band'), 'testBandRendered: UserData type');
close(fp.hFigure);
% testBandRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
threw = false;
@@ -43,7 +43,7 @@ function test_add_band()
close(fp.hFigure);
% testBandDefaults
- fp = FastPlot();
+ fp = FastSense();
fp.addBand(0, 1);
assert(fp.Bands(1).FaceAlpha > 0, 'testBandDefaults: FaceAlpha');
assert(numel(fp.Bands(1).FaceColor) == 3, 'testBandDefaults: FaceColor');
diff --git a/tests/test_add_line.m b/tests/test_add_line.m
index 2d795bae..00ce3277 100644
--- a/tests/test_add_line.m
+++ b/tests/test_add_line.m
@@ -1,10 +1,10 @@
function test_add_line()
-%TEST_ADD_LINE Tests for FastPlot.addLine method.
+%TEST_ADD_LINE Tests for FastSense.addLine method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
% testAddSingleLine
- fp = FastPlot();
+ fp = FastSense();
x = 1:100;
y = rand(1, 100);
fp.addLine(x, y);
@@ -13,30 +13,30 @@ function test_add_line()
assert(isequal(fp.Lines(1).Y, y), 'testAddSingleLine: Y mismatch');
% testAddMultipleLines
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:20, rand(1,20));
fp.addLine(1:5, rand(1,5));
assert(numel(fp.Lines) == 3, 'testAddMultipleLines: expected 3 lines');
% testLineOptions
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', 'r', 'DisplayName', 'S1');
assert(strcmp(fp.Lines(1).Options.Color, 'r'), 'testLineOptions: Color');
assert(strcmp(fp.Lines(1).Options.DisplayName, 'S1'), 'testLineOptions: DisplayName');
% testDownsampleMethodDefault
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
assert(strcmp(fp.Lines(1).DownsampleMethod, 'minmax'), 'testDownsampleMethodDefault');
% testDownsampleMethodOverride
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'DownsampleMethod', 'lttb');
assert(strcmp(fp.Lines(1).DownsampleMethod, 'lttb'), 'testDownsampleMethodOverride');
% testRejectsNonMonotonicX
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addLine([1 3 2 4], rand(1,4));
@@ -47,7 +47,7 @@ function test_add_line()
assert(threw, 'testRejectsNonMonotonicX: should have thrown');
% testRejectsMismatchedLengths
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addLine(1:10, rand(1,5));
@@ -58,7 +58,7 @@ function test_add_line()
assert(threw, 'testRejectsMismatchedLengths: should have thrown');
% testColumnVectorsAccepted
- fp = FastPlot();
+ fp = FastSense();
fp.addLine((1:10)', rand(10,1));
assert(numel(fp.Lines(1).X) == 10, 'testColumnVectors: numel');
assert(isrow(fp.Lines(1).X), 'testColumnVectors: must be row');
diff --git a/tests/test_add_marker.m b/tests/test_add_marker.m
index 9a7d0304..03f0abc7 100644
--- a/tests/test_add_marker.m
+++ b/tests/test_add_marker.m
@@ -1,35 +1,35 @@
function test_add_marker()
-%TEST_ADD_MARKER Tests for FastPlot.addMarker method.
+%TEST_ADD_MARKER Tests for FastSense.addMarker method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testAddMarker
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([10 20 30], [1 2 3], 'Marker', 'v', 'Color', [1 0 0], 'Label', 'Faults');
assert(numel(fp.Markers) == 1, 'testAddMarker: count');
assert(isequal(fp.Markers(1).X, [10 20 30]), 'testAddMarker: X');
assert(strcmp(fp.Markers(1).Label, 'Faults'), 'testAddMarker: Label');
% testMarkerRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addMarker([10 50], [0.5 0.8], 'Marker', 'd', 'MarkerSize', 10);
fp.render();
assert(~isempty(fp.Markers(1).hLine), 'testMarkerRendered: hLine');
assert(ishandle(fp.Markers(1).hLine), 'testMarkerRendered: valid handle');
ud = get(fp.Markers(1).hLine, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'marker'), 'testMarkerRendered: UserData type');
+ assert(strcmp(ud.FastSense.Type, 'marker'), 'testMarkerRendered: UserData type');
close(fp.hFigure);
% testMarkerDefaults
- fp = FastPlot();
+ fp = FastSense();
fp.addMarker([5], [1]);
assert(~isempty(fp.Markers(1).Marker), 'testMarkerDefaults: Marker shape');
assert(fp.Markers(1).MarkerSize > 0, 'testMarkerDefaults: MarkerSize');
% testMarkerRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
threw = false;
diff --git a/tests/test_add_sensor.m b/tests/test_add_sensor.m
index deb5ab9a..4fbd042a 100644
--- a/tests/test_add_sensor.m
+++ b/tests/test_add_sensor.m
@@ -1,5 +1,5 @@
function test_add_sensor()
-%TEST_ADD_SENSOR Tests for FastPlot.addSensor() integration.
+%TEST_ADD_SENSOR Tests for FastSense.addSensor() integration.
add_sensor_path();
@@ -9,7 +9,7 @@ function test_add_sensor()
s.Y = rand(1, 100) * 10;
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s);
assert(numel(fp.Lines) == 1, 'testBasic: one line added');
assert(strcmp(fp.Lines(1).Options.DisplayName, 'Chamber Pressure'), 'testBasic: display name');
@@ -25,7 +25,7 @@ function test_add_sensor()
s.addThresholdRule(struct('machine', 1), 10, 'Direction', 'upper', 'Label', 'HH');
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', true);
assert(numel(fp.Lines) == 1, 'testWithThresholds: only data line');
assert(numel(fp.Thresholds) >= 1, 'testWithThresholds: threshold(s) added');
@@ -39,7 +39,7 @@ function test_add_sensor()
s.addThresholdRule(struct(), 5, 'Direction', 'upper');
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s, 'ShowThresholds', false);
assert(numel(fp.Lines) == 1, 'testNoThresholds: only data line');
assert(numel(fp.Thresholds) == 0, 'testNoThresholds: no thresholds');
@@ -50,7 +50,7 @@ function test_add_sensor()
s.Y = rand(1, 10);
s.resolve();
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s);
assert(strcmp(fp.Lines(1).Options.DisplayName, 'flow_rate'), 'testFallbackName: uses Key');
diff --git a/tests/test_add_shaded.m b/tests/test_add_shaded.m
index 3c1add5d..7e1211d0 100644
--- a/tests/test_add_shaded.m
+++ b/tests/test_add_shaded.m
@@ -1,14 +1,14 @@
function test_add_shaded()
-%TEST_ADD_SHADED Tests for FastPlot.addShaded method.
+%TEST_ADD_SHADED Tests for FastSense.addShaded method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testAddShaded
x = 1:100;
y1 = ones(1,100) * 2;
y2 = ones(1,100) * -2;
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded(x, y1, y2, 'FaceColor', [0 0 1], 'FaceAlpha', 0.2);
assert(numel(fp.Shadings) == 1, 'testAddShaded: count');
assert(isequal(fp.Shadings(1).X, x), 'testAddShaded: X');
@@ -16,18 +16,18 @@ function test_add_shaded()
assert(isequal(fp.Shadings(1).Y2, y2), 'testAddShaded: Y2');
% testShadedRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addShaded(1:100, ones(1,100), zeros(1,100), 'FaceColor', [1 0 0]);
fp.render();
assert(~isempty(fp.Shadings(1).hPatch), 'testShadedRendered: hPatch');
assert(ishandle(fp.Shadings(1).hPatch), 'testShadedRendered: valid');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'shaded'), 'testShadedRendered: type');
+ assert(strcmp(ud.FastSense.Type, 'shaded'), 'testShadedRendered: type');
close(fp.hFigure);
% testShadedValidation
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded(1:10, 1:10, 1:5); % mismatched lengths
@@ -37,7 +37,7 @@ function test_add_shaded()
assert(threw, 'testShadedValidation: length mismatch');
% testShadedMonotonicX
- fp = FastPlot();
+ fp = FastSense();
threw = false;
try
fp.addShaded([3 1 2], [1 1 1], [0 0 0]);
@@ -47,7 +47,7 @@ function test_add_shaded()
assert(threw, 'testShadedMonotonicX');
% testShadedRejectsAfterRender
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
threw = false;
@@ -60,14 +60,14 @@ function test_add_shaded()
close(fp.hFigure);
% testShadedColumnVectors
- fp = FastPlot();
+ fp = FastSense();
fp.addShaded((1:10)', (1:10)', zeros(10,1));
assert(isrow(fp.Shadings(1).X), 'testShadedColumnVectors: X row');
assert(isrow(fp.Shadings(1).Y1), 'testShadedColumnVectors: Y1 row');
assert(isrow(fp.Shadings(1).Y2), 'testShadedColumnVectors: Y2 row');
% testAddFill
- fp = FastPlot();
+ fp = FastSense();
x = 1:50;
y = rand(1,50);
fp.addFill(x, y, 'FaceColor', [0 0.5 1], 'FaceAlpha', 0.2);
@@ -75,18 +75,18 @@ function test_add_shaded()
assert(all(fp.Shadings(1).Y2 == 0), 'testAddFill: baseline is 0');
% testAddFillCustomBaseline
- fp = FastPlot();
+ fp = FastSense();
fp.addFill(1:10, rand(1,10), 'Baseline', -1);
assert(all(fp.Shadings(1).Y2 == -1), 'testAddFillCustomBaseline');
% testAddFillRendered
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addFill(1:100, rand(1,100), 'FaceColor', [0 1 0]);
fp.render();
assert(ishandle(fp.Shadings(1).hPatch), 'testAddFillRendered: valid patch');
ud = get(fp.Shadings(1).hPatch, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'shaded'), 'testAddFillRendered: type is shaded');
+ assert(strcmp(ud.FastSense.Type, 'shaded'), 'testAddFillRendered: type is shaded');
close(fp.hFigure);
fprintf(' All 9 addShaded/addFill tests passed.\n');
diff --git a/tests/test_add_threshold.m b/tests/test_add_threshold.m
index fb617eef..28100b4c 100644
--- a/tests/test_add_threshold.m
+++ b/tests/test_add_threshold.m
@@ -1,22 +1,22 @@
function test_add_threshold()
-%TEST_ADD_THRESHOLD Tests for FastPlot.addThreshold method.
+%TEST_ADD_THRESHOLD Tests for FastSense.addThreshold method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
% testAddUpperThreshold
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5, 'Direction', 'upper');
assert(numel(fp.Thresholds) == 1, 'testAddUpperThreshold: count');
assert(fp.Thresholds(1).Value == 4.5, 'testAddUpperThreshold: value');
assert(strcmp(fp.Thresholds(1).Direction, 'upper'), 'testAddUpperThreshold: direction');
% testAddLowerThreshold
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(-2.0, 'Direction', 'lower');
assert(strcmp(fp.Thresholds(1).Direction, 'lower'), 'testAddLowerThreshold');
% testDefaults
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(5.0);
assert(strcmp(fp.Thresholds(1).Direction, 'upper'), 'testDefaults: direction');
assert(fp.Thresholds(1).ShowViolations == false, 'testDefaults: ShowViolations');
@@ -24,7 +24,7 @@ function test_add_threshold()
assert(strcmp(fp.Thresholds(1).Label, ''), 'testDefaults: Label');
% testCustomOptions
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(3.0, 'Direction', 'lower', ...
'ShowViolations', true, 'Color', [1 0 0], ...
'LineStyle', ':', 'Label', 'LowerBound');
@@ -35,14 +35,14 @@ function test_add_threshold()
assert(strcmp(t.Label, 'LowerBound'), 'testCustomOptions: Label');
% testMultipleThresholds
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(1.0);
fp.addThreshold(2.0);
fp.addThreshold(3.0);
assert(numel(fp.Thresholds) == 3, 'testMultipleThresholds');
% testTimeVaryingThreshold
- fp = FastPlot();
+ fp = FastSense();
thX = [0 10 20 30];
thY = [5.0 5.0 7.0 7.0];
fp.addThreshold(thX, thY, 'Direction', 'upper', 'ShowViolations', true, 'Label', 'StepTh');
@@ -54,7 +54,7 @@ function test_add_threshold()
assert(fp.Thresholds(1).ShowViolations == true, 'testTimeVarying: ShowViolations');
% testMixedThresholds — scalar and time-varying coexist
- fp = FastPlot();
+ fp = FastSense();
fp.addThreshold(4.5);
fp.addThreshold([0 10], [3.0 5.0], 'Direction', 'lower');
assert(numel(fp.Thresholds) == 2, 'testMixed: count');
diff --git a/tests/test_binary_search.m b/tests/test_binary_search.m
index 13b04e72..c9666219 100644
--- a/tests/test_binary_search.m
+++ b/tests/test_binary_search.m
@@ -1,9 +1,9 @@
function test_binary_search()
%TEST_BINARY_SEARCH Tests for binary_search private function.
- % We need access to the private function via the FastPlot directory
+ % We need access to the private function via the FastSense directory
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
x = [1 3 5 7 9];
diff --git a/tests/test_compute_violations.m b/tests/test_compute_violations.m
index efcf7c75..b661424c 100644
--- a/tests/test_compute_violations.m
+++ b/tests/test_compute_violations.m
@@ -2,7 +2,7 @@ function test_compute_violations()
%TEST_COMPUTE_VIOLATIONS Tests for compute_violations private function.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testUpperViolation
x = 1:10;
diff --git a/tests/test_compute_violations_dynamic.m b/tests/test_compute_violations_dynamic.m
index 8bc99aed..f4057a50 100644
--- a/tests/test_compute_violations_dynamic.m
+++ b/tests/test_compute_violations_dynamic.m
@@ -2,7 +2,7 @@ function test_compute_violations_dynamic()
%TEST_COMPUTE_VIOLATIONS_DYNAMIC Tests for time-varying threshold violations.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testUpperStepFunction: threshold steps from 5 to 8 at x=10
thX = [0 10 20];
diff --git a/tests/test_dashboard_builder_interaction.m b/tests/test_dashboard_builder_interaction.m
index 20317ed3..d4516212 100644
--- a/tests/test_dashboard_builder_interaction.m
+++ b/tests/test_dashboard_builder_interaction.m
@@ -436,7 +436,7 @@ function testPaletteButtonsAddWidgets()
sprintf('testPaletteButtonsAddWidgets: only %d buttons', numel(btns)));
initialCount = numel(engine.Widgets);
- % Use the KPI button (2nd from last) to avoid FastPlot requiring a line
+ % Use the KPI button (2nd from last) to avoid FastSense requiring a line
cb = get(btns(end-1), 'Callback');
cb(btns(end-1), []);
diff --git a/tests/test_datastore.m b/tests/test_datastore.m
index 612a5d0a..7a8cf6c0 100644
--- a/tests/test_datastore.m
+++ b/tests/test_datastore.m
@@ -1,6 +1,6 @@
function test_datastore()
-%TEST_DATASTORE Unit tests for FastPlotDataStore class.
-% Tests the SQLite/binary-backed data storage used by FastPlot to handle
+%TEST_DATASTORE Unit tests for FastSenseDataStore class.
+% Tests the SQLite/binary-backed data storage used by FastSense to handle
% large datasets without running out of memory. Covers creation, range
% queries, slice reads, edge cases, and cleanup.
@@ -11,7 +11,7 @@ function test_datastore()
% testCreateStore: basic construction stores metadata correctly
x = linspace(0, 100, 10000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
assert(ds.NumPoints == 10000, 'testCreateStore: NumPoints');
assert(ds.XMin == x(1), 'testCreateStore: XMin');
assert(ds.XMax == x(end), 'testCreateStore: XMax');
@@ -20,18 +20,18 @@ function test_datastore()
% testCreateStoreWithNaN: detects NaN in Y data
y2 = y; y2(500) = NaN;
- ds = FastPlotDataStore(x, y2);
+ ds = FastSenseDataStore(x, y2);
assert(ds.HasNaN == true, 'testCreateStoreWithNaN: HasNaN should be true');
ds.cleanup();
% testEmptyConstruction: empty construction returns valid zero-state
- ds = FastPlotDataStore();
+ ds = FastSenseDataStore();
assert(ds.NumPoints == 0, 'testEmptyConstruction: NumPoints');
assert(isnan(ds.XMin), 'testEmptyConstruction: XMin should be NaN');
ds.cleanup();
% testColumnVectorInput: accepts column vectors
- ds = FastPlotDataStore((1:100)', rand(100,1));
+ ds = FastSenseDataStore((1:100)', rand(100,1));
assert(ds.NumPoints == 100, 'testColumnVectorInput: NumPoints');
ds.cleanup();
@@ -40,7 +40,7 @@ function test_datastore()
% testGetRangeMiddle: query a middle range returns correct data
x = linspace(0, 100, 50000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, yr] = ds.getRange(20, 40);
assert(~isempty(xr), 'testGetRangeMiddle: should return data');
% All interior points must be within range (edges may have 1-pt padding)
@@ -54,7 +54,7 @@ function test_datastore()
% testGetRangeFullSpan: range covering entire dataset returns all points
x = 1:1000;
y = rand(1, 1000);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, yr] = ds.getRange(1, 1000);
assert(numel(xr) == 1000, 'testGetRangeFullSpan: should get all points');
assert(isequal(xr, x), 'testGetRangeFullSpan: X data must match');
@@ -66,7 +66,7 @@ function test_datastore()
n = 200000;
x = linspace(0, 1000, n);
y = cumsum(randn(1, n));
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, yr] = ds.getRange(500, 501);
% Should get a reasonable number of points (not all 200K)
assert(numel(xr) > 10, 'testGetRangeSmall: too few points');
@@ -79,7 +79,7 @@ function test_datastore()
% testGetRangeOutside: range outside data returns empty or edge points
x = 1:100;
y = rand(1, 100);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, ~] = ds.getRange(200, 300);
% Should either be empty or contain only the last data point
assert(numel(xr) <= 1, 'testGetRangeOutside: should be empty or single edge');
@@ -90,7 +90,7 @@ function test_datastore()
% testReadSliceExact: reading a specific index range returns correct data
x = 1:5000;
y = (1:5000) * 2;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xs, ys] = ds.readSlice(100, 200);
assert(numel(xs) == 101, 'testReadSliceExact: count');
assert(xs(1) == 100, 'testReadSliceExact: first X');
@@ -102,7 +102,7 @@ function test_datastore()
% testReadSliceFullRange: reading entire range matches original data
x = linspace(0, 10, 1000);
y = cos(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xs, ys] = ds.readSlice(1, 1000);
tol = 1e-12;
assert(max(abs(xs - x)) < tol, 'testReadSliceFullRange: X mismatch');
@@ -110,7 +110,7 @@ function test_datastore()
ds.cleanup();
% testReadSliceClamped: out-of-bounds indices are clamped
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
[xs, ~] = ds.readSlice(-5, 200);
assert(numel(xs) == 100, 'testReadSliceClamped: should clamp to full range');
assert(xs(1) == 1, 'testReadSliceClamped: start clamped');
@@ -124,7 +124,7 @@ function test_datastore()
n = 150000;
x = sort(rand(1, n)) * 1000;
y = randn(1, n);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xAll, yAll] = ds.readSlice(1, n);
tol = 1e-12;
assert(max(abs(xAll - x)) < tol, 'testDataIntegrity: X drift');
@@ -135,7 +135,7 @@ function test_datastore()
x = 1:100;
y = rand(1, 100);
y([10, 50, 90]) = NaN;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[~, yr] = ds.readSlice(1, 100);
assert(isnan(yr(10)), 'testDataIntegrityNaN: NaN at 10');
assert(isnan(yr(50)), 'testDataIntegrityNaN: NaN at 50');
@@ -145,7 +145,7 @@ function test_datastore()
% --- Range query returns row vectors ---
% testOutputShape: getRange and readSlice return row vectors
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
[xr, yr] = ds.getRange(100, 200);
assert(isrow(xr), 'testOutputShape: getRange X must be row');
assert(isrow(yr), 'testOutputShape: getRange Y must be row');
@@ -157,7 +157,7 @@ function test_datastore()
% --- Cleanup ---
% testCleanupDeletesFile: cleanup removes temp files from disk
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
% Store the path(s) before cleanup
hasDb = ~isempty(ds.DbPath) && exist(ds.DbPath, 'file');
hasBin = ~isempty(ds.BinPath) && exist(ds.BinPath, 'file');
@@ -171,7 +171,7 @@ function test_datastore()
assert(~exist(fpath, 'file'), 'testCleanupDeletesFile: file should be gone');
% testDestructorCleanup: deleting the object cleans up temp files
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
if ~isempty(ds.DbPath) && exist(ds.DbPath, 'file')
fpath = ds.DbPath;
else
@@ -186,7 +186,7 @@ function test_datastore()
n = 500000;
x = linspace(0, 10000, n);
y = sin(x / 100) + randn(1, n) * 0.1;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
assert(ds.NumPoints == n, 'testLargeDataset: NumPoints');
% Query a narrow range — should be fast and return correct subset
diff --git a/tests/test_datastore_edge_cases.m b/tests/test_datastore_edge_cases.m
index f48f5397..56d16db7 100644
--- a/tests/test_datastore_edge_cases.m
+++ b/tests/test_datastore_edge_cases.m
@@ -3,7 +3,7 @@ function test_datastore_edge_cases()
fprintf(' SKIPPED (known Octave classdef limitation)\n');
return;
end
-%TEST_DATASTORE_EDGE_CASES Edge-case and stress tests for FastPlotDataStore.
+%TEST_DATASTORE_EDGE_CASES Edge-case and stress tests for FastSenseDataStore.
% Covers: boundary conditions, special values (Inf, NaN), single-point
% datasets, repeated X values, multi-chunk queries, and binary fallback.
@@ -12,7 +12,7 @@ function test_datastore_edge_cases()
fprintf(' --- DataStore edge cases ---\n');
% 1. Single-point dataset
- ds = FastPlotDataStore(5, 10);
+ ds = FastSenseDataStore(5, 10);
assert(ds.NumPoints == 1, 'singlePoint: NumPoints');
assert(ds.XMin == 5, 'singlePoint: XMin');
assert(ds.XMax == 5, 'singlePoint: XMax');
@@ -25,7 +25,7 @@ function test_datastore_edge_cases()
fprintf(' single-point dataset: PASS\n');
% 2. Two-point dataset
- ds = FastPlotDataStore([1, 100], [10, 20]);
+ ds = FastSenseDataStore([1, 100], [10, 20]);
[xr, yr] = ds.getRange(1, 100);
assert(numel(xr) == 2, 'twoPoint: getRange count');
assert(xr(1) == 1 && xr(2) == 100, 'twoPoint: getRange X');
@@ -36,7 +36,7 @@ function test_datastore_edge_cases()
x = 1:100;
y = rand(1, 100);
y(25) = Inf; y(75) = -Inf;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[~, yr] = ds.readSlice(1, 100);
assert(isinf(yr(25)) && yr(25) > 0, 'infValues: +Inf preserved');
assert(isinf(yr(75)) && yr(75) < 0, 'infValues: -Inf preserved');
@@ -46,7 +46,7 @@ function test_datastore_edge_cases()
% 4. All-NaN Y data
x = 1:50;
y = nan(1, 50);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
assert(ds.HasNaN == true, 'allNaN: HasNaN');
[~, yr] = ds.readSlice(1, 50);
assert(all(isnan(yr)), 'allNaN: all values NaN');
@@ -56,7 +56,7 @@ function test_datastore_edge_cases()
% 5. Constant X (degenerate — all same timestamp)
x = ones(1, 100) * 42;
y = rand(1, 100);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
assert(ds.XMin == 42 && ds.XMax == 42, 'constantX: XMin==XMax');
[xr, yr] = ds.getRange(41, 43);
assert(numel(xr) == 100, 'constantX: getRange returns all');
@@ -66,14 +66,14 @@ function test_datastore_edge_cases()
% 6. Repeated X values (duplicates)
x = sort(repmat(1:50, 1, 3)); % [1 1 1 2 2 2 ... 50 50 50]
y = rand(1, 150);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, ~] = ds.getRange(10, 20);
assert(all(xr >= 9 & xr <= 21), 'duplicateX: range respected');
ds.cleanup();
fprintf(' repeated X values: PASS\n');
% 7. getRange with inverted range (xMin > xMax)
- ds = FastPlotDataStore(1:1000, rand(1, 1000));
+ ds = FastSenseDataStore(1:1000, rand(1, 1000));
[xr, ~] = ds.getRange(500, 100);
assert(isempty(xr), 'invertedRange: should return empty');
ds.cleanup();
@@ -82,7 +82,7 @@ function test_datastore_edge_cases()
% 8. getRange at exact data boundaries
x = linspace(0, 100, 10000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, ~] = ds.getRange(0, 0); % exact start
assert(numel(xr) >= 1, 'exactBoundary: at start');
[xr, ~] = ds.getRange(100, 100); % exact end
@@ -91,7 +91,7 @@ function test_datastore_edge_cases()
fprintf(' exact boundary queries: PASS\n');
% 9. readSlice with startIdx == endIdx (single point)
- ds = FastPlotDataStore(1:1000, (1:1000)*3);
+ ds = FastSenseDataStore(1:1000, (1:1000)*3);
[xs, ys] = ds.readSlice(500, 500);
assert(numel(xs) == 1, 'singleSlice: count');
assert(xs == 500 && ys == 1500, 'singleSlice: values');
@@ -102,7 +102,7 @@ function test_datastore_edge_cases()
n = 5000;
x = 1:n;
y = x * 2;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xs, ys] = ds.readSlice(n-2, n);
assert(numel(xs) == 3, 'endSlice: count');
assert(xs(end) == n, 'endSlice: last X');
@@ -111,7 +111,7 @@ function test_datastore_edge_cases()
fprintf(' end-of-data slice: PASS\n');
% 11. readSlice at very start of dataset
- ds = FastPlotDataStore(1:5000, (1:5000)*2);
+ ds = FastSenseDataStore(1:5000, (1:5000)*2);
[xs, ys] = ds.readSlice(1, 3);
assert(numel(xs) == 3, 'startSlice: count');
assert(xs(1) == 1 && ys(1) == 2, 'startSlice: first values');
@@ -121,7 +121,7 @@ function test_datastore_edge_cases()
% 12. Multiple getRange calls on same DataStore (caching/state)
x = linspace(0, 100, 50000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr1, ~] = ds.getRange(10, 20);
[xr2, ~] = ds.getRange(50, 60);
[xr3, ~] = ds.getRange(10, 20); % repeat first query
@@ -133,7 +133,7 @@ function test_datastore_edge_cases()
% 13. Large number of small getRange calls (stress)
x = linspace(0, 1000, 100000);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
tic;
for i = 1:100
xStart = rand * 900;
@@ -145,13 +145,13 @@ function test_datastore_edge_cases()
fprintf(' 100 random range queries: PASS (%.2fs)\n', elapsed);
% 14. cleanup is idempotent (calling twice doesn't error)
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
ds.cleanup();
ds.cleanup(); % should not throw
fprintf(' idempotent cleanup: PASS\n');
% 15. Operations after cleanup — storage file is gone
- ds = FastPlotDataStore(1:100, rand(1, 100));
+ ds = FastSenseDataStore(1:100, rand(1, 100));
if ~isempty(ds.DbPath); fpath = ds.DbPath; else; fpath = ds.BinPath; end
ds.cleanup();
assert(~exist(fpath, 'file'), 'afterCleanup: file should be gone');
@@ -160,7 +160,7 @@ function test_datastore_edge_cases()
% 16. Very large Y values (1e300)
x = 1:100;
y = ones(1, 100) * 1e300;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[~, yr] = ds.readSlice(1, 100);
assert(all(yr == 1e300), 'largeValues: preserved');
ds.cleanup();
@@ -168,7 +168,7 @@ function test_datastore_edge_cases()
% 17. Very small Y values (1e-300)
y = ones(1, 100) * 1e-300;
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[~, yr] = ds.readSlice(1, 100);
assert(all(abs(yr - 1e-300) < 1e-312), 'smallValues: preserved');
ds.cleanup();
@@ -177,7 +177,7 @@ function test_datastore_edge_cases()
% 18. Negative X values (descending not required but negative ok)
x = linspace(-100, -1, 500);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
assert(ds.XMin == -100 && ds.XMax == -1, 'negativeX: range');
[xr, ~] = ds.getRange(-60, -40);
assert(all(xr >= -61 & xr <= -39), 'negativeX: range query');
@@ -189,7 +189,7 @@ function test_datastore_edge_cases()
n = 200000;
x = linspace(0, 1000, n);
y = x .* 3; % simple linear for verification
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
% Query range that spans chunk boundaries
[xr, yr] = ds.getRange(400, 600);
% Verify Y = 3*X relationship holds across chunks
@@ -202,7 +202,7 @@ function test_datastore_edge_cases()
n = 100000;
x = linspace(0, 1000, n);
y = randn(1, n);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
[xr, ~] = ds.getRange(200, 800);
assert(all(diff(xr) >= 0), 'monotonicity: X must be non-decreasing');
ds.cleanup();
diff --git a/tests/test_datetime.m b/tests/test_datetime.m
index 63a4f7ec..7b119539 100644
--- a/tests/test_datetime.m
+++ b/tests/test_datetime.m
@@ -2,18 +2,18 @@ function test_datetime()
%TEST_DATETIME Tests for datetime X axis support.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
close all force;
drawnow;
% testXTypeDefaultIsNumeric
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
assert(strcmp(fp.XType, 'numeric'), 'testXTypeDefault: should be numeric');
% testXTypeDatenum
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24;
fp.addLine(x, rand(1,100), 'XType', 'datenum');
assert(strcmp(fp.XType, 'datenum'), 'testXTypeDatenum: should be datenum');
@@ -21,7 +21,7 @@ function test_datetime()
% testDatetimeAutoConvert
% Only run in MATLAB where datetime exists
if exist('datetime', 'class')
- fp = FastPlot();
+ fp = FastSense();
dt = datetime(2024,1,1) + hours(0:99);
fp.addLine(dt, rand(1,100));
assert(strcmp(fp.XType, 'datenum'), 'testDatetimeAutoConvert: should be datenum');
@@ -29,7 +29,7 @@ function test_datetime()
end
% testTickLabelsAreDateStrings
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:99)/24; % ~4 days of hourly data
fp.addLine(x, rand(1,100), 'XType', 'datenum');
fp.render();
@@ -47,7 +47,7 @@ function test_datetime()
% testTickFormatChangesOnZoom (MATLAB only — Octave lacks PostSet listeners)
if ~exist('OCTAVE_VERSION', 'builtin')
- fp = FastPlot();
+ fp = FastSense();
x = datenum(2024,1,1) + (0:9999)/86400; % ~0.1s resolution
fp.addLine(x, rand(1,10000), 'XType', 'datenum');
fp.render();
@@ -70,9 +70,9 @@ function test_datetime()
% testToolbarFormatX
% Verify the static helper returns date string for datenum XType
xVal = datenum(2024, 3, 15, 10, 30, 45);
- result = FastPlotToolbar.formatX(xVal, 'datenum');
+ result = FastSenseToolbar.formatX(xVal, 'datenum');
assert(any(result == ':'), 'testToolbarFormatX: should contain colon');
- resultNum = FastPlotToolbar.formatX(42.5, 'numeric');
+ resultNum = FastSenseToolbar.formatX(42.5, 'numeric');
assert(~any(resultNum == ':'), 'testToolbarFormatXNum: should not contain colon');
fprintf(' All datetime tests passed.\n');
diff --git a/tests/test_disk_advanced.m b/tests/test_disk_advanced.m
index c029e1f2..8e4b85f5 100644
--- a/tests/test_disk_advanced.m
+++ b/tests/test_disk_advanced.m
@@ -1,10 +1,10 @@
function test_disk_advanced()
-%TEST_DISK_ADVANCED Advanced integration tests for FastPlot disk storage.
+%TEST_DISK_ADVANCED Advanced integration tests for FastSense disk storage.
% Covers: storage mode transitions, multiple disk lines, pyramid building,
% updateData edge cases, re-render after update, and stress scenarios.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
if exist('OCTAVE_VERSION', 'builtin')
fprintf(' SKIPPED: requires MATLAB PostSet listeners.\n');
@@ -14,7 +14,7 @@ function test_disk_advanced()
fprintf(' --- Advanced disk storage tests ---\n');
% 1. Multiple disk lines in same figure
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
for i = 1:5
x = linspace(0, 100, 10000);
y = sin(x + i);
@@ -35,7 +35,7 @@ function test_disk_advanced()
fprintf(' multiple disk lines: PASS\n');
% 2. updateData: memory -> disk transition
- fp = FastPlot('MemoryLimit', 10000);
+ fp = FastSense('MemoryLimit', 10000);
fp.addLine(1:50, rand(1, 50)); % memory (800 bytes < 10000)
fp.render();
assert(isempty(fp.Lines(1).DataStore), 'memToDisk: starts in memory');
@@ -47,7 +47,7 @@ function test_disk_advanced()
fprintf(' memory -> disk transition: PASS\n');
% 3. updateData: disk -> memory transition
- fp = FastPlot('MemoryLimit', 10000);
+ fp = FastSense('MemoryLimit', 10000);
fp.addLine(linspace(0, 100, 5000), rand(1, 5000)); % disk
fp.render();
assert(~isempty(fp.Lines(1).DataStore), 'diskToMem: starts on disk');
@@ -68,7 +68,7 @@ function test_disk_advanced()
fprintf(' disk -> memory transition: PASS\n');
% 4. updateData preserves old DataStore cleanup
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
fp.render();
ds1 = fp.Lines(1).DataStore;
@@ -83,7 +83,7 @@ function test_disk_advanced()
fprintf(' updateData cleans old DataStore: PASS\n');
% 5. Render, update, re-render cycle
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 20000);
fp.addLine(x, sin(x));
fp.render();
@@ -98,7 +98,7 @@ function test_disk_advanced()
fprintf(' render-update-rerender cycle: PASS\n');
% 6. Zoom to very narrow range on disk line
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 100000;
x = linspace(0, 1000, n);
y = sin(x);
@@ -113,7 +113,7 @@ function test_disk_advanced()
fprintf(' very narrow zoom on disk: PASS\n');
% 7. Zoom out to full range after narrow zoom
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
@@ -133,7 +133,7 @@ function test_disk_advanced()
fprintf(' zoom in then out: PASS\n');
% 8. Mixed memory+disk lines render with correct data
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
x1 = 1:50; y1 = x1 * 2; % memory
x2 = linspace(0, 100, 5000); y2 = x2 * 3; % disk
fp.addLine(x1, y1, 'DisplayName', 'Mem');
@@ -151,7 +151,7 @@ function test_disk_advanced()
fprintf(' mixed mem+disk data fidelity: PASS\n');
% 9. Delete with multiple disk lines cleans all files
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
paths = {};
for i = 1:3
fp.addLine(1:5000, rand(1, 5000));
@@ -166,7 +166,7 @@ function test_disk_advanced()
fprintf(' delete cleans all disk files: PASS\n');
% 10. Disk line with NaN values renders without error
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 10000;
x = linspace(0, 100, n);
y = sin(x);
@@ -178,7 +178,7 @@ function test_disk_advanced()
fprintf(' disk line with NaN gap: PASS\n');
% 11. Threshold violations with disk line + NaN
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 10000);
y = sin(x); y(500:600) = NaN;
fp.addLine(x, y);
@@ -189,7 +189,7 @@ function test_disk_advanced()
fprintf(' threshold on disk+NaN line: PASS\n');
% 12. Threshold with lower direction on disk line
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 10000);
y = sin(x);
fp.addLine(x, y);
@@ -200,7 +200,7 @@ function test_disk_advanced()
fprintf(' lower threshold on disk line: PASS\n');
% 13. Multiple thresholds on disk line
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 100, 20000);
y = sin(x);
fp.addLine(x, y);
@@ -213,7 +213,7 @@ function test_disk_advanced()
fprintf(' multiple thresholds on disk: PASS\n');
% 14. MemoryLimit boundary: exactly at threshold
- fp = FastPlot('MemoryLimit', 1600); % 100 points * 8 * 2 = 1600
+ fp = FastSense('MemoryLimit', 1600); % 100 points * 8 * 2 = 1600
fp.addLine(1:100, rand(1, 100));
% 1600 bytes == 1600 limit → not strictly greater, stays in memory
assert(isempty(fp.Lines(1).DataStore), 'boundary: at limit stays memory');
@@ -223,7 +223,7 @@ function test_disk_advanced()
fprintf(' MemoryLimit exact boundary: PASS\n');
% 15. Rapid sequential updateData calls
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
fp.render();
for i = 1:10
diff --git a/tests/test_disk_storage.m b/tests/test_disk_storage.m
index 10560cf3..0ebd2cd6 100644
--- a/tests/test_disk_storage.m
+++ b/tests/test_disk_storage.m
@@ -1,11 +1,11 @@
function test_disk_storage()
-%TEST_DISK_STORAGE Integration tests for FastPlot disk-backed storage.
-% Tests that FastPlot correctly stores large datasets on disk via
-% FastPlotDataStore and that render, zoom/pan, updateData, and cleanup
+%TEST_DISK_STORAGE Integration tests for FastSense disk-backed storage.
+% Tests that FastSense correctly stores large datasets on disk via
+% FastSenseDataStore and that render, zoom/pan, updateData, and cleanup
% all work transparently with disk-backed lines.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
if exist('OCTAVE_VERSION', 'builtin')
fprintf(' SKIPPED: requires MATLAB PostSet listeners.\n');
@@ -15,27 +15,27 @@ function test_disk_storage()
% --- StorageMode and MemoryLimit properties ---
% testDefaultStorageMode: default is 'auto'
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
assert(strcmp(fp.StorageMode, 'auto'), 'testDefaultStorageMode');
% testStorageModeConstructor: can set via constructor
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
assert(strcmp(fp.StorageMode, 'disk'), 'testStorageModeConstructor');
% testMemoryLimitDefault: default is 500e6
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
assert(fp.MemoryLimit == 500e6, 'testMemoryLimitDefault');
% testMemoryLimitConstructor: can override via constructor
- fp = FastPlot('MemoryLimit', 100e6);
+ fp = FastSense('MemoryLimit', 100e6);
assert(fp.MemoryLimit == 100e6, 'testMemoryLimitConstructor');
% --- Auto storage mode triggers disk for large data ---
% testAutoModeDiskTrigger: data exceeding MemoryLimit goes to disk
- fp = FastPlot('MemoryLimit', 1000); % very low threshold: 1000 bytes
+ fp = FastSense('MemoryLimit', 1000); % very low threshold: 1000 bytes
n = 1000; % 1000 points * 8 bytes * 2 = 16000 bytes > 1000
x = linspace(0, 10, n);
y = sin(x);
@@ -50,7 +50,7 @@ function test_disk_storage()
'testAutoModeDiskTrigger: NumPoints must be correct');
% testAutoModeMemoryForSmall: small data stays in memory
- fp = FastPlot('MemoryLimit', 1e9); % 1 GB threshold
+ fp = FastSense('MemoryLimit', 1e9); % 1 GB threshold
fp.addLine(1:100, rand(1, 100));
assert(isempty(fp.Lines(1).DataStore), ...
'testAutoModeMemoryForSmall: should NOT have DataStore');
@@ -58,7 +58,7 @@ function test_disk_storage()
'testAutoModeMemoryForSmall: X should be in memory');
% testForceDiskMode: StorageMode='disk' forces all data to disk
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:50, rand(1, 50));
assert(~isempty(fp.Lines(1).DataStore), ...
'testForceDiskMode: small data should still go to disk');
@@ -66,7 +66,7 @@ function test_disk_storage()
'testForceDiskMode: NumPoints');
% testForceMemoryMode: StorageMode='memory' keeps all data in RAM
- fp = FastPlot('StorageMode', 'memory', 'MemoryLimit', 100);
+ fp = FastSense('StorageMode', 'memory', 'MemoryLimit', 100);
fp.addLine(1:10000, rand(1, 10000));
assert(isempty(fp.Lines(1).DataStore), ...
'testForceMemoryMode: should NOT use disk even if above limit');
@@ -74,7 +74,7 @@ function test_disk_storage()
% --- Render with disk-backed data ---
% testRenderDiskLine: disk-backed line renders without error
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 20000;
x = linspace(0, 100, n);
y = sin(x);
@@ -92,7 +92,7 @@ function test_disk_storage()
close(fp.hFigure);
% testRenderMixedLines: mix of memory and disk lines renders
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(1:10, rand(1, 10), 'DisplayName', 'Small'); % memory
fp.addLine(linspace(0,100,5000), rand(1,5000), 'DisplayName', 'Large'); % disk
fp.render();
@@ -104,7 +104,7 @@ function test_disk_storage()
% --- Zoom/pan with disk-backed data ---
% testZoomDiskLine: zooming re-downsamples from disk correctly
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
@@ -124,7 +124,7 @@ function test_disk_storage()
close(fp.hFigure);
% testZoomDiskLineDataFidelity: zoomed data preserves signal shape
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 100000;
x = linspace(0, 100, n);
y = x * 2; % simple linear — easy to verify
@@ -146,7 +146,7 @@ function test_disk_storage()
% --- updateData with disk-backed storage ---
% testUpdateDataDisk: updateData replaces disk-backed data
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
x = linspace(0, 10, 10000);
y = sin(x);
fp.addLine(x, y);
@@ -168,7 +168,7 @@ function test_disk_storage()
% --- Threshold violations with disk-backed data ---
% testThresholdsDiskLine: violations render correctly on disk lines
- fp = FastPlot('StorageMode', 'disk');
+ fp = FastSense('StorageMode', 'disk');
n = 10000;
x = linspace(0, 100, n);
y = sin(x); % values between -1 and 1
@@ -181,8 +181,8 @@ function test_disk_storage()
% --- Cleanup on delete ---
- % testDeleteCleansDiskFiles: deleting FastPlot cleans up DataStore files
- fp = FastPlot('StorageMode', 'disk');
+ % testDeleteCleansDiskFiles: deleting FastSense cleans up DataStore files
+ fp = FastSense('StorageMode', 'disk');
fp.addLine(1:5000, rand(1, 5000));
ds = fp.Lines(1).DataStore;
% Get the file path before deletion
@@ -200,7 +200,7 @@ function test_disk_storage()
% --- lineNumPoints helper ---
% testLineNumPoints: works for both memory and disk lines
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(1:50, rand(1, 50)); % memory
fp.addLine(1:5000, rand(1, 5000)); % disk
assert(fp.lineNumPoints(1) == 50, 'testLineNumPoints: memory line');
@@ -209,7 +209,7 @@ function test_disk_storage()
% --- lineXRange helper ---
% testLineXRange: returns correct endpoints for both storage types
- fp = FastPlot('MemoryLimit', 1000);
+ fp = FastSense('MemoryLimit', 1000);
fp.addLine(5:100, rand(1, 96)); % memory
fp.addLine(linspace(10,200,5000), rand(1,5000)); % disk
[mn1, mx1] = fp.lineXRange(1);
diff --git a/tests/test_downsample_violations.m b/tests/test_downsample_violations.m
index 38832cdf..3b2d00c3 100644
--- a/tests/test_downsample_violations.m
+++ b/tests/test_downsample_violations.m
@@ -2,7 +2,7 @@ function test_downsample_violations()
%TEST_DOWNSAMPLE_VIOLATIONS Tests for violation marker pixel-density culling.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testBasicDownsample: 10 violations in 3 pixel columns -> 3 points
xV = [1.0, 1.1, 1.2, 2.0, 2.1, 2.2, 3.0, 3.1, 3.2, 3.3];
diff --git a/tests/test_event_snapshot.m b/tests/test_event_snapshot.m
index f52775e8..67cc55c4 100644
--- a/tests/test_event_snapshot.m
+++ b/tests/test_event_snapshot.m
@@ -14,7 +14,7 @@ function add_event_path()
addpath(repoRoot);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
diff --git a/tests/test_fastplot_theme.m b/tests/test_fastsense_theme.m
similarity index 83%
rename from tests/test_fastplot_theme.m
rename to tests/test_fastsense_theme.m
index 0dfb7b4b..812a33f7 100644
--- a/tests/test_fastplot_theme.m
+++ b/tests/test_fastsense_theme.m
@@ -1,27 +1,27 @@
-function test_fastplot_theme()
-%TEST_FASTPLOT_THEME Tests for FastPlot theme integration.
+function test_fastsense_theme()
+%TEST_FASTSENSE_THEME Tests for FastSense theme integration.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testThemeConstructorString
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
assert(isstruct(fp.Theme), 'testThemeConstructorString: Theme must be struct');
assert(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testThemeConstructorString: dark bg');
% testThemeConstructorStruct
custom = struct('Background', [0.5 0.5 0.5]);
- fp = FastPlot('Theme', custom);
+ fp = FastSense('Theme', custom);
assert(isequal(fp.Theme.Background, [0.5 0.5 0.5]), 'testThemeConstructorStruct');
assert(isfield(fp.Theme, 'FontSize'), 'testThemeConstructorStruct: inherits defaults');
% testDefaultThemeWhenNoneSpecified
- fp = FastPlot();
+ fp = FastSense();
assert(isstruct(fp.Theme), 'testDefaultTheme: must have theme');
assert(isequal(fp.Theme.Background, [1 1 1]), 'testDefaultTheme: default bg');
% testThemeAppliedOnRender
- fp = FastPlot('Theme', 'dark');
+ fp = FastSense('Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
bgColor = get(fp.hFigure, 'Color');
@@ -31,7 +31,7 @@ function test_fastplot_theme()
close(fp.hFigure);
% testThemeFontApplied
- fp = FastPlot('Theme', 'scientific');
+ fp = FastSense('Theme', 'scientific');
fp.addLine(1:100, rand(1,100));
fp.render();
assert(strcmp(get(fp.hAxes, 'FontName'), 'Times New Roman'), 'testThemeFontApplied');
@@ -40,7 +40,7 @@ function test_fastplot_theme()
% testThemeWithParentAxes
fig = figure('Visible', 'off');
ax = axes('Parent', fig);
- fp = FastPlot('Parent', ax, 'Theme', 'dark');
+ fp = FastSense('Parent', ax, 'Theme', 'dark');
fp.addLine(1:100, rand(1,100));
fp.render();
axColor = get(ax, 'Color');
@@ -48,14 +48,14 @@ function test_fastplot_theme()
close(fig);
% testBackwardCompatNoTheme
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
assert(ishandle(fp.hAxes), 'testBackwardCompatNoTheme');
close(fp.hFigure);
% testAutoColorCycling
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
fp.addLine(1:10, rand(1,10));
@@ -66,7 +66,7 @@ function test_fastplot_theme()
assert(~isequal(c2, c3), 'testAutoColorCycling: colors 2 and 3 differ');
% testExplicitColorSkipsCycle
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10), 'Color', [1 0 0]);
fp.addLine(1:10, rand(1,10));
assert(isequal(fp.Lines(1).Options.Color, [1 0 0]), 'testExplicitColorSkipsCycle: explicit');
@@ -74,13 +74,13 @@ function test_fastplot_theme()
assert(isequal(fp.Lines(2).Options.Color, expected2), 'testExplicitColorSkipsCycle: auto gets first');
% testThresholdUsesThemeDefaults
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0], 'ThresholdStyle', ':'));
fp.addThreshold(5.0);
assert(isequal(fp.Thresholds(1).Color, [0 1 0]), 'testThresholdThemeDefaults: Color');
assert(strcmp(fp.Thresholds(1).LineStyle, ':'), 'testThresholdThemeDefaults: Style');
% testThresholdExplicitOverridesTheme
- fp = FastPlot('Theme', struct('ThresholdColor', [0 1 0]));
+ fp = FastSense('Theme', struct('ThresholdColor', [0 1 0]));
fp.addThreshold(5.0, 'Color', [1 0 0]);
assert(isequal(fp.Thresholds(1).Color, [1 0 0]), 'testThresholdOverride: Color');
diff --git a/tests/test_figure_layout.m b/tests/test_figure_layout.m
index f5a81994..69bb7da7 100644
--- a/tests/test_figure_layout.m
+++ b/tests/test_figure_layout.m
@@ -1,24 +1,24 @@
function test_figure_layout()
-%TEST_FIGURE_LAYOUT Tests for FastPlotGrid layout manager.
+%TEST_FIGURE_LAYOUT Tests for FastSenseGrid layout manager.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testConstruction
- fig = FastPlotGrid(2, 3);
+ fig = FastSenseGrid(2, 3);
assert(isequal(fig.Grid, [2 3]), 'testConstruction: Grid');
assert(~isempty(fig.hFigure), 'testConstruction: hFigure');
assert(ishandle(fig.hFigure), 'testConstruction: hFigure valid');
close(fig.hFigure);
- % testTileReturnsFastPlot
- fig = FastPlotGrid(2, 1);
+ % testTileReturnsFastSense
+ fig = FastSenseGrid(2, 1);
fp = fig.tile(1);
- assert(isa(fp, 'FastPlot'), 'testTileReturnsFastPlot');
+ assert(isa(fp, 'FastSense'), 'testTileReturnsFastSense');
close(fig.hFigure);
% testTileLazy
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fp1a = fig.tile(1);
fp1b = fig.tile(1);
% In Octave, handle == isn't always defined; check axes handle identity
@@ -27,7 +27,7 @@ function test_figure_layout()
close(fig.hFigure);
% testTileCreatesAxes
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fp = fig.tile(1);
fp.addLine(1:100, rand(1,100));
fp.render();
@@ -36,7 +36,7 @@ function test_figure_layout()
close(fig.hFigure);
% testMultipleTiles
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
for i = 1:4
fp = fig.tile(i);
fp.addLine(1:50, rand(1,50));
@@ -49,7 +49,7 @@ function test_figure_layout()
close(fig.hFigure);
% testRenderAllSkipsRendered
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fp1 = fig.tile(1);
fp1.addLine(1:10, rand(1,10));
fp1.render();
@@ -60,7 +60,7 @@ function test_figure_layout()
close(fig.hFigure);
% testOutOfBoundsTileErrors
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
threw = false;
try
fig.tile(5); % only 4 tiles in 2x2
@@ -71,7 +71,7 @@ function test_figure_layout()
close(fig.hFigure);
% testTileSpanning
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
fig.setTileSpan(1, [1 2]); % tile 1 spans both columns
fp1 = fig.tile(1);
fp1.addLine(1:50, rand(1,50));
@@ -82,13 +82,13 @@ function test_figure_layout()
close(fig.hFigure);
% testFigureThemePassedToTiles
- fig = FastPlotGrid(2, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(2, 1, 'Theme', 'dark');
fp = fig.tile(1);
assert(all(fp.Theme.Background < [0.2 0.2 0.2]), 'testFigureThemePassedToTiles');
close(fig.hFigure);
% testTileThemeOverride
- fig = FastPlotGrid(2, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(2, 1, 'Theme', 'dark');
fig.setTileTheme(1, struct('AxesColor', [0.3 0 0]));
fp = fig.tile(1);
assert(isequal(fp.Theme.AxesColor, [0.3 0 0]), 'testTileThemeOverride: AxesColor');
@@ -96,13 +96,13 @@ function test_figure_layout()
close(fig.hFigure);
% testFigureProperties
- fig = FastPlotGrid(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
+ fig = FastSenseGrid(1, 1, 'Name', 'MyDash', 'Position', [50 50 800 600]);
name = get(fig.hFigure, 'Name');
assert(strcmp(name, 'MyDash'), 'testFigureProperties: Name');
close(fig.hFigure);
% testTileLabels
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fp = fig.tile(1);
fp.addLine(1:50, rand(1,50));
fp.render();
@@ -113,21 +113,21 @@ function test_figure_layout()
close(fig.hFigure);
% testAxesReturnsRawAxes
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
ax = fig.axes(1);
assert(ishandle(ax), 'testAxesReturnsRawAxes: valid handle');
assert(strcmp(get(ax, 'Type'), 'axes'), 'testAxesReturnsRawAxes: is axes');
close(fig.hFigure);
% testAxesLazy
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
ax1 = fig.axes(1);
ax2 = fig.axes(1);
assert(isequal(ax1, ax2), 'testAxesLazy: same handle on repeat call');
close(fig.hFigure);
% testTileThenAxesErrors
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fig.tile(1);
threw = false;
try
@@ -139,7 +139,7 @@ function test_figure_layout()
close(fig.hFigure);
% testAxesThenTileErrors
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
fig.axes(1);
threw = false;
try
@@ -151,7 +151,7 @@ function test_figure_layout()
close(fig.hFigure);
% testMixedRenderAll
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
fig.tile(1).addLine(1:50, rand(1,50));
ax2 = fig.axes(2); bar(ax2, [1 2 3], [10 20 15]);
fig.tile(3).addLine(1:50, rand(1,50));
@@ -165,14 +165,14 @@ function test_figure_layout()
close(fig.hFigure);
% testAxesThemeApplied
- fig = FastPlotGrid(1, 1, 'Theme', 'dark');
+ fig = FastSenseGrid(1, 1, 'Theme', 'dark');
ax = fig.axes(1);
bgColor = get(ax, 'Color');
assert(all(bgColor < [0.3 0.3 0.3]), 'testAxesThemeApplied: dark background');
close(fig.hFigure);
% testLabelsOnRawAxes
- fig = FastPlotGrid(2, 1);
+ fig = FastSenseGrid(2, 1);
ax = fig.axes(1);
bar(ax, [1 2 3], [10 20 15]);
fig.setTileTitle(1, 'Bar Chart');
@@ -184,7 +184,7 @@ function test_figure_layout()
close(fig.hFigure);
% testAxesOutOfBounds
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
threw = false;
try
fig.axes(5);
@@ -195,7 +195,7 @@ function test_figure_layout()
close(fig.hFigure);
% testAxesTileSpanning
- fig = FastPlotGrid(2, 2);
+ fig = FastSenseGrid(2, 2);
fig.setTileSpan(1, [1 2]);
ax = fig.axes(1);
pos = get(ax, 'Position');
diff --git a/tests/test_linked_axes.m b/tests/test_linked_axes.m
index b8db6170..2f6e1024 100644
--- a/tests/test_linked_axes.m
+++ b/tests/test_linked_axes.m
@@ -3,7 +3,7 @@ function test_linked_axes()
% Requires PostSet listeners (MATLAB only, skipped on Octave).
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
if exist('OCTAVE_VERSION', 'builtin')
fprintf(' SKIPPED: Octave lacks PostSet listeners for axes properties.\n');
@@ -15,11 +15,11 @@ function test_linked_axes()
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1, 'LinkGroup', 'testgroup');
+ fp1 = FastSense('Parent', ax1, 'LinkGroup', 'testgroup');
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2, 'LinkGroup', 'testgroup');
+ fp2 = FastSense('Parent', ax2, 'LinkGroup', 'testgroup');
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
@@ -40,11 +40,11 @@ function test_linked_axes()
ax1 = subplot(2,1,1, 'Parent', fig);
ax2 = subplot(2,1,2, 'Parent', fig);
- fp1 = FastPlot('Parent', ax1);
+ fp1 = FastSense('Parent', ax1);
fp1.addLine(1:1000, rand(1,1000));
fp1.render();
- fp2 = FastPlot('Parent', ax2);
+ fp2 = FastSense('Parent', ax2);
fp2.addLine(1:1000, rand(1,1000));
fp2.render();
diff --git a/tests/test_live_pipeline.m b/tests/test_live_pipeline.m
index 146e39bd..6a50554e 100644
--- a/tests/test_live_pipeline.m
+++ b/tests/test_live_pipeline.m
@@ -16,7 +16,7 @@ function add_event_path()
addpath(repoRoot);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
diff --git a/tests/test_lttb_downsample.m b/tests/test_lttb_downsample.m
index f39ad72b..b869a0c9 100644
--- a/tests/test_lttb_downsample.m
+++ b/tests/test_lttb_downsample.m
@@ -2,7 +2,7 @@ function test_lttb_downsample()
%TEST_LTTB_DOWNSAMPLE Tests for lttb_downsample private function.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testOutputSize
x = 1:1000;
diff --git a/tests/test_mex_edge_cases.m b/tests/test_mex_edge_cases.m
index 727d5159..1cc49e79 100644
--- a/tests/test_mex_edge_cases.m
+++ b/tests/test_mex_edge_cases.m
@@ -3,7 +3,7 @@ function test_mex_edge_cases()
% Skips if MEX files are not compiled.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
has_bs = (exist('binary_search_mex', 'file') == 3);
has_mm = (exist('minmax_core_mex', 'file') == 3);
diff --git a/tests/test_mex_parity.m b/tests/test_mex_parity.m
index b8dc32fa..fe5e7b50 100644
--- a/tests/test_mex_parity.m
+++ b/tests/test_mex_parity.m
@@ -4,7 +4,7 @@ function test_mex_parity()
% Skips if MEX files are not compiled.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
has_bs = (exist('binary_search_mex', 'file') == 3);
has_mm = (exist('minmax_core_mex', 'file') == 3);
diff --git a/tests/test_minmax_downsample.m b/tests/test_minmax_downsample.m
index 564ca87d..4c3da823 100644
--- a/tests/test_minmax_downsample.m
+++ b/tests/test_minmax_downsample.m
@@ -2,7 +2,7 @@ function test_minmax_downsample()
%TEST_MINMAX_DOWNSAMPLE Tests for minmax_downsample private function.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testBasicReduction: 10 buckets -> 20 output points
x = 1:100;
diff --git a/tests/test_mksqlite_types.m b/tests/test_mksqlite_types.m
index b080ce15..84f8e848 100644
--- a/tests/test_mksqlite_types.m
+++ b/tests/test_mksqlite_types.m
@@ -124,7 +124,7 @@ function test_mksqlite_types()
n = 50000;
x = linspace(0, 100, n);
y = sin(x);
- ds = FastPlotDataStore(x, y);
+ ds = FastSenseDataStore(x, y);
% 10. addColumn with cell of strings
labels = cell(1, n);
@@ -234,14 +234,14 @@ function test_mksqlite_types()
n2 = 1000;
x2 = linspace(0, 100, n2);
y2 = sin(x2);
- ds2 = FastPlotDataStore(x2, y2);
+ ds2 = FastSenseDataStore(x2, y2);
% 23. toCategorical round-trip via struct
catData2.codes = uint32(mod(0:n2-1, 3) + 1);
catData2.categories = {'low', 'medium', 'high'};
ds2.addColumn('cat_struct', catData2);
slice = ds2.getColumnSlice('cat_struct', 1, 6);
- labels_back = FastPlotDataStore.toCategorical(slice);
+ labels_back = FastSenseDataStore.toCategorical(slice);
if exist('categorical', 'class')
assert(isa(labels_back, 'categorical'), ...
'toCategorical: should return categorical in MATLAB');
@@ -261,7 +261,7 @@ function test_mksqlite_types()
% 24. toCategorical with bad input should error
threw = false;
try
- FastPlotDataStore.toCategorical('not_a_struct');
+ FastSenseDataStore.toCategorical('not_a_struct');
catch
threw = true;
end
@@ -276,14 +276,14 @@ function test_mksqlite_types()
sliceN = ds2.getColumnSlice('cat_native', 1, 5);
assert(isstruct(sliceN) && isfield(sliceN, 'codes'), ...
'auto-convert categorical: should be stored as struct');
- labelsN = FastPlotDataStore.toCategorical(sliceN);
+ labelsN = FastSenseDataStore.toCategorical(sliceN);
assert(isa(labelsN, 'categorical'), ...
'auto-convert categorical: toCategorical should return categorical');
fprintf(' addColumn auto-convert categorical: PASS\n');
% 26. fromCategorical
c_test = categorical({'x','y','z','x'}, {'x','y','z'});
- s_test = FastPlotDataStore.fromCategorical(c_test);
+ s_test = FastSenseDataStore.fromCategorical(c_test);
assert(isequal(s_test.codes, uint32([1 2 3 1])), ...
'fromCategorical: codes mismatch');
assert(isequal(s_test.categories, {'x','y','z'}), ...
diff --git a/tests/test_multi_threshold.m b/tests/test_multi_threshold.m
index 8fd778a5..17c9e98f 100644
--- a/tests/test_multi_threshold.m
+++ b/tests/test_multi_threshold.m
@@ -2,10 +2,10 @@ function test_multi_threshold()
%TEST_MULTI_THRESHOLD Tests for per-threshold rendering with independent colors/markers.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testEachThresholdGetsOwnLine
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, randn(1,100));
fp.addThreshold(2.0, 'Direction', 'upper', 'Color', 'r', 'LineStyle', '--');
fp.addThreshold(1.0, 'Direction', 'upper', 'Color', [1 0.6 0], 'LineStyle', ':');
@@ -32,7 +32,7 @@ function test_multi_threshold()
close(fp.hFigure);
% testEachThresholdGetsOwnViolationMarkers
- fp = FastPlot();
+ fp = FastSense();
y = [0 0 0 1.5 1.5 0 0 0 2.5 2.5 0 0];
fp.addLine(1:12, y);
fp.addThreshold(2.0, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
@@ -59,7 +59,7 @@ function test_multi_threshold()
close(fp.hFigure);
% testThresholdWithoutViolationsGetsNoMarkers
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, zeros(1,10));
fp.addThreshold(5.0, 'Direction', 'upper', 'ShowViolations', true, 'Color', 'r');
fp.render();
@@ -73,7 +73,7 @@ function test_multi_threshold()
close(fp.hFigure);
% testShowViolationsFalseGetsNoMarkerHandle
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, 5*ones(1,10));
fp.addThreshold(2.0, 'Direction', 'upper', 'ShowViolations', false, 'Color', 'r');
fp.render();
@@ -84,7 +84,7 @@ function test_multi_threshold()
% testViolationsUpdateOnZoomPerThreshold (MATLAB only — needs PostSet listeners)
if ~exist('OCTAVE_VERSION', 'builtin')
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,100), 1.5*ones(1,100), zeros(1,100), 2.5*ones(1,100), zeros(1,100)];
x = 1:500;
fp.addLine(x, y);
@@ -109,15 +109,15 @@ function test_multi_threshold()
end
% testUserDataTagging
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, randn(1,100));
fp.addThreshold(1.0, 'Direction', 'upper', 'Label', 'AlarmHi', 'Color', 'r');
fp.render();
ud = get(fp.Thresholds(1).hLine, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'threshold'), 'UserData Type');
- assert(strcmp(ud.FastPlot.Name, 'AlarmHi'), 'UserData Name');
- assert(ud.FastPlot.ThresholdValue == 1.0, 'UserData ThresholdValue');
+ assert(strcmp(ud.FastSense.Type, 'threshold'), 'UserData Type');
+ assert(strcmp(ud.FastSense.Name, 'AlarmHi'), 'UserData Name');
+ assert(ud.FastSense.ThresholdValue == 1.0, 'UserData ThresholdValue');
close(fp.hFigure);
diff --git a/tests/test_notification_service.m b/tests/test_notification_service.m
index 20d51a6a..3da7a751 100644
--- a/tests/test_notification_service.m
+++ b/tests/test_notification_service.m
@@ -16,7 +16,7 @@ function add_event_path()
addpath(repoRoot);
addpath(fullfile(repoRoot, 'libs', 'EventDetection'));
addpath(fullfile(repoRoot, 'libs', 'SensorThreshold'));
- addpath(fullfile(repoRoot, 'libs', 'FastPlot'));
+ addpath(fullfile(repoRoot, 'libs', 'FastSense'));
setup();
end
diff --git a/tests/test_render.m b/tests/test_render.m
index ddeab935..6ba081d2 100644
--- a/tests/test_render.m
+++ b/tests/test_render.m
@@ -1,11 +1,11 @@
function test_render()
-%TEST_RENDER Tests for FastPlot.render method.
+%TEST_RENDER Tests for FastSense.render method.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
% testCreatesNewFigure
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Test');
fp.render();
assert(isfigure(fp.hFigure), 'testCreatesNewFigure: hFigure');
@@ -15,14 +15,14 @@ function test_render()
% testUsesExistingAxes
fig = figure('Visible', 'off');
ax = axes('Parent', fig);
- fp = FastPlot('Parent', ax);
+ fp = FastSense('Parent', ax);
fp.addLine(1:100, rand(1,100));
fp.render();
assert(fp.hAxes == ax, 'testUsesExistingAxes');
close(fig);
% testCreatesLineObjects
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L1');
fp.addLine(1:100, rand(1,100), 'DisplayName', 'L2');
fp.render();
@@ -32,28 +32,28 @@ function test_render()
close(fp.hFigure);
% testUserDataTagging
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'Sensor1');
fp.addThreshold(0.5, 'Label', 'UpperLim');
fp.render();
ud = get(fp.Lines(1).hLine, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'data_line'), 'testUserDataTagging: Type');
- assert(strcmp(ud.FastPlot.Name, 'Sensor1'), 'testUserDataTagging: Name');
- assert(ud.FastPlot.LineIndex == 1, 'testUserDataTagging: LineIndex');
+ assert(strcmp(ud.FastSense.Type, 'data_line'), 'testUserDataTagging: Type');
+ assert(strcmp(ud.FastSense.Name, 'Sensor1'), 'testUserDataTagging: Name');
+ assert(ud.FastSense.LineIndex == 1, 'testUserDataTagging: LineIndex');
close(fp.hFigure);
% testThresholdLineCreated (per-threshold)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.addThreshold(0.5, 'Direction', 'upper', 'Label', 'UL');
fp.render();
assert(isgraphics(fp.Thresholds(1).hLine, 'line'), 'testThresholdLineCreated');
ud = get(fp.Thresholds(1).hLine, 'UserData');
- assert(strcmp(ud.FastPlot.Type, 'threshold'), 'testThresholdLineCreated: Type');
+ assert(strcmp(ud.FastSense.Type, 'threshold'), 'testThresholdLineCreated: Type');
close(fp.hFigure);
% testViolationMarkersCreated (per-threshold)
- fp = FastPlot();
+ fp = FastSense();
y = [0.1 0.2 0.8 0.9 0.3 0.1];
fp.addLine(1:6, y);
fp.addThreshold(0.5, 'Direction', 'upper', 'ShowViolations', true);
@@ -66,7 +66,7 @@ function test_render()
close(fp.hFigure);
% testDoubleRenderError
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:10, rand(1,10));
fp.render();
threw = false;
@@ -79,7 +79,7 @@ function test_render()
close(fp.hFigure);
% testStaticAxisLimits
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
assert(strcmp(get(fp.hAxes, 'XLimMode'), 'manual'), 'testStaticAxisLimits: XLimMode');
diff --git a/tests/test_sensor_todisk.m b/tests/test_sensor_todisk.m
index 06f3172c..c6e17fdc 100644
--- a/tests/test_sensor_todisk.m
+++ b/tests/test_sensor_todisk.m
@@ -59,7 +59,7 @@ function test_sensor_todisk()
fprintf(' resolve with disk data: PASS\n');
%% 4. addSensor with disk-backed sensor
- fp = FastPlot();
+ fp = FastSense();
fp.addSensor(s2, 'ShowThresholds', true);
fp.render();
assert(numel(fp.Lines) >= 1, 'should have at least 1 line');
@@ -72,7 +72,7 @@ function test_sensor_todisk()
s3.X = linspace(0, 100, 10000);
s3.Y = rand(1, 10000);
s3.toDisk();
- fp2 = FastPlot();
+ fp2 = FastSense();
fp2.addSensor(s3);
fp2.render();
assert(numel(fp2.Lines) == 1, 'should have 1 line');
diff --git a/tests/test_theme.m b/tests/test_theme.m
index 231ed20a..8dca607c 100644
--- a/tests/test_theme.m
+++ b/tests/test_theme.m
@@ -1,10 +1,10 @@
function test_theme()
-%TEST_THEME Tests for FastPlotTheme function.
+%TEST_THEME Tests for FastSenseTheme function.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
% testDefaultPreset
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
assert(isstruct(t), 'testDefaultPreset: must return struct');
assert(isequal(t.Background, [1 1 1]), 'testDefaultPreset: Background');
assert(isfield(t, 'AxesColor'), 'testDefaultPreset: AxesColor field');
@@ -25,12 +25,12 @@ function test_theme()
assert(size(t.LineColorOrder, 2) == 3, 'testDefaultPreset: LineColorOrder must be Nx3');
% testNoArgsReturnsDefault
- t0 = FastPlotTheme();
- t1 = FastPlotTheme('default');
+ t0 = FastSenseTheme();
+ t1 = FastSenseTheme('default');
assert(isequal(t0, t1), 'testNoArgsReturnsDefault');
% testMergeOverrides
- t = FastPlotTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
+ t = FastSenseTheme('default', 'FontSize', 14, 'LineWidth', 2.0);
assert(t.FontSize == 14, 'testMergeOverrides: FontSize');
assert(t.LineWidth == 2.0, 'testMergeOverrides: LineWidth');
assert(isequal(t.Background, [1 1 1]), 'testMergeOverrides: Background unchanged');
@@ -38,37 +38,37 @@ function test_theme()
% testInvalidPresetErrors
threw = false;
try
- FastPlotTheme('nonexistent');
+ FastSenseTheme('nonexistent');
catch
threw = true;
end
assert(threw, 'testInvalidPresetErrors');
% testDarkPreset
- t = FastPlotTheme('dark');
+ t = FastSenseTheme('dark');
assert(all(t.Background < [0.2 0.2 0.2]), 'testDarkPreset: Background should be dark');
assert(all(t.ForegroundColor > [0.7 0.7 0.7]), 'testDarkPreset: ForegroundColor should be light');
assert(size(t.LineColorOrder, 2) == 3, 'testDarkPreset: LineColorOrder Nx3');
% testLightPreset
- t = FastPlotTheme('light');
+ t = FastSenseTheme('light');
assert(all(t.Background > [0.9 0.9 0.9]), 'testLightPreset: Background');
assert(size(t.LineColorOrder, 2) == 3, 'testLightPreset: LineColorOrder Nx3');
% testIndustrialPreset
- t = FastPlotTheme('industrial');
+ t = FastSenseTheme('industrial');
assert(t.LineWidth >= 1.0, 'testIndustrialPreset: LineWidth');
assert(size(t.LineColorOrder, 2) == 3, 'testIndustrialPreset: LineColorOrder Nx3');
% testScientificPreset
- t = FastPlotTheme('scientific');
+ t = FastSenseTheme('scientific');
assert(strcmp(t.FontName, 'Times New Roman'), 'testScientificPreset: FontName');
assert(t.GridAlpha == 0, 'testScientificPreset: no grid');
assert(t.LineWidth < 1.0, 'testScientificPreset: thin lines');
assert(size(t.LineColorOrder, 2) == 3, 'testScientificPreset: LineColorOrder Nx3');
% testOceanPreset
- t = FastPlotTheme('ocean');
+ t = FastSenseTheme('ocean');
assert(isequal(t.Background, [1 1 1]), 'testOceanPreset: Background should be white');
assert(isequal(t.AxesColor, [1 1 1]), 'testOceanPreset: AxesColor should be white');
assert(size(t.LineColorOrder, 2) == 3, 'testOceanPreset: LineColorOrder Nx3');
@@ -76,18 +76,18 @@ function test_theme()
% testStructAsPreset
custom = struct('Background', [0 0 0], 'FontSize', 16);
- t = FastPlotTheme(custom);
+ t = FastSenseTheme(custom);
assert(isequal(t.Background, [0 0 0]), 'testStructAsPreset: Background');
assert(t.FontSize == 16, 'testStructAsPreset: FontSize');
assert(isfield(t, 'GridColor'), 'testStructAsPreset: inherits defaults');
% testPaletteResolution
- t = FastPlotTheme('default');
+ t = FastSenseTheme('default');
assert(size(t.LineColorOrder, 1) >= 6, 'testPaletteResolution: at least 6 colors');
% testCustomPaletteMatrix
customColors = [1 0 0; 0 1 0; 0 0 1];
- t = FastPlotTheme('default', 'LineColorOrder', customColors);
+ t = FastSenseTheme('default', 'LineColorOrder', customColors);
assert(isequal(t.LineColorOrder, customColors), 'testCustomPaletteMatrix');
fprintf(' All 12 theme tests passed.\n');
diff --git a/tests/test_toolbar.m b/tests/test_toolbar.m
index fc1a765a..20960fb4 100644
--- a/tests/test_toolbar.m
+++ b/tests/test_toolbar.m
@@ -1,57 +1,57 @@
function test_toolbar()
-%TEST_TOOLBAR Tests for FastPlotToolbar class.
+%TEST_TOOLBAR Tests for FastSenseToolbar class.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
close all force;
drawnow;
- % testConstructorWithFastPlot
- fp = FastPlot();
+ % testConstructorWithFastSense
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
- assert(~isempty(tb.hToolbar), 'testConstructorWithFastPlot: hToolbar');
- assert(ishandle(tb.hToolbar), 'testConstructorWithFastPlot: ishandle');
+ tb = FastSenseToolbar(fp);
+ assert(~isempty(tb.hToolbar), 'testConstructorWithFastSense: hToolbar');
+ assert(ishandle(tb.hToolbar), 'testConstructorWithFastSense: ishandle');
close(fp.hFigure);
- % testConstructorWithFastPlotGrid
- fig = FastPlotGrid(1, 2);
+ % testConstructorWithFastSenseGrid
+ fig = FastSenseGrid(1, 2);
fp1 = fig.tile(1); fp1.addLine(1:100, rand(1,100));
fp2 = fig.tile(2); fp2.addLine(1:100, rand(1,100));
fig.renderAll();
- tb = FastPlotToolbar(fig);
+ tb = FastSenseToolbar(fig);
assert(~isempty(tb.hToolbar), 'testConstructorWithFPFigure: hToolbar');
close(fig.hFigure);
% testToolbarHasAllButtons (cursor, crosshair, grid, legend, autoscale, export, refresh, live, metadata, theme)
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
children = get(tb.hToolbar, 'Children');
assert(numel(children) == 11, ...
sprintf('testToolbarHasAllButtons: got %d', numel(children)));
close(fp.hFigure);
% testIconsAre16x16x3
- icons = FastPlotToolbar.makeIcon('grid');
+ icons = FastSenseToolbar.makeIcon('grid');
assert(isequal(size(icons), [16 16 3]), 'testIconsAre16x16x3');
% testAllIconNames
names = {'cursor', 'crosshair', 'grid', 'legend', 'autoscale', 'export', 'violations'};
for i = 1:numel(names)
- icon = FastPlotToolbar.makeIcon(names{i});
+ icon = FastSenseToolbar.makeIcon(names{i});
assert(isequal(size(icon), [16 16 3]), ...
sprintf('testAllIconNames: %s', names{i}));
end
% testToggleGrid
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
gridBefore = get(fp.hAxes, 'XGrid');
tb.toggleGrid();
gridAfter = get(fp.hAxes, 'XGrid');
@@ -59,10 +59,10 @@ function test_toolbar()
close(fp.hFigure);
% testToggleLegend
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100), 'DisplayName', 'TestLine');
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.toggleLegend();
hLeg = findobj(fp.hFigure, 'Type', 'axes', 'Tag', 'legend');
if isempty(hLeg)
@@ -75,11 +75,11 @@ function test_toolbar()
close(fp.hFigure);
% testAutoscaleY
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,50), 10*ones(1,50)];
fp.addLine(1:100, y);
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
% Zoom into first half (all zeros)
set(fp.hAxes, 'XLim', [1 50]);
drawnow;
@@ -91,10 +91,10 @@ function test_toolbar()
close(fp.hFigure);
% testExportPNG
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tmpFile = [tempname, '.png'];
tb.exportPNG(tmpFile);
assert(exist(tmpFile, 'file') == 2, 'testExportPNG: file should exist');
@@ -102,10 +102,10 @@ function test_toolbar()
close(fp.hFigure);
% testCrosshairMode
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
assert(strcmp(tb.Mode, 'none'), 'testCrosshairMode: initial mode');
tb.setCrosshair(true);
assert(strcmp(tb.Mode, 'crosshair'), 'testCrosshairMode: on');
@@ -114,10 +114,10 @@ function test_toolbar()
close(fp.hFigure);
% testCrosshairMutualExclusion
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.setCursor(true);
assert(strcmp(tb.Mode, 'cursor'), 'testMutualExcl: cursor on');
tb.setCrosshair(true);
@@ -126,10 +126,10 @@ function test_toolbar()
close(fp.hFigure);
% testCursorMode
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, rand(1,100));
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
tb.setCursor(true);
assert(strcmp(tb.Mode, 'cursor'), 'testCursorMode: on');
tb.setCursor(false);
@@ -137,21 +137,21 @@ function test_toolbar()
close(fp.hFigure);
% testSnapToNearest
- fp = FastPlot();
+ fp = FastSense();
fp.addLine([1 2 3 4 5], [10 20 30 40 50]);
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
[sx, sy, ~] = tb.snapToNearest(fp, 2.8, 25);
assert(sx == 3, sprintf('testSnapToNearest: x should be 3, got %g', sx));
assert(sy == 30, sprintf('testSnapToNearest: y should be 30, got %g', sy));
close(fp.hFigure);
% testViolationsToggle
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:100, [ones(1,50)*2, ones(1,50)*8]);
fp.addThreshold(5, 'Direction', 'upper', 'ShowViolations', true);
fp.render();
- tb = FastPlotToolbar(fp);
+ tb = FastSenseToolbar(fp);
% Violations should be visible initially
assert(fp.ViolationsVisible, 'testViolationsToggle: default true');
hM = fp.Thresholds(1).hMarkers;
diff --git a/tests/test_violation_cull_mex.m b/tests/test_violation_cull_mex.m
index 8497d87d..157ba7dd 100644
--- a/tests/test_violation_cull_mex.m
+++ b/tests/test_violation_cull_mex.m
@@ -2,7 +2,7 @@ function test_violation_cull_mex()
%TEST_VIOLATION_CULL_MEX Parity tests: MEX vs MATLAB fallback.
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
hasMex = (exist('violation_cull_mex', 'file') == 3);
if ~hasMex
diff --git a/tests/test_violations_mex_parity.m b/tests/test_violations_mex_parity.m
index c10a2950..1049c73d 100644
--- a/tests/test_violations_mex_parity.m
+++ b/tests/test_violations_mex_parity.m
@@ -100,5 +100,5 @@ function add_sensor_path()
repo_root = fileparts(test_dir);
addpath(repo_root);setup();
% Add private dirs so MEX is directly accessible for parity testing
- addpath(fullfile(repo_root, 'libs', 'FastPlot', 'private'));
+ addpath(fullfile(repo_root, 'libs', 'FastSense', 'private'));
end
diff --git a/tests/test_zoom_pan.m b/tests/test_zoom_pan.m
index 6c32be5c..166fd55d 100644
--- a/tests/test_zoom_pan.m
+++ b/tests/test_zoom_pan.m
@@ -3,7 +3,7 @@ function test_zoom_pan()
% Requires PostSet listeners (MATLAB only, skipped on Octave).
addpath(fullfile(fileparts(mfilename('fullpath')), '..'));setup();
- add_fastplot_private_path();
+ add_fastsense_private_path();
if exist('OCTAVE_VERSION', 'builtin')
fprintf(' SKIPPED: Octave lacks PostSet listeners for axes properties.\n');
@@ -11,7 +11,7 @@ function test_zoom_pan()
end
% testZoomUpdatesPlottedData
- fp = FastPlot();
+ fp = FastSense();
n = 100000;
x = linspace(0, 100, n);
y = sin(x);
@@ -31,7 +31,7 @@ function test_zoom_pan()
close(fp.hFigure);
% testLazySkipsRedundantUpdate
- fp = FastPlot();
+ fp = FastSense();
fp.addLine(1:1000, rand(1,1000));
fp.render();
@@ -44,7 +44,7 @@ function test_zoom_pan()
close(fp.hFigure);
% testViolationsUpdateOnZoom
- fp = FastPlot();
+ fp = FastSense();
y = [zeros(1,500), ones(1,500)*10, zeros(1,500)];
x = 1:1500;
fp.addLine(x, y);