1. 13 Jul, 2026 5 commits
    • Andrey Filippov's avatar
      CLAUDE: chain-rule diagnostic - RMS meas>solved pairs in the pose cycle trace · e8d95f75
      Andrey Filippov authored
      Per outer cycle: RE-MEASURED pure RMS (prepareLMA, after re-correlation) >
      MODEL-PREDICTED pure RMS (runLma, after the solve). Jacobian/chain-rule error
      signature (Andrey's hypothesis): solved_n low but meas_{n+1} bounces back up -
      the model overpromised and re-correlation takes it back. Healthy damping:
      meas_{n+1} ~ solved_n, both creep down. Zero extra computation - both values
      already existed inside IntersceneLma.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      e8d95f75
    • Andrey Filippov's avatar
      CLAUDE: curt.pose_lma_debug - per-inner-step solver logging for the pose LMA · 4ff201fa
      Andrey Filippov authored
      New int knob (0 = quiet): >=2 passes the level into the inner runLma so its
      existing per-step line prints (good/done flags, full/pure RMS, lambda), with a
      CuasPoseRT header attributing each block to its scene + outer cycle; 3-4 =
      the solver's deeper dumps. Shared IntersceneLma untouched.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      4ff201fa
    • Andrey Filippov's avatar
      CLAUDE: curt.pose_lambda - near-GN inner LMA start + innerLMA counts in trace · 972bcbda
      Andrey Filippov authored
      Root cause of the 6-13 outer cycles (Andrey's diagnosis, confirmed in code):
      the inner runLma restarts at ilp.ilma_lambda=0.1 EVERY outer measure<->solve
      cycle, and the 0.1%-improvement inner exit fires while steps are still
      lambda-limited -> outer loop under-relaxes (~0.8/cycle decay). New
      curt.pose_lambda (default 0.001, 0 = legacy ilma_lambda) starts the inner
      solve near-Gauss-Newton for the near-linear overdetermined 3-angle problem.
      Trace line now also logs inner runLma iterations per outer cycle + lambda0.
      
      07/12 21:56 run (legacy convergence + uniform MB): dstored RMS az/tilt/roll
      0.1416/0.0777/0.0983 vs per-tile-MB baseline 0.1355/0.0765/0.1005 = uniform
      MB VALIDATED (A1); 0 degenerates; outer cycles mean 7.4, max 13 @ lambda 0.1.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      972bcbda
    • Andrey Filippov's avatar
      CLAUDE: fix uniform-MB representative point + per-cycle dATR convergence trace · 923f3785
      Andrey Filippov authored
      - uniformMotionBlur: representative = defined reference tile nearest the frame
        center passing getMotionBlur's own gates (mirrored locally; the synthetic
        averaged frame-center point failed SILENTLY on every scene in the 07/12 run).
        Degenerate fallback now prints the tried point + rates (self-explaining).
      - leanFitScene: per-scene 'CuasPoseRT cycles: ... dATR/cycle = ...' trace line
        (fixed AND legacy modes) - the convergence-trajectory data for the open
        'why does azimuth need so many cycles' investigation (3 cycles: az RMS
        0.5209; 6 cycles: 0.1805; legacy baseline: 0.1355 px).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      923f3785
    • Andrey Filippov's avatar
      CLAUDE: lean v2 pose policies - uniform MB vector + fixed LMA cycles · 6731866f
      Andrey Filippov authored
      Phase A items 1-2 of the pose GPU-migration plan (Andrey's design 07/12/2026):
      - curt.pose_mb_uniform (default ON): ONE motion-blur vector per scene shared by
        all tiles - constant-rpm CUAS flow is uniform up to the roll component (small)
        and wobble (2nd degree). Same Jacobian-times-rates as per-tile getMotionBlur,
        evaluated at the frame center and broadcast; rates = finite differences of
        predicted poses, unchanged. OFF = legacy per-tile path (A/B knob).
      - curt.pose_cycles (default 3): EXACTLY N measure<->solve cycles, no convergence
        early exit (static GPU launch shape); convergence delta kept as QC printout
        (flags scenes missing the legacy exit_change_atr). 0 = legacy convergence exit.
      
      Validation = pose_test run vs 07/12 JNA baseline (497/497, az/tilt/roll RMS
      0.1355/0.0765/0.1005 px) - policy A/B by pose quality, not bit-exactness.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      6731866f
  2. 12 Jul, 2026 3 commits
    • Andrey Filippov's avatar
      CLAUDE: JNA hookup of the GPU TD consolidation + curt OOB margin params · 0937dbcc
      Andrey Filippov authored
      Use the frozen v1 kernel chain in the program instead of the Java CPU code
      (roadmap step 4, JNA-only per Andrey's 07/12/2026 ruling):
      - GpuQuad.execConsolidateSensorsTD: base hook, returns false (JCuda backend
        keeps the CPU bridge - no JCuda launch code for new kernels).
      - GpuQuadJna override -> TpJna.tp_proc_exec_consolidate: on-device chain,
        TD never leaves the GPU (zero-copy; only flattened TpTask streams cross);
        validated bit-exact vs the real-scene avg_td_oob oracle case
        (tile_processor_gpu jna/test_proc_consolidate, max|diff|=0).
      - CuasTD.consolidateToSlot0: shared bridge - GPU-first, CPU fallback now
        OOB-mask-capable (oobSensorMasks + masked consolidateSensorsTD), so both
        backends produce the v1-filtered average.
      - CuasPoseRT.leanMeasure + CuasRender.renderSceneVirtual: task sets hoisted
        out of the MB/no-MB branches and passed to the bridge (replaces the
        getCltData -> consolidateSensorsTD -> setCltData(0) round-trip).
      - CuasRtParameters: new curt.oob_soft / curt.oob_hard (defaults =
        CuasTD.OOB_SOFT/HARD_DEFAULT 12/8, frozen spec; 0/0 = v0 unfiltered A/B
        knob), new dialog group under CUAS RT; corr-xml keys _curt_oob_*;
        consumed by the bridge at both call sites and by the avg_td_oob export
        (replaces hardcoded defaults in CuasRT.kernelTest).
      Verified: mvn package; CuasTD headless self-test ALL PASSED (exit 0).
      Co-authored-by: 's avatarClaude Fable 5 <noreply@anthropic.com>
      0937dbcc
    • Andrey Filippov's avatar
      CLAUDE: avg_td_oob CPU oracle (2c OOB priority) + export + dropdown entry · eab1660e
      Andrey Filippov authored
      CuasTD.oobSensorMasks() = the contract oracle of the future
      index_consolidate (pass 1) + OOB priority (pass 2) kernels: input
      TpTask[2][] (MB pair, [1] may be null = no-MB, matching
      setInterTasksMotionBlur), sets matched by txy lookup; per tile - present
      (task!=0) in EVERY provided set, else mask 0; per sensor - depth = min
      over sets of tile-center distance to nearest frame edge; depth<hard
      always skipped, any sensor >=soft -> only those, else hard survivors as
      last resort; NaN xy excluded; margins 0 = tier off (frozen spec
      soft~12/hard~8 @4e0db8b).
      consolidateSensorsTD(fclt,counts,masks,colors): mask-gated average,
      mask 0 = whole-tile NaN poison; null masks = bit-exact v0 (2-arg
      delegates).
      AvgTdExport.exportOob(): case carries RAW flattened task streams (exact
      GPU struct layout, both sets) + margins in manifest + expected masks/
      avg/counts.
      KERNEL_TESTS += avg_td_oob; CuasRT.kernelTest case (set 1 = null until
      the RT-chain MB wiring).
      Headless self-test (java -cp ... cuas.rt.CuasTD): 18/18 PASSED
      (tiering, MB drop, no-MB mode, NaN xy, poison, v0 bit-exact repro).
      mvn -DskipTests clean package: OK.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      eab1660e
    • Andrey Filippov's avatar
      CLAUDE: curt.kernel_test dropdown - one GPU-kernel oracle test per run · 189b7f39
      Andrey Filippov authored
      Replaces the would-be per-kernel checkbox sprawl (Andrey 07/12 design):
      - CuasRtParameters: KERNEL_TESTS registry {none, avg_td} + kernel_test
        String param (addChoice, corr-xml _curt_kernel_test, unknown values
        sanitized to none); one dropdown entry per kernel in the 2c+ ladder.
      - CuasRT.diagnostics(): kernel_test != none -> EXCLUSIVE kernelTest()
        dispatch, nothing else runs that pass.
      - kernelTest() avg_td case = the AvgTdExport call site (settles the open
        pick): conditioned image_data of the GPU-bound scene -> uniform-grid
        convert -> CPU oracle + testdata case export (<model>/testdata/avg_td,
        incl. per-sensor TpTask XY for the OOB soft/hard-margin stage) ->
        validateConsolidation; imports+compares C++ results/ when present,
        else prints the exact tests_bin command to run.
      - CuasMotion.convertFromData: overload with tasks_out (old signature
        delegates) so the export gets the conversion TpTask grid.
      
      mvn -DskipTests clean package: OK. Run validation in Eclipse = Andrey's.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      189b7f39
  3. 11 Jul, 2026 3 commits
    • Andrey Filippov's avatar
      CLAUDE: Add fopen_dem_match.py - register SZXY terrain vs USGS LiDAR DEM · aa681507
      Andrey Filippov authored
      Per-segment absolute registration of the per-tile terrain models
      (*_SZXY.tiff: S/Z/X/Y slices) against a 3DEP DEM using the ground_planes
      geodetic anchor (lat/lon/alt + qenu with the validated axis adapter
      perm(2,0,1) signs(1,-1,-1)). Reports vertical offset (= IMS altitude error
      trace; observed -43..+19 m across passes), optional dx/dy/scale search,
      robust 2x25% trim. Validated on the pond segment 1763233023_625897:
      placement rms 0.17 m at scale 1.0; scale fitting documented as valid only
      on temporally stable relief (the 2020-flooded pond trims itself out).
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      aa681507
    • Andrey Filippov's avatar
      CLAUDE: fopen_export_colmap_poses.py - correct scale note: XML poses are true metres · f634b2ae
      Andrey Filippov authored
      Dense graveyard model triangulated with our poses puts the ground plane at
      z median -77.5 XML-units vs 77.4 m AGL from ELEV_GND - the earlier
      'SfM-scale' caveat was an analysis artifact (wrong sub-camera baseline
      assumption), retracted.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      f634b2ae
    • Andrey Filippov's avatar
      CLAUDE: Add fopen_export_colmap_poses.py - our poses as fixed COLMAP model · 339a3b3e
      Andrey Filippov authored
      Exports *-INTERFRAME.corr-xml scene poses as a COLMAP text sparse model
      (PINHOLE camera, empty points3D) so point_triangulator/OpenMVS can use our
      IMS/interscene poses with no SfM pose estimation - the FOPEN step-3 path
      for vegetation scenes where COLMAP's own mapper fails.
      
      Convention verified against the 2026-07-10 graveyard run (ref
      1763232420_274928): R = diag(1,-1,-1) @ (Ry(az)Rx(tilt)Rz(roll))^T,
      t = -R C. Fixed-pose triangulation on the corrected NADIR-MERGED-RECTILINEAR
      renders gives 0.453 px mean reprojection (COLMAP free mapper: 0.351 px on
      the same images).
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      339a3b3e
  4. 10 Jul, 2026 8 commits
    • Andrey Filippov's avatar
      CLAUDE: undistortPxPy(): invert correction direction (getRDistByR) · 79c105c4
      Andrey Filippov authored
      The RECTILINEAR nadir pass multiplied sampling coordinates by getRByRDist()
      (distorted->ideal), but sampling positions must be moved to where the ideal
      ray lands in the distorted image - the FORWARD distortion getRDistByR(),
      same direction as GeometryCorrection.getImageCoordinates(). The old code
      ADDED the common radial distortion to the output instead of removing it.
      
      Evidence (graveyard ref 1763232420_274928, flat constant-disparity terrain
      where translation flow must be uniform for a true pinhole image):
      - plain NADIR-MERGED edge/center flow ratio 0.965 (expected 0.954 from the
        calibration polynomial: ~4.8 px barrel at the edge),
      - old RECTILINEAR 0.952 - worse than uncorrected,
      - COLMAP self-calibrated f=1003/k1=-0.385 on the old rectilinear stack.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      79c105c4
    • Andrey Filippov's avatar
      CLAUDE: renderNadirSequence(): null rim tiles with corrupt grid positions · af0e34b9
      Andrey Filippov authored
      Analysis of the -NADIR-SCENE-PXPYD[-NULLCAM] dumps (graveyard ref
      1763232420_274928) showed the transformFromVirtual() refinement output is
      accurate to <0.3 px in the interior, but produces garbage coordinates
      (5..100 px off) in a rim band at the edge of the valid region, where the
      interpolation works one-sided over NaN-filled disparity. Rendered, those
      tiles put wrong content in a border strip: COLMAP fit it as fake barrel
      distortion (f=1000, k1=-0.38) and image-based rotation measurements were
      contaminated (apparent ~0.6x roll).
      
      A correct scene-frame grid position is the tile center + small ERS
      displacement, so tiles straying more than 4 px are nulled and render as
      NaN instead of wrong content, slightly shrinking the usable FOV at the rim.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      af0e34b9
    • Andrey Filippov's avatar
      CLAUDE: renderNadirSequence(): add -NADIR-SCENE-PXPYD-NULLCAM debug dump · 35fd4536
      Andrey Filippov authored
      Second per-scene grid computed with scene_QuadClt=null - the exact camera
      model used inside Cuas.transformFromVirtual()'s refinement loop. Its
      non-uniformity isolates the refinement residual; its difference from
      -NADIR-SCENE-PXPYD isolates the scene-ERS-instance effect. Saved only on
      the first (non-undistorted) pass.
      
      Context: 2026-07-10 analysis of the first -NADIR-SCENE-PXPYD dump showed
      the sampling grid contains rotation ~0.31x scene roll (R2=0.77) plus
      correlated scale (~0.955) and shift_y (to -24 px) concentrated in the
      high-roll-rate half of the graveyard segment - explaining the ~0.6x
      in-plane content rotation and COLMAP's f=1000/k1=-0.38 self-calibration.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      35fd4536
    • Andrey Filippov's avatar
      CLAUDE: renderNadirSequence(): dump per-scene sampling grids as -NADIR-SCENE-PXPYD · 8157473b
      Andrey Filippov authored
      Save the actual scene-frame pXpYD fed to renderGPUFromDSI (after
      transformToScenePxPyD and optional undistort) as a pX/pY/D hyperstack at
      tile resolution, one frame per scene, suffix -NADIR-SCENE-PXPYD[-RECTILINEAR].
      For offline verification of the nadir render geometry: the grid should be
      near-uniform (tile centers + ERS displacement); any residual rotation
      proportional to scene roll would explain the halved in-plane rotation
      observed in the 2026-07-10 graveyard COLMAP test.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      8157473b
    • Andrey Filippov's avatar
      CLAUDE: Fix renderNadirSequence(): missing ref->scene transform of pXpYD · a3f665e2
      Andrey Filippov authored
      getNadirDisparityMaps() returns pXpYD in the SEGMENT REFERENCE frame
      (Cuas.transformFromVirtual() output), but renderNadirSequence() passed it
      to renderGPUFromDSI() with ZERO3 pose and the scene as its own reference,
      so each scene image was sampled at reference-frame coordinates. Each nadir
      frame thus carried an extra ref->scene terrain warp: effective camera
      poses vs the segment reference were ~doubled (ground translation 2x, small
      rotations ~2x), and the identity transform also canceled ERS compensation.
      On flat terrain the extra plane homography mimics a valid pose change, so
      COLMAP converged self-consistently but disagreed with the exported poses
      (Sim(3)/free monocular scale absorbs the 2x translation; rotations do not
      scale, explaining the large angular residuals, worst on high-rotation-rate
      sequences).
      
      Now transformToScenePxPyD() maps the reference-frame pXpYD into each
      scene's own frame (pose + ERS, same machinery as the verified
      frozen-terrain path) before rendering with ZERO3/self, where the identity
      pass is an exact pass-through. Output becomes a global-shutter virtual
      view at each scene's nominal pose. Also converts disparity to the scene
      frame for 16-sensor parallax compensation, and drops the defensive clone
      (the transform returns new arrays). Docs updated to state the frame
      conventions.
      Co-authored-by: 's avatarClaude <claude@elphel.com>
      a3f665e2
    • Andrey Filippov's avatar
    • Andrey Filippov's avatar
      CLAUDE: TestDataView: manifest-shaped ImageJ hyperstack viewer for test-case/results buffers · c9acd835
      Andrey Filippov authored
      Kills the manual raw-import papercut: dims come from manifest.txt, TD
      buffers (trailing 256) render as tile grids with presentCltData quadrant
      placement, per-tile planes as tilesX x tilesY images, generic fallback
      otherwise. viewCase/viewResults/showAll; verified shapes on the avg_td
      round-trip case (80x64 x16 TD grid, 5x4 counts).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      c9acd835
    • Andrey Filippov's avatar
      CLAUDE: gpu.testdata package: standalone kernel-test export/import (oracle contract) · 1acb4341
      Andrey Filippov authored
      New package com.elphel.imagej.gpu.testdata implementing the Java side of
      tile_processor_gpu/src/tests/testdata_format.md:
      - TestDataWriter: raw little-endian arrays + manifest.txt (prm/buf records)
      - TestDataReader: parse manifest or C++ results back for ImageJ comparison
      - AvgTdExport: full clt_average_sensors test case (per-sensor TD from
        GpuQuad, CuasTD.consolidateSensorsTD expected outputs + counts, optional
        TpTask per-sensor XY for the OOB stage) + compareResults round-trip check
      
      Round-trip verified bit-exact (max|diff|=0): TestDataWriter -> CUDA
      test_avg_td on GPU -> TestDataReader.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      1acb4341
  5. 08 Jul, 2026 5 commits
    • Andrey Filippov's avatar
      CLAUDE: robust average v2: NO NaN frame - all contributors + median/IQR rejection · 6a274e46
      Andrey Filippov authored
      Andrey's correction: the eroded average left a wide NaN frame (and all
      its descendants - EVAL diffs). The average virtual image must be defined
      wherever ANY scene provides (a single bad first/last row/col at most):
      combine ALL available contributors, let the count taper naturally near
      the edges, and reject junk providers per pixel as OUTLIERS vs the MEDIAN
      with an IQR-based robust sigma (immune to heavy contamination, unlike
      mean/sigma). Fewer than 4 providers - plain mean; zero - NaN. Geometric
      erosion (erodeDefined/erodedMasks/AVG_EDGE_ERODE) removed.
      
      Next (Andrey): per-TILE outlier rejection in the 16-sensor TD
      consolidation, anticipating the GPU migration (candidate indicator:
      CC(0,0) flux, possibly + quadrant energy).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      6a274e46
    • Andrey Filippov's avatar
      CLAUDE: -CUAS-RT-RENDER-EVAL: log / log-diff / diff hyperstack (Andrey's spec) · 8726cc75
      Andrey Filippov authored
      New evaluation product with the RT render (replaces the manual
      run-UM-in-ImageJ workflow): merged component only, z = robust all-scenes
      average + each scene, t ordered for ImageJ auto-range: 1) pixel LoG (the
      pre-DNN kernel, LINEAR) of the image, 2) LoG of (scene - average),
      3) plain (scene - average); t2/t3 are 0 for the average frame. The
      average is the new robust one (edge-eroded + outlier-rejected),
      extracted into shared helpers (erodedMasks/robustAverage) used by both
      saveRenderHyper and the EVAL builder.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      8726cc75
    • Andrey Filippov's avatar
      CLAUDE: RT-RENDER average slices: per-scene edge erosion + outlier rejection · c8cd84bd
      Andrey Filippov authored
      The temporal averages accumulated per-scene edge junk into stable margin
      artifacts (ROWCOL-04: worst columns x=12,20,28 = 8-px tile pitch -
      partially covered virtual tiles at the warped-coverage edge; the wobble
      sweeps which tiles are partial). For the two AVERAGE slices only
      (individual scenes stay liberal/untouched): each scene's contribution is
      box-eroded 24 px (3 tile pitches, AVG_EDGE_ERODE - clears the
      partial-tile ring) and outlier-rejected (3 sigma vs the first-pass mean
      when >= 4 providers, per Andrey's >1-non-NaN-provider rule); zero eroded
      providers -> honest NaN.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      c8cd84bd
    • Andrey Filippov's avatar
      CLAUDE: RT rowcol: untrusted-line guard (inlier fraction) + physical cap · c0096034
      Andrey Filippov authored
      ROWCOL-04 localization: RT rows regression (18.0 vs 10.6 pre-rework) is
      CONTENT BIAS, zero in the sky and +10..22 counts in terrain rows - with
      dense high-contrast content nearly every |UM residual| exceeds max_abs,
      all pixels get the outlier weight and the weighted mean degenerates to
      the row's content mean (the small weights cancel), stamping bias bands.
      lineAverage now zeroes a line's correction when its inlier fraction is
      below rowcol_min_inlier (default 0.33 - content-dominated lines cannot
      yield a line-noise measurement) or when |estimate| > max_abs (line noise
      cannot physically exceed the gate scale). Both guards are no-ops with
      the gate off (max_abs INF - every pixel is an inlier).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      c0096034
    • Andrey Filippov's avatar
      CLAUDE: ROWCOL frame-edge margin + physical line cap; RT: single high-pass (QC/ROWCOL-03 findings) · 8db6269b
      Andrey Filippov authored
      ROWCOL-03 QC FAIL (rms 52.9 unchanged by erosion) proved the junk edge
      columns are FULLY covered with DEFINED-BUT-WRONG back-projection values
      (left-edge convert_direct artifact class) - erosion cannot see them:
      - exclude a 16px frame-edge band from the content-excluded estimator by
        geometry (ROWCOL_BP_EDGE_MARGIN); those lines take the legacy fallback;
      - physical cap in the per-line merge: a content-excluded line value over
        max_abs cannot be line noise - use legacy (also blunts any future
        ROWCOL-01-class estimator failure).
      
      RT conditioning: profile HPF now applies ONLY when rowcol_um_sigma==0.
      Stacking it on the UM measurement double-high-passed the row-offset
      estimate ((1-G10)(1-G8)): removed fraction at period ~20 rows dropped
      96% -> 91%, residual mid-band line noise x2 - measured merged RT-RENDER
      rows metric 10.60 (ROWCOL-02, pre-rework) -> 18.73 (ROWCOL-03). Single
      sigma-10 high-pass removes strictly more noise at every period than the
      old sigma-8-only path and protects the LoG band at least as well.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      8db6269b
  6. 07 Jul, 2026 13 commits
    • Andrey Filippov's avatar
      CLAUDE: disparity conditioning: fill small foreground clusters with background (Laplacian) · 66bd669a
      Andrey Filippov authored
      Where a small foreground object (the 3-tile roadside sign, disp ~22)
      stands in front of a distant background both disparities are legitimate,
      but for CUAS the background matters: a drone flying exactly behind the
      sign must stay detectable. conditionDisparityCuas now detects connected
      clusters of local near-outliers (disparity above the local 7x7 median by
      curt.disp_fg_over, default 2 px) up to curt.disp_fg_tiles (default 8,
      0 = off) tiles and re-fills them with zero-curvature background
      disparity (TileProcessor.fillNaNs Laplacian relaxation). All three RT
      call sites (render, pose, appropriation) share the one conditioned
      source as before.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      66bd669a
    • Andrey Filippov's avatar
      CLAUDE: ROWCOL edge erosion + RT rowcol rework (order/UM/gate) + QC harness · 275f812b
      Andrey Filippov authored
      1. calculateRowColBackProject: ERODE the coverage mask (blurred mask >=
         ROWCOL_BP_ERODE=0.95 ~ 16px inside at sigma 10) before the masked UM
         and averaging - the back-projection is unreliable near its own
         boundary and boundary garbage dominated the partially-covered EDGE
         columns in v013-ROWCOL-02 (per-x maxima ~1000 for x<14, interior
         clean at 13-39 counts). Excluded edge lines drop below MIN_COVER and
         take the legacy per-line fallback.
      
      2. RT conditioning row/col (problem 2, borrowed from the oracle path,
         /jp4/ input unchanged):
         - REORDER: row/col now AFTER photometric+FPN. Measuring on raw
           captured the FPN's static line structure (rms ~6/12 counts) which
           the later FPN subtraction removed AGAIN - negative FPN line
           structure was injected into the output.
         - UM before averaging (new curt.rowcol_um_sigma, default 10, 0=off):
           profiles measured on an unsharp-masked copy, subtracted from the
           original - content no longer biases the averages and the max_abs
           gate acts on residual counts.
         - rowcol_max_abs default 50 (calibrated counts; configs saved before
           this change carry 0 = no gate - set 50 to enable).
      
      3. CuasQC (Andrey's regression-protection design): per-product health
         statistics with sequence-independent pass bands, appended per run to
         <center>-QC.json; FAIL prints loudly, never aborts. Increment 1:
         ROWCOL vectors (rms<=25, scene-max p95<=500 - both of today's
         defects would have failed) + FPN (rms, row/col line-structure
         energy), hooked after calculation AND reuse in CorrectionFPN.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      275f812b
    • Andrey Filippov's avatar
      CLAUDE: fix ROWCOL back-project baseline mismatch (v013-ROWCOL-01 junk) · 947c199c
      Andrey Filippov authored
      The first calculateRowColBackProject mixed two baselines in one image:
      content-excluded residual (~0, regression baseline) inside the
      back-projection coverage, full raw-level image-FPN outside it. Whole
      lines fell outside the max_abs gate and the outlier-weighted average
      degenerated to the content mean: vectors reached ~2300 counts (legacy
      ~340) and stamped junk bands at the coverage-window margins into all
      per-sensor images (v013-ROWCOL-01 MERGED-DBG slices 141/408 etc).
      
      Now the two baselines never mix: masked UM (blur(value*mask)/blur(mask))
      high-passes the residual within coverage only; NaN-aware line averages
      use covered pixels only (getLineAvgNaN); lines with under 10% coverage
      (ROWCOL_BP_MIN_COVER) fall back to the pure legacy UM+gating estimate
      per line (mergeLineProfiles). Console reports the line-fallback share.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      947c199c
    • Andrey Filippov's avatar
      CLAUDE: fix MCP dialog values silently discarded on submit · b70a9f6b
      Andrey Filippov authored
      The registry entry is cleared by submitCurrent() (and again by
      showDialog()) BEFORE applyCltDialog() runs the getNext*() reads, so
      getValueOrDefault() - which looked the session up via the registry -
      always saw null and fell back to every field's default: any value set
      via POST /mcp/dialog/values was silently lost and OK re-applied the
      loaded config. The dialog now keeps its OWN session reference for the
      reads and the await; the registry cleanup clears only its own session
      (covers the timeout path without clobbering a newer dialog).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      b70a9f6b
    • Andrey Filippov's avatar
      CLAUDE: remove cuas_calc_fpn/cuas_calc_rowcol - file existence is THE recalc trigger · b056e1a5
      Andrey Filippov authored
      Delete-the-file rule (Andrey): FPN and row/col noise recalculate ONLY
      when <center>-FPN.tiff / <center>-ROWCOL.tiff are missing in the model
      directory. The two force-recalc checkboxes are removed from the dialog
      and the config (stale _cuas_calc_* keys in old corr-xml are ignored on
      load). Reuse printlns name the exact file to delete; the dialog shows
      addMessage() notes in place of the removed checkboxes.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      b056e1a5
    • Andrey Filippov's avatar
      CLAUDE: Row/Col correction (RT step 2): curt rowcol_* dialog params +... · 3cc0997b
      Andrey Filippov authored
      CLAUDE: Row/Col correction (RT step 2): curt rowcol_* dialog params + content-excluded noise calculation
      
      2a: CuasConditioning rowcol_* Config now dialog-driven (curt.rowcol_en/
      rowcol_hpf/rowcol_hpf_sigma/rowcol_max_abs/rowcol_outlier, "CUAS RT" tab)
      via CuasConditioning.configFromCurt(); RT Row/Col is optional/bypassable
      (turn rowcol_en OFF when the FLIR internal correction is verified OK).
      Defaults reproduce the previous hardcoded Config bit-exactly
      (rowcol_max_abs 0 = the old INFINITY no-gate).
      
      2b: new CorrectionFPN.calculateRowColBackProject() (gated by NEW
      imp.cuas_backprop_rowcol, default ON): subtract the back-projected
      (pose-transformed, photometric-matched) virtual center from each scene
      BEFORE the UM + line averaging, so bright content no longer biases the
      row/col averages (the dark horizontal/vertical line artifact). Falls
      back to (image - FPN) where the back-projection is undefined; serial
      scene loop (GPU back-projection per scene) - borrowed/non-RT path only.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      3cc0997b
    • Andrey Filippov's avatar
    • Andrey Filippov's avatar
      CLAUDE: test 7 - windowed-LoG TD product (correlation machinery): broadband... · 284f6ae1
      Andrey Filippov authored
      CLAUDE: test 7 - windowed-LoG TD product (correlation machinery): broadband exact, crease bands UNCHANGED
      
      Andrey's separate-LoG proposal prototyped on the CPU oracle: LoG as a windowed
      16x16 DATA tile (taps pre-divided by the sine window AND cosAtten so the
      effective filter is the exact flux-normalized LoG), full 16-mult quad product
      per tile (GPU correlateAccumulateTiles table == convolve_tile(conj(data),k) -
      verified term-by-term), dttt_iie back (mode-TRANSPOSED = GPU dttii_2d),
      corr_unfold_tile, windowed OLA with sum(w^2) normalization.
      
      RESULT: impulse fidelity 2.0e-3 (no aberration-kernel cross-term - a separate
      pass), but the ramp crease bands are IDENTICAL to the per-bin fold (+/-0.546):
      the DTT symmetric-extension reflection is only attenuated by the window, not
      removed - the crease is BASIS-INHERENT to any single-tile TD product. The
      per-bin fold is the degenerate (symmetric-kernel) case of this same product.
      Band-free LoG requires pixel-domain convolution on the assembled image.
      
      Calibrated conventions along the way (documented in code): correlation product
      table, dttii mode transpose, corr_unfold patch mapping (+1 offset, no flip),
      global gain 4.000, window and cos tap precompensation.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      284f6ae1
    • Andrey Filippov's avatar
      CLAUDE: test 6 extension - crease bands per kernel type (Andrey's symmetry argument quantified) · da5c157f
      Andrey Filippov authored
      Same ramp, same chain: identity 0.000; aberration-like kernel 0.624 counts
      (band/output 0.18% - present in every render, invisible under content);
      pure LoG 0.547 (176% of its near-zero output); folded 0.682. The aberration
      kernels DO band identically in absolute counts - the LoG only unmasks them
      by removing the content. Corollary: the CURRENT pixel-LoG conditioning also
      reveals the render's own crease bands (the oracle product bands too, with a
      different pattern).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      da5c157f
    • Andrey Filippov's avatar
      CLAUDE: test 6 - sky-band root cause reproduced: symmetric-extension crease... · b70a65c5
      Andrey Filippov authored
      CLAUDE: test 6 - sky-band root cause reproduced: symmetric-extension crease response to LINEAR content
      
      Constant -> exactly 0; ramp 5/row -> 8-row-periodic band pattern
      (0,-0.008,-0.297,-0.547,+0.547,+0.297,+0.008,0) = the LOG-01 run's measured sky
      bands scaled by the gradient (2.5/row -> -0.14,-0.30,+0.35,+0.16). Pure double
      CPU chain -> not float32, not GPU, not a kernel coefficient: pixel LoG of a ramp
      is 0 (odd symmetry) but the per-tile symmetric convolution sees the mirrored
      extension's slope crease at tile boundaries. Inherent to any per-bin TD multiply
      (present under aberration kernels too, masked by content - Andrey's LPF-era
      artifact class, confirmed in substance).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      b70a65c5
    • Andrey Filippov's avatar
      CLAUDE: LoG isolation test (curt.log_ident) - identity vs pure-LoG kernels, aberrations skipped · 7b6d0284
      Andrey Filippov authored
      Andrey's discriminator for the fold-vs-kernel-interaction question: with
      rend_test + new 'RT render LoG isolation (identity krnl)' ON, saves
      -CUAS-RT-RENDER-ID (identity kernels: q0=1, q1..3=0, CltExtra=0 - aberration
      correction AND fractional offsets skipped), -ID-LOG-ORACLE (pixel LoG of -ID),
      and -LOG-ONLY (pure-LoG kernels, CuasLogFold.uniformKernels(log_td)).
      If -LOG-ONLY vs -ID-LOG-ORACLE residual persists, the fold/L0 is wrong; if it
      collapses to the wrap floor, the aberration-kernel interaction is responsible.
      Refactor: pixel-LoG application extracted to applyPixelLog(); log_test and
      log_ident share the kernel fetch/restore (finally).
      
      Evidence so far (offline, this evening's run): per-sensor high-bin tilt varies
      s07 +1.3% .. s01 +2.4% with identical scene content => kernel-dependent;
      per-quadrant deviation maps identical (no single-coefficient signature);
      kx=0 column regionally incoherent (row-structure channel, separate issue).
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      7b6d0284
    • Andrey Filippov's avatar
      CLAUDE: RT-RENDER* hyperstacks organized like -INDIVIDUAL-CUAS-DBG (merged first, 2 average frames) · c9b0452a
      Andrey Filippov authored
      t (channels): merged FIRST then s00..s15; z (frames): 'average' (all scenes) +
      'average-f:l' (middle-half, renderSceneSequence default range) then scenes -
      same dimensions as -CUAS-INDIVIDUAL-CUAS-DBG (17 x 499 x H x W) so ImageJ can
      subtract the stacks directly. NaN-tolerant per-pixel averages. Applies to all
      three products (RT-RENDER, -LOG-ORACLE, -LOG-FOLDED). Per Andrey 07/06/2026.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      c9b0452a
    • Andrey Filippov's avatar
      CLAUDE: RT-seed step 1b wiring - LoG A/B products in the RT render (curt.log_test) · 0fe8f5c1
      Andrey Filippov authored
      With 'CUAS RT render' + new 'RT render LoG A/B (folded kernels)' checkboxes ON,
      testRenderSequence saves two more hyperstacks comparable to -CUAS-RT-RENDER:
      - -CUAS-RT-RENDER-LOG-ORACLE: the product convolved with the EXISTING pre-DNN
        pixel-domain LoG (same CuasRTUtils.convolve2DLReLU instance construction as
        CuasDetectRT.detectTargets, LINEAR alpha=1);
      - -CUAS-RT-RENDER-LOG-FOLDED: the same render chain re-run with the LoG folded
        into the GPU aberration kernels (CuasLogFold.getLogTd tap-precompensated +
        foldKernels, setConvolutionKernels force re-upload) - NO pixel convolution;
        original kernels restored in a finally block.
      Render loop extracted verbatim into renderPass(), hyperstack save into
      saveRenderHyper() so both passes share the exact chain. Offline verdict:
      attic/CLAUDE/compare_cuda_versions.py --only LOG-
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      0fe8f5c1
  7. 06 Jul, 2026 3 commits
    • Andrey Filippov's avatar
      CLAUDE: CuasLogFold - LoG-into-kernel fold + synthetic impulse/grating... · cfc93456
      Andrey Filippov authored
      CLAUDE: CuasLogFold - LoG-into-kernel fold + synthetic impulse/grating self-test (roadmap RT-seed step 1)
      
      Findings (all validated to stated precision by the self-test, exit 0):
      - Per-bin TD quad-multiply == pixel convolution with cos(pi*dx/16)*cos(pi*dy/16)
        ATTENUATED taps (matches norm_sym_weights in calculateCLTKernel; shift-tap
        error exactly 1-cos(pi/16) before compensation). getLogTd() therefore
        pre-compensates LoG taps by 1/cosAtten so the EFFECTIVE filter is the true
        pixel LoG (machine-exact at non-bin gratings).
      - Residual floors: symmetric-extension wrap ~0.5-2.5% (inherent to the lapped
        structure); folded-vs-pixel-LoG A/B cross-term ~7% on a pessimistic spread
        kernel (test 5 - predicts the full-run A/B floor).
      - clt_symmetrize_kernel quadrant-3 (AA) sign pattern looks like a latent
        copy-paste of the AS expression: pure-AA kernel test - math sign 2.6e-3,
        code sign 1.9e-1. Production kernel files likely carry the wrong AA sign.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      cfc93456
    • Andrey Filippov's avatar
      CLAUDE: FPN iteration - composite rebuilt center over original (NaN-hole fix) · 953f5efd
      Andrey Filippov authored
      POSE-13 forensics (from files, run 02:18-02:24): the iteration executed but dG
      came out defined on only 5% of the frame (right-edge strip + terrain patches),
      so fpn2 = fpn1 over 95% - the ghost survived. Chain: rebuild accumulation was
      healthy (494/494 scenes, ~75% per scene, ~85% union) but a single-sequence
      new-average center keeps NaN holes in the weak sky (no parent cumulative, no
      fillNewGaps), and convert_direct of a NaN-holed center image NaN-poisons
      nearly all back-projected tiles (task inversion + overlap spread).
      
      Fix: composite before the second back-propagation - keep rebuilt values where
      defined, fall back to the original center in the holes. There dG measures the
      pass-1 residual (~0), so it degrades to "no correction where not rebuilt"
      instead of NaN. Adds a coverage printout and a cuas_debug save of the
      composited center (-FPN-CENTER2-ITERn) so the next run is file-verifiable.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      953f5efd
    • Andrey Filippov's avatar
      CLAUDE: FPN second back-propagation iteration (imp.cuas_fpn_iters, default 1 = old behavior) · 3b1049d6
      Andrey Filippov authored
      FPN = mean(scene - backProject(center)) is a fixed point that preserves the
      center's own content residual (the rotating ghost): recomputing against the
      same contaminated center reproduces the same ghost regardless of rot_period
      or photometric vintage (POSE-12 confirmed: 43.1/92.0 unchanged).
      
      Iterate per Andrey's design (internal handoff 2026-07-06):
        1. subtract fpn_k from scenes in memory (setApplyFPN, delta-aware)
        2. rebuild the center IMAGE from the corrected scenes over integer
           rotations - new Cuas.rebuildCenterImageInMemory(): new-average only
           (no parent cumulative fold), NOTHING persisted, center_clt and
           image_center untouched (the .cuas cumulative is upstream state)
        3. back-propagate against the rebuilt center image (swapped in/restored
           around the measurement) -> residual dG = the ghost
        4. fpn_{k+1} = fpn_k + dG in NEW arrays (scenes hold fpn_k references as
           applied-FPN for delta re-apply); prints |dG| RMS/max per iteration
        5. cuas_debug saves per-iteration -FPN-DG-ITERn
      
      Gated by new dialog field "FPN back-propagation iterations" next to
      "Rotation period"; default 1 keeps the POSE-12 baseline bit-reproducible.
      Verify by RT-RENDER horizon/sky pk-pk (43.1/92.0 -> temporal-noise floor).
      
      Data path verified: applyFPN sets hasNewImageData, honored by both
      GpuQuad.setBayerImages and GpuQuadJna, so corrected pixels reach the GPU
      for the rebuild and the second back-propagation.
      Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
      3b1049d6