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
......@@ -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