Commit 6b67e25e authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: item-4 R3 - RT LoG stream into the offline detector (det_rt_log_file)...

CLAUDE: item-4 R3 - RT LoG stream into the offline detector (det_rt_log_file) + det_ema_gate sizing stats

New saved param curt.det_rt_log_file: the mode-3 detector consumes a pose-RT
run's -CUAS-RT-LOG detection frames (LoG - avg) instead of its own
subtract-avg+LoG; with the merged stack present and curt_subtract_avg on it
still computes the offline frames and prints the RELATIVE-tol compare
(ruling 3.3 - offline subtracts PRE-LoG, RT subtracts POST-LoG, equal by
linearity except NaN edges) before swapping the RT frames in. No merged
stack = the RT stack ingests as primary input. Outputs tagged -RTLOG;
missing timestamps / synth_src combinations fail LOUD.

det_log_save runs now also accumulate a |LoG-avg| log-histogram and print
the post-LoG noise floor (sigma, p50..p99.99, max) + det_ema_gate
candidates (4/5/6 sigma) and the percentile the current gate admits -
the sizing data ruling 3.1 asked for (dial stays Andrey's).
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 6ec3ea29
......@@ -20,6 +20,7 @@ import ij.ImageStack;
public class CuasDetectRT {
public static final String SUFFIX_FPIXELS_TIFF = "-CUAS-MERGED-CUAS.tiff";
public static final String SUFFIX_SYNTH_TIFF = "-CUAS-SYNTHETIC-CUAS.tiff"; // synthetic input (curt_synth_src) // By Claude on 06/11/2026
public static final String SUFFIX_RT_LOG_TIFF = "-CUAS-RT-LOG.tiff"; // pose-RT per-scene detection frames (LoG - avg), det_log_save output (item 4 R3 A/B input) // By Claude on 07/19/2026
public static final String SUFFIX_LOG = "-LoG";
public static final String SUFFIX_CONV2D = "-CONV2D";
// SUFFIX_CONV3D3 removed 2026-06-20 (dead after 3d3/MF cleanup); see tag cuas-layer1. // By Claude
......@@ -52,6 +53,9 @@ public class CuasDetectRT {
int height;
String [] time_stamps;
float [][] synth_pixels = null; // synthetic reference grid (scaled, NOT LoG'd), injected per pyramid level; null = real-only // By Claude on 06/14/2026
float [][] rt_log_pixels = null; // item 4 R3: pose-RT detection frames (LoG - avg) from det_rt_log_file, slice order // By Claude on 07/19/2026
String [] rt_log_ts = null; // their per-slice timestamps (scene image names) // By Claude on 07/19/2026
boolean rt_log_primary = false; // true = no merged stack; the RT stack IS the ingested input (conditioning fully skipped, no oracle compare) // By Claude on 07/19/2026
double infinity;
// mode=3 (current, fast, bypasses OpticalFlow extras): read the merged-CUAS stack from a file in
......@@ -94,9 +98,63 @@ public class CuasDetectRT {
fpixels = null;
dpixels = null;
}
loadRtLogInput(debugLevel); // item 4 R3: det_rt_log_file (empty = no-op); may ingest the RT stack as primary when no merged stack exists // By Claude on 07/19/2026
return;
}
/** Item 4 R3 (detector A/B): load the pose-RT -CUAS-RT-LOG detection-frame stack named by
* curt.det_rt_log_file (a directory = its newest *-CUAS-RT-LOG.tiff). With a merged stack already
* ingested the RT frames replace the offline subtract-avg+LoG result inside detectTargets() (after
* the RELATIVE-tol oracle compare); with NO merged stack the RT stack is ingested as the primary
* input and conditioning is skipped entirely. Fail-LOUD (exception), not fail-safe: a silently
* half-configured A/B would corrupt the experiment. By Claude on 07/19/2026 */
private void loadRtLogInput(int debugLevel) {
final String rt_path_raw = clt_parameters.curt.det_rt_log_file.trim();
if (rt_path_raw.isEmpty()) return;
String rt_path = rt_path_raw;
if (!new java.io.File(rt_path).exists() && !new java.io.File(rt_path).isAbsolute()) {
rt_path = model_directory + java.io.File.separator + rt_path_raw; // bare name = relative to the model dir
}
java.io.File rt_file = new java.io.File(rt_path);
if (rt_file.isDirectory()) { // directory = newest matching stack in it (same convention as the merged-stack scan)
String [] cand = CorrectionParameters.getFilesByExtensionAsArray(rt_file.getPath(), SUFFIX_RT_LOG_TIFF);
if (cand.length == 0) throw new IllegalStateException("det_rt_log_file: no *"+SUFFIX_RT_LOG_TIFF+" in directory "+rt_file.getPath());
rt_path = newestFile(cand);
}
if (!new java.io.File(rt_path).exists()) throw new IllegalStateException("det_rt_log_file: not found: "+rt_path_raw);
ImagePlus imp_rt = new ImagePlus(rt_path);
if ((imp_rt.getWidth() <= 0) || (imp_rt.getStackSize() < 1)) throw new IllegalStateException("det_rt_log_file: failed to read stack: "+rt_path);
if (fpixels == null) { // no merged stack: the RT stack IS the input (pure RT-shape run, no oracle compare)
String rt_name = Path.of(rt_path).getFileName().toString();
String core_base = rt_name.toLowerCase().endsWith(SUFFIX_RT_LOG_TIFF.toLowerCase()) ?
rt_name.substring(0, rt_name.length() - SUFFIX_RT_LOG_TIFF.length()) : imp_rt.getTitle();
ingest(imp_rt, core_base, debugLevel);
if (fpixels == null) throw new IllegalStateException("det_rt_log_file: ingest failed for "+rt_path);
rt_log_primary = true;
System.out.println("CuasDetectRT: RT detection-frame stack is the PRIMARY input ("+fpixels.length+
" frames from "+rt_path+") - subtract-avg+LoG conditioning will be SKIPPED (frames are already LoG - avg)");
} else { // merged stack present: keep the RT frames aside for the compare-and-swap in detectTargets()
ImageStack rst = imp_rt.getStack();
if ((imp_rt.getWidth() != width) || (imp_rt.getHeight() != height)) {
throw new IllegalStateException("det_rt_log_file: size "+imp_rt.getWidth()+"x"+imp_rt.getHeight()+
" != merged stack "+width+"x"+height);
}
int first_slice = 1;
for (; (first_slice <= rst.getSize()) && !Character.isDigit(rst.getSliceLabel(first_slice).charAt(0)); first_slice++);
int nrt = rst.getSize() - first_slice + 1;
if (nrt <= 0) throw new IllegalStateException("det_rt_log_file: no timestamp-labeled slices in "+rt_path);
rt_log_pixels = new float [nrt][];
rt_log_ts = new String [nrt];
for (int i = 0; i < nrt; i++) {
rt_log_ts[i] = rst.getSliceLabel(first_slice + i);
rt_log_pixels[i] = (float []) rst.getPixels(first_slice + i);
}
System.out.println("CuasDetectRT: loaded RT detection-frame stack ("+nrt+" frames) from "+rt_path+
" - will replace the offline subtract-avg+LoG result (with a RELATIVE-tol compare where computable)");
}
base_name += "-RTLOG"; // distinct output names: never overwrite the offline arm of the A/B
}
// mode=0 (OpticalFlow curt_en path): consume a PRE-GENERATED merged-CUAS stack (ImagePlus). CUDA-free -
// the GPU generator (CuasRanging.prepareFpixels(), which uses the CUDA tile-processor kernels) is called
// explicitly by the caller, where the QuadCLT/GPU context lives, so this class stays independent of the
......@@ -922,6 +980,10 @@ public class CuasDetectRT {
+ " (synthetic 11x11 grid spans ~"+SYNTH_ROI+"; aim the ROI inside it)"); // By Claude on 06/15/2026
}
}
final boolean rt_log_mode = rt_log_primary || (rt_log_pixels != null); // item 4 R3 detector A/B // By Claude on 07/19/2026
if (rt_log_mode && clt_parameters.curt.synth_src) { // the A/B is a real-data gate; synthetic injection would invalidate it // By Claude on 07/19/2026
throw new IllegalStateException("det_rt_log_file is set together with curt_synth_src - not supported (the R3 A/B is a real-data gate); clear one of them");
}
final double min_frac_last = clt_parameters.curt.min_frac; // By Claude on 06/12/2026
if (clt_parameters.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+
......@@ -985,7 +1047,10 @@ 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.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 (rt_log_primary) { // item 4 R3: the ingested frames ARE the RT detection frames (LoG - avg) - no conditioning here // By Claude on 07/19/2026
System.out.println(now()+" detectTargets(): RT detection-frame input (det_rt_log_file) - subtract-average and LoG are SKIPPED (frames arrive already conditioned)");
}
if (clt_parameters.curt.subtract_avg && !rt_log_primary && (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 (rt_log_primary skip by Claude on 07/19/2026)
int npx = dpixels[0].length;
double [] mean = new double [npx];
int [] cnt = new int [npx];
......@@ -1012,6 +1077,11 @@ public class CuasDetectRT {
double alpha_pyr = 1.0; // pyramid averaging is now LINEAR (identity, no LReLU); rleak_pyr removed 2026-06-20, 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 (rt_log_primary) { // item 4 R3: frames are already (LoG - avg) - identity copy into the conditioned array // By Claude on 07/19/2026
for (int nseq = 0; nseq < dpixels_log.length; nseq++) {
System.arraycopy(dpixels[nseq], 0, dpixels_log[nseq], 0, dpixels[nseq].length);
}
} else {
System.out.println(now()+" detectTargets(): convolve2DLReLU (LoG)"); // By Claude on 06/11/2026
for (int nseq = 0; nseq < dpixels_log.length; nseq++) {
cuasRTUtils.convolve2DLReLU(
......@@ -1020,6 +1090,7 @@ public class CuasDetectRT {
dpixels_log[nseq], // double [] result_in,
alpha0); // final double alpha)
}
}
if (save_LoG_pixels) {
String title_conv2d = getBaseName()+SUFFIX_CONV2D+"-PSF"+d2s(cuasRTUtils.getPsfRadius())+
"-KR"+d2s(cuasRTUtils.getKernel2dRadius())+"-ALPHA0_"+d2s(alpha0);
......@@ -1034,6 +1105,54 @@ public class CuasDetectRT {
QuadCLTCPU.saveImagePlusInDirectory(imp_conv2d, getModelDirectory());
}
if (!rt_log_primary && (rt_log_pixels != null)) { // item 4 R3: compare the offline conditioned frames vs the RT stream, then SWAP the RT frames in // By Claude on 07/19/2026
// RELATIVE tol tier (ruling 3.3): offline = LoG(frame - whole-sequence union mean), RT = GPU LoG(frame) - base
// (prior-run average LoG'd in Java double, + gated EMA if enabled). Equal by LINEARITY only when the bases match
// (RT run with det_avg_file = the SAME sequence's -CUAS-RT-AVG and det_ema_rate = 0) and except at NaN-substitution
// edges; the compare REPORTS (no hard gate) - the verdict is Andrey's per 3.3.
final java.util.HashMap<String, float[]> rt_map = new java.util.HashMap<String, float[]>();
for (int i = 0; i < rt_log_ts.length; i++) rt_map.put(rt_log_ts[i], rt_log_pixels[i]);
final boolean cmp = clt_parameters.curt.subtract_avg; // without SUBAVG the offline frames have no background subtracted - numbers would be apples-to-oranges
int matched = 0;
java.util.ArrayList<String> missing = new java.util.ArrayList<String>();
double worst_rel = 0.0, sum_rel = 0.0; int worst_i = -1; long nan_mm_total = 0;
for (int i = 0; i < dpixels_log.length; i++) {
float [] rt = rt_map.get(time_stamps[i]);
if (rt == null) { missing.add(time_stamps[i]); continue; }
matched++;
if (cmp) {
double mag = 0.0, amax = 0.0; long nan_mm = 0;
double [] off = dpixels_log[i];
for (int p = 0; p < off.length; p++) {
boolean on = !Double.isNaN(off[p]), rn = !Float.isNaN(rt[p]);
if (on) { double a = Math.abs(off[p]); if (a > mag) mag = a; }
if (on && rn) { double d = Math.abs(off[p] - rt[p]); if (d > amax) amax = d; }
else if (on ^ rn) nan_mm++; // the known pre-vs-post-LoG NaN-edge divergence - counted, not diffed
}
double rel = (mag > 0) ? (amax / mag) : 0.0;
sum_rel += rel; nan_mm_total += nan_mm;
if (rel > worst_rel) { worst_rel = rel; worst_i = i; }
}
double [] dst = dpixels_log[i];
for (int p = 0; p < dst.length; p++) dst[p] = rt[p]; // the swap: downstream (pyramid/DNN) consumes the RT stream
}
if (!missing.isEmpty()) { // fail LOUD: a partially-swapped sequence is not an A/B of anything
throw new IllegalStateException("det_rt_log_file: "+missing.size()+" of "+dpixels_log.length+
" merged-stack timestamps have no RT detection frame (first missing: "+missing.get(0)+
") - the RT run and the merged stack must cover the same scenes");
}
if (cmp) {
System.out.println(now()+" detectTargets(): RT-vs-offline conditioned frames over "+matched+
" scenes: worst rel "+worst_rel+" (scene "+worst_i+(worst_i >= 0 ? (" "+time_stamps[worst_i]) : "")+
"), mean rel "+(sum_rel/Math.max(1, matched))+", NaN-mismatch px total "+nan_mm_total+
" (rel = max|off-rt| / max|off| per frame; expect a small floor from GPU-float render + prior-file base"+
" - EXACT linearity needs det_avg_file = this sequence's -CUAS-RT-AVG and det_ema_rate 0)");
} else {
System.out.println(now()+" detectTargets(): RT frames swapped in for "+matched+
" scenes; oracle compare SKIPPED (curt_subtract_avg is off - offline frames would have no background subtracted)");
}
System.out.println(now()+" detectTargets(): detection input = RT stream (det_rt_log_file); downstream outputs carry the -RTLOG name tag");
}
// 3d3 coarse-velocity path (and its conv5d-from-3d3 stage) removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
// The fine-velocity detector is now the DNN front-end fed from dpixels_pyramid; nothing consumes a 3d3 coarse-velocity history.
......
......@@ -2915,6 +2915,13 @@ public class CuasPoseRT {
clt_parameters.curt.det_log_save) ?
new ImageStack(center_CLT.getGeometryCorrection().getSensorWH()[0],
center_CLT.getGeometryCorrection().getSensorWH()[1]) : null;
// item 4 R3: det_ema_gate sizing - |LoG - avg| noise-floor statistics over the whole run,
// accumulated from the det_log_save readbacks (log10 histogram of |diff| in [1e-6, 1e3),
// 512 bins). Percentiles land within ~4% (one bin) - plenty for sizing a gate dial.
// By Claude on 07/19/2026.
final long [] det_diff_hist = (det_log_stack != null) ? new long [512] : null;
final long [] det_diff_cnt = {0L, 0L}; // [0] valid px, [1] exact zeros (kept out of the log bins)
final double [] det_diff_max = {0.0};
// item 4 step-4 (MAP v2, Andrey 07/19): move the render stage onto its OWN
// carved green-ctx module BEFORE the timed loop (the NVRTC compile must not
// land in scene 0's slot). KEY LAW: carve the AGGRESSOR - the render's
......@@ -3596,8 +3603,18 @@ public class CuasPoseRT {
det_render_issued[0] = false;
}
if ((det_log_stack != null) && det_log_active[0]) { // item 4 R2 DEBUG readback (ruling 3.4) // By Claude on 07/19/2026
det_log_stack.addSlice(ts_name, det_gq.renderLogGet(0)); // detection frame = LoG - avg (blocking)
final float [] det_diff = det_gq.renderLogGet(0); // detection frame = LoG - avg (blocking)
det_log_stack.addSlice(ts_name, det_diff);
det_render_issued[0] = false; // renderLogGet drained the render stream
for (float v : det_diff) { // item 4 R3: |diff| histogram for the det_ema_gate sizing // By Claude on 07/19/2026
if (Float.isNaN(v)) continue;
det_diff_cnt[0]++;
final double ad = Math.abs(v);
if (ad == 0.0) { det_diff_cnt[1]++; continue; }
if (ad > det_diff_max[0]) det_diff_max[0] = ad;
int bin = (int) ((Math.log10(ad) + 6.0) * (512.0 / 9.0)); // 1e-6..1e3 over 512 bins
det_diff_hist[(bin < 0) ? 0 : ((bin > 511) ? 511 : bin)]++;
}
}
} catch (Exception e) {
det_render_ok[0] = false;
......@@ -3832,6 +3849,43 @@ public class CuasPoseRT {
final ImagePlus imp_log = new ImagePlus(center_CLT.getImageName()+"-CUAS-RT-LOG", det_log_stack);
imp_log.getProcessor().resetMinAndMax();
center_CLT.saveImagePlusInModelDirectory(null, imp_log); // title as filename
// item 4 R3: det_ema_gate sizing from this run's post-LoG noise floor. Percentiles of |diff|
// from the log10 histogram; sigma from the median (|d| of zero-mean gaussian: median = 0.6745*sigma).
// Targets are a vanishing pixel fraction, so the low/mid percentiles are pure background; the gate
// suggestion is k*sigma (admit background updates, reject real content). RECOMMENDATION ONLY -
// the dial is Andrey's (ruling 3.1). By Claude on 07/19/2026.
if (det_diff_cnt[0] > 0) {
final double [] want = {0.50, 0.90, 0.99, 0.999, 0.9999};
final double [] pval = new double [want.length];
long seen = det_diff_cnt[1]; // exact zeros sort first
int wi = 0;
for (int b = 0; (b < det_diff_hist.length) && (wi < want.length); b++) {
seen += det_diff_hist[b];
while ((wi < want.length) && (seen >= (long) (want[wi] * det_diff_cnt[0]))) {
pval[wi++] = Math.pow(10.0, ((b + 1) * 9.0 / 512.0) - 6.0); // bin upper edge
}
}
while (wi < want.length) pval[wi++] = det_diff_max[0];
final double sigma = pval[0] / 0.6745;
long below_gate = det_diff_cnt[1];
final double gate = clt_parameters.curt.det_ema_gate;
if (gate > 0) {
final int gbin = (int) ((Math.log10(gate) + 6.0) * (512.0 / 9.0));
for (int b = 0; (b <= gbin) && (b < det_diff_hist.length); b++) below_gate += det_diff_hist[b];
}
System.out.println(String.format(
"CuasPoseRT: post-LoG |diff| noise floor over %,d valid px (%d scenes): sigma(from p50) %.3f;"+
" p50 %.3f p90 %.3f p99 %.3f p99.9 %.3f p99.99 %.3f max %.3f counts",
det_diff_cnt[0], det_log_stack.getSize(), sigma,
pval[0], pval[1], pval[2], pval[3], pval[4], det_diff_max[0]));
System.out.println(String.format(
"CuasPoseRT: det_ema_gate sizing: current %.3f admits %.4f%% of px; candidates 4*sigma=%.3f"+
" 5*sigma=%.3f 6*sigma=%.3f (dial stays Andrey's - ruling 3.1)%s",
gate, 100.0 * below_gate / det_diff_cnt[0],
4*sigma, 5*sigma, 6*sigma,
clt_parameters.curt.det_avg_file.trim().isEmpty() ?
" [CAVEAT: base = EMA seed this run - early frames converge, stats run low; size from a prior-file run]" : ""));
}
}
// -POSE-RT-CORR2D (DEBUG): per-scene pixel-domain correlations vs the virtual center // By Claude on 07/04/2026
if ((stack_corr != null) && (stack_corr.getSize() > 0)) {
......
......@@ -35,6 +35,7 @@ public class CuasRtParameters {
public boolean det_avg_save = true; // item 4 R2: accumulate the NaN-aware raw-domain running average on the GPU during the run and save it after the loop as -CUAS-RT-AVG (the NEXT run's det_avg_file). One D2H after the loop - free during the timed stage. // By Claude on 07/19/2026
public double det_ema_rate = 0.02; // item 4 R2 (ruling 3.1: EMA refresh reasonable to TRY): per-scene EMA rate of the post-LoG average, avg += rate*(LoG - avg) where the gate admits. 0 = OFF (prior-file-only base, no refresh). // By Claude on 07/19/2026
public double det_ema_gate = 10.0; // item 4 R2 (ruling 3.1: the EMA MUST be gated so extremely slow-apparent-motion targets - fast but head-on, ~static px - are never absorbed into the background): update only where |LoG - avg| <= this (post-LoG counts). <=0 = UNGATED (a loud console warning; only for experiments). Default 10 is a placeholder dial - size it from the post-LoG noise floor of real runs. // By Claude on 07/19/2026
public String det_rt_log_file = ""; // item 4 R3 (detector A/B): path to a pose-RT run's -CUAS-RT-LOG stack (det_log_save output; a directory = use its newest *-CUAS-RT-LOG.tiff). Non-empty = the offline detector (proc mode 3) consumes these RT detection frames INSTEAD of its own subtract-avg+LoG conditioning; when the merged-CUAS stack is also present AND curt_subtract_avg is on, the offline frames are still computed and compared (RELATIVE tol, ruling 3.3 - offline subtracts PRE-LoG, RT subtracts POST-LoG, equal by linearity except NaN edges). Outputs get an -RTLOG name suffix. Empty = normal offline path. // By Claude on 07/19/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 boolean pose_full = false; // DEBUG: use ALL strength-selected tiles (~1074) - the -POSE-RT-TILE-CALIB calibration is neither read nor written (temporary bypass of the 150-tile filter for measurement debugging). // By Claude on 07/04/2026
public boolean pose_corr_save = false; // DEBUG: save the per-scene 2D correlations vs the virtual center in the pixel domain (-POSE-RT-CORR2D: z=scenes, tile grid of 16x16 cells, last LMA cycle) - lean engine only. // By Claude on 07/04/2026
......@@ -172,6 +173,8 @@ public class CuasRtParameters {
"Item 4 R2 (ruling 3.1): per-scene EMA rate of the post-LoG average, avg += rate*(LoG-avg) where the gate admits. 0 = OFF (prior-file-only base).");
gd.addNumericField("EMA gate |LoG-avg| <=", this.det_ema_gate, 6,8,"counts", // By Claude on 07/19/2026 (item 4 R2)
"Item 4 R2 (ruling 3.1: the EMA MUST be gated): update the average only where |LoG-avg| is at most this (post-LoG counts) so slow-apparent-motion targets are never absorbed. <=0 = UNGATED (loud warning; experiments only).");
gd.addStringField("RT LoG stack for detection (A/B)", this.det_rt_log_file, 60, // By Claude on 07/19/2026 (item 4 R3)
"Item 4 R3 detector A/B: path to a pose-RT run's -CUAS-RT-LOG stack (or a directory holding one). Non-empty = the offline detector consumes these RT detection frames instead of its own subtract-avg+LoG; with the merged stack present and subtract-average on, the offline frames are also computed and compared (RELATIVE tol). Outputs get -RTLOG in the name. Empty = normal offline path.");
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).");
......@@ -398,6 +401,7 @@ public class CuasRtParameters {
this.det_avg_save = gd.getNextBoolean(); // By Claude on 07/19/2026 (item 4 R2)
this.det_ema_rate = gd.getNextNumber(); // By Claude on 07/19/2026 (item 4 R2)
this.det_ema_gate = gd.getNextNumber(); // By Claude on 07/19/2026 (item 4 R2)
this.det_rt_log_file = gd.getNextString().trim();// By Claude on 07/19/2026 (item 4 R3)
this.pose_lean = gd.getNextBoolean(); // By Claude on 07/05/2026
this.pose_full = gd.getNextBoolean(); // By Claude on 07/04/2026
this.pose_corr_save = gd.getNextBoolean(); // By Claude on 07/04/2026
......@@ -519,6 +523,7 @@ public class CuasRtParameters {
properties.setProperty(prefix+"det_avg_save", this.det_avg_save+""); // boolean // By Claude on 07/19/2026 (item 4 R2)
properties.setProperty(prefix+"det_ema_rate", this.det_ema_rate+""); // double // By Claude on 07/19/2026 (item 4 R2)
properties.setProperty(prefix+"det_ema_gate", this.det_ema_gate+""); // double // By Claude on 07/19/2026 (item 4 R2)
properties.setProperty(prefix+"det_rt_log_file", this.det_rt_log_file); // String // By Claude on 07/19/2026 (item 4 R3)
properties.setProperty(prefix+"pose_lean", this.pose_lean+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"pose_full", this.pose_full+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_corr_save", this.pose_corr_save+""); // boolean // By Claude on 07/04/2026
......@@ -640,6 +645,7 @@ public class CuasRtParameters {
if (properties.getProperty(prefix+"det_avg_save")!=null) this.det_avg_save=Boolean.parseBoolean(properties.getProperty(prefix+"det_avg_save")); // By Claude on 07/19/2026 (item 4 R2)
if (properties.getProperty(prefix+"det_ema_rate")!=null) this.det_ema_rate=Double.parseDouble(properties.getProperty(prefix+"det_ema_rate")); // By Claude on 07/19/2026 (item 4 R2)
if (properties.getProperty(prefix+"det_ema_gate")!=null) this.det_ema_gate=Double.parseDouble(properties.getProperty(prefix+"det_ema_gate")); // By Claude on 07/19/2026 (item 4 R2)
if (properties.getProperty(prefix+"det_rt_log_file")!=null) this.det_rt_log_file=properties.getProperty(prefix+"det_rt_log_file").trim(); // By Claude on 07/19/2026 (item 4 R3)
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+"pose_full")!=null) this.pose_full=Boolean.parseBoolean(properties.getProperty(prefix+"pose_full")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_corr_save")!=null) this.pose_corr_save=Boolean.parseBoolean(properties.getProperty(prefix+"pose_corr_save")); // By Claude on 07/04/2026
......@@ -764,6 +770,7 @@ public class CuasRtParameters {
cp.det_avg_save = this.det_avg_save; // By Claude on 07/19/2026 (item 4 R2)
cp.det_ema_rate = this.det_ema_rate; // By Claude on 07/19/2026 (item 4 R2)
cp.det_ema_gate = this.det_ema_gate; // By Claude on 07/19/2026 (item 4 R2)
cp.det_rt_log_file = this.det_rt_log_file; // By Claude on 07/19/2026 (item 4 R3)
cp.pose_lean = this.pose_lean;
cp.pose_full = this.pose_full; // By Claude on 07/04/2026
cp.pose_corr_save = this.pose_corr_save; // By Claude on 07/04/2026
......
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