Commit 472435db authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: CuasPoseRT phase A - RT pose-adjustment prototype (curt_pose_test)

Top-level scene iterator re-generating per-scene 3-angle poses against the
persistent virtual-center reference, RT-style: ascending time order, zero-order
prediction seeding (fit anchored to the center, prediction only warm-starts the
LMA), single pass on the final combo DSI (no refinement pass - it only existed
because disparity arrived after initial orientations offline). Measurement
engine = proven Interscene.adjustPairsLMAInterscene (reference GPU data set
once); phase B will swap it for the lean TD-average x virtual-center path with
GPU argmax+eigen kernels, keeping this iterator + CSV as the oracle.

- new cuas/rt/CuasPoseRT.testPoseSequence(): reference prep (strength>
  curt_pose_str tile selection, setReferenceGPU with center CLT), stored-pose
  seed/truth from center ErsCorrection scenes_poses, per-scene fit with 3-angle
  param_select (XYZ locked), ERS dt from pose finite differences (disable_ers),
  MB off, coast-on-failure; writes -POSE-RT-TEST.csv + fitted-vs-stored summary
- params curt_pose_test (bool) + curt_pose_str (1.0) - 6 plumbing sites
- OpticalFlow curt_en branch: curt_pose_test runs INSTEAD of detection

Build: mvn compile clean. Runtime validation pending (Eclipse/Eyesis run on
sequence 1773135476_186641, truth = re-adjusted stored poses).
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 5e14bb72
/**
**
** CuasPoseRT.java - RT pose-adjustment prototype: per-scene 3-angle pose
** fitting against the persistent virtual-center reference.
**
** Copyright (C) 2026 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** CuasPoseRT.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
package com.elphel.imagej.cuas.rt;
import java.io.FileWriter;
import java.io.IOException;
import com.elphel.imagej.cameras.CLTParameters;
import com.elphel.imagej.gpu.TpTask;
import com.elphel.imagej.tileprocessor.ErsCorrection;
import com.elphel.imagej.tileprocessor.Interscene;
import com.elphel.imagej.tileprocessor.OpticalFlow;
import com.elphel.imagej.tileprocessor.QuadCLT;
import com.elphel.imagej.tileprocessor.QuadCLTCPU;
import com.elphel.imagej.tileprocessor.TwoQuadCLT;
import ij.Prefs;
/**
* Phase A of the RT pose-adjustment package (design: ANDREY_CONTINUE 2026-07-03,
* details in imagej-elphel-internal handoffs). A top-level scene iterator that
* re-generates the per-scene 3-angle (az, tilt, roll) poses of a CUAS sequence
* by fitting each scene directly against the persistent VIRTUAL-CENTER reference
* (center CLT), in ascending time order, seeded by prediction — the RT processing
* pattern. Uses the proven offline measurement engine
* (Interscene.adjustPairsLMAInterscene(), which assumes the reference GPU data is
* set once for all scenes); Phase B will swap that engine for the lean
* TD-average x virtual-center correlation with the GPU argmax+eigen kernels,
* keeping this iterator and its comparison output unchanged as the oracle.
*
* Differences from the offline setInitialOrientationsCuas():
* - ascending scene order (RT: "now" keeps arriving) instead of descending;
* - pose seed = previous fitted pose (zero-order prediction; the fit is anchored
* to the virtual center, so prediction only warm-starts the LMA and never
* accumulates into the geometry) instead of IMS integration;
* - single pass with the FINAL combo DSI (no refinement pass needed - the offline
* refinement only existed because disparity arrived after initial orientations);
* - tile selection by simple strength threshold (curt_pose_str) of the combo DSI
* (equivalent to old getReliableTiles: >1.0 gives 1074 vs 1055 tiles on the
* reference sequence); the optimized minimal selection is a future slow-loop task.
*
* Output: per-scene CSV (predicted/fitted/stored poses + deltas + rms) in the model
* directory and a console summary of fitted-vs-stored statistics. Stored poses
* (scenes_poses of the center ErsCorrection, restored from INTERFRAME corr-xml)
* are the comparison truth - the re-adjusted offline set fitted from the same
* DSI vintage.
*
* By Claude on 07/03/2026, from Andrey's design.
*/
public class CuasPoseRT {
public static final double [] ZERO3 = {0.0, 0.0, 0.0};
/**
* Re-generate per-scene poses against the virtual-center reference, RT-style.
*
* @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
* @param quadCLTs scene sequence (time-ascending indices), instances built
* with image data (e.g. by CuasRanging.prepareFpixels())
* @param debugLevel debug level
* @return fitted poses [nscene][2][3] ({xyz,atr}, xyz locked to zero) or null
*/
public static double [][][] testPoseSequence(
final CLTParameters clt_parameters,
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 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;
final double mb_max_gain = clt_parameters.imp.mb_max_gain_inter;
final double min_offset = clt_parameters.imp.min_offset;
final double max_offset = clt_parameters.imp.max_rel_offset *
center_CLT.getTilesX() * center_CLT.getTileSize();
final double max_rms = clt_parameters.imp.eig_use ?
clt_parameters.imp.eig_max_rms : clt_parameters.imp.max_rms;
final double [] reg_weights = clt_parameters.ilp.ilma_regularization_weights;
final double [] lma_rms = new double [clt_parameters.imp.eig_use ? 6 : 4];
// 3-angle parameter selection: azimuth, tilt (+ optionally roll), XYZ locked
// (rotation-only pose: displacements are good enough from the mechanical
// construction; same as offline CUAS lock_position=true)
final boolean [] param_select = ErsCorrection.getParamSelect(
false, // use_Z (lock_position)
clt_parameters.imp.lma_use_R, // use_R
false, // use_XY (lock_position)
true, // use_AT
false, false, false); // ERS az/tilt/roll - off
if (debugLevel > -3) {
System.out.print("CuasPoseRT.testPoseSequence(): param_select=[");
for (boolean b : param_select) System.out.print(b ? "+" : "-");
System.out.println("], min_str="+min_str+", max_offset="+max_offset);
}
// ---- Reference prep (ONCE) - the persistent virtual-center TD reference ----
final boolean is_aux = center_CLT.isAux();
final double [][] center_dsi = center_CLT.dsi;
final double [] disparity = center_dsi[is_aux ? TwoQuadCLT.DSI_DISPARITY_AUX : TwoQuadCLT.DSI_DISPARITY_MAIN];
final double [] disparity_lma = center_dsi[is_aux ? TwoQuadCLT.DSI_DISPARITY_AUX_LMA : TwoQuadCLT.DSI_DISPARITY_MAIN_LMA];
final double [] strength = center_dsi[is_aux ? TwoQuadCLT.DSI_STRENGTH_AUX : TwoQuadCLT.DSI_STRENGTH_MAIN];
final double [] center_disparity = (use_lma_dsi && (disparity_lma != null)) ? disparity_lma : disparity;
final boolean [] reliable_ref = new boolean [strength.length];
int num_reliable = 0;
for (int i = 0; i < strength.length; i++) {
reliable_ref[i] = (strength[i] > min_str) && !Double.isNaN(center_disparity[i]);
if (reliable_ref[i]) num_reliable++;
}
if (debugLevel > -3) {
System.out.println("CuasPoseRT.testPoseSequence(): num_reliable="+num_reliable+
" (strength > "+min_str+")");
}
final double [][] pXpYD_center = OpticalFlow.transformToScenePxPyD(
null, // final Rectangle [] extra_woi,
center_disparity, // final double [] disparity_ref,
ZERO3, // final double [] scene_xyz,
ZERO3, // final double [] scene_atr,
center_CLT, // final QuadCLT scene_QuadClt,
center_CLT); // final QuadCLT reference_QuadClt
final float [][] fclt = new float [][] {center_CLT.getCenterClt()};
final TpTask [][] tp_tasks_center = Interscene.setReferenceGPU(
clt_parameters, // CLTParameters clt_parameters,
center_CLT, // QuadCLT ref_scene,
center_disparity, // double [] ref_disparity,
pXpYD_center, // double [][] ref_pXpYD,
fclt, // final float [][] fclt,
reliable_ref, // final boolean [] selection,
margin, // final int margin,
mb_tau, // double mb_tau,
mb_max_gain, // double mb_max_gain,
null, // double [][] mb_vectors (center does not move)
debugLevel); // int debug_level
// ---- Stored poses (comparison truth + seed) ----
final ErsCorrection ers_center = center_CLT.getErsCorrection();
final double [][][] stored = new double [quadCLTs.length][][];
for (int i = 0; i < quadCLTs.length; i++) if (quadCLTs[i] != null) {
stored[i] = ers_center.getSceneXYZATR(quadCLTs[i].getImageName()); // may be null
}
int earliest = -1;
for (int i = 0; i < quadCLTs.length; i++) if (quadCLTs[i] != null) { earliest = i; break; }
if (earliest < 0) {
System.out.println("CuasPoseRT.testPoseSequence(): no scenes");
return null;
}
// Seed: earliest stored pose ("cheating" bootstrap); identity if unavailable.
// Any scene works as the entry point - every fit is anchored to the virtual
// center, not chained to neighbors.
double [][] predicted = (stored[earliest] != null) ?
new double [][] {stored[earliest][0].clone(), stored[earliest][1].clone()} :
new double [][] {ZERO3.clone(), ZERO3.clone()};
if (stored[earliest] == null) {
System.out.println("CuasPoseRT.testPoseSequence(): WARNING - no stored pose for seed scene "+
quadCLTs[earliest].getImageName()+", seeding with identity");
}
// ---- Ascending per-scene loop (the RT iterator) ----
final double [][][] fitted = new double [quadCLTs.length][][];
final int [] fail_reason = new int [1];
final StringBuffer sb = new StringBuffer();
sb.append("index, timestamp, pred_az, pred_tilt, pred_roll, fit_az, fit_tilt, fit_roll,"+
" stored_az, stored_tilt, stored_roll, dfit_az, dfit_tilt, dfit_roll, rms, weight, num_tiles, fail\n");
int num_ok = 0, num_fail = 0;
double [] sum2_d = new double [3];
double [] max_d = new double [3];
int num_cmp = 0;
double prev_ts = Double.NaN;
double [][] prev_pose = null;
for (int nscene = earliest; nscene < quadCLTs.length; nscene++) {
if (quadCLTs[nscene] == null) continue;
final String ts_name = quadCLTs[nscene].getImageName();
final double ts = Double.parseDouble(ts_name.replace("_", "."));
// ERS velocities from finite differences of the pose sequence (substitute
// for the offline PIMU rates; only the residual/wobble rates ~0.05 rad/s -
// ERS params are not fitted, disable_ers=true below)
double [][] dxyzatr_dt = new double [][] {ZERO3.clone(), ZERO3.clone()};
if ((prev_pose != null) && !Double.isNaN(prev_ts) && (ts > prev_ts)) {
for (int j = 0; j < 3; j++) {
dxyzatr_dt[1][j] = (predicted[1][j] - prev_pose[1][j]) / (ts - prev_ts);
}
}
quadCLTs[nscene].getErsCorrection().setErsDt(
QuadCLTCPU.scaleDtToErs(clt_parameters, dxyzatr_dt));
fail_reason[0] = 0;
double [][] pose = Interscene.adjustPairsLMAInterscene(
clt_parameters, // CLTParameters clt_parameters,
true, // boolean initial_adjust,
false, // boolean fpn_disable,
true, // boolean disable_ers,
new double [] {min_offset, max_offset, 0.0}, // double [] min_max,
fail_reason, // int [] fail_reason,
center_CLT, // QuadCLT ref_QuadClt (virtual center)
center_disparity, // double [] ref_disparity,
center_CLT, // QuadCLT first_QuadClt (virtual center)
pXpYD_center, // double [][] pXpYD_ref,
clt_parameters.imp.cuas_min_confidence, // double min_confidence (as re-adjust: final-DSI vintage)
reliable_ref, // boolean [] reliable_ref,
null, // boolean [] reliable_all,
tp_tasks_center[0], // TpTask[] tp_tasks_ref,
quadCLTs[nscene], // QuadCLT scene_QuadClt,
predicted, // double [][] camera_xyzatr (initial),
predicted, // double [][] scene_xyzatr_pull,
new double [2][3], // double [][] ref_xyzatr,
param_select, // boolean[] param_select,
reg_weights, // double [] param_regweights,
lma_rms, // double [] rms_out,
max_rms, // double max_rms,
mb_tau, // double mb_tau,
mb_max_gain, // double mb_max_gain,
null, // double [][] mb_vectors (MB off in phase A),
null, // double [][][] coord_motion_rslt,
debugLevel - 2); // int debug_level
final boolean ok = (pose != null);
if (ok) {
fitted[nscene] = pose;
num_ok++;
} else {
// coast: keep the prediction as this scene's pose, continue the sequence
fitted[nscene] = new double [][] {predicted[0].clone(), predicted[1].clone()};
num_fail++;
if (debugLevel > -4) {
System.out.println("CuasPoseRT: scene "+nscene+" ("+ts_name+") FAILED, reason="+
fail_reason[0]+" ("+Interscene.getFailReason(fail_reason[0])+"), coasting prediction");
}
}
// CSV row + comparison stats
final double [] st = (stored[nscene] != null) ? stored[nscene][1] : null;
sb.append(nscene+", "+ts_name);
for (int j = 0; j < 3; j++) sb.append(String.format(", %.6f", predicted[1][j]));
for (int j = 0; j < 3; j++) sb.append(String.format(", %.6f", fitted[nscene][1][j]));
for (int j = 0; j < 3; j++) sb.append((st != null) ? String.format(", %.6f", st[j]) : ", NaN");
for (int j = 0; j < 3; j++) {
double d = (st != null) ? (fitted[nscene][1][j] - st[j]) : Double.NaN;
sb.append((st != null) ? String.format(", %.6f", d) : ", NaN");
if (ok && (st != null)) {
sum2_d[j] += d * d;
if (Math.abs(d) > max_d[j]) max_d[j] = Math.abs(d);
}
}
if (ok && (stored[nscene] != null)) num_cmp++;
sb.append(String.format(", %.6f, %.1f, %.0f, %d\n",
ok ? lma_rms[0] : Double.NaN, lma_rms[2], lma_rms[3], fail_reason[0]));
// zero-order prediction for the next scene
prev_pose = predicted;
prev_ts = ts;
predicted = new double [][] {fitted[nscene][0].clone(), fitted[nscene][1].clone()};
}
// ---- Output ----
final String csv_path = center_CLT.getX3dDirectory(true) + Prefs.getFileSeparator() +
center_CLT.getImageName() + "-POSE-RT-TEST.csv";
try (FileWriter fw = new FileWriter(csv_path)) {
fw.write(sb.toString());
System.out.println("CuasPoseRT.testPoseSequence(): saved "+csv_path);
} catch (IOException e) {
System.out.println("CuasPoseRT.testPoseSequence(): FAILED to save "+csv_path+": "+e.getMessage());
}
System.out.println("CuasPoseRT.testPoseSequence(): scenes OK="+num_ok+", failed(coasted)="+num_fail+
", compared="+num_cmp);
if (num_cmp > 0) {
final String [] names = {"azimuth", "tilt", "roll"};
for (int j = 0; j < 3; j++) {
System.out.println(String.format(
" fitted-stored %8s: RMS=%9.6f rad (%8.4f mrad), max=%9.6f rad",
names[j], Math.sqrt(sum2_d[j]/num_cmp), 1000*Math.sqrt(sum2_d[j]/num_cmp), max_d[j]));
}
}
return fitted;
}
}
...@@ -1127,6 +1127,8 @@ min_str_neib_fpn 0.35 ...@@ -1127,6 +1127,8 @@ min_str_neib_fpn 0.35
public boolean curt_en = true; // enable cuas rt calculation (not needed with a separate button) 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_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_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
//=== LoG prefilter === //=== LoG prefilter ===
public double curt_psf_radius = 1.0; // sensor PSF radius for LoG pre-filter 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 public double curt_n_sigma = 4.0; // cutoff LoG kernel array, number of sigmas
...@@ -3416,6 +3418,10 @@ min_str_neib_fpn 0.35 ...@@ -3416,6 +3418,10 @@ min_str_neib_fpn 0.35
"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."); "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, 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)."); "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.addMessage("=== LoG prefilter ==="); gd.addMessage("=== LoG prefilter ===");
gd.addNumericField("Optical PSF radius", this.curt_psf_radius, 6,8,"pix", gd.addNumericField("Optical PSF radius", this.curt_psf_radius, 6,8,"pix",
...@@ -5008,6 +5014,8 @@ min_str_neib_fpn 0.35 ...@@ -5008,6 +5014,8 @@ min_str_neib_fpn 0.35
this.curt_en = gd.getNextBoolean(); this.curt_en = gd.getNextBoolean();
this.curt_calib = gd.getNextBoolean(); // By Claude on 07/03/2026 this.curt_calib = gd.getNextBoolean(); // By Claude on 07/03/2026
this.curt_cond_test = gd.getNextBoolean(); 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_psf_radius = gd.getNextNumber(); this.curt_psf_radius = gd.getNextNumber();
this.curt_n_sigma = gd.getNextNumber(); this.curt_n_sigma = gd.getNextNumber();
...@@ -6374,6 +6382,8 @@ min_str_neib_fpn 0.35 ...@@ -6374,6 +6382,8 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"curt_en", this.curt_en+""); // boolean 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_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_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_psf_radius", this.curt_psf_radius+""); // double properties.setProperty(prefix+"curt_psf_radius", this.curt_psf_radius+""); // double
properties.setProperty(prefix+"curt_n_sigma", this.curt_n_sigma+""); // double properties.setProperty(prefix+"curt_n_sigma", this.curt_n_sigma+""); // double
...@@ -6774,6 +6784,8 @@ min_str_neib_fpn 0.35 ...@@ -6774,6 +6784,8 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"curt_en")!=null) this.curt_en=Boolean.parseBoolean(properties.getProperty(prefix+"curt_en")); 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_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_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_psf_radius")!=null) this.curt_psf_radius=Double.parseDouble(properties.getProperty(prefix+"curt_psf_radius")); 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")); if (properties.getProperty(prefix+"curt_n_sigma")!=null) this.curt_n_sigma=Double.parseDouble(properties.getProperty(prefix+"curt_n_sigma"));
...@@ -9059,6 +9071,8 @@ min_str_neib_fpn 0.35 ...@@ -9059,6 +9071,8 @@ min_str_neib_fpn 0.35
imp.curt_en = this.curt_en; imp.curt_en = this.curt_en;
imp.curt_calib = this.curt_calib; // By Claude on 07/03/2026 imp.curt_calib = this.curt_calib; // By Claude on 07/03/2026
imp.curt_cond_test = this.curt_cond_test; 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_psf_radius = this.curt_psf_radius; imp.curt_psf_radius = this.curt_psf_radius;
imp.curt_n_sigma = this.curt_n_sigma; 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 // rleak0 imp.X copy removed 2026-06-20 (LReLU now LINEAR); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
......
...@@ -7289,7 +7289,19 @@ java.lang.NullPointerException ...@@ -7289,7 +7289,19 @@ java.lang.NullPointerException
ImageDtt.THREADS_MAX, // int threadsMax, ImageDtt.THREADS_MAX, // int threadsMax,
debugLevel); // int debugLevel debugLevel); // int debugLevel
} }
if (clt_parameters.imp.curt_cond_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 +
// fitted-vs-stored summary (truth = scenes_poses restored from INTERFRAME corr-xml).
// By Claude on 07/03/2026, from Andrey's design.
System.out.println("===== CUAS RT pose test (curt_pose_test): per-scene 3-angle fit vs virtual center =====");
com.elphel.imagej.cuas.rt.CuasPoseRT.testPoseSequence(
clt_parameters, // CLTParameters clt_parameters,
master_CLT, // QuadCLT center_CLT,
quadCLTs, // QuadCLT [] quadCLTs,
debugLevel); // int debugLevel
} else if (clt_parameters.imp.curt_cond_test) {
// Conditioning/calibration diagnostic (curt_cond_test), runs INSTEAD of RT detection: // Conditioning/calibration diagnostic (curt_cond_test), runs INSTEAD of RT detection:
// raw /jp4/ baseline (no photometric/FPN/conditioning), saved as -CUAS-PERSENSOR-RAW for // 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 // side-by-side compare with the conditioned -CUAS-PERSENSOR (saved by the calibration step when
......
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