Commit 042a0c4b authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: extract all curt_* into CuasRtParameters class (imp.curt), dialog order preserved

Per Andrey: move every curt_* parameter out of IntersceneMatchParameters into
its own class (like CLTParameters.imp/ofp/... peers), held as
IntersceneMatchParameters.curt = new CuasRtParameters(). All 61 params: field
decls, dialogQuestions/Answers, set/getProperties, clone. Access changes
imp.curt_X -> imp.curt.X (114 external sites across OpticalFlow/CuasDetectRT/
CuasPoseRT); short field names (curt_ prefix dropped, class name conveys it).

corr-xml COMPATIBLE (no conversion needed): delegated as
curt.set/getProperties(prefix+"curt_", props) with short keys, so full keys
stay ..._imp_curt_X byte-identical (verified: 61 old == 61 new).

Verified: compiles clean; 61 params in every section; dialogQ add* == dialogA
getNext* == 61, verbatim order (pairing preserved); interleaved non-curt
air_/fgnd_ decls intact. Relieves setProperties 54865->52127, dialogQuestions
22385->21267, clone -503B (the methods our pose work grows).

NOTE: getProperties READER stays 63291/65535 - its bloat is ~1103 NON-curt
getProperty reads (curt reads were already in getPropertiesCuasRT since 06/12);
relieving it needs a separate non-curt extraction (flagged for Andrey).
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 1c807750
......@@ -158,14 +158,14 @@ public class CuasDetectRT {
fpixels[i] = (float[]) stack.getPixels (first_slice + i);
}
base_name = core_base_name;
if (clt_parameters.imp.curt_subtract_avg) base_name += "-SUBAVG"; // distinct output filenames for average-subtracted runs (don't overwrite) // By Claude on 06/14/2026
if (clt_parameters.imp.curt_synth_src) { // load the synthetic reference grid separately (NOT mixed here) // By Claude on 06/14/2026
if (clt_parameters.imp.curt.subtract_avg) base_name += "-SUBAVG"; // distinct output filenames for average-subtracted runs (don't overwrite) // By Claude on 06/14/2026
if (clt_parameters.imp.curt.synth_src) { // load the synthetic reference grid separately (NOT mixed here) // By Claude on 06/14/2026
// Real (loaded above) is the pyramid base. The synthetic file holds NORMALIZED
// (peak 1) clean targets / a velocity-reference grid: load + scale it, keep it
// aside (NO LoG - it has no slowly-varying background), and inject it TILED into
// each pyramid level just before conv5d/DNN, so it is never averaged across levels
// and looks the same at every level while the real noise is averaged (SNR up ~sqrt2/level).
double synth_scale = clt_parameters.imp.curt_synth_scale;
double synth_scale = clt_parameters.imp.curt.synth_scale;
// Synthetic grid is sequence-INDEPENDENT: read it from the shared dir (list SET "cuasSynth")
// when set; otherwise fall back to the per-sequence model_directory (old behavior / single-
// sequence mode where the SET key is absent). By Claude on 06/24/2026
......@@ -284,8 +284,8 @@ public class CuasDetectRT {
/** [i0,i1) scene-index window for the timing ROI (curt_time_from/to), or full range if open/empty. // By Claude on 06/14/2026 */
private int [] timeWindow(String [] ts) {
int n = (ts == null) ? 0 : ts.length;
double from = clt_parameters.imp.curt_time_from;
double to = clt_parameters.imp.curt_time_to;
double from = clt_parameters.imp.curt.time_from;
double to = clt_parameters.imp.curt.time_to;
if ((n == 0) || ((from <= 0) && (to <= 0))) return new int[]{0, n};
double minSec = Double.POSITIVE_INFINITY;
double [] tv = new double [n];
......@@ -560,19 +560,19 @@ public class CuasDetectRT {
Rectangle roi,
String title_base,
boolean save_individual) {
int period = clt_parameters.imp.curt_recur_period;
double w = clt_parameters.imp.curt_recur_w;
double leak = clt_parameters.imp.curt_recur_leak;
double wthresh = clt_parameters.imp.curt_recur_wthresh;
double spread = clt_parameters.imp.curt_recur_spread;
int max_clust = clt_parameters.imp.curt_recur_max_clust;
double fit_rat = clt_parameters.imp.curt_recur_fit_rat;
double rs_frac = clt_parameters.imp.curt_recur_rs_frac;
double rs_min = clt_parameters.imp.curt_recur_rs_min;
int pix_decimate = clt_parameters.imp.curt_pix_decimate;
int vel_radius = clt_parameters.imp.curt_vel_radius;
int vel_decimate = clt_parameters.imp.curt_vel_decimate;
double dbg_min = clt_parameters.imp.curt_vel_dbgmin;
int period = clt_parameters.imp.curt.recur_period;
double w = clt_parameters.imp.curt.recur_w;
double leak = clt_parameters.imp.curt.recur_leak;
double wthresh = clt_parameters.imp.curt.recur_wthresh;
double spread = clt_parameters.imp.curt.recur_spread;
int max_clust = clt_parameters.imp.curt.recur_max_clust;
double fit_rat = clt_parameters.imp.curt.recur_fit_rat;
double rs_frac = clt_parameters.imp.curt.recur_rs_frac;
double rs_min = clt_parameters.imp.curt.recur_rs_min;
int pix_decimate = clt_parameters.imp.curt.pix_decimate;
int vel_radius = clt_parameters.imp.curt.vel_radius;
int vel_decimate = clt_parameters.imp.curt.vel_decimate;
double dbg_min = clt_parameters.imp.curt.vel_dbgmin;
int num_5d = conv5d_roi.length;
CuasRecurrentBuffer recurrentBuffer = new CuasRecurrentBuffer(
roi.width, // int roi_width,
......@@ -735,25 +735,25 @@ public class CuasDetectRT {
int [] c5_levels,
Rectangle roi,
String title_conv5d) {
final int dnn_stride = Math.max(1, clt_parameters.imp.curt_dnn_stride);
final boolean use_l2 = clt_parameters.imp.curt_dnn_l2; // run Layer-2 on the DGX: -OFFSET carries L2 det+vel instead of L1. By Claude 06/22/2026
final String l2model = use_l2 ? clt_parameters.imp.curt_dnn_l2_model : ""; // L2 run dir on the DGX; empty = L1-only (old way)
final int dnn_stride = Math.max(1, clt_parameters.imp.curt.dnn_stride);
final boolean use_l2 = clt_parameters.imp.curt.dnn_l2; // run Layer-2 on the DGX: -OFFSET carries L2 det+vel instead of L1. By Claude 06/22/2026
final String l2model = use_l2 ? clt_parameters.imp.curt.dnn_l2_model : ""; // L2 run dir on the DGX; empty = L1-only (old way)
// L2 model id appended as the LAST filename suffix on -OFFSET so runs of different L2 models don't
// collide (and Dolphin's begin...end.tiff truncation still shows the model). By Claude on 06/24/2026
final String l2tag = use_l2 ? ("-" + l2model.substring(l2model.lastIndexOf('/') + 1)) : "";
final int W = getWidth(), H = getHeight();
final boolean save_rect = clt_parameters.imp.curt_save_c5rect;
final boolean save_hyper = clt_parameters.imp.curt_save_c5hyper;
final boolean synth = clt_parameters.imp.curt_synth_src && (synth_pixels != null) && (synth_pixels.length > 0);
final boolean synth_bg = clt_parameters.imp.curt_synth_bg;
final boolean save_rect = clt_parameters.imp.curt.save_c5rect;
final boolean save_hyper = clt_parameters.imp.curt.save_c5hyper;
final boolean synth = clt_parameters.imp.curt.synth_src && (synth_pixels != null) && (synth_pixels.length > 0);
final boolean synth_bg = clt_parameters.imp.curt.synth_bg;
final int n_synth = synth ? synth_pixels.length : 0;
try { // auto-launch the DGX server if not already running (deploy bundled/override scripts, ssh-start, poll) // By Claude on 06/20/2026
if (!clt_parameters.imp.curt_dnn_local) // local native backend has no server to launch. By Claude on 06/27/2026
CuasDnnRemote.ensureServer(clt_parameters.imp.curt_dnn_remote_host, clt_parameters.imp.curt_dnn_remote_model, l2model, clt_parameters.imp.curt_dnn_remote_srcdir);
if (!clt_parameters.imp.curt.dnn_local) // local native backend has no server to launch. By Claude on 06/27/2026
CuasDnnRemote.ensureServer(clt_parameters.imp.curt.dnn_remote_host, clt_parameters.imp.curt.dnn_remote_model, l2model, clt_parameters.imp.curt.dnn_remote_srcdir);
} catch (Exception e) { System.out.println("runDnnRemote(): server auto-launch failed: "+e); }
try (CuasDnnBackend remote = clt_parameters.imp.curt_dnn_local
? new CuasDnnLocal(clt_parameters.imp.curt_dnn_local_dir, clt_parameters.imp.curt_dnn_remote_model, l2model)
: new CuasDnnRemote(clt_parameters.imp.curt_dnn_remote_host)) {
try (CuasDnnBackend remote = clt_parameters.imp.curt.dnn_local
? new CuasDnnLocal(clt_parameters.imp.curt.dnn_local_dir, clt_parameters.imp.curt.dnn_remote_model, l2model)
: new CuasDnnRemote(clt_parameters.imp.curt.dnn_remote_host)) {
// Build the upload array: LoG-conditioned real (optionally synth_bg_avg-decimated upstream), optionally
// with synthetic targets mixed in (tiled synth[t % n_synth]; clean = zero bg first) - matching the local
// per-level injection (CuasDetectRT.java synth block) but PRE-pyramid; the DGX then averages it into levels.
......@@ -817,8 +817,8 @@ public class CuasDetectRT {
// batched: request the level's in-window scenes in chunks; the DGX runs them continuously
// (production throughput) and ghostbusts on the GPU (so -OFFSET s + ROI 121 are both clean -
// no Java-side ghostbust). rmax_cells = vmax*vel_decimate (<=0 disables). By Claude on 06/20/2026
double rmax = (clt_parameters.imp.curt_dnn_vmax > 0) ?
clt_parameters.imp.curt_dnn_vmax * clt_parameters.imp.curt_vel_decimate : 0.0;
double rmax = (clt_parameters.imp.curt.dnn_vmax > 0) ?
clt_parameters.imp.curt.dnn_vmax * clt_parameters.imp.curt.vel_decimate : 0.0;
final int REQ = 64; // scenes per round-trip (reply byte[] ~419MB at 640x512, < 2GB array cap)
for (int j0 = 0; j0 < num; j0 += REQ) {
int cnt = Math.min(REQ, num - j0);
......@@ -850,8 +850,8 @@ public class CuasDetectRT {
final int [] ord = use_l2 ? new int[]{2, 3, 4, 0, 1, 5} : new int[]{2, 3, 4, 0, 1};
final String [] off_labels = use_l2 ? new String[]{"s","Vx","Vy","dx","dy","age"} : new String[]{"s","Vx","Vy","dx","dy"};
// NaN Vx,Vy,dx,dy where s < curt_dnn_thresh so velocity shows only at detections (ImageJ ignores NaN); keep s + age full. By Claude on 06/20/2026
final double off_thr = clt_parameters.imp.curt_dnn_thresh;
final double velScale = 1.0 / Math.max(1, clt_parameters.imp.curt_vel_decimate); // Vx,Vy: cells -> px/level-frame (1/vel_decimate) // By Claude on 06/20/2026
final double off_thr = clt_parameters.imp.curt.dnn_thresh;
final double velScale = 1.0 / Math.max(1, clt_parameters.imp.curt.vel_decimate); // Vx,Vy: cells -> px/level-frame (1/vel_decimate) // By Claude on 06/20/2026
double [][][] off5_w = new double [ord.length][nsc][]; // window the full-frame offset for -OFFSET
for (int k = 0; k < nsc; k++) {
double [] sCh = off5[2][win_dnn[0]+k]; // s channel (off5 index 2)
......@@ -885,35 +885,35 @@ public class CuasDetectRT {
boolean batch_mode,
int debugLevel) {
boolean save_linear_cuas = true;
int curt_pyramid = clt_parameters.imp.curt_pyramid;
double curt_psf_radius = clt_parameters.imp.curt_psf_radius;
double curt_n_sigma = clt_parameters.imp.curt_n_sigma;
int curt_pyramid = clt_parameters.imp.curt.pyramid;
double curt_psf_radius = clt_parameters.imp.curt.psf_radius;
double curt_n_sigma = clt_parameters.imp.curt.n_sigma;
// rleak0 local removed 2026-06-20 (LReLU conditioning now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
int curt_pix_decimate = clt_parameters.imp.curt_pix_decimate;
int curt_vel_decimate = clt_parameters.imp.curt_vel_decimate;
int curt_vel_radius = clt_parameters.imp.curt_vel_radius;
boolean curt_vel_thresh_en =clt_parameters.imp.curt_vel_thresh_en;
int curt_vel_suppr_rad =clt_parameters.imp.curt_vel_suppr_rad;
double curt_vel_athresh = clt_parameters.imp.curt_vel_athresh;
double curt_vel_rthresh = clt_parameters.imp.curt_vel_rthresh;
double curt_vel_dbg_min = clt_parameters.imp.curt_vel_dbgmin; // temporary, testing with strong targets, make clean background
boolean curt_recur_en = clt_parameters.imp.curt_recur_en; // By Claude on 06/09/2026
int curt_recur_period = clt_parameters.imp.curt_recur_period; // By Claude on 06/09/2026
double curt_recur_w = clt_parameters.imp.curt_recur_w; // By Claude on 06/09/2026
double curt_recur_leak = clt_parameters.imp.curt_recur_leak; // By Claude on 06/09/2026
double curt_recur_wthresh =clt_parameters.imp.curt_recur_wthresh; // By Claude on 06/09/2026
double curt_recur_spread = clt_parameters.imp.curt_recur_spread; // By Claude on 06/09/2026
int curt_recur_max_clust = clt_parameters.imp.curt_recur_max_clust; // By Claude on 06/09/2026
double curt_recur_fit_rat = clt_parameters.imp.curt_recur_fit_rat; // By Claude on 06/10/2026
double curt_recur_rs_frac = clt_parameters.imp.curt_recur_rs_frac; // By Claude on 06/10/2026
double curt_recur_rs_min = clt_parameters.imp.curt_recur_rs_min; // By Claude on 06/10/2026
int curt_pix_decimate = clt_parameters.imp.curt.pix_decimate;
int curt_vel_decimate = clt_parameters.imp.curt.vel_decimate;
int curt_vel_radius = clt_parameters.imp.curt.vel_radius;
boolean curt_vel_thresh_en =clt_parameters.imp.curt.vel_thresh_en;
int curt_vel_suppr_rad =clt_parameters.imp.curt.vel_suppr_rad;
double curt_vel_athresh = clt_parameters.imp.curt.vel_athresh;
double curt_vel_rthresh = clt_parameters.imp.curt.vel_rthresh;
double curt_vel_dbg_min = clt_parameters.imp.curt.vel_dbgmin; // temporary, testing with strong targets, make clean background
boolean curt_recur_en = clt_parameters.imp.curt.recur_en; // By Claude on 06/09/2026
int curt_recur_period = clt_parameters.imp.curt.recur_period; // By Claude on 06/09/2026
double curt_recur_w = clt_parameters.imp.curt.recur_w; // By Claude on 06/09/2026
double curt_recur_leak = clt_parameters.imp.curt.recur_leak; // By Claude on 06/09/2026
double curt_recur_wthresh =clt_parameters.imp.curt.recur_wthresh; // By Claude on 06/09/2026
double curt_recur_spread = clt_parameters.imp.curt.recur_spread; // By Claude on 06/09/2026
int curt_recur_max_clust = clt_parameters.imp.curt.recur_max_clust; // By Claude on 06/09/2026
double curt_recur_fit_rat = clt_parameters.imp.curt.recur_fit_rat; // By Claude on 06/10/2026
double curt_recur_rs_frac = clt_parameters.imp.curt.recur_rs_frac; // By Claude on 06/10/2026
double curt_recur_rs_min = clt_parameters.imp.curt.recur_rs_min; // By Claude on 06/10/2026
double[] curt_temp_weights = clt_parameters.imp.curt_temp_weights.clone();
double[] curt_temp_weights = clt_parameters.imp.curt.temp_weights.clone();
boolean curt_save_c5full = clt_parameters.imp.curt_save_c5full;
boolean curt_save_c5rect = clt_parameters.imp.curt_save_c5rect;
Rectangle curt_save_select = clt_parameters.imp.curt_save_select;
if (clt_parameters.imp.curt_synth_src) { // synthetic grid: HONOR the user ROI so it can be shrunk - the full-grid SYNTH_ROI (320x320) OOMs the per-velocity render (~12x expansion per axis); fall back to SYNTH_ROI only when no ROI is set // By Claude on 06/15/2026
boolean curt_save_c5full = clt_parameters.imp.curt.save_c5full;
boolean curt_save_c5rect = clt_parameters.imp.curt.save_c5rect;
Rectangle curt_save_select = clt_parameters.imp.curt.save_select;
if (clt_parameters.imp.curt.synth_src) { // synthetic grid: HONOR the user ROI so it can be shrunk - the full-grid SYNTH_ROI (320x320) OOMs the per-velocity render (~12x expansion per axis); fall back to SYNTH_ROI only when no ROI is set // By Claude on 06/15/2026
if (curt_save_select == null) {
curt_save_select = new Rectangle(SYNTH_ROI);
System.out.println("Synthetic input: no ROI set - using full-grid SYNTH_ROI = "+curt_save_select);
......@@ -922,8 +922,8 @@ public class CuasDetectRT {
+ " (synthetic 11x11 grid spans ~"+SYNTH_ROI+"; aim the ROI inside it)"); // By Claude on 06/15/2026
}
}
final double min_frac_last = clt_parameters.imp.curt_min_frac; // By Claude on 06/12/2026
if (clt_parameters.imp.curt_synth_src && (min_frac_last > 0)) { // By Claude on 06/12/2026
final double min_frac_last = clt_parameters.imp.curt.min_frac; // By Claude on 06/12/2026
if (clt_parameters.imp.curt.synth_src && (min_frac_last > 0)) { // By Claude on 06/12/2026
System.out.println("WARNING: synthetic (B-measurement) run with curt_min_frac = "+min_frac_last+
" - this NONLINEAR gate punches zeros into the strongest ridge cells; set 0 for a linear measurement");
}
......@@ -964,9 +964,9 @@ public class CuasDetectRT {
// (the LEV-L noise floor, N=2^L) into a sequence (length = the "Time ROI" window; open/-1 = all frames) and force a single level - restoring the
// old synthetic+background mode speed. SUBAVG then runs over this short sequence; the SYNTHETIC targets are
// injected later (after SUBAVG), so they never enter the average. Velocity cells then encode LEV1/2/3.
final boolean synth_fast = clt_parameters.imp.curt_synth_src && (clt_parameters.imp.curt_synth_bg_avg > 1);
if (synth_fast && (dpixels != null) && (dpixels.length >= clt_parameters.imp.curt_synth_bg_avg)) {
final int navg = clt_parameters.imp.curt_synth_bg_avg;
final boolean synth_fast = clt_parameters.imp.curt.synth_src && (clt_parameters.imp.curt.synth_bg_avg > 1);
if (synth_fast && (dpixels != null) && (dpixels.length >= clt_parameters.imp.curt.synth_bg_avg)) {
final int navg = clt_parameters.imp.curt.synth_bg_avg;
int ngrp = dpixels.length / navg; // each group = navg input frames -> one averaged (LEV) frame
String [] ts_grp = new String [ngrp];
for (int k = 0; k < ngrp; k++) ts_grp[k] = time_stamps[k*navg + navg - 1]; // last ts of each navg-group (the LEV timestamp)
......@@ -985,7 +985,7 @@ public class CuasDetectRT {
this.dpixels = davg; this.time_stamps = tsavg; dpixels = davg;
System.out.println(now()+" detectTargets(): synth fast path - bg-averaged x"+navg+" -> "+kout+"/"+ngrp+" frames (Time ROI groups ["+g0+","+g1+")), single level"); // By Claude on 06/20/2026
}
if (clt_parameters.imp.curt_subtract_avg && (dpixels != null) && (dpixels.length > 0)) { // de-streak: subtract the static background before LoG so the sharp treeline edge (and its tile-grid ringing) is gone; the moving target is not in the average // By Claude on 06/14/2026
if (clt_parameters.imp.curt.subtract_avg && (dpixels != null) && (dpixels.length > 0)) { // de-streak: subtract the static background before LoG so the sharp treeline edge (and its tile-grid ringing) is gone; the moving target is not in the average // By Claude on 06/14/2026
int npx = dpixels[0].length;
double [] mean = new double [npx];
int [] cnt = new int [npx];
......@@ -1039,13 +1039,13 @@ public class CuasDetectRT {
// The fine-velocity detector is now the DNN front-end fed from dpixels_pyramid; nothing consumes a 3d3 coarse-velocity history.
// building pyramid
int pyramid_levels = synth_fast ? 1 : clt_parameters.imp.curt_pyramid; // synth fast path forces a single level // By Claude on 06/20/2026
int pyramid_levels = synth_fast ? 1 : clt_parameters.imp.curt.pyramid; // synth fast path forces a single level // By Claude on 06/20/2026
// Single level selector for ALL heavy per-level paths (3d3/conv5d, C5P-direct, DNN): // By Claude on 06/13/2026
// curt_c5_levels = {} -> all built levels; {k} -> run the heavy stages only at level k
// (the cheap temporalAverageLReLU/convolve3D3LReLU pyramid chain still builds up to k).
// Synthetic input now uses the same pyramid + level selection as real data (the old
// pyramid_levels=1 force and the curt_synth_bg_avg N= decimation were retired).
final int [] c5_levels = synth_fast ? new int[0] : clt_parameters.imp.curt_c5_levels; // synth fast path -> all built (= level 0 only) // By Claude on 06/20/2026
final int [] c5_levels = synth_fast ? new int[0] : clt_parameters.imp.curt.c5_levels; // synth fast path -> all built (= level 0 only) // By Claude on 06/20/2026
double [][][] dpixels_pyramid = new double [pyramid_levels][][];
String [][] ts_pyramid = new String [pyramid_levels][];
......@@ -1115,7 +1115,7 @@ public class CuasDetectRT {
}
}
// --- Synthetic reference grid injection + sqrt(2) noise check ---------------------- // By Claude on 06/14/2026
if (clt_parameters.imp.curt_synth_src && (synth_pixels != null) && (synth_pixels.length > 0)) {
if (clt_parameters.imp.curt.synth_src && (synth_pixels != null) && (synth_pixels.length > 0)) {
// sqrt(2) check: full-frame std of the PURE real frame 0 should drop ~/sqrt(2) per level.
for (int nlev = 0; nlev < pyramid_levels; nlev++) {
if ((dpixels_pyramid[nlev] == null) || (dpixels_pyramid[nlev].length == 0)) continue;
......@@ -1130,7 +1130,7 @@ public class CuasDetectRT {
// across levels) while the real noise is averaged. Moving cells wrap every n_synth frames
// (a deliberate recurrent-decay test case). C5P/DNN read this; legacy 3d3-conv5d does not.
int n_synth = synth_pixels.length;
boolean synth_bg = clt_parameters.imp.curt_synth_bg; // false = clean targets only: drop the real background (+its noise/NaNs) before injecting // By Claude on 06/15/2026
boolean synth_bg = clt_parameters.imp.curt.synth_bg; // false = clean targets only: drop the real background (+its noise/NaNs) before injecting // By Claude on 06/15/2026
for (int nlev = 0; nlev < pyramid_levels; nlev++) {
if (!c5LevelSelected(c5_levels, nlev)) continue;
double [][] lev = dpixels_pyramid[nlev];
......@@ -1150,7 +1150,7 @@ public class CuasDetectRT {
if (save_LoG_pixels) {
for (int nlev = 0; nlev < pyramid_levels; nlev++) {
if (!c5LevelSelected(c5_levels, nlev) || (dpixels_pyramid[nlev] == null)) continue;
String title_mix = getBaseName()+"-SYNTHMIX"+(synth_bg?"B":"")+(clt_parameters.imp.curt_subtract_avg?"-SUBAVG":"")+"-LEV"+nlev;
String title_mix = getBaseName()+"-SYNTHMIX"+(synth_bg?"B":"")+(clt_parameters.imp.curt.subtract_avg?"-SUBAVG":"")+"-LEV"+nlev;
ImagePlus imp_mix = ShowDoubleFloatArrays.makeArrays(
dpixels_pyramid[nlev], getWidth(), getHeight(), title_mix, ts_pyramid[nlev]);
imp_mix.setDisplayRange(CuasRTUtils.IMP_MINMAX[0], CuasRTUtils.IMP_MINMAX[1]);
......@@ -1166,12 +1166,12 @@ public class CuasDetectRT {
// same shape as the C5P output, saved as -DNN-RECT / -DNN-HYPER-RECT. N (temporal
// depth, 8 or 9) is read from the loaded ONNX. Reuses curt_c5_levels for level gating. Recurrent feed is the next step
// (the field is [0,1]-scaled, unlike the C5P matched-filter response - needs rescale).
if (!clt_parameters.imp.curt_dnn_model.isEmpty() && (curt_save_select != null) && !clt_parameters.imp.curt_dnn_remote && !clt_parameters.imp.curt_dnn_local) { // local CPU path (remote=DGX / curt_dnn_local=native LibTorch blocks below) // By Claude on 06/13/2026, remote guard 06/20/2026, local guard 06/27/2026
final int vr_dnn = clt_parameters.imp.curt_vel_radius; // By Claude on 06/13/2026
final int dnn_stride = Math.max(1, clt_parameters.imp.curt_dnn_stride); // 1 = every slice (testing), 4 = production 50% overlap // By Claude on 06/14/2026
if (!clt_parameters.imp.curt.dnn_model.isEmpty() && (curt_save_select != null) && !clt_parameters.imp.curt.dnn_remote && !clt_parameters.imp.curt.dnn_local) { // local CPU path (remote=DGX / curt_dnn_local=native LibTorch blocks below) // By Claude on 06/13/2026, remote guard 06/20/2026, local guard 06/27/2026
final int vr_dnn = clt_parameters.imp.curt.vel_radius; // By Claude on 06/13/2026
final int dnn_stride = Math.max(1, clt_parameters.imp.curt.dnn_stride); // 1 = every slice (testing), 4 = production 50% overlap // By Claude on 06/14/2026
try { // By Claude on 06/13/2026
CuasDnnInfer dnn = new CuasDnnInfer(clt_parameters.imp.curt_dnn_model, 8); // 8 = fallback hint only // By Claude on 06/13/2026
dnn.setPatch(clt_parameters.imp.curt_dnn_patch); // 24 or 32 (RF/training patch) - must match the loaded model // By Claude on 06/16/2026
CuasDnnInfer dnn = new CuasDnnInfer(clt_parameters.imp.curt.dnn_model, 8); // 8 = fallback hint only // By Claude on 06/13/2026
dnn.setPatch(clt_parameters.imp.curt.dnn_patch); // 24 or 32 (RF/training patch) - must match the loaded model // By Claude on 06/16/2026
final int N_dnn = dnn.getNFrames(); // 8 or 9, read from the loaded ONNX input shape -> 8/9 models swap at runtime // By Claude on 06/15/2026
for (int nlev = 0; nlev < pyramid_levels; nlev++) { // By Claude on 06/13/2026
if (!c5LevelSelected(c5_levels, nlev)) continue; // level gating (curt_c5_levels) // By Claude on 06/13/2026
......@@ -1185,7 +1185,7 @@ public class CuasDetectRT {
for (int k = 0; k < num_all; k++) cand_ts[k] = ts_pyramid[nlev][k * dnn_stride + N_dnn - 1]; // By Claude on 06/14/2026
int [] tw = timeWindow(cand_ts); int w0 = tw[0], num = tw[1] - tw[0]; // By Claude on 06/14/2026
if (num <= 0) continue; // By Claude on 06/14/2026
double dnn_thresh = clt_parameters.imp.curt_dnn_thresh; // By Claude on 06/13/2026
double dnn_thresh = clt_parameters.imp.curt.dnn_thresh; // By Claude on 06/13/2026
if (dnn.isReg()) { // continuous-velocity (reg) head: save {S,Vx,Vy,sigma} + offset hyperstacks; no grid/ghostbuster/recurrent. By Claude on 06/17/2026
String title_reg = title_conv5d+"-DNN"+((nlev > 0)?("-LEV"+nlev):"")+"-ROI"+curt_save_select.x+"_"+curt_save_select.y+"_"+curt_save_select.width+"_"+curt_save_select.height;
int rnpr = curt_save_select.width * curt_save_select.height;
......@@ -1216,13 +1216,13 @@ public class CuasDetectRT {
svxys, curt_save_select.width, title_reg+"-VXYS", ts_reg, new String[]{"S","Vx","Vy","sigma"}, false), clt_parameters.imp), getModelDirectory());
QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(ShowDoubleFloatArrays.showArraysHyperstack(
soffr, curt_save_select.width, title_reg+"-OFFSET", ts_reg, new String[]{"dx","dy","s"}, false), clt_parameters.imp), getModelDirectory());
if (!clt_parameters.imp.curt_stage2_model.isEmpty()) { // v2 Stage-2: vote + learned refine views // By Claude on 06/18/2026
if (!clt_parameters.imp.curt.stage2_model.isEmpty()) { // v2 Stage-2: vote + learned refine views // By Claude on 06/18/2026
int rw2 = curt_save_select.width, rh2 = curt_save_select.height, Nm1v = N_dnn - 1;
double [][][] votem = new double [1][num][rnpr]; // vote heatmap (accS), tail-indexed
double [][][] refd = new double [3][num][rnpr]; // refined {S,Vx,Vy}, tail-indexed
double [][][] heads = new double [1][num][rnpr]; // detection re-indexed to head (T0) // By Claude on 06/18/2026
try {
CuasStage2Infer s2 = new CuasStage2Infer(clt_parameters.imp.curt_stage2_model);
CuasStage2Infer s2 = new CuasStage2Infer(clt_parameters.imp.curt.stage2_model);
for (int j = 0; j < num; j++) {
double [][] acc = voteScatter(svxys[0][j], svxys[1][j], svxys[2][j], rw2, rh2, Nm1v);
votem[0][j] = acc[0].clone(); // raw vote heatmap (display)
......@@ -1268,8 +1268,8 @@ public class CuasDetectRT {
// grid distribution-vote (-GVOTE / -GHEADS via voteScatterGrid) removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// Ghostbuster: drop untrained corner velocities (cell-R > vmax*vel_decimate) before save // By Claude on 06/15/2026
// + recurrent feed, so the spurious corner sidelobes don't confuse the recurrent (s=0 for ghost-peak pixels)
if (clt_parameters.imp.curt_dnn_vmax > 0) { // By Claude on 06/15/2026
double rmax_cells = clt_parameters.imp.curt_dnn_vmax * clt_parameters.imp.curt_vel_decimate;
if (clt_parameters.imp.curt.dnn_vmax > 0) { // By Claude on 06/15/2026
double rmax_cells = clt_parameters.imp.curt.dnn_vmax * clt_parameters.imp.curt.vel_decimate;
for (int j = 0; j < num; j++) dnnGhostbust(dnn_roi[j], dnn_off[j], vr_dnn, rmax_cells);
}
// ROI tag in the filename (x_y_w_h) so the python flight-log analysis auto-restores the ROI - no manual entry. By Claude on 06/16/2026
......@@ -1281,7 +1281,7 @@ public class CuasDetectRT {
QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(cuasRTUtils.showConvKernel5d( // By Claude on 06/13/2026
dnn_w, curt_save_select, ts_dnn_w, title_dnn+"-RECT"), clt_parameters.imp), getModelDirectory()); // metadata: all curt_* // By Claude on 06/16/2026
} // By Claude on 06/13/2026
if (clt_parameters.imp.curt_save_c5hyper) { // By Claude on 06/13/2026
if (clt_parameters.imp.curt.save_c5hyper) { // By Claude on 06/13/2026
QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(cuasRTUtils.showConvKernel5dHyperRect( // By Claude on 06/13/2026
dnn_w, curt_save_select, ts_dnn_w, title_dnn+"-HYPER-RECT"), clt_parameters.imp), getModelDirectory()); // metadata: all curt_* // By Claude on 06/16/2026
} // By Claude on 06/13/2026
......@@ -1307,8 +1307,8 @@ public class CuasDetectRT {
// Feed the DNN field to the recurrent layer (Layer 2): as-is, or offset-splatted (px+dx,py+dy). // By Claude on 06/14/2026
// Tune the recurrent blend with curt_recur_w (0.25/0.75) etc.; the field is [0,1]-scaled so rs_min may need lowering.
if (run_recur && (num > 0)) {
boolean splat = clt_parameters.imp.curt_dnn_recur_splat;
double rscale = clt_parameters.imp.curt_dnn_recur_scale; // DNN field ~0.1 -> recurrent rs_min ~1.0 // By Claude on 06/14/2026
boolean splat = clt_parameters.imp.curt.dnn_recur_splat;
double rscale = clt_parameters.imp.curt.dnn_recur_scale; // DNN field ~0.1 -> recurrent rs_min ~1.0 // By Claude on 06/14/2026
double [][][][] dnn_feed = new double [num][][][];
for (int j = 0; j < num; j++) {
double [][][] f = splat ? splatField(dnn_roi[j], dnn_off[j], curt_save_select) : dnn_roi[j];
......@@ -1333,7 +1333,7 @@ public class CuasDetectRT {
} // By Claude on 06/13/2026
} // By Claude on 06/13/2026
// Remote DGX inference path (curt_dnn_remote): upload conditioned stack, DGX builds pyramid + infers. // By Claude on 06/20/2026
if ((curt_save_select != null) && (clt_parameters.imp.curt_dnn_remote || clt_parameters.imp.curt_dnn_local)) { // DGX server OR in-process native LibTorch (curt_dnn_local). By Claude on 06/27/2026
if ((curt_save_select != null) && (clt_parameters.imp.curt.dnn_remote || clt_parameters.imp.curt.dnn_local)) { // DGX server OR in-process native LibTorch (curt_dnn_local). By Claude on 06/27/2026
runDnnRemote(clt_parameters, cuasRTUtils, dpixels_log, ts_pyramid, pyramid_levels, c5_levels, curt_save_select, title_conv5d); // By Claude on 06/20/2026
}
System.out.println(now()+" detectTargets(): done"); // By Claude on 06/11/2026
......
......@@ -466,7 +466,7 @@ public class CuasPoseRT {
/**
* Re-generate per-scene poses against the virtual-center reference, RT-style.
*
* @param clt_parameters processing parameters (uses imp.curt_pose_str threshold,
* @param clt_parameters processing parameters (uses imp.curt.pose_str threshold,
* imp.lma_use_R, LMA/offset limits as the offline flow)
* @param center_CLT virtual-center reference: must have CenterClt (fclt) and
* the final combo DSI restored
......@@ -480,7 +480,7 @@ public class CuasPoseRT {
final QuadCLT center_CLT,
final QuadCLT [] quadCLTs,
final int debugLevel) {
final double min_str = clt_parameters.imp.curt_pose_str; // e.g. 1.0
final double min_str = clt_parameters.imp.curt.pose_str; // e.g. 1.0
final boolean use_lma_dsi = clt_parameters.imp.use_lma_dsi;
final int margin = clt_parameters.imp.margin;
final double mb_tau = clt_parameters.imp.mb_tau;
......@@ -530,9 +530,9 @@ public class CuasPoseRT {
// rank-N budget) and AND with the strength mask - a filtered run. Otherwise run FULL
// (all strength-selected tiles) and generate the calibration at the end.
boolean full_selection = true; // the tile calibration is (re)saved only from a full-selection run
ImagePlus imp_max = clt_parameters.imp.curt_pose_recalc ? null :
ImagePlus imp_max = clt_parameters.imp.curt.pose_recalc ? null :
center_CLT.readImagePlusFromModelDirectory(TILE_CALIB_SUFFIX);
if ((imp_max == null) && !clt_parameters.imp.curt_pose_recalc) { // legacy name fallback
if ((imp_max == null) && !clt_parameters.imp.curt.pose_recalc) { // legacy name fallback
imp_max = center_CLT.readImagePlusFromModelDirectory(TILE_CALIB_SUFFIX_OLD);
}
if (imp_max != null) {
......@@ -540,8 +540,8 @@ public class CuasPoseRT {
final boolean [] filt = deriveSelection(
fmax,
center_CLT.getTilesX(),
clt_parameters.imp.curt_pose_dxy_k,
clt_parameters.imp.curt_pose_num_tiles,
clt_parameters.imp.curt.pose_dxy_k,
clt_parameters.imp.curt.pose_num_tiles,
debugLevel);
int num_filt = 0;
for (int i = 0; i < reliable_ref.length; i++) {
......@@ -553,7 +553,7 @@ public class CuasPoseRT {
num_filt+" tiles (of "+num_reliable+" by strength)");
} else {
System.out.println("CuasPoseRT.testPoseSequence(): "+
(clt_parameters.imp.curt_pose_recalc ? "curt_pose_recalc ON" : TILE_CALIB_SUFFIX+" not found")+
(clt_parameters.imp.curt.pose_recalc ? "curt_pose_recalc ON" : TILE_CALIB_SUFFIX+" not found")+
" - FULL run, will generate the calibration");
}
final double [][] pXpYD_center = OpticalFlow.transformToScenePxPyD(
......@@ -620,7 +620,7 @@ public class CuasPoseRT {
}
// Phase B lean engine (curt_pose_lean): ImageDtt instance for the convert stage,
// created once (mirrors interCorrPair's construction)
final ImageDtt image_dtt_lean = clt_parameters.imp.curt_pose_lean ? new ImageDtt(
final ImageDtt image_dtt_lean = clt_parameters.imp.curt.pose_lean ? new ImageDtt(
center_CLT.getNumSensors(),
clt_parameters.transform_size,
clt_parameters.img_dtt,
......@@ -629,7 +629,7 @@ public class CuasPoseRT {
center_CLT.isLwir(),
clt_parameters.getScaleStrength(center_CLT.isAux()),
center_CLT.getGPU()) : null;
if (clt_parameters.imp.curt_pose_lean) {
if (clt_parameters.imp.curt.pose_lean) {
System.out.println("CuasPoseRT.testPoseSequence(): LEAN measurement engine (phase B): "+
"TD-average(16) x virtual-center single conj-multiply. NOTE: no MB compensation "+
"in lean v1 - compare against the NOMB baseline");
......@@ -666,7 +666,7 @@ public class CuasPoseRT {
// the upload alive through interCorrPair's own setBayerImages(false).
// A2 results legitimately diverge from phase A (cleaner input) - judge by own
// dstored quality. By Claude on 07/05/2026, from Andrey's design.
if (clt_parameters.imp.curt_pose_raw) {
if (clt_parameters.imp.curt.pose_raw) {
final boolean raw_ok = CuasConditioning.conditionSceneToGpu(
quadCLTs[nscene], // QuadCLT scene (jp4 + calibration + FPN)
null, // Config (defaults: rowcol + photometric + FPN)
......@@ -711,7 +711,7 @@ public class CuasPoseRT {
fail_reason[0] = 0;
final double [][][] coord_motion_rslt = new double [3][][]; // [centers, vector_XYS, eigen] of the last LMA cycle
double [][] pose;
if (clt_parameters.imp.curt_pose_lean) {
if (clt_parameters.imp.curt.pose_lean) {
pose = leanFitScene(
clt_parameters, // CLTParameters clt_parameters,
image_dtt_lean, // ImageDtt image_dtt,
......@@ -882,8 +882,8 @@ public class CuasPoseRT {
final boolean [] keep = deriveSelection(
fmax,
tilesX,
clt_parameters.imp.curt_pose_dxy_k,
clt_parameters.imp.curt_pose_num_tiles,
clt_parameters.imp.curt.pose_dxy_k,
clt_parameters.imp.curt.pose_num_tiles,
debugLevel);
final float [] fkeep = new float [num_pix];
for (int i = 0; i < num_pix; i++) fkeep[i] = keep[i] ? 1.0f : 0.0f;
......
/**
** CuasRtParameters.java - CUAS real-time (curt_*) parameters, extracted from
** IntersceneMatchParameters (2026-07-05) to keep it under the 64KB method-bytecode
** limit and group all curt_* in one navigable place. Held as
** IntersceneMatchParameters.curt; persisted with the same property keys
** (prefix+"curt_"+short) so old .corr-xml files still load. GPLv3 (Elphel norm).
** By Claude on 07/05/2026, from Andrey's design.
*/
package com.elphel.imagej.tileprocessor;
import java.awt.Rectangle;
import java.util.Properties;
import com.elphel.imagej.common.GenericJTabbedDialogMcp;
public class CuasRtParameters {
public boolean en = true; // enable cuas rt calculation (not needed with a separate button)
public boolean calib = false; // first step of the CUAS RT processing flow: per-sensor photometric (re)calibration - fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales, apply + save (reference scene INTERFRAME corr-xml, quadCLT_main -> main config). Bypass when off. // By Claude on 07/03/2026
public boolean cond_test = false; // conditioning/calibration isolation test inside the en branch: build the QuadCLT instances (borrowed calibration) then print per-sensor average spread (CuasMotion.perSensorAveragesFromTD) instead of normal RT detection; well-calibrated -> 16 sensor averages match (spread ~0). // By Claude on 07/01/2026
public boolean pose_test = false; // RT pose-adjustment prototype (phase A) inside the en branch: re-generate per-scene 3-angle poses against the virtual-center reference, ascending, prediction-seeded (CuasPoseRT.testPoseSequence) instead of RT detection; writes -POSE-RT-TEST.csv + fitted-vs-stored summary. // By Claude on 07/03/2026
public double pose_str = 1.0; // reliable-tile strength threshold over the combo-DSI strength for the pose test tile selection (1.0 ~ old getReliableTiles population). // By Claude on 07/03/2026
public double pose_dxy_k = 0.75; // tile-selection outlier gate: keep tiles with max-over-scenes residual <= median + k*NMAD of the finite per-tile maxes (scale-free - adapts to footage quality/sequence length; NaN-in-any-scene = +inf, always rejected). <=0 - skip the gate. // By Claude on 07/04/2026
public int pose_num_tiles = 150; // tile-selection compute budget: after the gate, keep this many BEST (smallest max-residual) tiles; threshold-free rank - always yields the best available population. <=0 - no cap. // By Claude on 07/04/2026
public boolean pose_recalc = false; // force a FULL-selection pose run that regenerates the -POSE-RT-TILE-CALIB calibration even if it exists. Default (false): automatic FPN-style reuse - if -POSE-RT-TILE-CALIB exists, derive the selection from it (NMAD gate + rank-N) and use it; if not, run full and generate it. // By Claude on 07/04/2026
public boolean pose_raw = false; // phase A2 ingest: per scene read RAW /jp4/, condition with the current calibration (CuasConditioning: rowcol + photometric + FPN) and FORCE-upload straight to the GPU, bypassing the QuadCLT prepared image_data (which carries the old broken Photogrammetric Calibration). Judge by own dstored quality, not agreement with phase A. // By Claude on 07/05/2026
public boolean pose_lean = false; // phase B measurement engine: TD-average the 16 sensors (CuasTD, CPU bridge) then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen (getMaxXYCmEig) -> 3-angle LMA. All existing GPU kernels. v1: NO motion-blur compensation - compare vs the NOMB baseline. // By Claude on 07/05/2026
public double psf_radius = 1.0; // sensor PSF radius for LoG pre-filter
public double n_sigma = 4.0; // cutoff LoG kernel array, number of sigmas
public int pyramid = 7; // temporal pyramid levels
public int pix_decimate = 1; // decimate pixel resolution
public int vel_decimate = 4; // decimate velocities
public int vel_radius = 5; // velocities radius in decimated samples
public boolean vel_thresh_en = true; // zero out per-(sub)pixel velocities, if they have stronger neighbors in 4D space
public int vel_suppr_rad = 3; // suppress weaker in this radius
public double vel_athresh = 1.0; // absolute threshold: discard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this value
public double vel_rthresh = 0.1; // relative threshold: discard this pixel-velocity if it has immediate neighbor stronger by this value times stronger value
public double vel_dbgmin = 0.0; // For testing recurrent with strong targets, zero out lower values
public double[] temp_weights = {1,1,1,1,1}; // historic weights for 5D convolution ([0] is the latest sample)
public boolean recur_en = true; // enable recurrent accumulation buffer (Layer 2) // By Claude on 06/09/2026
public int recur_period = 4; // time units between buffer updates (= vel_decimate for integer-pixel shifts) // By Claude on 06/09/2026
public double recur_w = 0.25; // measurement weight w: buf = leak*(1-w)*shift(buf) + w*conditioned(meas) // By Claude on 06/09/2026
public double recur_leak = 1.0; // extra decay of the shifted prediction per update (gap decay = leak*(1-w) for fixed w) // By Claude on 06/09/2026
public double recur_wthresh = 0.0; // if >0: adaptive per-pixel weight w_eff=w*tanh(strength/wthresh); 0 - fixed w // By Claude on 06/09/2026
public double recur_spread = 0.5; // predict-step velocity diffusion: 3-tap (spread,1,spread) normalized, lets the max migrate between velocity cells; <=0 - off // By Claude on 06/10/2026
public int recur_max_clust = 5; // max 4D-connected survivor cluster size treated as one target (half-cosine bump fit); larger - linear pass-through // By Claude on 06/10/2026
public double recur_fit_rat = 2.0; // max disagreement of per-survivor peak estimates (max/min) for the bump fit; failed fit - per-survivor single-point bumps // By Claude on 06/10/2026
public double recur_rs_frac = 0.5; // re-sharpen blob growth threshold as fraction of the blob max; <=0 - re-sharpening off // By Claude on 06/10/2026
public double recur_rs_min = 1.0; // re-sharpen minimal blob maximum to re-fit; weaker content passes through as residue // By Claude on 06/10/2026
public int [] c5_levels = {}; // pyramid levels to process (empty - all); skips the heavy DNN front-end on others; retained as the DNN level gate // By Claude on 06/13/2026
public String dnn_model = ""; // C5P DNN front-end model (ONNX): empty = disabled; local path, scp user@host:path, or http(s) URL fetched to cache; overrides bundled resource (mirrors tile_processor_gpu) // By Claude on 06/13/2026
public String stage2_model = ""; // C5P DNN v2 Stage-2 (learned Hough-vote refine) ONNX: empty = Stage-1 reg field only; when set + a reg Stage-1 model, the reg branch votes (tail T=P-V*(N-1), s^2-weighted) + refines -> saves -VOTE heatmap + -REFINED detection views. By Claude on 06/18/2026
public double dnn_thresh = 0.0; // VISUALIZATION-ONLY s-threshold: NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 / the recurrent (always full field) nor the -RECT/-HYPER-RECT data - do NOT use for critical computation. // By Claude on 06/13/2026, viz-only 06/20/2026
public int dnn_stride = 1; // DNN temporal output stride (per pyramid-level slice): 1 = every step (testing, watch each temporal unit); 4 = production (50% overlap, matches the convolver's integer-pixel-shift cadence = recur_period) // By Claude on 06/14/2026
public double dnn_vmax = 1.4; // "ghostbuster": trained DNN velocity limit (px/frame); zero velocity-grid cells beyond this radius (cell-R > vmax*vel_decimate) and discard pixels whose peak lands there (s=0) - the untrained corner cells emit spurious sidelobes that would confuse the recurrent. Set to match the loaded model's training vmax_px (PM models=1.4, base=1.0); <=0 disables // By Claude on 06/15/2026
public int dnn_patch = 24; // DNN receptive-field / training patch size (px): inferROI extracts this PxP patch per ROI pixel (half=P/2 = the output pixel). MUST match the loaded model (24 = base/PM models, 32 = larger-attention model) // By Claude on 06/16/2026
public boolean dnn_remote = false; // run the DNN front-end on the remote DGX server (CuasDnnRemote) instead of local CPU ORT: upload the conditioned stack once, DGX builds the pyramid + full-res shift-and-stitch, returns full-frame {dx,dy,s,Vx,Vy} (-OFFSET) + ROI 121-cell softmax*s (-RECT/-HYPER-RECT). Local CPU path + recurrent feed untouched when off. // By Claude on 06/20/2026
public String dnn_remote_host = "192.168.0.62:5577"; // DGX inference server host:port for dnn_remote (see attic/imagej-elphel-internal/c5p_dnn/infer_server.py) // By Claude on 06/20/2026
public String dnn_remote_model = "runs/weighted9_pm_s"; // DGX-side run dir (with model.pt) the auto-launched server loads (passed as RUN=) // By Claude on 06/20/2026
public String dnn_remote_srcdir = ""; // server-scripts override dir: empty = bundled jar resource (cuas_dnn/), set = local dir - same default-vs-override scheme as the GPU kernels (cuda_project_directory) // By Claude on 06/20/2026
public boolean dnn_local = false; // run the DNN front-end in-process via native LibTorch (CuasDnnLocal/libtpdnn.so) instead of the remote Python server - identical L1+L2 result, no DGX/server. Overrides dnn_remote when set. // By Claude on 06/27/2026
public String dnn_local_dir = ""; // override dir holding <model>/model.ts.pt (+.meta.json) for dnn_local: empty = bundled jar resource (cuas_dnn/) - same default-vs-override scheme as the kernels. // By Claude on 06/27/2026
public boolean dnn_l2 = false; // run the trained Layer-2 (track-before-detect ConvGRU) on the DGX after L1: -OFFSET then carries L2 {det,Vx,Vy} (L1's full-res, NON-ghostbusted field fed in, recurrence over the scene/time axis). Off = L1 offset5 as before (re-run with this off to inspect L1). Requires dnn_remote. // By Claude on 06/22/2026
public String dnn_l2_model = "runs/l2_v1"; // DGX-side Layer-2 run dir (with model.pt) the auto-launched server loads (passed as RUN2=) // By Claude on 06/22/2026
public boolean dnn_recur_splat = false; // when feeding the DNN field to the recurrent layer: false = feed per-pixel field as-is; true = splat each pixel's velocity vector to its fractional offset (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin // By Claude on 06/14/2026
public double dnn_recur_scale = 10.0; // multiply the DNN field (softmax*s, peaks ~0.1) by this before the recurrent feed, to reach the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Alternative to lowering recur_rs_min // By Claude on 06/14/2026
public boolean synth_src = true; // default set for the synthetic B-measurement experiment (set false for real-data runs); reads *-CUAS-SYNTHETIC-CUAS.tiff, output titles get -SYNTH // By Claude on 06/12/2026
public double synth_scale = 5.0; // synthetic target peak, counts (synthetic file is peak-1 normalized; scaled at load) // By Claude on 06/12/2026
public int synth_bg_avg = 1; // synth quick-run: average this many real frames per output frame (=2^LEV noise floor, e.g. 8=LEV3) + force single level; 1=off // By Claude on 06/20/2026
public boolean synth_bg = true; // add the real *-CUAS-MERGED-CUAS.tiff scene under the synthetic targets (label-matched frames); false - clean targets only // By Claude on 06/12/2026
public boolean subtract_avg = false; // subtract the input temporal average (over the whole sequence) before LoG - removes static background (treeline edge -> kills its tile-grid streak); moving targets survive. NOTE: uses the whole sequence (not realtime); realtime would use a prior-run average // By Claude on 06/14/2026
public double min_frac = 0.0; // default 0 for linear synthetic/B runs (production value ~0.1); zeroes conv5d outputs where the newest frame contributes less than this fraction (NONLINEAR dark-frame gate) // By Claude on 06/12/2026
public boolean save_c5full = false; // save fine velocities [direction][scene][subpixels]
public boolean save_c5rect = true; // save fine velocities for selected rectangle only [scene][flattened image]
public boolean save_c5hyper = true; // save per-velocity HYPER-RECT hyperstacks (bottom slider=velocity, second=time) for C5P and posterior outputs - watch a low-SNR target evolve at fixed velocity // By Claude on 06/13/2026
public Rectangle save_select = new Rectangle(98, 265, 82, 24); // Example selection for 1773135527_803834
public double time_from = -1.0; // timing ROI start (timestamp seconds): <=0 open; 0<v<10000 = last-4 of seconds (expanded from the file's range, rollover-aware); >=10000 explicit. Clips saved RECT/HYPER/DNN/C5P stacks to the time window // By Claude on 06/14/2026
public double time_to = -1.0; // timing ROI end (timestamp seconds): same convention as time_from; the whole 'to' second is included // By Claude on 06/14/2026
public void dialogQuestions(GenericJTabbedDialogMcp gd) {
gd.addCheckbox ("CUAS realtime enable", this.en,
"Enable testing of the realtime CUAS detection.");
gd.addCheckbox ("CUAS RT photometric calibration", this.calib, // By Claude on 07/03/2026
"First step of the RT processing flow: per-sensor photometric (re)calibration - fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales, apply and save (reference scene INTERFRAME corr-xml, quadCLT_main for the main configuration). Bypass when off.");
gd.addCheckbox ("CUAS RT conditioning test", this.cond_test,
"Isolation test inside the en branch: build QuadCLT instances (borrowed calibration), then print per-sensor average spread (CuasMotion.perSensorAveragesFromTD) instead of normal RT detection. Well-calibrated -> the 16 sensor averages match (spread ~0).");
gd.addCheckbox ("CUAS RT pose test", this.pose_test, // By Claude on 07/03/2026
"RT pose-adjustment prototype (phase A): re-generate per-scene 3-angle poses against the virtual-center reference (ascending, prediction-seeded) instead of RT detection. Writes -POSE-RT-TEST.csv and a fitted-vs-stored summary.");
gd.addNumericField("Pose test reliable strength", this.pose_str, 5,7,"", // By Claude on 07/03/2026
"Tile selection for the pose test: combo-DSI strength threshold (1.0 gives ~ the old getReliableTiles population).");
gd.addNumericField("Pose test outlier gate k (NMAD)", this.pose_dxy_k, 5,7,"", // By Claude on 07/04/2026
"Keep tiles with max-over-scenes residual <= median + k*NMAD of finite per-tile maxes (scale-free; NaN in any scene always rejected). <=0 - skip the gate.");
gd.addNumericField("Pose test number of best tiles", this.pose_num_tiles, 0,7,"", // By Claude on 07/04/2026
"After the gate keep this many best (smallest max-residual) tiles - the RT compute budget. <=0 - no cap.");
gd.addCheckbox ("Pose test force recalc calibration", this.pose_recalc, // By Claude on 07/04/2026
"Force a FULL pose run that regenerates -POSE-RT-TILE-CALIB even if it exists. Default OFF = automatic reuse: use the calibration if present (filtered run), else run full and generate it.");
gd.addCheckbox ("Pose test raw-jp4 ingest (A2)", this.pose_raw, // By Claude on 07/05/2026
"Per scene: read RAW /jp4/, condition with the CURRENT calibration (rowcol+photometric+FPN, CuasConditioning) and force-upload straight to the GPU, bypassing the prepared image_data (old broken Photogrammetric Calibration).");
gd.addCheckbox ("Pose test lean correlation (B)", this.pose_lean, // By Claude on 07/05/2026
"Phase B measurement: TD-average the 16 sensors, then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen -> 3-angle LMA. v1 has NO motion-blur compensation (compare vs the NOMB baseline).");
gd.addMessage("=== LoG prefilter ===");
gd.addNumericField("Optical PSF radius", this.psf_radius, 6,8,"pix",
"Sensor optical PSF radius for the LoG pre-filter.");
gd.addNumericField("N-sigmas for LoG cutoff", this.n_sigma, 6,8,"x",
"Cutoff LoG kernel array, number of sigmas.");
// rleak0 dialog field removed 2026-06-20 (LReLU conditioning now LINEAR, alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addMessage("=== Temporal binary pyramid ===");
gd.addNumericField("Temporal pyramid levels", this.pyramid, 0,3,"",
"Number of binary temporal pyramid levels.");
// rleak_pyr dialog field removed 2026-06-20 (pyramid averaging now LINEAR, alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addMessage("=== Fine velocities layer ===");
gd.addNumericField("Pixel decimate", this.pix_decimate, 0,3,"",
"Decimate pixels (increase resolution).");
gd.addNumericField("Velocity decimate", this.vel_decimate, 0,3,"",
"Decimate velocities (increase velocity resolution).");
gd.addNumericField("Velocities radius", this.vel_radius, 0,3,"",
"Velocities radius in decimated samples.");
gd.addCheckbox ("Filter by stronger 4d space neighbors", this.vel_thresh_en,
"Zero-out velocity components if they have stronger neighbors");
gd.addNumericField("Velocities suppress radius", this.vel_suppr_rad, 0,3,"",
"Suppress weaker in this radius.");
gd.addNumericField("Absolute threshold", this.vel_athresh, 6,8,"",
"Discard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this valuediscard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this value.");
gd.addNumericField("Relative thershold", this.vel_rthresh, 6,8,"",
"Discard this pixel-velocity if it has immediate neighbor stronger by this value times stronger value.");
gd.addNumericField("Remove weaker velocities", this.vel_dbgmin, 6,8,"",
"Debug feature for testing recurrent with strong targets - zero out weaker (set 10.0).");
gd.addStringField ("Historic weight for 5D convolution", IntersceneMatchParameters.doublesToString(temp_weights), 80,
"Historic weights for 5D convolution ([0] is the latest sample). Will be normalized");
gd.addMessage("=== Layer 2 recurrent accumulation buffer ==="); // By Claude on 06/09/2026
gd.addCheckbox ("Enable recurrent buffer", this.recur_en, // By Claude on 06/09/2026
"Maintain a recurrent 4D (pixel, velocity) accumulation buffer over the selected rectangle."); // By Claude on 06/09/2026
gd.addNumericField("Update period", this.recur_period, 0,3,"time units", // By Claude on 06/09/2026
"Time units between buffer updates. Equal to velocity decimation for integer-pixel shifts (1 px per minimum velocity)."); // By Claude on 06/09/2026
gd.addNumericField("Measurement weight", this.recur_w, 6,8,"", // By Claude on 06/09/2026
"Update rule: buf = leak*(1-w)*shift(buf) + w*conditioned(measurement). Gap decay = leak*(1-w) with fixed w."); // By Claude on 06/09/2026
gd.addNumericField("Prediction leak", this.recur_leak, 6,8,"", // By Claude on 06/09/2026
"Extra decay of the velocity-shifted prediction per update. Keep leak^n_gap >= 0.2-0.3 for expected dark gaps."); // By Claude on 06/09/2026
gd.addNumericField("Adaptive weight threshold", this.recur_wthresh, 6,8,"", // By Claude on 06/09/2026
"If >0: per-pixel adaptive weight w_eff = w*tanh(strength/wthresh), dark frames give w_eff~0 (pure prediction). 0 - fixed w."); // By Claude on 06/09/2026
gd.addNumericField("Velocity diffusion weight", this.recur_spread, 6,8,"", // By Claude on 06/10/2026
"Predict-step process noise: 3-tap (spread,1,spread) normalized diffusion over vx,vy after the shift. Lets the buffer maximum migrate between velocity cells (half-grid velocities). <=0 - off."); // By Claude on 06/10/2026
gd.addNumericField("Max target cluster size", this.recur_max_clust, 0,3,"", // By Claude on 06/09/2026
"Survivor clusters up to this size are one target: fit a 4D half-cosine bump (3-pix half-period, half-pixel-grid center) and inject its full grid sampling. Larger clusters (weak linear signal) pass through unchanged."); // By Claude on 06/10/2026
gd.addNumericField("Bump fit max peak ratio", this.recur_fit_rat, 6,8,"", // By Claude on 06/10/2026
"Reject the single-bump fit when per-survivor peak estimates (value/model_weight) disagree by more than this ratio; then each survivor injects its own single-point bump."); // By Claude on 06/10/2026
gd.addNumericField("Re-sharpen blob threshold fraction", this.recur_rs_frac, 6,8,"", // By Claude on 06/10/2026
"After merging the measurement, peel buffer blobs (4D-connected cells above this fraction of the blob max) and re-fit each as a canonical half-cosine at its fractional centroid, conserving total energy. <=0 - off."); // By Claude on 06/10/2026
gd.addNumericField("Re-sharpen min blob max", this.recur_rs_min, 6,8,"", // By Claude on 06/10/2026
"Stop peeling when the strongest remaining cell is below this (filter-output units); sub-threshold residue passes through unchanged."); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening dialog fields removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addStringField ("C5P/DNN pyramid levels", IntersceneMatchParameters.intsToString(this.c5_levels), 40, // By Claude on 06/13/2026
"Process the DNN front-end only on these pyramid levels (space/comma separated, e.g. \"2 3\"). Empty - all levels. Skips the heavy work on others - main speedup. Pyramid frames still build for all levels up to the max selected."); // By Claude on 06/13/2026
gd.addStringField ("C5P DNN model (ONNX)", this.dnn_model, 60, // By Claude on 06/13/2026
"Trained DNN front-end model location. Empty = disabled (use matched-filter/posterior path). Local path, scp user@host:/path (fetched to cache), or http(s) URL. Overrides any bundled resource - same default-vs-override scheme as the GPU kernel sources."); // By Claude on 06/13/2026
gd.addStringField ("C5P Stage-2 vote-refine (ONNX)", this.stage2_model, 60, // By Claude on 06/18/2026
"v2 Stage-2 learned Hough-vote refine model. Empty = Stage-1 reg field only. When set (with a reg Stage-1 model) the reg branch adds the vote heatmap (-VOTE) and refined detection (-REFINED) views.");
gd.addCheckbox ("DNN remote (run on DGX)", this.dnn_remote, // grouped with the model fields // By Claude on 06/20/2026
"Run the DNN on the remote DGX inference server instead of local CPU: upload the conditioned stack once, the DGX builds the pyramid + full-res shift-and-stitch, returns full-frame {dx,dy,s,Vx,Vy} (-OFFSET) and ROI 121-cell softmax*s (-RECT/-HYPER-RECT). Local CPU path (+ recurrent feed) used when off."); // By Claude on 06/20/2026
gd.addStringField ("DNN remote host:port", this.dnn_remote_host, 24, // By Claude on 06/20/2026
"DGX inference server address for 'DNN remote' (default 192.168.0.62:5577)."); // By Claude on 06/20/2026
gd.addStringField ("DNN remote model (DGX run dir)", this.dnn_remote_model, 24, // By Claude on 06/20/2026
"DGX-side run directory (containing model.pt) the auto-launched server loads, e.g. runs/weighted9_pm_s.");
gd.addStringField ("DNN remote server src (empty=bundled)", this.dnn_remote_srcdir, 40, // By Claude on 06/20/2026
"Override dir for the DGX server scripts (infer_server.py / run_infer_server.sh): empty = bundled jar resource (cuas_dnn/); set = local dir. Same default-vs-override (bundled resource vs local repo) scheme as the GPU kernels - bundled is the working version, refresh it after server-script dev.");
gd.addCheckbox ("DNN local (in-process LibTorch)", this.dnn_local, // By Claude on 06/27/2026
"Run the DNN front-end in-process via native LibTorch (libtpdnn.so / JNA) instead of the remote Python server - identical L1+L2 result, no DGX/server. When set, overrides 'DNN remote'. Needs -Djna.library.path pointing at libtpdnn.so.");
gd.addStringField ("DNN local model dir (empty=bundled)", this.dnn_local_dir, 40, // By Claude on 06/27/2026
"Override dir holding <model>/model.ts.pt (+ .meta.json) for 'DNN local': empty = bundled jar resource (cuas_dnn/). Same default-vs-override scheme as the kernels. Uses the same model names as the remote fields.");
gd.addCheckbox ("DNN Layer-2 (run on DGX)", this.dnn_l2, // By Claude on 06/22/2026
"Run the trained Layer-2 track-before-detect ConvGRU on the DGX after L1 (requires 'DNN remote'). -OFFSET then shows L2 {det,Vx,Vy} (L1's full-res non-ghostbusted field fed in, recurrence over time), titled -DNN-L2-. Uncheck to re-run the old L1 way."); // By Claude on 06/22/2026
gd.addStringField ("DNN Layer-2 model (DGX run dir)", this.dnn_l2_model, 24, // By Claude on 06/22/2026
"DGX-side Layer-2 run directory (containing model.pt) the auto-launched server loads as RUN2=, e.g. runs/l2_v1.");
gd.addNumericField("DNN s-threshold (VIZ ONLY)", this.dnn_thresh, 6,8,"", // By Claude on 06/13/2026, viz-only 06/20/2026
"VISUALIZATION ONLY - NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 (the recurrent always sees the full field) nor the -RECT/-HYPER-RECT data. Do NOT use for critical computation - it is a display mask.");
gd.addCheckbox ("DNN recurrent feed: offset-splat", this.dnn_recur_splat, // By Claude on 06/14/2026
"Feeding the DNN field to the recurrent layer: unchecked = feed per-pixel field as-is; checked = splat each pixel to its fractional (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin. Output gets a -SPLAT mark."); // By Claude on 06/14/2026
gd.addNumericField("DNN recurrent feed scale", this.dnn_recur_scale, 4,8,"", // By Claude on 06/14/2026
"Multiply the DNN field (peaks ~0.1) by this before the recurrent feed so it reaches the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Set 1 and instead lower recur_rs_min if you prefer."); // By Claude on 06/14/2026
gd.addNumericField("DNN ghostbuster vmax", this.dnn_vmax, 4,8,"pix/frame", // By Claude on 06/15/2026
"Zero DNN velocities beyond this radius (untrained corner cells) and discard pixels peaking there (s=0); match the model's training vmax_px (PM=1.4, base=1.0); <=0 disables.");
// dnn_t8frac dialog field removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addNumericField("DNN patch size (RF)", this.dnn_patch, 0,3,"pix", // By Claude on 06/16/2026
"Receptive-field / training patch the model was built at (24 = base/PM, 32 = larger-attention). MUST match the loaded model.");
gd.addNumericField("DNN temporal stride", this.dnn_stride, 0,3,"slices", // By Claude on 06/14/2026
"DNN output stride along the pyramid-level time axis: 1 = a fresh inference at every slice (testing, watch each temporal step); 4 = production (50% overlap of the window, matches the convolver's integer-pixel-shift cadence)."); // By Claude on 06/14/2026
gd.addCheckbox ("Use synthetic input", this.synth_src, // By Claude on 06/11/2026
"Read *-CUAS-SYNTHETIC-CUAS.tiff (generated test targets) instead of *-CUAS-MERGED-CUAS.tiff from the same model directory; all output titles get a -SYNTH mark."); // By Claude on 06/11/2026
gd.addNumericField("Synthetic target peak", this.synth_scale, 6,8,"counts", // By Claude on 06/12/2026
"Scale applied to the (peak-1 normalized) synthetic targets at load = target peak in counts. Reference: birds ~3, background sigma ~1.7, strong targets >30."); // By Claude on 06/12/2026
gd.addNumericField("Synthetic bg frame averaging", this.synth_bg_avg, 0,3,"frames", // By Claude on 06/20/2026
"Synth quick-run: average this many consecutive REAL frames per output frame (LEV noise floor = 2^LEV: 2=LEV1, 4=LEV2, 8=LEV3) and force a single level. 1 = off (full pyramid)."); // By Claude on 06/20/2026
gd.addCheckbox ("Subtract input temporal average", this.subtract_avg, // By Claude on 06/14/2026
"Subtract the per-pixel temporal average of the input (whole sequence) before LoG. Removes the static treeline edge and its tile-grid streak; moving targets are not in the average so they survive. Uses the whole sequence (not realtime - realtime would use a prior-run average)."); // By Claude on 06/14/2026
gd.addCheckbox ("Synthetic over real background", this.synth_bg, // By Claude on 06/12/2026
"Add the real *-CUAS-MERGED-CUAS.tiff scene under the scaled synthetic targets (frames matched by timestamp label). Unchecked - clean targets on zero background (linear B measurement)."); // By Claude on 06/12/2026
gd.addNumericField("Min newest-frame fraction", this.min_frac, 6,8,"", // By Claude on 06/12/2026
"Zero fine-velocity outputs where the newest frame contributes less than this fraction of the accumulated response (dark-frame feedforward gate). NONLINEAR - punches holes into ridge maxima; set 0 for linear/synthetic B-measurement runs."); // By Claude on 06/12/2026
gd.addMessage("=== Debug, saving images ===");
gd.addCheckbox ("Save full velocities hyperstack", this.save_c5full,
"Save fine velocities [direction][scene][subpixels].");
gd.addCheckbox ("Save velocities for rectangle", this.save_c5rect,
"Save fine velocities for selected rectangle only [scene][flattened image].");
gd.addCheckbox ("Save per-velocity hyperstacks", this.save_c5hyper, // By Claude on 06/13/2026
"HYPER-RECT views (bottom slider = velocity, second slider/scrollwheel = time) for the C5P output and one per posterior lambda - watch a low-SNR target evolve at a fixed velocity."); // By Claude on 06/13/2026
gd.addStringField ("Output selection Rectangle", IntersceneMatchParameters.rectangleToString(save_select), 40, "Selection Rectangle:left, top, width,height");
gd.addNumericField("Time ROI from (s)", this.time_from, 3,12,"s", // 3 decimals (fixed) - stable round-trip on OK // By Claude on 06/14/2026
"Timing ROI start: clips saved RECT/HYPER/DNN/C5P stacks to this time window. -1 = open. Convenience: enter the last 4 digits of the seconds (0<v<10000) and the high digits are guessed from the file's timestamp range (rollover-aware); >=10000 = explicit seconds."); // By Claude on 06/14/2026
gd.addNumericField("Time ROI to (s)", this.time_to, 3,12,"s", // 3 decimals (fixed) - stable round-trip on OK // By Claude on 06/14/2026
"Timing ROI end: same convention as 'from'. The whole 'to' second is included. -1 = open."); // By Claude on 06/14/2026
}
public void dialogAnswers(GenericJTabbedDialogMcp gd) {
this.en = gd.getNextBoolean();
this.calib = gd.getNextBoolean(); // By Claude on 07/03/2026
this.cond_test = gd.getNextBoolean();
this.pose_test = gd.getNextBoolean(); // By Claude on 07/03/2026
this.pose_str = gd.getNextNumber(); // By Claude on 07/03/2026
this.pose_dxy_k = gd.getNextNumber(); // By Claude on 07/04/2026
this.pose_num_tiles =(int) gd.getNextNumber(); // By Claude on 07/04/2026
this.pose_recalc = gd.getNextBoolean(); // By Claude on 07/04/2026
this.pose_raw = gd.getNextBoolean(); // By Claude on 07/05/2026
this.pose_lean = gd.getNextBoolean(); // By Claude on 07/05/2026
this.psf_radius = gd.getNextNumber();
this.n_sigma = gd.getNextNumber();
// rleak0 getNext removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.pyramid = (int) gd.getNextNumber();
// rleak_pyr getNext removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.pix_decimate = (int) gd.getNextNumber();
this.vel_decimate = (int) gd.getNextNumber();
this.vel_radius = (int) gd.getNextNumber();
this.vel_thresh_en = gd.getNextBoolean();
this.vel_suppr_rad = (int) gd.getNextNumber();
this.vel_athresh = gd.getNextNumber();
this.vel_rthresh = gd.getNextNumber();
this.vel_dbgmin = gd.getNextNumber();
this.temp_weights = IntersceneMatchParameters.StringToDoubles(gd.getNextString(), 0);
this.recur_en = gd.getNextBoolean(); // By Claude on 06/09/2026
this.recur_period = (int) gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_w = gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_leak = gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_wthresh = gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_spread = gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_max_clust=(int) gd.getNextNumber(); // By Claude on 06/09/2026
this.recur_fit_rat = gd.getNextNumber(); // By Claude on 06/10/2026
this.recur_rs_frac = gd.getNextNumber(); // By Claude on 06/10/2026
this.recur_rs_min = gd.getNextNumber(); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening getNext* removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.c5_levels = IntersceneMatchParameters.StringToInts(gd.getNextString()); // By Claude on 06/13/2026
this.dnn_model = gd.getNextString().trim(); // By Claude on 06/13/2026
this.stage2_model = gd.getNextString().trim(); // By Claude on 06/18/2026
this.dnn_remote = gd.getNextBoolean(); // grouped with the model fields // By Claude on 06/20/2026
this.dnn_remote_host = gd.getNextString().trim(); // By Claude on 06/20/2026
this.dnn_remote_model = gd.getNextString().trim(); // By Claude on 06/20/2026
this.dnn_remote_srcdir = gd.getNextString().trim(); // By Claude on 06/20/2026
this.dnn_local = gd.getNextBoolean(); // By Claude on 06/27/2026
this.dnn_local_dir = gd.getNextString().trim(); // By Claude on 06/27/2026
this.dnn_l2 = gd.getNextBoolean(); // By Claude on 06/22/2026
this.dnn_l2_model = gd.getNextString().trim(); // By Claude on 06/22/2026
this.dnn_thresh = gd.getNextNumber(); // By Claude on 06/13/2026
this.dnn_recur_splat = gd.getNextBoolean(); // By Claude on 06/14/2026
this.dnn_recur_scale = gd.getNextNumber(); // By Claude on 06/14/2026
this.dnn_vmax = gd.getNextNumber(); // By Claude on 06/15/2026
// dnn_t8frac getNext removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.dnn_patch = (int) gd.getNextNumber(); // By Claude on 06/16/2026
this.dnn_stride = (int) gd.getNextNumber(); // By Claude on 06/14/2026
this.synth_src = gd.getNextBoolean(); // By Claude on 06/11/2026
this.synth_scale = gd.getNextNumber(); // By Claude on 06/12/2026
this.synth_bg_avg = (int) gd.getNextNumber(); // By Claude on 06/20/2026
this.subtract_avg = gd.getNextBoolean(); // By Claude on 06/14/2026
this.synth_bg = gd.getNextBoolean(); // By Claude on 06/12/2026
this.min_frac = gd.getNextNumber(); // By Claude on 06/12/2026
this.save_c5full = gd.getNextBoolean();
this.save_c5rect = gd.getNextBoolean();
this.save_c5hyper = gd.getNextBoolean(); // By Claude on 06/13/2026
this.save_select = IntersceneMatchParameters.stringToRectangle(gd.getNextString());// Rectangle
this.time_from = gd.getNextNumber(); // By Claude on 06/14/2026
this.time_to = gd.getNextNumber(); // By Claude on 06/14/2026
}
public void setProperties(String prefix, Properties properties){
properties.setProperty(prefix+"en", this.en+""); // boolean
properties.setProperty(prefix+"calib", this.calib+""); // boolean // By Claude on 07/03/2026
properties.setProperty(prefix+"cond_test", this.cond_test+""); // boolean
properties.setProperty(prefix+"pose_test", this.pose_test+""); // boolean // By Claude on 07/03/2026
properties.setProperty(prefix+"pose_str", this.pose_str+""); // double // By Claude on 07/03/2026
properties.setProperty(prefix+"pose_dxy_k", this.pose_dxy_k+""); // double // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_num_tiles", this.pose_num_tiles+""); // int // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_recalc", this.pose_recalc+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_raw", this.pose_raw+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"pose_lean", this.pose_lean+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"psf_radius", this.psf_radius+""); // double
properties.setProperty(prefix+"n_sigma", this.n_sigma+""); // double
// rleak0 setProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"pyramid", this.pyramid+""); // int
// rleak_pyr setProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"pix_decimate", this.pix_decimate+""); // int
properties.setProperty(prefix+"vel_decimate", this.vel_decimate+""); // int
properties.setProperty(prefix+"vel_radius", this.vel_radius+""); // int
properties.setProperty(prefix+"vel_thresh_en", this.vel_thresh_en+""); // boolean
properties.setProperty(prefix+"vel_suppr_rad", this.vel_suppr_rad+""); // int
properties.setProperty(prefix+"vel_athresh", this.vel_athresh+""); // double
properties.setProperty(prefix+"vel_rthresh", this.vel_rthresh+""); // double
properties.setProperty(prefix+"vel_dbgmin", this.vel_dbgmin+""); // double
properties.setProperty(prefix+"temp_weights", IntersceneMatchParameters.doublesToString(this.temp_weights));
properties.setProperty(prefix+"recur_en", this.recur_en+""); // boolean // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_period", this.recur_period+""); // int // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_w", this.recur_w+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_leak", this.recur_leak+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_wthresh", this.recur_wthresh+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_spread", this.recur_spread+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_max_clust", this.recur_max_clust+"");// int // By Claude on 06/09/2026
properties.setProperty(prefix+"recur_fit_rat", this.recur_fit_rat+""); // double // By Claude on 06/10/2026
properties.setProperty(prefix+"recur_rs_frac", this.recur_rs_frac+""); // double // By Claude on 06/10/2026
properties.setProperty(prefix+"recur_rs_min", this.recur_rs_min+""); // double // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening setProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"c5_levels", IntersceneMatchParameters.intsToString(this.c5_levels)); // int [] // By Claude on 06/13/2026
properties.setProperty(prefix+"dnn_model", this.dnn_model); // String // By Claude on 06/13/2026
properties.setProperty(prefix+"stage2_model", this.stage2_model); // String // By Claude on 06/18/2026
properties.setProperty(prefix+"dnn_thresh", this.dnn_thresh+""); // double // By Claude on 06/13/2026
properties.setProperty(prefix+"dnn_recur_splat", this.dnn_recur_splat+""); // boolean // By Claude on 06/14/2026
properties.setProperty(prefix+"dnn_recur_scale", this.dnn_recur_scale+""); // double // By Claude on 06/14/2026
properties.setProperty(prefix+"dnn_stride", this.dnn_stride+""); // int // By Claude on 06/14/2026
properties.setProperty(prefix+"dnn_vmax", this.dnn_vmax+""); // double // By Claude on 06/15/2026
// dnn_t8frac setProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"dnn_patch", this.dnn_patch+""); // int // By Claude on 06/16/2026
properties.setProperty(prefix+"dnn_remote", this.dnn_remote+""); // boolean // By Claude on 06/20/2026
properties.setProperty(prefix+"dnn_remote_host", this.dnn_remote_host); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"dnn_remote_model", this.dnn_remote_model); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"dnn_remote_srcdir", this.dnn_remote_srcdir); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"dnn_local", this.dnn_local+""); // boolean // By Claude on 06/27/2026
properties.setProperty(prefix+"dnn_local_dir", this.dnn_local_dir); // String // By Claude on 06/27/2026
properties.setProperty(prefix+"dnn_l2", this.dnn_l2+""); // boolean // By Claude on 06/22/2026
properties.setProperty(prefix+"dnn_l2_model", this.dnn_l2_model); // String // By Claude on 06/22/2026
properties.setProperty(prefix+"synth_src", this.synth_src+""); // boolean // By Claude on 06/11/2026
properties.setProperty(prefix+"synth_scale", this.synth_scale+""); // double // By Claude on 06/12/2026
properties.setProperty(prefix+"synth_bg_avg", this.synth_bg_avg+""); // int // By Claude on 06/20/2026
properties.setProperty(prefix+"subtract_avg", this.subtract_avg+""); // boolean // By Claude on 06/14/2026
properties.setProperty(prefix+"synth_bg", this.synth_bg+""); // boolean // By Claude on 06/12/2026
properties.setProperty(prefix+"min_frac", this.min_frac+""); // double // By Claude on 06/12/2026
properties.setProperty(prefix+"save_c5full", this.save_c5full+""); // boolean
properties.setProperty(prefix+"save_c5rect", this.save_c5rect+""); // boolean
properties.setProperty(prefix+"save_c5hyper", this.save_c5hyper+""); // boolean // By Claude on 06/13/2026
properties.setProperty(prefix+"save_select", IntersceneMatchParameters.rectangleToString(save_select)+""); // Rectangle
properties.setProperty(prefix+"time_from", this.time_from+""); // double // By Claude on 06/14/2026
properties.setProperty(prefix+"time_to", this.time_to+""); // double // By Claude on 06/14/2026
}
public void getProperties(String prefix, Properties properties){
if (properties.getProperty(prefix+"en")!=null) this.en=Boolean.parseBoolean(properties.getProperty(prefix+"en"));
if (properties.getProperty(prefix+"calib")!=null) this.calib=Boolean.parseBoolean(properties.getProperty(prefix+"calib")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"cond_test")!=null) this.cond_test=Boolean.parseBoolean(properties.getProperty(prefix+"cond_test"));
if (properties.getProperty(prefix+"pose_test")!=null) this.pose_test=Boolean.parseBoolean(properties.getProperty(prefix+"pose_test")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"pose_str")!=null) this.pose_str=Double.parseDouble(properties.getProperty(prefix+"pose_str")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"pose_dxy_k")!=null) this.pose_dxy_k=Double.parseDouble(properties.getProperty(prefix+"pose_dxy_k")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_num_tiles")!=null) this.pose_num_tiles=Integer.parseInt(properties.getProperty(prefix+"pose_num_tiles")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_recalc")!=null) this.pose_recalc=Boolean.parseBoolean(properties.getProperty(prefix+"pose_recalc")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_raw")!=null) this.pose_raw=Boolean.parseBoolean(properties.getProperty(prefix+"pose_raw")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"pose_lean")!=null) this.pose_lean=Boolean.parseBoolean(properties.getProperty(prefix+"pose_lean")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"psf_radius")!=null) this.psf_radius=Double.parseDouble(properties.getProperty(prefix+"psf_radius"));
if (properties.getProperty(prefix+"n_sigma")!=null) this.n_sigma=Double.parseDouble(properties.getProperty(prefix+"n_sigma"));
// rleak0 getProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"pyramid")!=null) this.pyramid=Integer.parseInt(properties.getProperty(prefix+"pyramid"));
// rleak_pyr getProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"pix_decimate")!=null) this.pix_decimate=Integer.parseInt(properties.getProperty(prefix+"pix_decimate"));
if (properties.getProperty(prefix+"vel_decimate")!=null) this.vel_decimate=Integer.parseInt(properties.getProperty(prefix+"vel_decimate"));
if (properties.getProperty(prefix+"vel_radius")!=null) this.vel_radius=Integer.parseInt(properties.getProperty(prefix+"vel_radius"));
if (properties.getProperty(prefix+"vel_thresh_en")!=null) this.vel_thresh_en=Boolean.parseBoolean(properties.getProperty(prefix+"vel_thresh_en"));
if (properties.getProperty(prefix+"vel_suppr_rad")!=null) this.vel_suppr_rad=Integer.parseInt(properties.getProperty(prefix+"vel_suppr_rad"));
if (properties.getProperty(prefix+"vel_athresh")!=null) this.vel_athresh=Double.parseDouble(properties.getProperty(prefix+"vel_athresh"));
if (properties.getProperty(prefix+"vel_rthresh")!=null) this.vel_rthresh=Double.parseDouble(properties.getProperty(prefix+"vel_rthresh"));
if (properties.getProperty(prefix+"vel_dbgmin")!=null) this.vel_dbgmin=Double.parseDouble(properties.getProperty(prefix+"vel_dbgmin"));
if (properties.getProperty(prefix+"temp_weights")!=null) this.temp_weights= IntersceneMatchParameters.StringToDoubles(properties.getProperty(prefix+"temp_weights"),0); // use 0
if (properties.getProperty(prefix+"recur_en")!=null) this.recur_en=Boolean.parseBoolean(properties.getProperty(prefix+"recur_en")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_period")!=null) this.recur_period=Integer.parseInt(properties.getProperty(prefix+"recur_period")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_w")!=null) this.recur_w=Double.parseDouble(properties.getProperty(prefix+"recur_w")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_leak")!=null) this.recur_leak=Double.parseDouble(properties.getProperty(prefix+"recur_leak")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_wthresh")!=null) this.recur_wthresh=Double.parseDouble(properties.getProperty(prefix+"recur_wthresh")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_spread")!=null) this.recur_spread=Double.parseDouble(properties.getProperty(prefix+"recur_spread")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_max_clust")!=null) this.recur_max_clust=Integer.parseInt(properties.getProperty(prefix+"recur_max_clust")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"recur_fit_rat")!=null) this.recur_fit_rat=Double.parseDouble(properties.getProperty(prefix+"recur_fit_rat")); // By Claude on 06/10/2026
if (properties.getProperty(prefix+"recur_rs_frac")!=null) this.recur_rs_frac=Double.parseDouble(properties.getProperty(prefix+"recur_rs_frac")); // By Claude on 06/10/2026
if (properties.getProperty(prefix+"recur_rs_min")!=null) this.recur_rs_min=Double.parseDouble(properties.getProperty(prefix+"recur_rs_min")); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening getProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"c5_levels")!=null) this.c5_levels= IntersceneMatchParameters.StringToInts(properties.getProperty(prefix+"c5_levels")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"dnn_model")!=null) this.dnn_model=(String) properties.getProperty(prefix+"dnn_model"); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"stage2_model")!=null) this.stage2_model=(String) properties.getProperty(prefix+"stage2_model"); // By Claude on 06/18/2026
if (properties.getProperty(prefix+"dnn_thresh")!=null) this.dnn_thresh=Double.parseDouble(properties.getProperty(prefix+"dnn_thresh")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"dnn_recur_splat")!=null) this.dnn_recur_splat=Boolean.parseBoolean(properties.getProperty(prefix+"dnn_recur_splat")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"dnn_recur_scale")!=null) this.dnn_recur_scale=Double.parseDouble(properties.getProperty(prefix+"dnn_recur_scale")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"dnn_stride")!=null) this.dnn_stride=Integer.parseInt(properties.getProperty(prefix+"dnn_stride")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"dnn_vmax")!=null) this.dnn_vmax=Double.parseDouble(properties.getProperty(prefix+"dnn_vmax")); // By Claude on 06/15/2026
// dnn_t8frac getProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"dnn_patch")!=null) this.dnn_patch=Integer.parseInt(properties.getProperty(prefix+"dnn_patch")); // By Claude on 06/16/2026
if (properties.getProperty(prefix+"dnn_remote")!=null) this.dnn_remote=Boolean.parseBoolean(properties.getProperty(prefix+"dnn_remote")); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"dnn_remote_host")!=null) this.dnn_remote_host=(String) properties.getProperty(prefix+"dnn_remote_host"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"dnn_remote_model")!=null) this.dnn_remote_model=(String) properties.getProperty(prefix+"dnn_remote_model"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"dnn_remote_srcdir")!=null) this.dnn_remote_srcdir=(String) properties.getProperty(prefix+"dnn_remote_srcdir"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"dnn_local")!=null) this.dnn_local=Boolean.parseBoolean(properties.getProperty(prefix+"dnn_local")); // By Claude on 06/27/2026
if (properties.getProperty(prefix+"dnn_local_dir")!=null) this.dnn_local_dir=(String) properties.getProperty(prefix+"dnn_local_dir"); // By Claude on 06/27/2026
if (properties.getProperty(prefix+"dnn_l2")!=null) this.dnn_l2=Boolean.parseBoolean(properties.getProperty(prefix+"dnn_l2")); // By Claude on 06/22/2026
if (properties.getProperty(prefix+"dnn_l2_model")!=null) this.dnn_l2_model=(String) properties.getProperty(prefix+"dnn_l2_model"); // By Claude on 06/22/2026
if (properties.getProperty(prefix+"synth_src")!=null) this.synth_src=Boolean.parseBoolean(properties.getProperty(prefix+"synth_src")); // By Claude on 06/11/2026
if (properties.getProperty(prefix+"synth_scale")!=null) this.synth_scale=Double.parseDouble(properties.getProperty(prefix+"synth_scale")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"synth_bg_avg")!=null) this.synth_bg_avg=Integer.parseInt(properties.getProperty(prefix+"synth_bg_avg")); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"subtract_avg")!=null) this.subtract_avg=Boolean.parseBoolean(properties.getProperty(prefix+"subtract_avg")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"synth_bg")!=null) this.synth_bg=Boolean.parseBoolean(properties.getProperty(prefix+"synth_bg")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"min_frac")!=null) this.min_frac=Double.parseDouble(properties.getProperty(prefix+"min_frac")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"save_c5full")!=null) this.save_c5full=Boolean.parseBoolean(properties.getProperty(prefix+"save_c5full"));
if (properties.getProperty(prefix+"save_c5rect")!=null) this.save_c5rect=Boolean.parseBoolean(properties.getProperty(prefix+"save_c5rect"));
if (properties.getProperty(prefix+"save_c5hyper")!=null) this.save_c5hyper=Boolean.parseBoolean(properties.getProperty(prefix+"save_c5hyper")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"save_select")!=null) this.save_select=IntersceneMatchParameters.stringToRectangle((String) properties.getProperty(prefix+"save_select"));
if (properties.getProperty(prefix+"time_from")!=null) this.time_from=Double.parseDouble(properties.getProperty(prefix+"time_from")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"time_to")!=null) this.time_to=Double.parseDouble(properties.getProperty(prefix+"time_to")); // By Claude on 06/14/2026
}
public CuasRtParameters clone() throws CloneNotSupportedException {
CuasRtParameters cp = new CuasRtParameters();
cp.en = this.en;
cp.calib = this.calib;
cp.cond_test = this.cond_test;
cp.pose_test = this.pose_test;
cp.pose_str = this.pose_str;
cp.pose_dxy_k = this.pose_dxy_k;
cp.pose_num_tiles = this.pose_num_tiles;
cp.pose_recalc = this.pose_recalc;
cp.pose_raw = this.pose_raw;
cp.pose_lean = this.pose_lean;
cp.psf_radius = this.psf_radius;
cp.n_sigma = this.n_sigma;
cp.pyramid = this.pyramid;
cp.pix_decimate = this.pix_decimate;
cp.vel_decimate = this.vel_decimate;
cp.vel_radius = this.vel_radius;
cp.vel_thresh_en = this.vel_thresh_en;
cp.vel_suppr_rad = this.vel_suppr_rad;
cp.vel_athresh = this.vel_athresh;
cp.vel_rthresh = this.vel_rthresh;
cp.vel_dbgmin = this.vel_dbgmin;
cp.temp_weights = (this.temp_weights == null) ? null : this.temp_weights.clone();
cp.recur_en = this.recur_en;
cp.recur_period = this.recur_period;
cp.recur_w = this.recur_w;
cp.recur_leak = this.recur_leak;
cp.recur_wthresh = this.recur_wthresh;
cp.recur_spread = this.recur_spread;
cp.recur_max_clust = this.recur_max_clust;
cp.recur_fit_rat = this.recur_fit_rat;
cp.recur_rs_frac = this.recur_rs_frac;
cp.recur_rs_min = this.recur_rs_min;
cp.c5_levels = (this.c5_levels == null) ? null : this.c5_levels.clone();
cp.dnn_model = this.dnn_model;
cp.stage2_model = this.stage2_model;
cp.dnn_thresh = this.dnn_thresh;
cp.dnn_stride = this.dnn_stride;
cp.dnn_vmax = this.dnn_vmax;
cp.dnn_patch = this.dnn_patch;
cp.dnn_remote = this.dnn_remote;
cp.dnn_remote_host = this.dnn_remote_host;
cp.dnn_remote_model = this.dnn_remote_model;
cp.dnn_remote_srcdir = this.dnn_remote_srcdir;
cp.dnn_local = this.dnn_local;
cp.dnn_local_dir = this.dnn_local_dir;
cp.dnn_l2 = this.dnn_l2;
cp.dnn_l2_model = this.dnn_l2_model;
cp.dnn_recur_splat = this.dnn_recur_splat;
cp.dnn_recur_scale = this.dnn_recur_scale;
cp.synth_src = this.synth_src;
cp.synth_scale = this.synth_scale;
cp.synth_bg_avg = this.synth_bg_avg;
cp.synth_bg = this.synth_bg;
cp.subtract_avg = this.subtract_avg;
cp.min_frac = this.min_frac;
cp.save_c5full = this.save_c5full;
cp.save_c5rect = this.save_c5rect;
cp.save_c5hyper = this.save_c5hyper;
cp.save_select = (this.save_select == null) ? null : new Rectangle(this.save_select);
cp.time_from = this.time_from;
cp.time_to = this.time_to;
return cp;
}
}
......@@ -1124,78 +1124,18 @@ min_str_neib_fpn 0.35
public double cuas_rng_limit = 5000; // maximal displayed distance to target
// CUAS Realtime
public boolean curt_en = true; // enable cuas rt calculation (not needed with a separate button)
public boolean curt_calib = false; // first step of the CUAS RT processing flow: per-sensor photometric (re)calibration - fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales, apply + save (reference scene INTERFRAME corr-xml, quadCLT_main -> main config). Bypass when off. // By Claude on 07/03/2026
public boolean curt_cond_test = false; // conditioning/calibration isolation test inside the curt_en branch: build the QuadCLT instances (borrowed calibration) then print per-sensor average spread (CuasMotion.perSensorAveragesFromTD) instead of normal RT detection; well-calibrated -> 16 sensor averages match (spread ~0). // By Claude on 07/01/2026
public boolean curt_pose_test = false; // RT pose-adjustment prototype (phase A) inside the curt_en branch: re-generate per-scene 3-angle poses against the virtual-center reference, ascending, prediction-seeded (CuasPoseRT.testPoseSequence) instead of RT detection; writes -POSE-RT-TEST.csv + fitted-vs-stored summary. // By Claude on 07/03/2026
public double curt_pose_str = 1.0; // reliable-tile strength threshold over the combo-DSI strength for the pose test tile selection (1.0 ~ old getReliableTiles population). // By Claude on 07/03/2026
public double curt_pose_dxy_k = 0.75; // tile-selection outlier gate: keep tiles with max-over-scenes residual <= median + k*NMAD of the finite per-tile maxes (scale-free - adapts to footage quality/sequence length; NaN-in-any-scene = +inf, always rejected). <=0 - skip the gate. // By Claude on 07/04/2026
public int curt_pose_num_tiles = 150; // tile-selection compute budget: after the gate, keep this many BEST (smallest max-residual) tiles; threshold-free rank - always yields the best available population. <=0 - no cap. // By Claude on 07/04/2026
public boolean curt_pose_recalc = false; // force a FULL-selection pose run that regenerates the -POSE-RT-TILE-CALIB calibration even if it exists. Default (false): automatic FPN-style reuse - if -POSE-RT-TILE-CALIB exists, derive the selection from it (NMAD gate + rank-N) and use it; if not, run full and generate it. // By Claude on 07/04/2026
public boolean curt_pose_raw = false; // phase A2 ingest: per scene read RAW /jp4/, condition with the current calibration (CuasConditioning: rowcol + photometric + FPN) and FORCE-upload straight to the GPU, bypassing the QuadCLT prepared image_data (which carries the old broken Photogrammetric Calibration). Judge by own dstored quality, not agreement with phase A. // By Claude on 07/05/2026
public boolean curt_pose_lean = false; // phase B measurement engine: TD-average the 16 sensors (CuasTD, CPU bridge) then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen (getMaxXYCmEig) -> 3-angle LMA. All existing GPU kernels. v1: NO motion-blur compensation - compare vs the NOMB baseline. // By Claude on 07/05/2026
public CuasRtParameters curt = new CuasRtParameters(); // all curt_* extracted here // By Claude on 07/05/2026
//=== LoG prefilter ===
public double curt_psf_radius = 1.0; // sensor PSF radius for LoG pre-filter
public double curt_n_sigma = 4.0; // cutoff LoG kernel array, number of sigmas
// rleak0 removed 2026-06-20: LReLU conditioning is now LINEAR (alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
//=== Temporal binary pyramid ===
public int curt_pyramid = 7; // temporal pyramid levels
// rleak_pyr removed 2026-06-20: pyramid averaging is now LINEAR (alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// === Fine velocities layer ===
public int curt_pix_decimate = 1; // decimate pixel resolution
public int curt_vel_decimate = 4; // decimate velocities
public int curt_vel_radius = 5; // velocities radius in decimated samples
public boolean curt_vel_thresh_en = true; // zero out per-(sub)pixel velocities, if they have stronger neighbors in 4D space
public int curt_vel_suppr_rad = 3; // suppress weaker in this radius
public double curt_vel_athresh = 1.0; // absolute threshold: discard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this value
public double curt_vel_rthresh = 0.1; // relative threshold: discard this pixel-velocity if it has immediate neighbor stronger by this value times stronger value
public double curt_vel_dbgmin = 0.0; // For testing recurrent with strong targets, zero out lower values
public double[] curt_temp_weights = {1,1,1,1,1}; // historic weights for 5D convolution ([0] is the latest sample)
// === Layer 2 recurrent accumulation buffer === // By Claude on 06/09/2026
public boolean curt_recur_en = true; // enable recurrent accumulation buffer (Layer 2) // By Claude on 06/09/2026
public int curt_recur_period = 4; // time units between buffer updates (= curt_vel_decimate for integer-pixel shifts) // By Claude on 06/09/2026
public double curt_recur_w = 0.25; // measurement weight w: buf = leak*(1-w)*shift(buf) + w*conditioned(meas) // By Claude on 06/09/2026
public double curt_recur_leak = 1.0; // extra decay of the shifted prediction per update (gap decay = leak*(1-w) for fixed w) // By Claude on 06/09/2026
public double curt_recur_wthresh = 0.0; // if >0: adaptive per-pixel weight w_eff=w*tanh(strength/wthresh); 0 - fixed w // By Claude on 06/09/2026
public double curt_recur_spread = 0.5; // predict-step velocity diffusion: 3-tap (spread,1,spread) normalized, lets the max migrate between velocity cells; <=0 - off // By Claude on 06/10/2026
public int curt_recur_max_clust = 5; // max 4D-connected survivor cluster size treated as one target (half-cosine bump fit); larger - linear pass-through // By Claude on 06/10/2026
public double curt_recur_fit_rat = 2.0; // max disagreement of per-survivor peak estimates (max/min) for the bump fit; failed fit - per-survivor single-point bumps // By Claude on 06/10/2026
public double curt_recur_rs_frac = 0.5; // re-sharpen blob growth threshold as fraction of the blob max; <=0 - re-sharpening off // By Claude on 06/10/2026
public double curt_recur_rs_min = 1.0; // re-sharpen minimal blob maximum to re-fit; weaker content passes through as residue // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening (pre-DNN detector alternatives) removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
public int [] curt_c5_levels = {}; // pyramid levels to process (empty - all); skips the heavy DNN front-end on others; retained as the DNN level gate // By Claude on 06/13/2026
public String curt_dnn_model = ""; // C5P DNN front-end model (ONNX): empty = disabled; local path, scp user@host:path, or http(s) URL fetched to cache; overrides bundled resource (mirrors tile_processor_gpu) // By Claude on 06/13/2026
// DEPRECATED 2026-06-20 — may be revisited for Layer 2 // By Claude
public String curt_stage2_model = ""; // C5P DNN v2 Stage-2 (learned Hough-vote refine) ONNX: empty = Stage-1 reg field only; when set + a reg Stage-1 model, the reg branch votes (tail T=P-V*(N-1), s^2-weighted) + refines -> saves -VOTE heatmap + -REFINED detection views. By Claude on 06/18/2026
public double curt_dnn_thresh = 0.0; // VISUALIZATION-ONLY s-threshold: NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 / the recurrent (always full field) nor the -RECT/-HYPER-RECT data - do NOT use for critical computation. // By Claude on 06/13/2026, viz-only 06/20/2026
public int curt_dnn_stride = 1; // DNN temporal output stride (per pyramid-level slice): 1 = every step (testing, watch each temporal unit); 4 = production (50% overlap, matches the convolver's integer-pixel-shift cadence = curt_recur_period) // By Claude on 06/14/2026
public double curt_dnn_vmax = 1.4; // "ghostbuster": trained DNN velocity limit (px/frame); zero velocity-grid cells beyond this radius (cell-R > vmax*vel_decimate) and discard pixels whose peak lands there (s=0) - the untrained corner cells emit spurious sidelobes that would confuse the recurrent. Set to match the loaded model's training vmax_px (PM models=1.4, base=1.0); <=0 disables // By Claude on 06/15/2026
// dnn_t8frac (T-8 ghost filter) removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
public int curt_dnn_patch = 24; // DNN receptive-field / training patch size (px): inferROI extracts this PxP patch per ROI pixel (half=P/2 = the output pixel). MUST match the loaded model (24 = base/PM models, 32 = larger-attention model) // By Claude on 06/16/2026
public boolean curt_dnn_remote = false; // run the DNN front-end on the remote DGX server (CuasDnnRemote) instead of local CPU ORT: upload the conditioned stack once, DGX builds the pyramid + full-res shift-and-stitch, returns full-frame {dx,dy,s,Vx,Vy} (-OFFSET) + ROI 121-cell softmax*s (-RECT/-HYPER-RECT). Local CPU path + recurrent feed untouched when off. // By Claude on 06/20/2026
public String curt_dnn_remote_host = "192.168.0.62:5577"; // DGX inference server host:port for curt_dnn_remote (see attic/imagej-elphel-internal/c5p_dnn/infer_server.py) // By Claude on 06/20/2026
public String curt_dnn_remote_model = "runs/weighted9_pm_s"; // DGX-side run dir (with model.pt) the auto-launched server loads (passed as RUN=) // By Claude on 06/20/2026
public String curt_dnn_remote_srcdir = ""; // server-scripts override dir: empty = bundled jar resource (cuas_dnn/), set = local dir - same default-vs-override scheme as the GPU kernels (cuda_project_directory) // By Claude on 06/20/2026
public boolean curt_dnn_local = false; // run the DNN front-end in-process via native LibTorch (CuasDnnLocal/libtpdnn.so) instead of the remote Python server - identical L1+L2 result, no DGX/server. Overrides curt_dnn_remote when set. // By Claude on 06/27/2026
public String curt_dnn_local_dir = ""; // override dir holding <model>/model.ts.pt (+.meta.json) for curt_dnn_local: empty = bundled jar resource (cuas_dnn/) - same default-vs-override scheme as the kernels. // By Claude on 06/27/2026
public boolean curt_dnn_l2 = false; // run the trained Layer-2 (track-before-detect ConvGRU) on the DGX after L1: -OFFSET then carries L2 {det,Vx,Vy} (L1's full-res, NON-ghostbusted field fed in, recurrence over the scene/time axis). Off = L1 offset5 as before (re-run with this off to inspect L1). Requires curt_dnn_remote. // By Claude on 06/22/2026
public String curt_dnn_l2_model = "runs/l2_v1"; // DGX-side Layer-2 run dir (with model.pt) the auto-launched server loads (passed as RUN2=) // By Claude on 06/22/2026
public boolean curt_dnn_recur_splat = false; // when feeding the DNN field to the recurrent layer: false = feed per-pixel field as-is; true = splat each pixel's velocity vector to its fractional offset (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin // By Claude on 06/14/2026
public double curt_dnn_recur_scale = 10.0; // multiply the DNN field (softmax*s, peaks ~0.1) by this before the recurrent feed, to reach the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Alternative to lowering curt_recur_rs_min // By Claude on 06/14/2026
public boolean curt_synth_src = true; // default set for the synthetic B-measurement experiment (set false for real-data runs); reads *-CUAS-SYNTHETIC-CUAS.tiff, output titles get -SYNTH // By Claude on 06/12/2026
public double curt_synth_scale = 5.0; // synthetic target peak, counts (synthetic file is peak-1 normalized; scaled at load) // By Claude on 06/12/2026
public int curt_synth_bg_avg = 1; // synth quick-run: average this many real frames per output frame (=2^LEV noise floor, e.g. 8=LEV3) + force single level; 1=off // By Claude on 06/20/2026
public boolean curt_synth_bg = true; // add the real *-CUAS-MERGED-CUAS.tiff scene under the synthetic targets (label-matched frames); false - clean targets only // By Claude on 06/12/2026
public boolean curt_subtract_avg = false; // subtract the input temporal average (over the whole sequence) before LoG - removes static background (treeline edge -> kills its tile-grid streak); moving targets survive. NOTE: uses the whole sequence (not realtime); realtime would use a prior-run average // By Claude on 06/14/2026
public double curt_min_frac = 0.0; // default 0 for linear synthetic/B runs (production value ~0.1); zeroes conv5d outputs where the newest frame contributes less than this fraction (NONLINEAR dark-frame gate) // By Claude on 06/12/2026
// debug/saving images
public boolean curt_save_c5full = false; // save fine velocities [direction][scene][subpixels]
public boolean curt_save_c5rect = true; // save fine velocities for selected rectangle only [scene][flattened image]
public boolean curt_save_c5hyper = true; // save per-velocity HYPER-RECT hyperstacks (bottom slider=velocity, second=time) for C5P and posterior outputs - watch a low-SNR target evolve at fixed velocity // By Claude on 06/13/2026
public Rectangle curt_save_select = new Rectangle(98, 265, 82, 24); // Example selection for 1773135527_803834
public double curt_time_from = -1.0; // timing ROI start (timestamp seconds): <=0 open; 0<v<10000 = last-4 of seconds (expanded from the file's range, rollover-aware); >=10000 explicit. Clips saved RECT/HYPER/DNN/C5P stacks to the time window // By Claude on 06/14/2026
public double curt_time_to = -1.0; // timing ROI end (timestamp seconds): same convention as curt_time_from; the whole 'to' second is included // By Claude on 06/14/2026
// Airplane mode
public boolean air_mode_en = false; // enable airplane mode
......@@ -3417,144 +3357,7 @@ min_str_neib_fpn 0.35
"Maximal displayed distance to target.");
gd.addTab("CUAS RT", "CUAS Real Time");
gd.addCheckbox ("CUAS realtime enable", this.curt_en,
"Enable testing of the realtime CUAS detection.");
gd.addCheckbox ("CUAS RT photometric calibration", this.curt_calib, // By Claude on 07/03/2026
"First step of the RT processing flow: per-sensor photometric (re)calibration - fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales, apply and save (reference scene INTERFRAME corr-xml, quadCLT_main for the main configuration). Bypass when off.");
gd.addCheckbox ("CUAS RT conditioning test", this.curt_cond_test,
"Isolation test inside the curt_en branch: build QuadCLT instances (borrowed calibration), then print per-sensor average spread (CuasMotion.perSensorAveragesFromTD) instead of normal RT detection. Well-calibrated -> the 16 sensor averages match (spread ~0).");
gd.addCheckbox ("CUAS RT pose test", this.curt_pose_test, // By Claude on 07/03/2026
"RT pose-adjustment prototype (phase A): re-generate per-scene 3-angle poses against the virtual-center reference (ascending, prediction-seeded) instead of RT detection. Writes -POSE-RT-TEST.csv and a fitted-vs-stored summary.");
gd.addNumericField("Pose test reliable strength", this.curt_pose_str, 5,7,"", // By Claude on 07/03/2026
"Tile selection for the pose test: combo-DSI strength threshold (1.0 gives ~ the old getReliableTiles population).");
gd.addNumericField("Pose test outlier gate k (NMAD)", this.curt_pose_dxy_k, 5,7,"", // By Claude on 07/04/2026
"Keep tiles with max-over-scenes residual <= median + k*NMAD of finite per-tile maxes (scale-free; NaN in any scene always rejected). <=0 - skip the gate.");
gd.addNumericField("Pose test number of best tiles", this.curt_pose_num_tiles, 0,7,"", // By Claude on 07/04/2026
"After the gate keep this many best (smallest max-residual) tiles - the RT compute budget. <=0 - no cap.");
gd.addCheckbox ("Pose test force recalc calibration", this.curt_pose_recalc, // By Claude on 07/04/2026
"Force a FULL pose run that regenerates -POSE-RT-TILE-CALIB even if it exists. Default OFF = automatic reuse: use the calibration if present (filtered run), else run full and generate it.");
gd.addCheckbox ("Pose test raw-jp4 ingest (A2)", this.curt_pose_raw, // By Claude on 07/05/2026
"Per scene: read RAW /jp4/, condition with the CURRENT calibration (rowcol+photometric+FPN, CuasConditioning) and force-upload straight to the GPU, bypassing the prepared image_data (old broken Photogrammetric Calibration).");
gd.addCheckbox ("Pose test lean correlation (B)", this.curt_pose_lean, // By Claude on 07/05/2026
"Phase B measurement: TD-average the 16 sensors, then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen -> 3-angle LMA. v1 has NO motion-blur compensation (compare vs the NOMB baseline).");
gd.addMessage("=== LoG prefilter ===");
gd.addNumericField("Optical PSF radius", this.curt_psf_radius, 6,8,"pix",
"Sensor optical PSF radius for the LoG pre-filter.");
gd.addNumericField("N-sigmas for LoG cutoff", this.curt_n_sigma, 6,8,"x",
"Cutoff LoG kernel array, number of sigmas.");
// rleak0 dialog field removed 2026-06-20 (LReLU conditioning now LINEAR, alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addMessage("=== Temporal binary pyramid ===");
gd.addNumericField("Temporal pyramid levels", this.curt_pyramid, 0,3,"",
"Number of binary temporal pyramid levels.");
// rleak_pyr dialog field removed 2026-06-20 (pyramid averaging now LINEAR, alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addMessage("=== Fine velocities layer ===");
gd.addNumericField("Pixel decimate", this.curt_pix_decimate, 0,3,"",
"Decimate pixels (increase resolution).");
gd.addNumericField("Velocity decimate", this.curt_vel_decimate, 0,3,"",
"Decimate velocities (increase velocity resolution).");
gd.addNumericField("Velocities radius", this.curt_vel_radius, 0,3,"",
"Velocities radius in decimated samples.");
gd.addCheckbox ("Filter by stronger 4d space neighbors", this.curt_vel_thresh_en,
"Zero-out velocity components if they have stronger neighbors");
gd.addNumericField("Velocities suppress radius", this.curt_vel_suppr_rad, 0,3,"",
"Suppress weaker in this radius.");
gd.addNumericField("Absolute threshold", this.curt_vel_athresh, 6,8,"",
"Discard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this valuediscard this pixel-velocity if it has immediate neighbor (of 80=81-1) stronger by this value.");
gd.addNumericField("Relative thershold", this.curt_vel_rthresh, 6,8,"",
"Discard this pixel-velocity if it has immediate neighbor stronger by this value times stronger value.");
gd.addNumericField("Remove weaker velocities", this.curt_vel_dbgmin, 6,8,"",
"Debug feature for testing recurrent with strong targets - zero out weaker (set 10.0).");
gd.addStringField ("Historic weight for 5D convolution", IntersceneMatchParameters.doublesToString(curt_temp_weights), 80,
"Historic weights for 5D convolution ([0] is the latest sample). Will be normalized");
gd.addMessage("=== Layer 2 recurrent accumulation buffer ==="); // By Claude on 06/09/2026
gd.addCheckbox ("Enable recurrent buffer", this.curt_recur_en, // By Claude on 06/09/2026
"Maintain a recurrent 4D (pixel, velocity) accumulation buffer over the selected rectangle."); // By Claude on 06/09/2026
gd.addNumericField("Update period", this.curt_recur_period, 0,3,"time units", // By Claude on 06/09/2026
"Time units between buffer updates. Equal to velocity decimation for integer-pixel shifts (1 px per minimum velocity)."); // By Claude on 06/09/2026
gd.addNumericField("Measurement weight", this.curt_recur_w, 6,8,"", // By Claude on 06/09/2026
"Update rule: buf = leak*(1-w)*shift(buf) + w*conditioned(measurement). Gap decay = leak*(1-w) with fixed w."); // By Claude on 06/09/2026
gd.addNumericField("Prediction leak", this.curt_recur_leak, 6,8,"", // By Claude on 06/09/2026
"Extra decay of the velocity-shifted prediction per update. Keep leak^n_gap >= 0.2-0.3 for expected dark gaps."); // By Claude on 06/09/2026
gd.addNumericField("Adaptive weight threshold", this.curt_recur_wthresh, 6,8,"", // By Claude on 06/09/2026
"If >0: per-pixel adaptive weight w_eff = w*tanh(strength/wthresh), dark frames give w_eff~0 (pure prediction). 0 - fixed w."); // By Claude on 06/09/2026
gd.addNumericField("Velocity diffusion weight", this.curt_recur_spread, 6,8,"", // By Claude on 06/10/2026
"Predict-step process noise: 3-tap (spread,1,spread) normalized diffusion over vx,vy after the shift. Lets the buffer maximum migrate between velocity cells (half-grid velocities). <=0 - off."); // By Claude on 06/10/2026
gd.addNumericField("Max target cluster size", this.curt_recur_max_clust, 0,3,"", // By Claude on 06/09/2026
"Survivor clusters up to this size are one target: fit a 4D half-cosine bump (3-pix half-period, half-pixel-grid center) and inject its full grid sampling. Larger clusters (weak linear signal) pass through unchanged."); // By Claude on 06/10/2026
gd.addNumericField("Bump fit max peak ratio", this.curt_recur_fit_rat, 6,8,"", // By Claude on 06/10/2026
"Reject the single-bump fit when per-survivor peak estimates (value/model_weight) disagree by more than this ratio; then each survivor injects its own single-point bump."); // By Claude on 06/10/2026
gd.addNumericField("Re-sharpen blob threshold fraction", this.curt_recur_rs_frac, 6,8,"", // By Claude on 06/10/2026
"After merging the measurement, peel buffer blobs (4D-connected cells above this fraction of the blob max) and re-fit each as a canonical half-cosine at its fractional centroid, conserving total energy. <=0 - off."); // By Claude on 06/10/2026
gd.addNumericField("Re-sharpen min blob max", this.curt_recur_rs_min, 6,8,"", // By Claude on 06/10/2026
"Stop peeling when the strongest remaining cell is below this (filter-output units); sub-threshold residue passes through unchanged."); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening dialog fields removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addStringField ("C5P/DNN pyramid levels", intsToString(this.curt_c5_levels), 40, // By Claude on 06/13/2026
"Process the DNN front-end only on these pyramid levels (space/comma separated, e.g. \"2 3\"). Empty - all levels. Skips the heavy work on others - main speedup. Pyramid frames still build for all levels up to the max selected."); // By Claude on 06/13/2026
gd.addStringField ("C5P DNN model (ONNX)", this.curt_dnn_model, 60, // By Claude on 06/13/2026
"Trained DNN front-end model location. Empty = disabled (use matched-filter/posterior path). Local path, scp user@host:/path (fetched to cache), or http(s) URL. Overrides any bundled resource - same default-vs-override scheme as the GPU kernel sources."); // By Claude on 06/13/2026
gd.addStringField ("C5P Stage-2 vote-refine (ONNX)", this.curt_stage2_model, 60, // By Claude on 06/18/2026
"v2 Stage-2 learned Hough-vote refine model. Empty = Stage-1 reg field only. When set (with a reg Stage-1 model) the reg branch adds the vote heatmap (-VOTE) and refined detection (-REFINED) views.");
gd.addCheckbox ("DNN remote (run on DGX)", this.curt_dnn_remote, // grouped with the model fields // By Claude on 06/20/2026
"Run the DNN on the remote DGX inference server instead of local CPU: upload the conditioned stack once, the DGX builds the pyramid + full-res shift-and-stitch, returns full-frame {dx,dy,s,Vx,Vy} (-OFFSET) and ROI 121-cell softmax*s (-RECT/-HYPER-RECT). Local CPU path (+ recurrent feed) used when off."); // By Claude on 06/20/2026
gd.addStringField ("DNN remote host:port", this.curt_dnn_remote_host, 24, // By Claude on 06/20/2026
"DGX inference server address for 'DNN remote' (default 192.168.0.62:5577)."); // By Claude on 06/20/2026
gd.addStringField ("DNN remote model (DGX run dir)", this.curt_dnn_remote_model, 24, // By Claude on 06/20/2026
"DGX-side run directory (containing model.pt) the auto-launched server loads, e.g. runs/weighted9_pm_s.");
gd.addStringField ("DNN remote server src (empty=bundled)", this.curt_dnn_remote_srcdir, 40, // By Claude on 06/20/2026
"Override dir for the DGX server scripts (infer_server.py / run_infer_server.sh): empty = bundled jar resource (cuas_dnn/); set = local dir. Same default-vs-override (bundled resource vs local repo) scheme as the GPU kernels - bundled is the working version, refresh it after server-script dev.");
gd.addCheckbox ("DNN local (in-process LibTorch)", this.curt_dnn_local, // By Claude on 06/27/2026
"Run the DNN front-end in-process via native LibTorch (libtpdnn.so / JNA) instead of the remote Python server - identical L1+L2 result, no DGX/server. When set, overrides 'DNN remote'. Needs -Djna.library.path pointing at libtpdnn.so.");
gd.addStringField ("DNN local model dir (empty=bundled)", this.curt_dnn_local_dir, 40, // By Claude on 06/27/2026
"Override dir holding <model>/model.ts.pt (+ .meta.json) for 'DNN local': empty = bundled jar resource (cuas_dnn/). Same default-vs-override scheme as the kernels. Uses the same model names as the remote fields.");
gd.addCheckbox ("DNN Layer-2 (run on DGX)", this.curt_dnn_l2, // By Claude on 06/22/2026
"Run the trained Layer-2 track-before-detect ConvGRU on the DGX after L1 (requires 'DNN remote'). -OFFSET then shows L2 {det,Vx,Vy} (L1's full-res non-ghostbusted field fed in, recurrence over time), titled -DNN-L2-. Uncheck to re-run the old L1 way."); // By Claude on 06/22/2026
gd.addStringField ("DNN Layer-2 model (DGX run dir)", this.curt_dnn_l2_model, 24, // By Claude on 06/22/2026
"DGX-side Layer-2 run directory (containing model.pt) the auto-launched server loads as RUN2=, e.g. runs/l2_v1.");
gd.addNumericField("DNN s-threshold (VIZ ONLY)", this.curt_dnn_thresh, 6,8,"", // By Claude on 06/13/2026, viz-only 06/20/2026
"VISUALIZATION ONLY - NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 (the recurrent always sees the full field) nor the -RECT/-HYPER-RECT data. Do NOT use for critical computation - it is a display mask.");
gd.addCheckbox ("DNN recurrent feed: offset-splat", this.curt_dnn_recur_splat, // By Claude on 06/14/2026
"Feeding the DNN field to the recurrent layer: unchecked = feed per-pixel field as-is; checked = splat each pixel to its fractional (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin. Output gets a -SPLAT mark."); // By Claude on 06/14/2026
gd.addNumericField("DNN recurrent feed scale", this.curt_dnn_recur_scale, 4,8,"", // By Claude on 06/14/2026
"Multiply the DNN field (peaks ~0.1) by this before the recurrent feed so it reaches the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Set 1 and instead lower curt_recur_rs_min if you prefer."); // By Claude on 06/14/2026
gd.addNumericField("DNN ghostbuster vmax", this.curt_dnn_vmax, 4,8,"pix/frame", // By Claude on 06/15/2026
"Zero DNN velocities beyond this radius (untrained corner cells) and discard pixels peaking there (s=0); match the model's training vmax_px (PM=1.4, base=1.0); <=0 disables.");
// dnn_t8frac dialog field removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
gd.addNumericField("DNN patch size (RF)", this.curt_dnn_patch, 0,3,"pix", // By Claude on 06/16/2026
"Receptive-field / training patch the model was built at (24 = base/PM, 32 = larger-attention). MUST match the loaded model.");
gd.addNumericField("DNN temporal stride", this.curt_dnn_stride, 0,3,"slices", // By Claude on 06/14/2026
"DNN output stride along the pyramid-level time axis: 1 = a fresh inference at every slice (testing, watch each temporal step); 4 = production (50% overlap of the window, matches the convolver's integer-pixel-shift cadence)."); // By Claude on 06/14/2026
gd.addCheckbox ("Use synthetic input", this.curt_synth_src, // By Claude on 06/11/2026
"Read *-CUAS-SYNTHETIC-CUAS.tiff (generated test targets) instead of *-CUAS-MERGED-CUAS.tiff from the same model directory; all output titles get a -SYNTH mark."); // By Claude on 06/11/2026
gd.addNumericField("Synthetic target peak", this.curt_synth_scale, 6,8,"counts", // By Claude on 06/12/2026
"Scale applied to the (peak-1 normalized) synthetic targets at load = target peak in counts. Reference: birds ~3, background sigma ~1.7, strong targets >30."); // By Claude on 06/12/2026
gd.addNumericField("Synthetic bg frame averaging", this.curt_synth_bg_avg, 0,3,"frames", // By Claude on 06/20/2026
"Synth quick-run: average this many consecutive REAL frames per output frame (LEV noise floor = 2^LEV: 2=LEV1, 4=LEV2, 8=LEV3) and force a single level. 1 = off (full pyramid)."); // By Claude on 06/20/2026
gd.addCheckbox ("Subtract input temporal average", this.curt_subtract_avg, // By Claude on 06/14/2026
"Subtract the per-pixel temporal average of the input (whole sequence) before LoG. Removes the static treeline edge and its tile-grid streak; moving targets are not in the average so they survive. Uses the whole sequence (not realtime - realtime would use a prior-run average)."); // By Claude on 06/14/2026
gd.addCheckbox ("Synthetic over real background", this.curt_synth_bg, // By Claude on 06/12/2026
"Add the real *-CUAS-MERGED-CUAS.tiff scene under the scaled synthetic targets (frames matched by timestamp label). Unchecked - clean targets on zero background (linear B measurement)."); // By Claude on 06/12/2026
gd.addNumericField("Min newest-frame fraction", this.curt_min_frac, 6,8,"", // By Claude on 06/12/2026
"Zero fine-velocity outputs where the newest frame contributes less than this fraction of the accumulated response (dark-frame feedforward gate). NONLINEAR - punches holes into ridge maxima; set 0 for linear/synthetic B-measurement runs."); // By Claude on 06/12/2026
gd.addMessage("=== Debug, saving images ===");
gd.addCheckbox ("Save full velocities hyperstack", this.curt_save_c5full,
"Save fine velocities [direction][scene][subpixels].");
gd.addCheckbox ("Save velocities for rectangle", this.curt_save_c5rect,
"Save fine velocities for selected rectangle only [scene][flattened image].");
gd.addCheckbox ("Save per-velocity hyperstacks", this.curt_save_c5hyper, // By Claude on 06/13/2026
"HYPER-RECT views (bottom slider = velocity, second slider/scrollwheel = time) for the C5P output and one per posterior lambda - watch a low-SNR target evolve at a fixed velocity."); // By Claude on 06/13/2026
gd.addStringField ("Output selection Rectangle", rectangleToString(curt_save_select), 40, "Selection Rectangle:left, top, width,height");
gd.addNumericField("Time ROI from (s)", this.curt_time_from, 3,12,"s", // 3 decimals (fixed) - stable round-trip on OK // By Claude on 06/14/2026
"Timing ROI start: clips saved RECT/HYPER/DNN/C5P stacks to this time window. -1 = open. Convenience: enter the last 4 digits of the seconds (0<v<10000) and the high digits are guessed from the file's timestamp range (rollover-aware); >=10000 = explicit seconds."); // By Claude on 06/14/2026
gd.addNumericField("Time ROI to (s)", this.curt_time_to, 3,12,"s", // 3 decimals (fixed) - stable round-trip on OK // By Claude on 06/14/2026
"Timing ROI end: same convention as 'from'. The whole 'to' second is included. -1 = open."); // By Claude on 06/14/2026
curt.dialogQuestions(gd); // By Claude on 07/05/2026
gd.addTab("Airplane","Airplane mode (fast forward movement, low vertical speed");
gd.addCheckbox ("Enable airplane mode", this.air_mode_en,
......@@ -5026,78 +4829,7 @@ min_str_neib_fpn 0.35
this.cuas_min_disp_str = gd.getNextNumber();
this.cuas_rng_limit = gd.getNextNumber();
this.curt_en = gd.getNextBoolean();
this.curt_calib = gd.getNextBoolean(); // By Claude on 07/03/2026
this.curt_cond_test = gd.getNextBoolean();
this.curt_pose_test = gd.getNextBoolean(); // By Claude on 07/03/2026
this.curt_pose_str = gd.getNextNumber(); // By Claude on 07/03/2026
this.curt_pose_dxy_k = gd.getNextNumber(); // By Claude on 07/04/2026
this.curt_pose_num_tiles =(int) gd.getNextNumber(); // By Claude on 07/04/2026
this.curt_pose_recalc = gd.getNextBoolean(); // By Claude on 07/04/2026
this.curt_pose_raw = gd.getNextBoolean(); // By Claude on 07/05/2026
this.curt_pose_lean = gd.getNextBoolean(); // By Claude on 07/05/2026
this.curt_psf_radius = gd.getNextNumber();
this.curt_n_sigma = gd.getNextNumber();
// rleak0 getNext removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.curt_pyramid = (int) gd.getNextNumber();
// rleak_pyr getNext removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.curt_pix_decimate = (int) gd.getNextNumber();
this.curt_vel_decimate = (int) gd.getNextNumber();
this.curt_vel_radius = (int) gd.getNextNumber();
this.curt_vel_thresh_en = gd.getNextBoolean();
this.curt_vel_suppr_rad = (int) gd.getNextNumber();
this.curt_vel_athresh = gd.getNextNumber();
this.curt_vel_rthresh = gd.getNextNumber();
this.curt_vel_dbgmin = gd.getNextNumber();
this.curt_temp_weights = IntersceneMatchParameters. StringToDoubles(gd.getNextString(), 0);
this.curt_recur_en = gd.getNextBoolean(); // By Claude on 06/09/2026
this.curt_recur_period = (int) gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_w = gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_leak = gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_wthresh = gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_spread = gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_max_clust=(int) gd.getNextNumber(); // By Claude on 06/09/2026
this.curt_recur_fit_rat = gd.getNextNumber(); // By Claude on 06/10/2026
this.curt_recur_rs_frac = gd.getNextNumber(); // By Claude on 06/10/2026
this.curt_recur_rs_min = gd.getNextNumber(); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening getNext* removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.curt_c5_levels = StringToInts(gd.getNextString()); // By Claude on 06/13/2026
this.curt_dnn_model = gd.getNextString().trim(); // By Claude on 06/13/2026
this.curt_stage2_model = gd.getNextString().trim(); // By Claude on 06/18/2026
this.curt_dnn_remote = gd.getNextBoolean(); // grouped with the model fields // By Claude on 06/20/2026
this.curt_dnn_remote_host = gd.getNextString().trim(); // By Claude on 06/20/2026
this.curt_dnn_remote_model = gd.getNextString().trim(); // By Claude on 06/20/2026
this.curt_dnn_remote_srcdir = gd.getNextString().trim(); // By Claude on 06/20/2026
this.curt_dnn_local = gd.getNextBoolean(); // By Claude on 06/27/2026
this.curt_dnn_local_dir = gd.getNextString().trim(); // By Claude on 06/27/2026
this.curt_dnn_l2 = gd.getNextBoolean(); // By Claude on 06/22/2026
this.curt_dnn_l2_model = gd.getNextString().trim(); // By Claude on 06/22/2026
this.curt_dnn_thresh = gd.getNextNumber(); // By Claude on 06/13/2026
this.curt_dnn_recur_splat = gd.getNextBoolean(); // By Claude on 06/14/2026
this.curt_dnn_recur_scale = gd.getNextNumber(); // By Claude on 06/14/2026
this.curt_dnn_vmax = gd.getNextNumber(); // By Claude on 06/15/2026
// dnn_t8frac getNext removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
this.curt_dnn_patch = (int) gd.getNextNumber(); // By Claude on 06/16/2026
this.curt_dnn_stride = (int) gd.getNextNumber(); // By Claude on 06/14/2026
this.curt_synth_src = gd.getNextBoolean(); // By Claude on 06/11/2026
this.curt_synth_scale = gd.getNextNumber(); // By Claude on 06/12/2026
this.curt_synth_bg_avg = (int) gd.getNextNumber(); // By Claude on 06/20/2026
this.curt_subtract_avg = gd.getNextBoolean(); // By Claude on 06/14/2026
this.curt_synth_bg = gd.getNextBoolean(); // By Claude on 06/12/2026
this.curt_min_frac = gd.getNextNumber(); // By Claude on 06/12/2026
this.curt_save_c5full = gd.getNextBoolean();
this.curt_save_c5rect = gd.getNextBoolean();
this.curt_save_c5hyper = gd.getNextBoolean(); // By Claude on 06/13/2026
this.curt_save_select = stringToRectangle(gd.getNextString());// Rectangle
this.curt_time_from = gd.getNextNumber(); // By Claude on 06/14/2026
this.curt_time_to = gd.getNextNumber(); // By Claude on 06/14/2026
curt.dialogAnswers(gd); // By Claude on 07/05/2026
this.air_mode_en = gd.getNextBoolean();
this.air_sync_ims = gd.getNextBoolean();
......@@ -6399,78 +6131,7 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"cuas_min_disp_str", this.cuas_min_disp_str+""); // double
properties.setProperty(prefix+"cuas_rng_limit", this.cuas_rng_limit+""); // double
properties.setProperty(prefix+"curt_en", this.curt_en+""); // boolean
properties.setProperty(prefix+"curt_calib", this.curt_calib+""); // boolean // By Claude on 07/03/2026
properties.setProperty(prefix+"curt_cond_test", this.curt_cond_test+""); // boolean
properties.setProperty(prefix+"curt_pose_test", this.curt_pose_test+""); // boolean // By Claude on 07/03/2026
properties.setProperty(prefix+"curt_pose_str", this.curt_pose_str+""); // double // By Claude on 07/03/2026
properties.setProperty(prefix+"curt_pose_dxy_k", this.curt_pose_dxy_k+""); // double // By Claude on 07/04/2026
properties.setProperty(prefix+"curt_pose_num_tiles", this.curt_pose_num_tiles+""); // int // By Claude on 07/04/2026
properties.setProperty(prefix+"curt_pose_recalc", this.curt_pose_recalc+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"curt_pose_raw", this.curt_pose_raw+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"curt_pose_lean", this.curt_pose_lean+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"curt_psf_radius", this.curt_psf_radius+""); // double
properties.setProperty(prefix+"curt_n_sigma", this.curt_n_sigma+""); // double
// rleak0 setProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_pyramid", this.curt_pyramid+""); // int
// rleak_pyr setProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_pix_decimate", this.curt_pix_decimate+""); // int
properties.setProperty(prefix+"curt_vel_decimate", this.curt_vel_decimate+""); // int
properties.setProperty(prefix+"curt_vel_radius", this.curt_vel_radius+""); // int
properties.setProperty(prefix+"curt_vel_thresh_en", this.curt_vel_thresh_en+""); // boolean
properties.setProperty(prefix+"curt_vel_suppr_rad", this.curt_vel_suppr_rad+""); // int
properties.setProperty(prefix+"curt_vel_athresh", this.curt_vel_athresh+""); // double
properties.setProperty(prefix+"curt_vel_rthresh", this.curt_vel_rthresh+""); // double
properties.setProperty(prefix+"curt_vel_dbgmin", this.curt_vel_dbgmin+""); // double
properties.setProperty(prefix+"curt_temp_weights", IntersceneMatchParameters.doublesToString(this.curt_temp_weights));
properties.setProperty(prefix+"curt_recur_en", this.curt_recur_en+""); // boolean // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_period", this.curt_recur_period+""); // int // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_w", this.curt_recur_w+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_leak", this.curt_recur_leak+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_wthresh", this.curt_recur_wthresh+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_spread", this.curt_recur_spread+""); // double // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_max_clust", this.curt_recur_max_clust+"");// int // By Claude on 06/09/2026
properties.setProperty(prefix+"curt_recur_fit_rat", this.curt_recur_fit_rat+""); // double // By Claude on 06/10/2026
properties.setProperty(prefix+"curt_recur_rs_frac", this.curt_recur_rs_frac+""); // double // By Claude on 06/10/2026
properties.setProperty(prefix+"curt_recur_rs_min", this.curt_recur_rs_min+""); // double // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening setProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_c5_levels", intsToString(this.curt_c5_levels)); // int [] // By Claude on 06/13/2026
properties.setProperty(prefix+"curt_dnn_model", this.curt_dnn_model); // String // By Claude on 06/13/2026
properties.setProperty(prefix+"curt_stage2_model", this.curt_stage2_model); // String // By Claude on 06/18/2026
properties.setProperty(prefix+"curt_dnn_thresh", this.curt_dnn_thresh+""); // double // By Claude on 06/13/2026
properties.setProperty(prefix+"curt_dnn_recur_splat", this.curt_dnn_recur_splat+""); // boolean // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_dnn_recur_scale", this.curt_dnn_recur_scale+""); // double // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_dnn_stride", this.curt_dnn_stride+""); // int // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_dnn_vmax", this.curt_dnn_vmax+""); // double // By Claude on 06/15/2026
// dnn_t8frac setProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_dnn_patch", this.curt_dnn_patch+""); // int // By Claude on 06/16/2026
properties.setProperty(prefix+"curt_dnn_remote", this.curt_dnn_remote+""); // boolean // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_dnn_remote_host", this.curt_dnn_remote_host); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_dnn_remote_model", this.curt_dnn_remote_model); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_dnn_remote_srcdir", this.curt_dnn_remote_srcdir); // String // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_dnn_local", this.curt_dnn_local+""); // boolean // By Claude on 06/27/2026
properties.setProperty(prefix+"curt_dnn_local_dir", this.curt_dnn_local_dir); // String // By Claude on 06/27/2026
properties.setProperty(prefix+"curt_dnn_l2", this.curt_dnn_l2+""); // boolean // By Claude on 06/22/2026
properties.setProperty(prefix+"curt_dnn_l2_model", this.curt_dnn_l2_model); // String // By Claude on 06/22/2026
properties.setProperty(prefix+"curt_synth_src", this.curt_synth_src+""); // boolean // By Claude on 06/11/2026
properties.setProperty(prefix+"curt_synth_scale", this.curt_synth_scale+""); // double // By Claude on 06/12/2026
properties.setProperty(prefix+"curt_synth_bg_avg", this.curt_synth_bg_avg+""); // int // By Claude on 06/20/2026
properties.setProperty(prefix+"curt_subtract_avg", this.curt_subtract_avg+""); // boolean // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_synth_bg", this.curt_synth_bg+""); // boolean // By Claude on 06/12/2026
properties.setProperty(prefix+"curt_min_frac", this.curt_min_frac+""); // double // By Claude on 06/12/2026
properties.setProperty(prefix+"curt_save_c5full", this.curt_save_c5full+""); // boolean
properties.setProperty(prefix+"curt_save_c5rect", this.curt_save_c5rect+""); // boolean
properties.setProperty(prefix+"curt_save_c5hyper", this.curt_save_c5hyper+""); // boolean // By Claude on 06/13/2026
properties.setProperty(prefix+"curt_save_select", rectangleToString(curt_save_select)+""); // Rectangle
properties.setProperty(prefix+"curt_time_from", this.curt_time_from+""); // double // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_time_to", this.curt_time_to+""); // double // By Claude on 06/14/2026
curt.setProperties(prefix+"curt_", properties); // By Claude on 07/05/2026
properties.setProperty(prefix+"air_mode_en", this.air_mode_en+""); // boolean
properties.setProperty(prefix+"air_sync_ims", this.air_sync_ims+""); // boolean
......@@ -6805,82 +6466,6 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"synth_add_offs", synth_add_offs+""); // boolean
}
private void getPropertiesCuasRT(String prefix,Properties properties){ // split out of getProperties() - 64KB method limit // By Claude on 06/12/2026
if (properties.getProperty(prefix+"curt_en")!=null) this.curt_en=Boolean.parseBoolean(properties.getProperty(prefix+"curt_en"));
if (properties.getProperty(prefix+"curt_calib")!=null) this.curt_calib=Boolean.parseBoolean(properties.getProperty(prefix+"curt_calib")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"curt_cond_test")!=null) this.curt_cond_test=Boolean.parseBoolean(properties.getProperty(prefix+"curt_cond_test"));
if (properties.getProperty(prefix+"curt_pose_test")!=null) this.curt_pose_test=Boolean.parseBoolean(properties.getProperty(prefix+"curt_pose_test")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"curt_pose_str")!=null) this.curt_pose_str=Double.parseDouble(properties.getProperty(prefix+"curt_pose_str")); // By Claude on 07/03/2026
if (properties.getProperty(prefix+"curt_pose_dxy_k")!=null) this.curt_pose_dxy_k=Double.parseDouble(properties.getProperty(prefix+"curt_pose_dxy_k")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"curt_pose_num_tiles")!=null) this.curt_pose_num_tiles=Integer.parseInt(properties.getProperty(prefix+"curt_pose_num_tiles")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"curt_pose_recalc")!=null) this.curt_pose_recalc=Boolean.parseBoolean(properties.getProperty(prefix+"curt_pose_recalc")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"curt_pose_raw")!=null) this.curt_pose_raw=Boolean.parseBoolean(properties.getProperty(prefix+"curt_pose_raw")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"curt_pose_lean")!=null) this.curt_pose_lean=Boolean.parseBoolean(properties.getProperty(prefix+"curt_pose_lean")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"curt_psf_radius")!=null) this.curt_psf_radius=Double.parseDouble(properties.getProperty(prefix+"curt_psf_radius"));
if (properties.getProperty(prefix+"curt_n_sigma")!=null) this.curt_n_sigma=Double.parseDouble(properties.getProperty(prefix+"curt_n_sigma"));
// rleak0 getProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_pyramid")!=null) this.curt_pyramid=Integer.parseInt(properties.getProperty(prefix+"curt_pyramid"));
// rleak_pyr getProperty removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_pix_decimate")!=null) this.curt_pix_decimate=Integer.parseInt(properties.getProperty(prefix+"curt_pix_decimate"));
if (properties.getProperty(prefix+"curt_vel_decimate")!=null) this.curt_vel_decimate=Integer.parseInt(properties.getProperty(prefix+"curt_vel_decimate"));
if (properties.getProperty(prefix+"curt_vel_radius")!=null) this.curt_vel_radius=Integer.parseInt(properties.getProperty(prefix+"curt_vel_radius"));
if (properties.getProperty(prefix+"curt_vel_thresh_en")!=null) this.curt_vel_thresh_en=Boolean.parseBoolean(properties.getProperty(prefix+"curt_vel_thresh_en"));
if (properties.getProperty(prefix+"curt_vel_suppr_rad")!=null) this.curt_vel_suppr_rad=Integer.parseInt(properties.getProperty(prefix+"curt_vel_suppr_rad"));
if (properties.getProperty(prefix+"curt_vel_athresh")!=null) this.curt_vel_athresh=Double.parseDouble(properties.getProperty(prefix+"curt_vel_athresh"));
if (properties.getProperty(prefix+"curt_vel_rthresh")!=null) this.curt_vel_rthresh=Double.parseDouble(properties.getProperty(prefix+"curt_vel_rthresh"));
if (properties.getProperty(prefix+"curt_vel_dbgmin")!=null) this.curt_vel_dbgmin=Double.parseDouble(properties.getProperty(prefix+"curt_vel_dbgmin"));
if (properties.getProperty(prefix+"curt_temp_weights")!=null) this.curt_temp_weights= IntersceneMatchParameters.StringToDoubles(properties.getProperty(prefix+"curt_temp_weights"),0); // use 0
if (properties.getProperty(prefix+"curt_recur_en")!=null) this.curt_recur_en=Boolean.parseBoolean(properties.getProperty(prefix+"curt_recur_en")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_period")!=null) this.curt_recur_period=Integer.parseInt(properties.getProperty(prefix+"curt_recur_period")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_w")!=null) this.curt_recur_w=Double.parseDouble(properties.getProperty(prefix+"curt_recur_w")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_leak")!=null) this.curt_recur_leak=Double.parseDouble(properties.getProperty(prefix+"curt_recur_leak")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_wthresh")!=null) this.curt_recur_wthresh=Double.parseDouble(properties.getProperty(prefix+"curt_recur_wthresh")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_spread")!=null) this.curt_recur_spread=Double.parseDouble(properties.getProperty(prefix+"curt_recur_spread")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_max_clust")!=null) this.curt_recur_max_clust=Integer.parseInt(properties.getProperty(prefix+"curt_recur_max_clust")); // By Claude on 06/09/2026
if (properties.getProperty(prefix+"curt_recur_fit_rat")!=null) this.curt_recur_fit_rat=Double.parseDouble(properties.getProperty(prefix+"curt_recur_fit_rat")); // By Claude on 06/10/2026
if (properties.getProperty(prefix+"curt_recur_rs_frac")!=null) this.curt_recur_rs_frac=Double.parseDouble(properties.getProperty(prefix+"curt_recur_rs_frac")); // By Claude on 06/10/2026
if (properties.getProperty(prefix+"curt_recur_rs_min")!=null) this.curt_recur_rs_min=Double.parseDouble(properties.getProperty(prefix+"curt_recur_rs_min")); // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening getProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_c5_levels")!=null) this.curt_c5_levels= IntersceneMatchParameters.StringToInts(properties.getProperty(prefix+"curt_c5_levels")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"curt_dnn_model")!=null) this.curt_dnn_model=(String) properties.getProperty(prefix+"curt_dnn_model"); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"curt_stage2_model")!=null) this.curt_stage2_model=(String) properties.getProperty(prefix+"curt_stage2_model"); // By Claude on 06/18/2026
if (properties.getProperty(prefix+"curt_dnn_thresh")!=null) this.curt_dnn_thresh=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_thresh")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"curt_dnn_recur_splat")!=null) this.curt_dnn_recur_splat=Boolean.parseBoolean(properties.getProperty(prefix+"curt_dnn_recur_splat")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_dnn_recur_scale")!=null) this.curt_dnn_recur_scale=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_recur_scale")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_dnn_stride")!=null) this.curt_dnn_stride=Integer.parseInt(properties.getProperty(prefix+"curt_dnn_stride")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_dnn_vmax")!=null) this.curt_dnn_vmax=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_vmax")); // By Claude on 06/15/2026
// dnn_t8frac getProperty removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_dnn_patch")!=null) this.curt_dnn_patch=Integer.parseInt(properties.getProperty(prefix+"curt_dnn_patch")); // By Claude on 06/16/2026
if (properties.getProperty(prefix+"curt_dnn_remote")!=null) this.curt_dnn_remote=Boolean.parseBoolean(properties.getProperty(prefix+"curt_dnn_remote")); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_dnn_remote_host")!=null) this.curt_dnn_remote_host=(String) properties.getProperty(prefix+"curt_dnn_remote_host"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_dnn_remote_model")!=null) this.curt_dnn_remote_model=(String) properties.getProperty(prefix+"curt_dnn_remote_model"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_dnn_remote_srcdir")!=null) this.curt_dnn_remote_srcdir=(String) properties.getProperty(prefix+"curt_dnn_remote_srcdir"); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_dnn_local")!=null) this.curt_dnn_local=Boolean.parseBoolean(properties.getProperty(prefix+"curt_dnn_local")); // By Claude on 06/27/2026
if (properties.getProperty(prefix+"curt_dnn_local_dir")!=null) this.curt_dnn_local_dir=(String) properties.getProperty(prefix+"curt_dnn_local_dir"); // By Claude on 06/27/2026
if (properties.getProperty(prefix+"curt_dnn_l2")!=null) this.curt_dnn_l2=Boolean.parseBoolean(properties.getProperty(prefix+"curt_dnn_l2")); // By Claude on 06/22/2026
if (properties.getProperty(prefix+"curt_dnn_l2_model")!=null) this.curt_dnn_l2_model=(String) properties.getProperty(prefix+"curt_dnn_l2_model"); // By Claude on 06/22/2026
if (properties.getProperty(prefix+"curt_synth_src")!=null) this.curt_synth_src=Boolean.parseBoolean(properties.getProperty(prefix+"curt_synth_src")); // By Claude on 06/11/2026
if (properties.getProperty(prefix+"curt_synth_scale")!=null) this.curt_synth_scale=Double.parseDouble(properties.getProperty(prefix+"curt_synth_scale")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"curt_synth_bg_avg")!=null) this.curt_synth_bg_avg=Integer.parseInt(properties.getProperty(prefix+"curt_synth_bg_avg")); // By Claude on 06/20/2026
if (properties.getProperty(prefix+"curt_subtract_avg")!=null) this.curt_subtract_avg=Boolean.parseBoolean(properties.getProperty(prefix+"curt_subtract_avg")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_synth_bg")!=null) this.curt_synth_bg=Boolean.parseBoolean(properties.getProperty(prefix+"curt_synth_bg")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"curt_min_frac")!=null) this.curt_min_frac=Double.parseDouble(properties.getProperty(prefix+"curt_min_frac")); // By Claude on 06/12/2026
if (properties.getProperty(prefix+"curt_save_c5full")!=null) this.curt_save_c5full=Boolean.parseBoolean(properties.getProperty(prefix+"curt_save_c5full"));
if (properties.getProperty(prefix+"curt_save_c5rect")!=null) this.curt_save_c5rect=Boolean.parseBoolean(properties.getProperty(prefix+"curt_save_c5rect"));
if (properties.getProperty(prefix+"curt_save_c5hyper")!=null) this.curt_save_c5hyper=Boolean.parseBoolean(properties.getProperty(prefix+"curt_save_c5hyper")); // By Claude on 06/13/2026
if (properties.getProperty(prefix+"curt_save_select")!=null) this.curt_save_select=stringToRectangle((String) properties.getProperty(prefix+"curt_save_select"));
if (properties.getProperty(prefix+"curt_time_from")!=null) this.curt_time_from=Double.parseDouble(properties.getProperty(prefix+"curt_time_from")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_time_to")!=null) this.curt_time_to=Double.parseDouble(properties.getProperty(prefix+"curt_time_to")); // By Claude on 06/14/2026
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"ims_use")!=null) this.ims_use=Boolean.parseBoolean(properties.getProperty(prefix+"ims_use"));
......@@ -7832,7 +7417,7 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"cuas_min_disp_str")!=null) this.cuas_min_disp_str=Double.parseDouble(properties.getProperty(prefix+"cuas_min_disp_str"));
if (properties.getProperty(prefix+"cuas_rng_limit")!=null) this.cuas_rng_limit=Double.parseDouble(properties.getProperty(prefix+"cuas_rng_limit"));
getPropertiesCuasRT(prefix, properties); // all curt_* reads, in field-declaration order // By Claude on 06/12/2026 (64KB method limit)
curt.getProperties(prefix+"curt_", properties); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"air_mode_en")!=null) this.air_mode_en=Boolean.parseBoolean(properties.getProperty(prefix+"air_mode_en"));
if (properties.getProperty(prefix+"air_sync_ims")!=null) this.air_sync_ims=Boolean.parseBoolean(properties.getProperty(prefix+"air_sync_ims"));
......@@ -9098,77 +8683,7 @@ min_str_neib_fpn 0.35
imp.cuas_min_disp_str = this.cuas_min_disp_str;
imp.cuas_rng_limit = this.cuas_rng_limit;
imp.curt_en = this.curt_en;
imp.curt_calib = this.curt_calib; // By Claude on 07/03/2026
imp.curt_cond_test = this.curt_cond_test;
imp.curt_pose_test = this.curt_pose_test; // By Claude on 07/03/2026
imp.curt_pose_str = this.curt_pose_str; // By Claude on 07/03/2026
imp.curt_pose_dxy_k = this.curt_pose_dxy_k; // By Claude on 07/04/2026
imp.curt_pose_num_tiles = this.curt_pose_num_tiles; // By Claude on 07/04/2026
imp.curt_pose_recalc = this.curt_pose_recalc; // By Claude on 07/04/2026
imp.curt_pose_raw = this.curt_pose_raw; // By Claude on 07/05/2026
imp.curt_pose_lean = this.curt_pose_lean; // By Claude on 07/05/2026
imp.curt_psf_radius = this.curt_psf_radius;
imp.curt_n_sigma = this.curt_n_sigma;
// rleak0 imp.X copy removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
imp.curt_pyramid = this.curt_pyramid;
// rleak_pyr imp.X copy removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// 3d3 coarse-velocity path removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
imp.curt_pix_decimate = this.curt_pix_decimate;
imp.curt_vel_decimate = this.curt_vel_decimate;
imp.curt_vel_radius = this.curt_vel_radius;
imp.curt_vel_thresh_en = this.curt_vel_thresh_en;
imp.curt_vel_suppr_rad = this.curt_vel_suppr_rad;
imp.curt_vel_athresh = this.curt_vel_athresh;
imp.curt_vel_rthresh = this.curt_vel_rthresh;
imp.curt_vel_dbgmin = this.curt_vel_dbgmin;
imp.curt_temp_weights = this.curt_temp_weights.clone();
imp.curt_recur_en = this.curt_recur_en; // By Claude on 06/09/2026
imp.curt_recur_period = this.curt_recur_period; // By Claude on 06/09/2026
imp.curt_recur_w = this.curt_recur_w; // By Claude on 06/09/2026
imp.curt_recur_leak = this.curt_recur_leak; // By Claude on 06/09/2026
imp.curt_recur_wthresh = this.curt_recur_wthresh; // By Claude on 06/09/2026
imp.curt_recur_spread = this.curt_recur_spread; // By Claude on 06/09/2026
imp.curt_recur_max_clust = this.curt_recur_max_clust; // By Claude on 06/09/2026
imp.curt_recur_fit_rat = this.curt_recur_fit_rat; // By Claude on 06/10/2026
imp.curt_recur_rs_frac = this.curt_recur_rs_frac; // By Claude on 06/10/2026
imp.curt_recur_rs_min = this.curt_recur_rs_min; // By Claude on 06/10/2026
// C5P matched-filter / Bayes-posterior / whitening imp.X copy removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
imp.curt_c5_levels = (this.curt_c5_levels == null) ? null : this.curt_c5_levels.clone(); // null/empty = all levels // By Claude on 06/13/2026
imp.curt_dnn_model = this.curt_dnn_model; // By Claude on 06/13/2026
imp.curt_stage2_model = this.curt_stage2_model; // By Claude on 06/18/2026
imp.curt_dnn_thresh = this.curt_dnn_thresh; // By Claude on 06/13/2026
imp.curt_dnn_recur_splat = this.curt_dnn_recur_splat; // By Claude on 06/14/2026
imp.curt_dnn_recur_scale = this.curt_dnn_recur_scale; // By Claude on 06/14/2026
imp.curt_dnn_stride = this.curt_dnn_stride; // By Claude on 06/14/2026
imp.curt_dnn_vmax = this.curt_dnn_vmax; // By Claude on 06/15/2026
// dnn_t8frac imp.X copy removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
imp.curt_dnn_patch = this.curt_dnn_patch; // By Claude on 06/16/2026
imp.curt_dnn_remote = this.curt_dnn_remote; // By Claude on 06/20/2026
imp.curt_dnn_remote_host = this.curt_dnn_remote_host; // By Claude on 06/20/2026
imp.curt_dnn_remote_model = this.curt_dnn_remote_model; // By Claude on 06/20/2026
imp.curt_dnn_remote_srcdir = this.curt_dnn_remote_srcdir; // By Claude on 06/20/2026
imp.curt_dnn_local = this.curt_dnn_local; // By Claude on 06/27/2026
imp.curt_dnn_local_dir = this.curt_dnn_local_dir; // By Claude on 06/27/2026
imp.curt_dnn_l2 = this.curt_dnn_l2; // By Claude on 06/22/2026
imp.curt_dnn_l2_model = this.curt_dnn_l2_model; // By Claude on 06/22/2026
imp.curt_synth_src = this.curt_synth_src; // By Claude on 06/11/2026
imp.curt_synth_scale = this.curt_synth_scale; // By Claude on 06/12/2026
imp.curt_synth_bg_avg = this.curt_synth_bg_avg; // By Claude on 06/20/2026
imp.curt_subtract_avg = this.curt_subtract_avg; // By Claude on 06/14/2026
imp.curt_synth_bg = this.curt_synth_bg; // By Claude on 06/12/2026
imp.curt_min_frac = this.curt_min_frac; // By Claude on 06/12/2026
imp.curt_save_c5full = this.curt_save_c5full;
imp.curt_save_c5rect = this.curt_save_c5rect;
imp.curt_save_c5hyper = this.curt_save_c5hyper; // By Claude on 06/13/2026
imp.curt_save_select = new Rectangle(this.curt_save_select);
imp.curt_time_from = this.curt_time_from; // By Claude on 06/14/2026
imp.curt_time_to = this.curt_time_to; // By Claude on 06/14/2026
try { imp.curt = this.curt.clone(); } catch (CloneNotSupportedException e) {} // By Claude on 07/05/2026
imp.air_mode_en = this.air_mode_en;
imp.air_sync_ims = this.air_sync_ims;
......
......@@ -7239,7 +7239,7 @@ java.lang.NullPointerException
// Moved to the very end, after 3D
// boolean test_vegetation = true;
if (master_CLT.hasCenterClt() && clt_parameters.imp.cuas_targets_en && !clt_parameters.imp.curt_en) { // cuas mode
if (master_CLT.hasCenterClt() && clt_parameters.imp.cuas_targets_en && !clt_parameters.imp.curt.en) { // cuas mode
if (debugLevel >-3) {
System.out.println("===== Running CUAS ranging in Oracle mode. =====");
}
......@@ -7264,7 +7264,7 @@ java.lang.NullPointerException
// Generate the merged-CUAS stack on the GPU EXPLICITLY here (CuasRanging.prepareFpixels() uses the CUDA
// tile-processor kernels - may be incompatible with a future CUDA), then hand the plain ImagePlus to the
// CUDA-free CuasDetectRT. By Claude on 06/24/2026
if (clt_parameters.imp.curt_en && master_CLT.hasCenterClt()) {
if (clt_parameters.imp.curt.en && master_CLT.hasCenterClt()) {
System.out.println("===== Running CUAS RT detection (curt_en). =====");
CuasRanging cuasRangingRT = new CuasRanging(
clt_parameters, // CLTParameters clt_parameters,
......@@ -7274,7 +7274,7 @@ java.lang.NullPointerException
ImagePlus imp_targets = cuasRangingRT.prepareFpixels(); // GPU generator (explicit, CUDA-sensitive); also builds the QuadCLT instances = borrowed-calibration source
if (clt_parameters.imp.curt_calib) {
if (clt_parameters.imp.curt.calib) {
// By Claude on 07/03/2026: first step of the CUAS RT processing flow - per-sensor photometric
// (re)calibration: fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales,
// apply in memory (master_CLT + reference scene + quadCLT_main -> top-menu config, template for
......@@ -7285,11 +7285,11 @@ java.lang.NullPointerException
master_CLT, // QuadCLT master_CLT (combo DSI source, in-memory apply)
quadCLTs[ref_index], // QuadCLT ref_scene (photometric owner, INTERFRAME corr-xml)
quadCLT_main, // QuadCLT quadCLT_main (main config + new-instance template)
clt_parameters.imp.curt_cond_test, // boolean save_stacks
clt_parameters.imp.curt.cond_test, // boolean save_stacks
ImageDtt.THREADS_MAX, // int threadsMax,
debugLevel); // int debugLevel
}
if (clt_parameters.imp.curt_pose_test) {
if (clt_parameters.imp.curt.pose_test) {
// RT pose-adjustment prototype phase A (curt_pose_test), runs INSTEAD of RT detection:
// re-generate per-scene 3-angle poses against the virtual-center reference, ascending,
// prediction-seeded, single pass on the final combo DSI. Output: -POSE-RT-TEST.csv +
......@@ -7301,14 +7301,14 @@ java.lang.NullPointerException
master_CLT, // QuadCLT center_CLT,
quadCLTs, // QuadCLT [] quadCLTs,
debugLevel); // int debugLevel
} else if (clt_parameters.imp.curt_cond_test) {
} else if (clt_parameters.imp.curt.cond_test) {
// Conditioning/calibration diagnostic (curt_cond_test), runs INSTEAD of RT detection:
// raw /jp4/ baseline (no photometric/FPN/conditioning), saved as -CUAS-PERSENSOR-RAW for
// side-by-side compare with the conditioned -CUAS-PERSENSOR (saved by the calibration step when
// curt_calib is on, or rendered here otherwise). Both stacks use the same uniform sensor-domain
// task grid - never leftover GPU task state. By Claude on 07/01/2026, restructured 07/03/2026.
System.out.println("===== CUAS RT conditioning test (curt_cond_test): per-sensor average spread =====");
if (!clt_parameters.imp.curt_calib) { // conditioned baseline not yet rendered by the calibration step
if (!clt_parameters.imp.curt.calib) { // conditioned baseline not yet rendered by the calibration step
QuadCLT cond_phys = master_CLT.getGPUQuad().getQuadCLT(); // physical scene bound to the GPU
if (cond_phys != null) { // the actual image_data (bypass image_data_alt), same grid as raw
CuasMotion.perSensorFromData(clt_parameters, master_CLT, cond_phys.getOrigImageData(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment