From 70d5837c548573f045d4230cb41960e52687763b Mon Sep 17 00:00:00 2001
From: Alexandru Bercuci <abercuci@niham.nipne.ro>
Date: Tue, 11 Feb 2025 13:48:19 +0200
Subject: [PATCH] add calibration to the TRD2D online unpacker

---
 algo/detectors/trd2d/ReadoutConfig.h | 26 +++++++++++++++++++-------
 algo/detectors/trd2d/Unpack.cxx      |  8 ++++++--
 algo/detectors/trd2d/UnpackMS.cxx    |  6 ++----
 algo/detectors/trd2d/UnpackMS.h      | 16 ++++++++++++++--
 algo/global/ParFiles.cxx             | 13 ++++++++++---
 5 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/algo/detectors/trd2d/ReadoutConfig.h b/algo/detectors/trd2d/ReadoutConfig.h
index 3974f8b39..f63026808 100644
--- a/algo/detectors/trd2d/ReadoutConfig.h
+++ b/algo/detectors/trd2d/ReadoutConfig.h
@@ -148,20 +148,32 @@ namespace cbm::algo::trd2d
   class ReadoutCalib {
 
    public:
+    struct ChanNoise {
+      uint8_t tDelay;    /// time [clk] delay wrt to causing primary signal
+      uint8_t tWindow;   /// time [clk] window to search for noisy signal
+      uint16_t lDThres;  /// Threshold [ADU] for dynamic channel noise
+      uint16_t lSThres;  /// threshold [ADU] for static channel noise (happens independently)
+
+      CBM_YAML_PROPERTIES(
+        yaml::Property(&ChanNoise::tDelay, "delay", "time delay wrt the causing signal"),
+        yaml::Property(&ChanNoise::tWindow, "window", "time window for noise signal search"),
+        yaml::Property(&ChanNoise::lDThres, "dnoise", "Max signal value for cutting dynamic noise signals"),
+        yaml::Property(&ChanNoise::lSThres, "snoise", "Max signal value for cutting static noise signals"));
+    };
     struct ChanDescriptor {
-      bool maskFlag;        /// HW mask flag for channel
-      uint8_t tOffset;      /// time correction in clk
-      uint16_t lThreshold;  /// SW threshold for ringing channels
-      float baseline;       /// Baseline correction for channel
-      float gainfee;        /// ASIC gain deviation for channel
+      bool maskFlag;    /// HW mask flag for channel
+      uint8_t tOffset;  /// time [clk] correction
+      float baseline;   /// Baseline correction for channel
+      float gainfee;    /// ASIC gain deviation for channel
+      ChanNoise noise;  /// noise descriptor [ChanNoise]
 
       CBM_YAML_FORMAT(YAML::Flow);
       CBM_YAML_PROPERTIES(
         yaml::Property(&ChanDescriptor::maskFlag, "mask", "Channel masking flag"),
         yaml::Property(&ChanDescriptor::tOffset, "toff", "Channel wise time offset"),
-        yaml::Property(&ChanDescriptor::lThreshold, "thres", "SW masking by threshold"),
         yaml::Property(&ChanDescriptor::baseline, "bline", "Baseline correction"),
-        yaml::Property(&ChanDescriptor::gainfee, "gainfee", "Gain correction for FEE channel"));
+        yaml::Property(&ChanDescriptor::gainfee, "gainfee", "Gain correction for FEE channel"),
+        yaml::Property(&ChanDescriptor::noise,  "noise", "Dynamic noise descriptor"));
     };
 
     /** @brief Constructor **/
diff --git a/algo/detectors/trd2d/Unpack.cxx b/algo/detectors/trd2d/Unpack.cxx
index 880a61091..5cc2d37bc 100644
--- a/algo/detectors/trd2d/Unpack.cxx
+++ b/algo/detectors/trd2d/Unpack.cxx
@@ -43,8 +43,12 @@ Unpack::Unpack(const Config& config) : fConfig(config)
         auto pars            = setup.ChanMap(equip, asic, chan);
         chanPar.fPadAddress  = pars.padAddress;  // Pad address for channel
         uint16_t ch          = std::abs(pars.padAddress);
-        auto calDet          = calib.GetChannelFeeCalib(par.fModId, ch);
-        par.fCalibParams[ch] = {calDet.maskFlag, calDet.tOffset, calDet.lThreshold, calDet.baseline, calDet.gainfee};
+        auto calCh           = calib.GetChannelFeeCalib(par.fModId, ch);
+        par.fCalibParams[ch] = {calCh.maskFlag,
+                                calCh.tOffset,
+                                calCh.baseline,
+                                calCh.gainfee,
+                                {calCh.noise.tDelay, calCh.noise.tWindow, calCh.noise.lDThres, calCh.noise.lSThres}};
         chanPar.fMask        = pars.maskFlag;    // Flag channel mask
         chanPar.fDaqOffset   = pars.tOffset;     // Time calibration parameter
         chanPar.fSignalThres = pars.lThreshold;  // Threshold cut
diff --git a/algo/detectors/trd2d/UnpackMS.cxx b/algo/detectors/trd2d/UnpackMS.cxx
index 1739bcd04..24fb88e66 100644
--- a/algo/detectors/trd2d/UnpackMS.cxx
+++ b/algo/detectors/trd2d/UnpackMS.cxx
@@ -394,7 +394,6 @@ namespace cbm::algo::trd2d
         case eMessageType::kEpoch: ctx.fMess.readEW<m24>(w); break;
         default: break;  // no way to reach this line
       }
-
       // PROCESS EPOCH MESSAGES
       if (ctx.fMess.type == eMessageType::kEpoch) {
         if (ctx.fMess.ch == 0) {  // check word integrity
@@ -433,7 +432,6 @@ namespace cbm::algo::trd2d
     for (uint16_t ipad(0); ipad < NFASPMOD * NFASPPAD; ipad++) {
       if (!ctx.fRobDigi[ipad].size()) continue;
       for (auto id : ctx.fRobDigi[ipad]) {
-        // L_(debug) << id.ToString();
         outputDigis.emplace_back(std::move(id));
       }
     }
@@ -448,7 +446,7 @@ namespace cbm::algo::trd2d
     constexpr uint8_t m24 =
       uint8_t(eMessageVersion::kMess24);  // message versions compatible with the current algo specialization
     const uint8_t fasp_mod_id = fParams.mapFaspId2Mod<m24>(messes[0].fasp);
-    L_(debug) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id;
+    L_(debug) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id << " ns=" << messes.size();
     if (fParams.fAsicParams.find(fasp_mod_id) == fParams.fAsicParams.end()) {
       L_(error) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id
                 << " not mapped to param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex << (int) fParams.fEqAdd;
@@ -461,7 +459,7 @@ namespace cbm::algo::trd2d
       const uint32_t mch            = std::abs(chPar.fPadAddress);
       const CalibChannelPar& calPar = fParams.fCalibParams.at(mch);
       // skip message if threshold set and signal under
-      if (calPar.fSignalThres && imess.data <= calPar.fSignalThres) continue;
+      if (calPar.noise.fSignalThres && imess.data <= calPar.noise.fSignalThres) continue;
       const uint32_t pad     = mch / 2;
       const bool hasPairingR = bool(chPar.fPadAddress > 0);
       const uint64_t lTime   = time + calPar.fDaqOffset + imess.tlab;
diff --git a/algo/detectors/trd2d/UnpackMS.h b/algo/detectors/trd2d/UnpackMS.h
index fc00cd1a9..8bf64c43c 100644
--- a/algo/detectors/trd2d/UnpackMS.h
+++ b/algo/detectors/trd2d/UnpackMS.h
@@ -129,17 +129,29 @@ namespace cbm::algo::trd2d
     std::vector<UnpackChannelPar> fChanParams;  ///< Parameters for different channels
   };
 
+  /** @struct NoiseChannelPar
+   ** @author Alexandru Bercuci <abercuci@niham.nipne.ro>
+   ** @since 10 February 2025
+   ** @brief TRD2D noise parameters for one Asic channel
+   **/
+  struct NoiseChannelPar {
+    uint8_t tDelay        = 0;  /// time [clk] delay wrt to causing primary signal
+    uint8_t tWindow       = 0;  /// time [clk] window to search for noisy signal
+    uint16_t lThreshold   = 0;  ///< Signal threshold for induced - dynamic noise
+    uint16_t fSignalThres = 0;  ///< Signal threshold for independent - static noise
+  };
+
   /** @struct CalibChannelPar
    ** @author Alexandru Bercuci <abercuci@niham.nipne.ro>
    ** @since 4 February 2025
-   ** @brief TRD2D Calibration parameters (time and signal) for one Asic channel
+   ** @brief TRD2D Calibration parameters for one Asic channel
    **/
   struct CalibChannelPar {
     bool fMask            = false;  ///< Flag for channel masking
     uint8_t fDaqOffset    = 0;      ///< Time calibration parameter
-    uint16_t fSignalThres = 0;      ///< Signal threshold to remove ringing channels
     float fBaseline       = 0.;     ///< baseline correction
     float fGainFee        = -1.;    ///< gain correction wrt to reference
+    NoiseChannelPar noise = {};     ///< noise channel parametrisation
   };
 
   /** @struct UnpackPar
diff --git a/algo/global/ParFiles.cxx b/algo/global/ParFiles.cxx
index 7ac22ffb6..81636f1b4 100644
--- a/algo/global/ParFiles.cxx
+++ b/algo/global/ParFiles.cxx
@@ -38,6 +38,7 @@ ParFiles::ParFiles(uint32_t runId)
 
       trd.readout     = "TrdReadoutSetup_mcbm2022.yaml";
       trd.readout2d   = "TrdReadout2DSetup_mcbm2022.yaml";
+      trd.fee2d       = "Trd2dUnCalibFee.yaml";
       trd.hitfinder   = "TrdHitfinderPar_mcbm2022.yaml";
       trd.hitfinder2d = "TrdHitfinder2DPar_mcbm2022.yaml";
 
@@ -57,7 +58,8 @@ ParFiles::ParFiles(uint32_t runId)
       tof.hitfinder = "TofHitfinderPar_mcbm2024.yaml";
 
       trd.readout     = "TrdReadoutSetup_mcbm2024.yaml";
-      trd.readout2d   = "TrdReadout2DSetup_mcbm2022.yaml";  // TODO: no new readout for TRD2D?
+      trd.readout2d   = "TrdReadout2DSetup_mcbm2022.yaml";  // same mCBM2022 readout for TRD2D
+      trd.fee2d       = "Trd2dUnCalibFee.yaml";             // dummy calibration
       trd.hitfinder   = "TrdHitfinderPar_mcbm2024.yaml";
       trd.hitfinder2d = "TrdHitfinder2DPar_mcbm2024.yaml";
 
@@ -77,8 +79,8 @@ ParFiles::ParFiles(uint32_t runId)
       tof.hitfinder = "mcbm2024_05/TofHitfinderPar.yaml";
 
       trd.readout     = "mcbm2024_05/TrdReadoutSetup.yaml";
-      trd.readout2d   = "mcbm2025/Trd2dReadoutSetup.yaml";
-      trd.fee2d       = "mcbm2025/Trd2dCalibFee.yaml";
+      trd.readout2d   = "TrdReadout2DSetup_mcbm2022.yaml";  // same mCBM2022 readout for TRD2D
+      trd.fee2d       = "Trd2dUnCalibFee.yaml";             // dummy calibration
       trd.hitfinder   = "mcbm2024_05/TrdHitfinderPar.yaml";
       trd.hitfinder2d = "mcbm2024_05/TrdHitfinder2DPar.yaml";
 
@@ -105,6 +107,11 @@ ParFiles::ParFiles(uint32_t runId)
       ca.mainConfig = "mcbm2025_02/TrackingChainConfig.yaml";
       break;
 
+      // case Setup::mCBM2025_02:
+      //   trd.readout2d   = "mcbm2025_02/Trd2dReadoutSetup.yaml";
+      //   trd.fee2d       = "mcbm2025_02/Trd2dCalibFee.yaml";
+      //   break;
+
     default: throw FatalError("Unknown setup: {}", ToString(setup));
   }
 }
-- 
GitLab