diff --git a/core/detectors/rich/CbmRichDigiMapManager.cxx b/core/detectors/rich/CbmRichDigiMapManager.cxx
index 087740cbdf0408f3674e2f401488262011db1dc9..5e264b0e5cd36f455694cf7df4d22de8c3f96067 100644
--- a/core/detectors/rich/CbmRichDigiMapManager.cxx
+++ b/core/detectors/rich/CbmRichDigiMapManager.cxx
@@ -88,10 +88,10 @@ void CbmRichDigiMapManager::Init()
         case 0: {
           // RICH detector
           //std::cout<<"RICH"<<std::endl;
-          const TGeoMatrix* curMatrix = geoIterator.GetCurrentMatrix();
-          const Double_t* curNodeTr   = curMatrix->GetTranslation();
+          const TGeoMatrix* curMatrix   = geoIterator.GetCurrentMatrix();
+          const Double_t* curNodeTr     = curMatrix->GetTranslation();
           const TGeoMatrix* localMatrix = curNode->GetMatrix();  // local transformation of pixel in MAPMT volume
-          string path                 = string(nodePath.Data());
+          string path                   = string(nodePath.Data());
 
           size_t pmtInd = path.find_last_of("/");
           if (string::npos == pmtInd) continue;
@@ -143,10 +143,10 @@ void CbmRichDigiMapManager::Init()
 
         case 1: {
           //std::cout<<"mRICH"<<std::endl;
-          const TGeoMatrix* curMatrix = geoIterator.GetCurrentMatrix();
-          const Double_t* curNodeTr   = curMatrix->GetTranslation();
+          const TGeoMatrix* curMatrix   = geoIterator.GetCurrentMatrix();
+          const Double_t* curNodeTr     = curMatrix->GetTranslation();
           const TGeoMatrix* localMatrix = curNode->GetMatrix();  // local transformation of pixel in MAPMT volume
-          string path                 = string(nodePath.Data());
+          string path                   = string(nodePath.Data());
 
           size_t pmtInd = path.find_last_of("/");
           if (string::npos == pmtInd) continue;
@@ -322,9 +322,10 @@ CbmRichPmtData* CbmRichDigiMapManager::GetPmtDataById(Int_t id)
   return it->second;
 }
 
-vector<Int_t> CbmRichDigiMapManager::GetNeighbourPixels(Int_t address, Int_t N, Bool_t direct, Bool_t diagonal)
+vector<Int_t> CbmRichDigiMapManager::GetNeighbourPixels(Int_t address, Int_t n, Bool_t direct, Bool_t diagonal)
 {
   vector<Int_t> neighbourPixels;
+  if (n == 0) return neighbourPixels;
   CbmRichPixelData* addressPixelData = GetPixelDataByAddress(address);
   Int_t indX                         = addressPixelData->fPixelId % 8;
   Int_t indY                         = addressPixelData->fPixelId / 8;
@@ -334,18 +335,18 @@ vector<Int_t> CbmRichDigiMapManager::GetNeighbourPixels(Int_t address, Int_t N,
     CbmRichPixelData* iPixelData = GetPixelDataByAddress(iAddr);
     Int_t iIndX                  = iPixelData->fPixelId % 8;
     Int_t iIndY                  = iPixelData->fPixelId / 8;
-    if (direct && !diagonal && N == 1) {  // direct neighbours
+    if (direct && !diagonal && n == 1) {  // direct neighbours
       if ((abs(iIndX - indX) + abs(iIndY - indY)) == 1) neighbourPixels.push_back(iAddr);
     }
-    else if (!direct && diagonal && N == 1) {  // diagonal neighbours
+    else if (!direct && diagonal && n == 1) {  // diagonal neighbours
       if ((abs(iIndX - indX) == 1) && (abs(iIndY - indY) == 1)) neighbourPixels.push_back(iAddr);
     }
     else if (direct && diagonal) {  // all neighbours in (2N+1)*(2N+1) grid
-      if ((abs(iIndX - indX) <= N) && (abs(iIndY - indY) <= N)) neighbourPixels.push_back(iAddr);
+      if ((abs(iIndX - indX) <= n) && (abs(iIndY - indY) <= n)) neighbourPixels.push_back(iAddr);
     }
     else {
       LOG(error) << "ERROR: Unrecogniced option in CbmRichDigiMapManager::GetNeighbourPixels " << endl
-                 << " N = " << N << " direct = " << direct << " diagonal = " << diagonal;
+                 << " n = " << n << " direct = " << direct << " diagonal = " << diagonal;
     }
   }
   return neighbourPixels;
diff --git a/core/detectors/rich/CbmRichDigiMapManager.h b/core/detectors/rich/CbmRichDigiMapManager.h
index 54a6323b279d6cbc37db3f1708e9acb57933d7e5..d4a9604081b12fb4b047ee46558af8ca4775cf99 100644
--- a/core/detectors/rich/CbmRichDigiMapManager.h
+++ b/core/detectors/rich/CbmRichDigiMapManager.h
@@ -68,28 +68,36 @@ public:
 
   /*
    * \brief Return the addresses of the neighbour pixels.
+   * \param address Pixel address
+   * \param n Size of the grid (2n+1)*(2n+1)
+   * \param direct return direct neighbours
+   * \param diagonal return diagonal neighbours
    */
   std::vector<Int_t> GetNeighbourPixels(Int_t address, Int_t N, Bool_t direct = true, Bool_t diagonal = true);
 
   /*
    * \brief Return the addresses of the direct neighbour pixels.
+   * \param address Pixel address
    */
   std::vector<Int_t> GetDirectNeighbourPixels(Int_t address) { return GetNeighbourPixels(address, 1, true, false); }
 
   /*
    * \brief Return the addresses of the diagonal neighbour pixels.
+   * \param address Pixel address
    */
   std::vector<Int_t> GetDiagonalNeighbourPixels(Int_t address) { return GetNeighbourPixels(address, 1, false, true); }
 
   /*
-   * \brief Return the addresses of pixels in a (2N+1)*(2N+1) grid,
+   * \brief Return the addresses of pixels in a (2n+1)*(2n+1) grid,
    * with the address pixel in the center of the grid.
    * Addresses are limited to the same MAPMT as the input address.
    * Needed for noise digis caused by charged particles.
+   * \param address Pixel address
+   * \param n Size of the grid (2n+1)*(2n+1)
    */
-  std::vector<Int_t> GetNxNNeighbourPixels(Int_t address, Int_t N)
+  std::vector<Int_t> GetNxNNeighbourPixels(Int_t address, Int_t n)
   {
-    return GetNeighbourPixels(address, N, true, true);
+    return GetNeighbourPixels(address, n, true, true);
   }
 
 public:
diff --git a/macro/rich/geotest/run_digi.C b/macro/rich/geotest/run_digi.C
index 1ebc322414f6f43642a231961e2645d71dc0f969..85dacd37f4a928878c7531c00ead6769bd73c25f 100644
--- a/macro/rich/geotest/run_digi.C
+++ b/macro/rich/geotest/run_digi.C
@@ -27,8 +27,7 @@ void run_digi(const string& traFile, const string& parFile, const string& digiFi
   run.SetMonitorFile("");
 
   CbmRichDigitizer* richDigitizer = new CbmRichDigitizer();
-  richDigitizer->SetMaxNofHitsPerPmtCut(65);
-  richDigitizer->SetNoiseDigiRate(0.);
+  richDigitizer->SetEventNoiseRate(0.);
   run.SetDigitizer(ECbmModuleId::kRich, richDigitizer, "RichPoint", true);
 
   run.Run(nEvents);
diff --git a/macro/rich/run/run_digi.C b/macro/rich/run/run_digi.C
index 8b91747631f48b9af7d912882d59571c5c3509f4..20093cb2628cdba4385ce46dbf356bbdec73eeed 100644
--- a/macro/rich/run/run_digi.C
+++ b/macro/rich/run/run_digi.C
@@ -31,7 +31,6 @@ void run_digi(const string& traFile  = "/Users/slebedev/Development/cbm/data/sim
   run.SetMonitorFile("");
 
   CbmRichDigitizer* richDigitizer = new CbmRichDigitizer();
-  richDigitizer->SetMaxNofHitsPerPmtCut(65);
   run.SetDigitizer(ECbmModuleId::kRich, richDigitizer, "RichPoint", true);
 
   run.Run(nEvents);
diff --git a/reco/detectors/rich/CMakeLists.txt b/reco/detectors/rich/CMakeLists.txt
index 7fecbf83e010114b46eaceebb273453eff64791c..becc3e386c136430fc70b1efdd8ecc87c5abab77 100644
--- a/reco/detectors/rich/CMakeLists.txt
+++ b/reco/detectors/rich/CMakeLists.txt
@@ -34,6 +34,7 @@ set(SRCS
   qa/CbmRichGeoTestOpt.cxx
   qa/CbmRichRecoQa.cxx
   qa/CbmL1RichRingQa.cxx
+  qa/CbmRichDigiQa.cxx
 
   unpack/CbmRichUnpackAlgo.cxx
   unpack/CbmRichUnpackAlgo2022.cxx
diff --git a/reco/detectors/rich/CbmRichRecoLinkDef.h b/reco/detectors/rich/CbmRichRecoLinkDef.h
index 8739d2c8657490ca67fcc988c48c37ab0dd8b886..a832c0dd25658ce645712bbbd8b6586ee53ffd7c 100644
--- a/reco/detectors/rich/CbmRichRecoLinkDef.h
+++ b/reco/detectors/rich/CbmRichRecoLinkDef.h
@@ -32,6 +32,7 @@
 #pragma link C++ class CbmRichRecoQa + ;
 #pragma link C++ class CbmRichRecoTbQa + ;
 #pragma link C++ class CbmL1RichRingQa + ;
+#pragma link C++ class CbmRichDigiQa + ;
 
 //unpack
 #pragma link C++ class CbmRichUnpackAlgo + ;
diff --git a/reco/detectors/rich/qa/CbmRichDigiQa.cxx b/reco/detectors/rich/qa/CbmRichDigiQa.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4524ad7b3695664afa90a1f0ca9adcf15e85b9c4
--- /dev/null
+++ b/reco/detectors/rich/qa/CbmRichDigiQa.cxx
@@ -0,0 +1,123 @@
+/* Copyright (C) 2023-2023 UGiessen, Giessen
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Martin Beyer [committer] */
+
+#include "CbmRichDigiQa.h"
+
+#include "CbmDigiManager.h"
+#include "CbmHistManager.h"
+#include "CbmRichDetectorData.h"
+#include "CbmRichDigi.h"
+#include "CbmRichDigiMapManager.h"
+
+#include <FairRootManager.h>
+#include <Logger.h>
+
+#include <TDirectory.h>
+#include <TFile.h>
+
+InitStatus CbmRichDigiQa::Init()
+{
+  CbmRichDigiMapManager::GetInstance();
+
+  fDigiMan = CbmDigiManager::Instance();
+  fDigiMan->Init();
+  if (!fDigiMan->IsPresent(ECbmModuleId::kRich)) LOG(fatal) << "CbmRichDigiQa::Init: No RichDigi array!";
+
+  InitHistograms();
+
+  return kSUCCESS;
+}
+
+void CbmRichDigiQa::InitHistograms()
+{
+  fHM = new CbmHistManager();
+
+  fHM->Create1<TH1D>("fhDigiDt", "same address consecutive digis time diff;dt [ns];entries", 1001, -0.5, 10000.5);
+
+  fHM->Create1<TH1D>("fhDigiDtEdge", "same address consecutive digis time diff;dt [ns];entries", 101, -0.5, 100.5);
+
+  fHM->Create1<TH1D>("fhDigiDistH", "horizontal distance of digis same pmt;DIndX [in pixels];entries", 11, -0.5, 10.5);
+
+  fHM->Create1<TH1D>("fhDigiDistV", "vertical distance of digis same pmt;DIndY [in pixels];entries", 11, -0.5, 10.5);
+
+  fHM->Create2<TH2D>("fhDigiNeighbours", "digi neighbours same pmt;DIndX [in pixels];DIndY [in pixels];entries", 5,
+                     -2.5, 2.5, 5, -2.5, 2.5);
+}
+
+void CbmRichDigiQa::Exec(Option_t* /*option*/)
+{
+  LOG(debug) << GetName() << " Event " << fEventNum;
+  fEventNum++;
+
+  Int_t nofDigis = fDigiMan->GetNofDigis(ECbmModuleId::kRich);
+  for (Int_t i = 0; i < nofDigis; i++) {
+    const CbmRichDigi* digi = fDigiMan->Get<CbmRichDigi>(i);
+    if (!digi) continue;
+    Int_t pmtId = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(digi->GetAddress())->fPmtId;
+    if (fToTLimitLow > 0. && fToTLimitHigh > 0.) {
+      if (digi->GetToT() < fToTLimitHigh && digi->GetToT() > fToTLimitLow) {
+        fFiredTimes[digi->GetAddress()].push_back(digi->GetTime());
+        fPmtDigisTimeAddress[pmtId].push_back(std::make_pair(digi->GetTime(), digi->GetAddress()));
+      }
+    }
+    else {
+      fFiredTimes[digi->GetAddress()].push_back(digi->GetTime());
+      fPmtDigisTimeAddress[pmtId].push_back(std::make_pair(digi->GetTime(), digi->GetAddress()));
+    }
+  }
+
+  // Fill deadtimes
+  for (auto& [address, times] : fFiredTimes) {
+    std::sort(times.begin(), times.end());
+    for (auto it = times.begin(); it != times.end(); ++it) {
+      if (*it < 0.)
+        LOG(warn) << "Digi time < 0.: "
+                  << "address: " << address << " time: " << *it << " ns";
+
+      if (it != times.begin()) {
+        Double_t dt = *it - *std::prev(it);
+        fHM->H1("fhDigiDt")->Fill(dt);
+        if (dt < 100.5) { fHM->H1("fhDigiDtEdge")->Fill(dt); }
+      }
+    }
+  }
+
+  // Fill crosstalk digis
+  for (auto& [pmt, digis] : fPmtDigisTimeAddress) {
+    std::sort(digis.begin(), digis.end());
+    for (auto it0 = digis.begin(); it0 != digis.end(); ++it0) {
+      Int_t indX0 = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(it0->second)->fPixelId % 8;
+      Int_t indY0 = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(it0->second)->fPixelId / 8;
+      for (auto it1 = it0 + 1; it1 != digis.end(); ++it1) {
+        if (abs(it0->first - it1->first) < fCrosstalkTimeLimit) {
+          Int_t indX1 = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(it1->second)->fPixelId % 8;
+          Int_t indY1 = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(it1->second)->fPixelId / 8;
+          if (indX0 == indX1 && indY0 == indY1) continue;
+          if (indY0 == indY1) fHM->H1("fhDigiDistH")->Fill(indX1 - indX0);
+          if (indX0 == indX1) fHM->H1("fhDigiDistV")->Fill(indY1 - indY0);
+          if (abs(indX0 - indX1) > 1 || abs(indY0 - indY1) > 1) continue;
+          fHM->H2("fhDigiNeighbours")->Fill(indX1 - indX0, indY0 - indY1);
+        }
+        else if (it1->first - it0->first > fCrosstalkTimeLimit) {
+          break;
+        }
+      }
+    }
+  }
+
+  fFiredTimes.clear();
+  fPmtDigisTimeAddress.clear();
+}
+
+void CbmRichDigiQa::Finish()
+{
+  TDirectory* oldir = gDirectory;
+  TFile* outFile    = FairRootManager::Instance()->GetOutFile();
+  if (outFile != nullptr) {
+    outFile->mkdir(GetName());
+    outFile->cd(GetName());
+    fHM->WriteToFile();
+  }
+  gDirectory->cd(oldir->GetPath());
+}
diff --git a/reco/detectors/rich/qa/CbmRichDigiQa.h b/reco/detectors/rich/qa/CbmRichDigiQa.h
new file mode 100644
index 0000000000000000000000000000000000000000..25822a5c28a7266e4a63c1fbf2da77b5be8541f9
--- /dev/null
+++ b/reco/detectors/rich/qa/CbmRichDigiQa.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2023-2023 UGiessen, Giessen
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Martin Beyer [committer] */
+
+/**
+* \file CbmRichDigiQa.h
+* \author M.Beyer
+* \date 2023
+**/
+
+#ifndef CBMRICHDIGIQA_H
+#define CBMRICHDIGIQA_H
+
+#include "FairTask.h"
+
+#include <map>
+#include <vector>
+
+class CbmDigiManager;
+class CbmRichDigi;
+class CbmHistManager;
+class TClonesArray;
+
+/**
+* \class CbmRichDigiQa
+*
+* \brief Class for pixel deadtime and crosstalk Qa.
+*
+* \author M.Beyer
+* \date 2023
+**/
+class CbmRichDigiQa : public FairTask {
+public:
+  /** Default constructor */
+  CbmRichDigiQa() : FairTask("CbmRichDigiQa") {};
+
+  /** Destructor */
+  ~CbmRichDigiQa() = default;
+
+  /** Copy constructor (disabled) */
+  CbmRichDigiQa(const CbmRichDigiQa&) = delete;
+
+  /** Assignment operator (disabled) */
+  CbmRichDigiQa operator=(const CbmRichDigiQa&) = delete;
+
+  /** Inherited from FairTask */
+  InitStatus Init();
+
+  /** Inherited from FairTask */
+  void Exec(Option_t* option);
+
+  /** Inherited from FairTask */
+  void Finish();
+
+  /** Initialize histogram manager */
+  void InitHistograms();
+
+  /** 
+    * \brief Set ToT cut
+    * \param[in] low lower limit
+    * \param[in] high upper limit
+    */
+  void SetToTLimits(Double_t low, Double_t high)
+  {
+    fToTLimitLow  = low;
+    fToTLimitHigh = high;
+  }
+
+  /**
+    * \brief Set time limit in which a neighbour digi is considered crosstalk
+    * \param[in] limit absolue time limit
+    */
+  void SetCrosstalkTimeLimit(Double_t limit) { fCrosstalkTimeLimit = limit; }
+
+private:
+  int fEventNum {};
+
+  CbmDigiManager* fDigiMan {nullptr};
+  CbmHistManager* fHM {nullptr};
+
+  TClonesArray* fRichPoints {nullptr};
+
+  std::map<Int_t, std::vector<Double_t>> fFiredTimes {};  // Store times of fired digis for each pixel in Ts
+  std::map<Int_t, std::vector<std::pair<Double_t, Int_t>>>
+    fPmtDigisTimeAddress {};  // Store times and addresses of fired digis for each pmt in Ts
+
+  Double_t fCrosstalkTimeLimit {5.};  // Time in which a neighbour digi is considered crosstalk
+  Double_t fToTLimitLow {-1.};        // Lower limit for ToT cut
+  Double_t fToTLimitHigh {-1.};       // Upper limit for ToT cut
+
+  ClassDef(CbmRichDigiQa, 1)
+};
+
+#endif
diff --git a/sim/detectors/rich/CbmRichDigitizer.cxx b/sim/detectors/rich/CbmRichDigitizer.cxx
index 6b6761cd6ed0154b02a3b7d14db50bfcc066eefc..dedeebf2c3e0175cf588d975c4994417ff097ecb 100644
--- a/sim/detectors/rich/CbmRichDigitizer.cxx
+++ b/sim/detectors/rich/CbmRichDigitizer.cxx
@@ -1,6 +1,6 @@
-/* Copyright (C) 2015-2020 GSI/JINR-LIT, Darmstadt/Dubna
+/* Copyright (C) 2015-2023 GSI/JINR-LIT, Darmstadt/Dubna
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Andrey Lebedev [committer], Volker Friese, Florian Uhlig, Semen Lebedev */
+   Authors: Martin Beyer, Andrey Lebedev [committer], Volker Friese, Florian Uhlig, Semen Lebedev */
 
 /**
 * \file CbmRichDigitizer.cxx
@@ -14,64 +14,39 @@
 #include "CbmLink.h"
 #include "CbmMCTrack.h"
 #include "CbmMatch.h"
-#include "CbmRichDetectorData.h"  // for CbmRichPmtData, CbmRichPixelData
+#include "CbmRichDetectorData.h"
 #include "CbmRichDigi.h"
 #include "CbmRichDigiMapManager.h"
 #include "CbmRichGeoManager.h"
 #include "CbmRichPoint.h"
 
-#include "FairEventHeader.h"
-#include "FairRunAna.h"
-#include "FairRunSim.h"
+#include <FairEventHeader.h>
+#include <FairRunAna.h>
+#include <FairRunSim.h>
 #include <Logger.h>
 
-#include "TClonesArray.h"
-#include "TGeoManager.h"
-#include "TRandom.h"
-#include "TStopwatch.h"
+#include <TClonesArray.h>
+#include <TGeoManager.h>
+#include <TMath.h>
+#include <TRandom.h>
+#include <TStopwatch.h>
 
 #include <cassert>
 #include <iomanip>
 #include <iostream>
 
-using namespace std;
-
-CbmRichDigitizer::CbmRichDigitizer()
-  : CbmDigitize<CbmRichDigi>("RichDigitize")
-  , fEventNum(0)
-  , fRichPoints(NULL)
-  , fRichDigis(NULL)
-  , fRichDigiMatches(nullptr)
-  , fMcTracks(NULL)
-  , fNofPoints(0.)
-  , fNofDigis(0.)
-  , fTimeTot(0.)
-  , fPmt()
-  , fCrossTalkProbability(0.02)
-  , fNoiseDigiRate(5.)
-  , fDetectorType(CbmRichPmtTypeCosy17NoWls)
-  , fMaxNofHitsPerPmtCut(65)
-  , fDataMap()
-  , fTimeResolution(1.)
-  , fDarkRatePerPixel(1000)
-  , fPixelDeadTime(30.)
-  , fFiredPixelsMap()
-  , fDoZShift(true)
-{
-}
-
-CbmRichDigitizer::~CbmRichDigitizer() {}
-
+using std::fixed;
+using std::left;
+using std::right;
+using std::setprecision;
+using std::setw;
 
 InitStatus CbmRichDigitizer::Init()
 {
-
-  // Screen output
   std::cout << std::endl;
   LOG(info) << "==========================================================";
   LOG(info) << GetName() << ": Initialisation";
 
-  //FairTask* daq = FairRun::Instance()->GetTask("Daq");
   if (!fEventMode) { LOG(info) << "CbmRichDigitizer uses TimeBased mode."; }
   else {
     LOG(info) << "CbmRichDigitizer uses Events mode.";
@@ -84,11 +59,11 @@ InitStatus CbmRichDigitizer::Init()
   CbmRichDigiMapManager::GetInstance();
   CbmRichGeoManager::GetInstance();
 
-  fRichPoints = (TClonesArray*) manager->GetObject("RichPoint");
-  if (NULL == fRichPoints) { Fatal("CbmRichDigitizer::Init", "No RichPoint array!"); }
+  fRichPoints = static_cast<TClonesArray*>(manager->GetObject("RichPoint"));
+  if (!fRichPoints) LOG(fatal) << "CbmRichDigitizer::Init: No RichPoint array!";
 
-  fMcTracks = (TClonesArray*) manager->GetObject("MCTrack");
-  if (NULL == fMcTracks) { Fatal("CbmRichDigitizer::Init", "No MCTrack array!"); }
+  fMcTracks = static_cast<TClonesArray*>(manager->GetObject("MCTrack"));
+  if (!fMcTracks) LOG(fatal) << "CbmRichDigitizer::Init: No MCTrack array!";
 
   RegisterOutput();
 
@@ -105,8 +80,8 @@ InitStatus CbmRichDigitizer::Init()
   }
 
   LOG(info) << GetName() << ": Initialisation successful";
-
-  fFiredPixelsMap.clear();
+  LOG(info) << "==========================================================";
+  std::cout << std::endl;
 
   return kSUCCESS;
 }
@@ -116,31 +91,21 @@ void CbmRichDigitizer::Exec(Option_t* /*option*/)
   TStopwatch timer;
   timer.Start();
 
-  fEventNum++;
-  LOG(debug) << fName << ": Event  " << fEventNum;
-
-
-  // Clear data map
-  for (auto& data : fDataMap) {
-    if (data.second.first) delete data.second.first;    // digi
-    if (data.second.second) delete data.second.second;  // match
-  }
-  fDataMap.clear();
-
   Double_t oldEventTime = fCurrentEventTime;
   GetEventInfo();
 
-  LOG(debug) << fName << ": EventNumber: " << fCurrentEvent << ", EventTime: " << fCurrentEventTime;
-
-  if (fProduceNoise) GenerateNoiseBetweenEvents(oldEventTime, fCurrentEventTime);
-
   Int_t nPoints = ProcessMcEvent();
 
-  Int_t nDigis = AddDigisToOutputArray();
+  Double_t tNoiseStart = fEventNum ? oldEventTime : fRunStartTime;
+  if (fProduceNoise) AddDarkRateNoise(tNoiseStart, fCurrentEventTime);
 
+  if (fEventMode) fPixelsLastFiredTime.clear();
+  Double_t processTime = fEventMode ? -1. : fCurrentEventTime;
+  Int_t nDigis         = ProcessBuffers(processTime);
 
   // --- Statistics
   timer.Stop();
+  fEventNum++;
   fNofPoints += nPoints;
   fNofDigis += nDigis;
   fTimeTot += timer.RealTime();
@@ -151,9 +116,36 @@ void CbmRichDigitizer::Exec(Option_t* /*option*/)
             << ". Exec time " << setprecision(6) << timer.RealTime() << " s.";
 }
 
+void CbmRichDigitizer::Finish()
+{
+  TStopwatch timer;
+  if (!fEventMode) {
+    std::cout << std::endl;
+    LOG(info) << GetName() << ": Finish run";
+    LOG(info) << GetName() << ": Processing analogue buffers";
+    timer.Start();
+    Int_t nDigis = ProcessBuffers(-1.);
+    timer.Stop();
+    fTimeTot += timer.RealTime();
+    LOG(info) << GetName() << ": " << nDigis << " digis created and sent to DAQ";
+    fNofDigis += nDigis;
+  }
+
+  std::cout << std::endl;
+  LOG(info) << "=====================================";
+  LOG(info) << GetName() << ": Run summary";
+  LOG(info) << "Events processed    : " << fEventNum;
+  LOG(info) << "RichPoint / event   : " << setprecision(1) << fNofPoints / Double_t(fEventNum);
+  LOG(info) << "RichDigi / event    : " << fNofDigis / Double_t(fEventNum);
+  LOG(info) << "Digis per point     : " << setprecision(6) << fNofDigis / Double_t(fNofPoints);
+  LOG(info) << "Real time per event : " << fTimeTot / Double_t(fEventNum) << " s";
+  LOG(info) << "=====================================";
+}
+
 Int_t CbmRichDigitizer::ProcessMcEvent()
 {
   Int_t nofRichPoints = fRichPoints->GetEntriesFast();
+
   LOG(debug) << fName << ": EventNum:" << fCurrentEvent << " InputNum:" << fCurrentInput
              << " EventTime:" << fCurrentEventTime << " nofRichPoints:" << nofRichPoints;
 
@@ -161,30 +153,12 @@ Int_t CbmRichDigitizer::ProcessMcEvent()
     CbmRichPoint* point = (CbmRichPoint*) fRichPoints->At(j);
     ProcessPoint(point, j, fCurrentMCEntry, fCurrentInput);
   }
-  // cout << "nofDigis:" << fRichDigis->GetEntriesFast() << endl;
 
-  AddNoiseDigis(fCurrentMCEntry, fCurrentInput);
+  AddEventNoise(fCurrentMCEntry, fCurrentInput);
 
   return nofRichPoints;
 }
 
-void CbmRichDigitizer::GenerateNoiseBetweenEvents(Double_t oldEventTime, Double_t newEventTime)
-{
-  Int_t nofPixels         = CbmRichDigiMapManager::GetInstance().GetPixelAddresses().size();
-  Double_t dT             = newEventTime - oldEventTime;
-  Double_t nofNoisePixels = nofPixels * dT * (fDarkRatePerPixel / 1.e9);
-
-  LOG(debug) << "CbmRichDigitizer::GenerateNoiseBetweenEvents deltaTime:" << dT << " nofPixels:" << nofPixels
-             << " nofNoisePixels:" << nofNoisePixels;
-
-  for (Int_t j = 0; j < nofNoisePixels; j++) {
-    Int_t address = CbmRichDigiMapManager::GetInstance().GetRandomPixelAddress();
-    CbmLink link(1., -1, -1, -1);
-    Double_t time = gRandom->Uniform(oldEventTime, newEventTime);
-    AddDigi(address, time, link);
-  }
-}
-
 void CbmRichDigitizer::ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t eventNum, Int_t inputNum)
 {
   // LOG(info) << "ProcessPoint " << pointId;
@@ -193,15 +167,16 @@ void CbmRichDigitizer::ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t ev
   Double_t zNew = point->GetZ();
   if (fDoZShift) zNew = zNew - 0.001;
   gGeoManager->FindNode(point->GetX(), point->GetY(), zNew);
-  string path(gGeoManager->GetPath());
+  std::string path(gGeoManager->GetPath());
   Int_t address = CbmRichDigiMapManager::GetInstance().GetPixelAddressByPath(path);
-
+  if (address < 0) return;
   Int_t trackId = point->GetTrackID();
   //LOG(info) << "address:" << address << " path:" << path << " trackId:" << trackId << "X:" << point->GetX() << " Y:" << point->GetY() << " Z:" << zNew;
   if (trackId < 0) return;
   CbmMCTrack* p = (CbmMCTrack*) fMcTracks->At(trackId);
   if (p == NULL) return;
   Int_t gcode = TMath::Abs(p->GetPdgCode());
+  Double_t charge = p->GetCharge();
 
   CbmLink link(1., pointId, eventNum, inputNum);
 
@@ -219,165 +194,143 @@ void CbmRichDigitizer::ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t ev
     isDetected = true;
   }
 
-  Double_t time   = fCurrentEventTime + point->GetTime();
-  Double_t deltaT = gRandom->Gaus(0., fTimeResolution);
-  time += deltaT;
-  if (isDetected) { AddDigi(address, time, link); }
+  Double_t time = fCurrentEventTime + point->GetTime();
+  if (isDetected) {
+    AddSignalToBuffer(address, time, link);
+    if (gcode == 50000050 && address > 0) AddCrossTalk(address, time, link);
+    if (charge != 0. && address > 0) AddChargedParticleCluster(address, time, eventNum, inputNum);
+  }
 }
 
-
-void CbmRichDigitizer::Finish()
+void CbmRichDigitizer::AddSignalToBuffer(Int_t address, Double_t time, const CbmLink& link)
 {
-  std::cout << std::endl;
-  LOG(info) << "=====================================";
-  LOG(info) << GetName() << ": Run summary";
-  LOG(info) << "Events processed    : " << fEventNum;
-  LOG(info) << "RichPoint / event   : " << setprecision(1) << fNofPoints / Double_t(fEventNum);
-  LOG(info) << "RichDigi / event    : " << fNofDigis / Double_t(fEventNum);
-  LOG(info) << "Digis per point     : " << setprecision(6) << fNofDigis / fNofPoints;
-  LOG(info) << "Real time per event : " << fTimeTot / Double_t(fEventNum) << " s";
-  LOG(info) << "=====================================";
+  fSignalBuffer[address].emplace_back(std::make_pair(time, new CbmLink(link)));
 }
 
-void CbmRichDigitizer::AddCrossTalkDigis(CbmRichDigi* digi)
+void CbmRichDigitizer::AddCrossTalk(Int_t address, Double_t time, const CbmLink& link)
 {
-  Bool_t crosstalkDigiDetected = false;
-  vector<Int_t> directPixels   = CbmRichDigiMapManager::GetInstance().GetDirectNeighbourPixels(digi->GetAddress());
-  vector<Int_t> diagonalPixels = CbmRichDigiMapManager::GetInstance().GetDiagonalNeighbourPixels(digi->GetAddress());
-
-  for (UInt_t i = 0; i < directPixels.size(); i++) {
-    if (gRandom->Rndm() < fCrossTalkProbability && !crosstalkDigiDetected) {
-      //FindRichHitPositionMAPMT(0., x + r, y, xHit, yHit, pmtID);
-      crosstalkDigiDetected = true;
-      break;
-    }
-  }
-
-  if (!crosstalkDigiDetected) {
-    for (UInt_t i = 0; i < diagonalPixels.size(); i++) {
-      if (gRandom->Rndm() < fCrossTalkProbability / 4. && !crosstalkDigiDetected) {
-        //FindRichHitPositionMAPMT(0., x + r, y, xHit, yHit, pmtID);
-        crosstalkDigiDetected = true;
-        break;
-      }
+  std::vector<Int_t> directPixels   = CbmRichDigiMapManager::GetInstance().GetDirectNeighbourPixels(address);
+  std::vector<Int_t> diagonalPixels = CbmRichDigiMapManager::GetInstance().GetDiagonalNeighbourPixels(address);
+  /* clang-format off */
+  Double_t crosstalkCreatedProbability = 1 - pow(1 - fCrossTalkProbability, directPixels.size()) *
+                                             pow(1 - fCrossTalkProbability / 4., diagonalPixels.size());
+  
+  Int_t crosstalkAddress = -1;
+  if (gRandom->Uniform() < crosstalkCreatedProbability) {
+    Double_t thresholdDirectDiagonal = directPixels.size() / float(directPixels.size() + diagonalPixels.size() / 4.);
+    if (gRandom->Uniform() < thresholdDirectDiagonal) {
+      crosstalkAddress = directPixels[gRandom->Integer(directPixels.size())];
+    } else {
+      crosstalkAddress = diagonalPixels[gRandom->Integer(diagonalPixels.size())];
     }
   }
-
-  if (crosstalkDigiDetected) {
-    //AddDigi(posHit, posHitErr, RichDetID, pmtID, ampl, pointInd);
-    //fNofCrossTalkDigis++;
-  }
+  /* clang-format on */
+  if (crosstalkAddress != -1) AddSignalToBuffer(crosstalkAddress, time, link);
 }
 
-Int_t CbmRichDigitizer::AddDigisToOutputArray()
+void CbmRichDigitizer::AddChargedParticleCluster(Int_t address, Double_t time, Int_t eventNum, Int_t inputNum)
 {
-  Int_t nofDigis = 0;
-
-  // fMaxNofHitsPerPmtCut is a maximum number of hits which can be registered per PMT per event.
-  // If more then the whole PMT is skipped
-  map<Int_t, Int_t> digisPerPmtMap;
-  for (auto const& dm : fDataMap) {
-    CbmRichPixelData* pixelData =
-      CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(dm.second.first->GetAddress());
-    if (nullptr == pixelData) continue;
-    Int_t pmtId = pixelData->fPmtId;
-    digisPerPmtMap[pmtId]++;
-  }
-
-  Int_t nofSkippedPmts = 0;
-  for (auto const& dm : digisPerPmtMap) {
-    if (dm.second > fMaxNofHitsPerPmtCut) nofSkippedPmts++;
-  }
-
-  Int_t nofSkippedDigis = 0;
-  for (auto const& dm : fDataMap) {
-    CbmRichPixelData* pixelData =
-      CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(dm.second.first->GetAddress());
-    if (nullptr == pixelData) continue;
-    if (digisPerPmtMap[pixelData->fPmtId] > fMaxNofHitsPerPmtCut) {
-      nofSkippedDigis++;
-      continue;
+  Int_t sourcePixelId = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(address)->fPixelId;
+  std::vector<Int_t> neighbourAddresses =
+    CbmRichDigiMapManager::GetInstance().GetNxNNeighbourPixels(address, fClusterSize);
+  for (UInt_t i = 0; i < neighbourAddresses.size(); i++) {
+    Int_t iPixelId = CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(neighbourAddresses[i])->fPixelId;
+    Double_t d     = TMath::Sqrt((sourcePixelId % 8 - iPixelId % 8) * (sourcePixelId % 8 - iPixelId % 8)
+                             + (sourcePixelId / 8 - iPixelId / 8) * (sourcePixelId / 8 - iPixelId / 8));
+    if (gRandom->Uniform(1.) < fClusterSignalProbability / d) {
+      CbmLink link(1., -1, eventNum, inputNum);
+      AddSignalToBuffer(neighbourAddresses[i], time, link);
     }
-
-    CbmRichDigi* digi = new CbmRichDigi();
-    digi->SetAddress(dm.second.first->GetAddress());
-    CbmMatch* digiMatch = new CbmMatch(*dm.second.second);
-    digi->SetTime(dm.second.first->GetTime());
-    //SendDigi(digi, digiMatch);
-    if (fCreateMatches) SendData(digi->GetTime(), digi, digiMatch);
-    else
-      SendData(digi->GetTime(), digi);
-    nofDigis++;
-  }  //# digis in map
-
-  LOG(debug) << "Number of RICH digis before skip: " << fDataMap.size();
-  LOG(debug) << "Nof skipped PMTs:" << nofSkippedPmts;
-  LOG(debug) << "Nof skipped digis:" << nofSkippedDigis;
-  LOG(debug) << "Number of RICH digis: " << nofDigis;
-  return nofDigis;
+  }
 }
 
-void CbmRichDigitizer::AddNoiseDigis(Int_t eventNum, Int_t inputNum)
+void CbmRichDigitizer::AddEventNoise(Int_t eventNum, Int_t inputNum)
 {
   Int_t nofPixels        = CbmRichDigiMapManager::GetInstance().GetPixelAddresses().size();
-  Double_t dT            = 50.;  //ns
   Double_t nofRichPoints = fRichPoints->GetEntriesFast();
-  Double_t nofNoiseDigis = nofRichPoints * nofPixels * dT * (fNoiseDigiRate / 1.e9);
+  Double_t nofNoiseDigis = nofRichPoints * nofPixels * fEventNoiseInterval * (fEventNoiseRate / 1.e9);
+
+  LOG(debug) << "CbmRichDigitizer::AddEventNoise NofAllPixels:" << nofPixels << " nofNoiseDigis:" << nofNoiseDigis;
 
-  LOG(debug) << "CbmRichDigitizer::AddNoiseDigis NofAllPixels:" << nofPixels << " nofNoiseDigis:" << nofNoiseDigis;
   for (Int_t j = 0; j < nofNoiseDigis; j++) {
     Int_t address = CbmRichDigiMapManager::GetInstance().GetRandomPixelAddress();
     CbmLink link(1., -1, eventNum, inputNum);
-    Double_t time = fCurrentEventTime + gRandom->Uniform(0, dT);
-    AddDigi(address, time, link);
+    Double_t time = fCurrentEventTime + gRandom->Uniform(0, fEventNoiseInterval);
+    AddSignalToBuffer(address, time, link);
   }
 }
 
-void CbmRichDigitizer::AddDigi(Int_t address, Double_t time, const CbmLink& link)
+void CbmRichDigitizer::AddDarkRateNoise(Double_t oldEventTime, Double_t newEventTime)
 {
-  Bool_t wasFired   = fFiredPixelsMap.count(address) > 0;
-  Bool_t isDetected = true;
-  if (!fEventMode && wasFired) {
-    Double_t lastFiredTime = fFiredPixelsMap[address];
-    Double_t dt            = std::fabs(time - lastFiredTime);
-    if (dt < fPixelDeadTime) {
-      isDetected = false;
-      //    LOG(info) << "CbmRichDigitizer::AddDigi pixel NOT registered: address:" << address << " cur-last=dT: "<< time << "-"
-      //                                << lastFiredTime << "=" <<  dt << " fPixelDeadTime:" << fPixelDeadTime
-      //                                << " fFiredPixelsMap.size():" << fFiredPixelsMap.size() << " link: " << link.GetIndex();
-    }
-    else {
-      isDetected = true;
-      //    LOG(info) << "CbmRichDigitizer::AddDigi pixel registered: address:" << address << " cur-last=dT: "<< time << "-"
-      //                                << lastFiredTime << "=" <<  dt << " fPixelDeadTime:" << fPixelDeadTime
-      //                                << " fFiredPixelsMap.size():" << fFiredPixelsMap.size() << " link: " << link.GetIndex();
-    }
-  }
-  else {
-    isDetected = true;
-    // LOG(info) << "CbmRichDigitizer::AddDigi pixel was not fired before: address:" << address << " time:" << time
-    //        << " fFiredPixelsMap.size():" << fFiredPixelsMap.size() << " link: " << link.GetIndex();
+  Int_t nofPixels         = CbmRichDigiMapManager::GetInstance().GetPixelAddresses().size();
+  Double_t dT             = newEventTime - oldEventTime;
+  Double_t nofNoisePixels = nofPixels * dT * (fDarkRatePerPixel / 1.e9);
+
+  LOG(debug) << "CbmRichDigitizer::AddDarkRateNoise deltaTime:" << dT << " nofPixels:" << nofPixels
+             << " nofNoisePixels:" << nofNoisePixels;
+
+  for (Int_t j = 0; j < nofNoisePixels; j++) {
+    Int_t address = CbmRichDigiMapManager::GetInstance().GetRandomPixelAddress();
+    CbmLink link(1., -1, -1, -1);
+    Double_t time = gRandom->Uniform(oldEventTime, newEventTime);
+    AddSignalToBuffer(address, time, link);
   }
+}
 
-  if (isDetected) {
-    auto it = fDataMap.find(address);
-    if (it == fDataMap.end()) {
-      CbmRichDigi* digi = new CbmRichDigi();
-      digi->SetAddress(address);
-      digi->SetTime(time);
-      CbmMatch* match = new CbmMatch();
-      match->AddLink(link);
-      pair<CbmRichDigi*, CbmMatch*> value(digi, match);
-      fDataMap.insert(pair<Int_t, pair<CbmRichDigi*, CbmMatch*>>(address, value));
+Int_t CbmRichDigitizer::ProcessBuffers(Double_t processTime)
+{
+  Double_t maxNewDigiTime = processTime - fPixelDeadTime;
+  Int_t nofDigis {};
+
+  for (auto& dm : fSignalBuffer) {
+    std::sort(
+      dm.second.begin(), dm.second.end(),
+      [](const std::pair<Double_t, CbmLink*>& a, const std::pair<Double_t, CbmLink*>& b) { return a.first < b.first; });
+
+    CbmRichDigi* digi   = nullptr;
+    CbmMatch* digiMatch = nullptr;
+    auto it             = dm.second.begin();
+    for (; it != dm.second.end(); ++it) {
+      Double_t signalTime = it->first;
+      if (processTime >= 0. && signalTime > processTime) break;
+      CbmLink* link      = it->second;
+      Bool_t createsDigi = true;
+
+      auto itFpm = fPixelsLastFiredTime.find(dm.first);
+      if (itFpm != fPixelsLastFiredTime.end()) {
+        Double_t lastFiredTime = itFpm->second;
+        if (signalTime - lastFiredTime < fPixelDeadTime) createsDigi = false;
+      }
+
+      if (createsDigi) {
+        if (digi) {  // Add previous digi if exists
+          fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
+          nofDigis++;
+          digi      = nullptr;  // Needed because of potential break statement
+          digiMatch = nullptr;
+        }
+        Double_t digiTime = signalTime + gRandom->Gaus(0., fTimeResolution);
+        if (processTime >= 0. && digiTime > maxNewDigiTime) break;
+        digi = new CbmRichDigi();
+        digi->SetAddress(dm.first);
+        digi->SetTime(digiTime);
+        digiMatch = new CbmMatch();
+        digiMatch->AddLink(*link);
+        fPixelsLastFiredTime[dm.first] = signalTime;  // Deadtime is from signal to signal
+      }
+      else {
+        if (digi && digiMatch) digiMatch->AddLink(*link);
+      }
+      delete it->second;
     }
-    else {
-      CbmMatch* match = it->second.second;
-      match->AddLink(link);
+    dm.second.erase(dm.second.begin(), it);
+    if (digi) {  // Add last digi if exists
+      fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
+      nofDigis++;
     }
   }
 
-  fFiredPixelsMap[address] = time;
+  return nofDigis;
 }
 
-
 ClassImp(CbmRichDigitizer)
diff --git a/sim/detectors/rich/CbmRichDigitizer.h b/sim/detectors/rich/CbmRichDigitizer.h
index 9c0bf86b7fa7a0d60a52b7cfed983b54b90152e5..6283766327bbe9157ecaa1ca91cf6d9534cad87b 100644
--- a/sim/detectors/rich/CbmRichDigitizer.h
+++ b/sim/detectors/rich/CbmRichDigitizer.h
@@ -1,6 +1,6 @@
-/* Copyright (C) 2015-2020 GSI/JINR-LIT, Darmstadt/Dubna
+/* Copyright (C) 2015-2023 GSI/JINR-LIT, Darmstadt/Dubna
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Semen Lebedev, Andrey Lebedev [committer] */
+   Authors: Semen Lebedev, Andrey Lebedev [committer], Martin Beyer */
 
 /**
 * \file CbmRichDigitizer.h
@@ -23,12 +23,9 @@
 #include <map>
 
 class TClonesArray;
-//class CbmRichDigi;
 class CbmRichPoint;
 class CbmLink;
 
-using namespace std;
-
 
 /**
 * \class CbmRichDigitizer
@@ -40,79 +37,82 @@ using namespace std;
 **/
 class CbmRichDigitizer : public CbmDigitize<CbmRichDigi> {
 public:
-  /**
-    * \brief Default constructor.
-    */
-  CbmRichDigitizer();
-
-  /**
-    * \brief Destructor.
-    */
-  virtual ~CbmRichDigitizer();
+  /** Default constructor */
+  CbmRichDigitizer() : CbmDigitize<CbmRichDigi>("RichDigitize") {};
 
+  /** Destructor */
+  virtual ~CbmRichDigitizer() = default;
 
-  /** @brief Detector system ID
-    ** @return kRich
-    **/
-  ECbmModuleId GetSystemId() const { return ECbmModuleId::kRich; }
+  /** Copy constructor (disabled) */
+  CbmRichDigitizer(const CbmRichDigitizer&) = delete;
 
+  /** Assignment operator (disabled) */
+  CbmRichDigitizer& operator=(const CbmRichDigitizer&) = delete;
 
-  /**
-    * \brief Inherited from FairTask.
+  /** 
+    * \brief Detector system ID
+    * \return kRich
     */
+  ECbmModuleId GetSystemId() const { return ECbmModuleId::kRich; }
+
+  /** Inherited from FairTask */
   virtual InitStatus Init();
 
-  /**
-    * \brief Inherited from FairTask.
-    */
+  /** Inherited from FairTask */
   virtual void Exec(Option_t* option);
 
-  /**
-    * \brief Inherited from FairTask.
-    */
+  /** Inherited from FairTask */
   virtual void Finish();
 
-  /**
-    * \brief Set crosstalk probability.
-    */
-  void SetCrossTalkProbability(Double_t crosstalk) { fCrossTalkProbability = crosstalk; }
-
-  /**
-    * \brief Set detector type
-    */
+  /** Set detector type */
   void SetDetectorType(CbmRichPmtTypeEnum detType) { fDetectorType = detType; }
 
-  /**
-    * \brief noise rate per McRichPoint / per  pixel / per second :
-             hofNoiseDigis = nofRichPoints * nofPixels * dT(50 ns) * (fNoiseDigiRate / 1.e9);
-    */
-  void SetNoiseDigiRate(Double_t noise) { fNoiseDigiRate = noise; }
+  /** Set time resolution for digis */
+  void SetTimeResolution(Double_t dt) { fTimeResolution = dt; }
 
   /**
-    * \brief Set collection efficiency for photoelectrons in PMT optics.
+    * \brief Set pixel dead time between signals (without time smearing). 
+    * The resulting dead time at digi level is approximately:
+    * pixel dead time - 2*5*time resolution (5 sigma from gauss smearing for 2 digis each).
     */
-  void SetCollectionEfficiency(Double_t collEff) { fPmt.SetCollectionEfficiency(collEff); }
+  void SetPixelDeadTime(Double_t dt) { fPixelDeadTime = dt; }
+
+  /** Set crosstalk probability */
+  void SetCrossTalkProbability(Double_t crosstalk) { fCrossTalkProbability = crosstalk; }
 
   /**
-    * \brief Set additional smearing of MC Points due to light scattering in mirror.
+    * \brief Set event noise rate per McRichPoint / per  pixel / per second :
+    * nofNoiseSignals = nofRichPoints * nofPixels * event noise interval * (event noise rate / 1.e9);
     */
-  //void SetSigmaMirror(Double_t sigMirror) {fSigmaMirror = sigMirror;}
+  void SetEventNoiseRate(Double_t noise) { fEventNoiseRate = noise; }
 
   /**
-    * \brief Set Time resolution.
+    * \brief Set event noise interval in ns.
+    * Add noise signals from: current event time to current event time + event noise interval.
     */
-  void SetTimeResolution(Double_t dt) { fTimeResolution = dt; }
+  void SetEventNoiseInterval(Double_t dT) { fEventNoiseInterval = dT; }
 
+  /** Set dark rate per pixel in Hz */
+  void SetDarkRatePerPixel(Double_t darkRate) { fDarkRatePerPixel = darkRate; }
 
   /**
-    * \brief Set Pixel dead time.
+    * \brief Set charged particle cluster signal probability for direct neighbors.
+    * The probability for pixels further away decreases with 1/distance.
+    * Produced signals are limited to the same PMT as the source signal pixel and the defined cluster size. 
     */
-  void SetPixelDeadTime(Double_t dt) { fPixelDeadTime = dt; }
+  void SetClusterSignalProbability(Double_t intensity) { fClusterSignalProbability = intensity; }
 
   /**
-    * \brief Set Maximum nimber of hits per PMT cut.
+    * \brief Set cluster size for charged particle clusters. 
+    * Resulting cluster size : (2*size + 1)*(2*size + 1) pixels.
     */
-  void SetMaxNofHitsPerPmtCut(Double_t nofHits) { fMaxNofHitsPerPmtCut = nofHits; }
+  void SetClusterSize(UInt_t size) { fClusterSize = size; }
+
+  /** Set collection efficiency for photoelectrons in PMT optics */
+  void SetCollectionEfficiency(Double_t collEff) { fPmt.SetCollectionEfficiency(collEff); }
+
+  /** Set additional smearing of MC Points due to light scattering in mirror */
+  // void SetSigmaMirror(Double_t sigMirror) {fSigmaMirror = sigMirror;}
 
   /**
    * \brief Set if you want to shift z MC point value (workaround for GEANT4).
@@ -121,83 +121,82 @@ public:
 
 
 private:
-  Int_t fEventNum;
-
-  TClonesArray* fRichPoints;       // RICH MC points
-  TClonesArray* fRichDigis;        // RICH digis (output array)
-  TClonesArray* fRichDigiMatches;  // RICH digi matches (output array)
-  TClonesArray* fMcTracks;         // Monte-Carlo tracks
-
-  Double_t fNofPoints;  // total number of MCPoints processed
-  Double_t fNofDigis;   // total number of digis created
-  Double_t fTimeTot;    // sum of execution time
-
-  CbmRichPmt fPmt;
-  Double_t fCrossTalkProbability;  // probability of the crosstalk for direct neighbor for one pixel
-  Double_t fNoiseDigiRate;         // noise rate per McRichPoint / per  pixel / per second :
-  // hofNoiseDigis = nofRichPoints * nofPixels * dT(50 ns) * (fNoiseDigiRate / 1.e9);
-  CbmRichPmtTypeEnum fDetectorType;
-  Int_t fMaxNofHitsPerPmtCut;  // maximum number of hits which can be registered per PMT per event.
-                               // If more then the whole PMT is skipped
-
-  map<Int_t, pair<CbmRichDigi*, CbmMatch*>> fDataMap;
-
-  Double_t fTimeResolution;              // in ns
-  Double_t fDarkRatePerPixel;            // dark rate per pixel in Hz
-  Double_t fPixelDeadTime;               // in ns, during this time pixel can not be fired
-  map<Int_t, Double_t> fFiredPixelsMap;  // first: pixel address, second: last fired time.
-  Bool_t
-    fDoZShift;  // Set if you want to shift z MC point value (workaround for GEANT4). Must be set to true if one runs full RICH geoemtry with GEANT4, fot mCBM set to false
-
-  /*
-    * \brief Add crasstalk digis to the output array for the digi assuming fCrossTalkProbability
-    */
-  void AddCrossTalkDigis(CbmRichDigi* digi);
+  Int_t fEventNum {};
 
-  /*
-    * \brief Add fNofNoiseDigis number of digis.
-    */
-  void AddNoiseDigis(Int_t eventNum, Int_t inputNum);
+  TClonesArray* fRichPoints {nullptr};       // RICH MC points
+  TClonesArray* fRichDigis {nullptr};        // RICH digis (output array)
+  TClonesArray* fRichDigiMatches {nullptr};  // RICH digi matches (output array)
+  TClonesArray* fMcTracks {nullptr};         // Monte-Carlo tracks
 
-  /*
-    * \brief Process CbmRichPoint. Main method which is calle dfor all CbmRichPoints.
-    */
-  void ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t eventNum, Int_t inputNum);
+  Int_t fNofPoints {};   // total number of MCPoints processed
+  Int_t fNofDigis {};    // total number of digis created
+  Double_t fTimeTot {};  // sum of execution time
 
-  /*
-    * \brief Add all the fired digis to the output array
-    * \@value Number of digis written
-    */
-  Int_t AddDigisToOutputArray();
+  CbmRichPmt fPmt {};
+  CbmRichPmtTypeEnum fDetectorType {CbmRichPmtTypeCosy17NoWls};
+
+  Double_t fTimeResolution {1.};              // in ns, time resolution for digis
+  Double_t fPixelDeadTime {50.};              // in ns, deadtime for one pixel
+  Double_t fCrossTalkProbability {0.02};      // probability of the crosstalk for direct neighbor for one pixel
+  Double_t fEventNoiseRate {5.};              // noise rate per McRichPoint / per  pixel / per second
+  Double_t fEventNoiseInterval {50.};         // in ns, interval to generate event noise signals
+  Double_t fDarkRatePerPixel {1000.};         // dark rate per pixel in Hz
+  Double_t fClusterSignalProbability {0.37};  // cluster intensity
+  UInt_t fClusterSize {0};                    // cluster size
+
+  std::map<Int_t, std::vector<std::pair<Double_t, CbmLink*>>>
+    fSignalBuffer {};  // first: pixel address, second: signal buffer
 
-  /*
+  std::map<Int_t, Double_t> fPixelsLastFiredTime {};  // first: pixel address, second: last fired time
+  Bool_t fDoZShift {
+    true};  // Set if you want to shift z MC point value (workaround for GEANT4). Must be set to true if one runs full RICH geoemtry with GEANT4, fot mCBM set to false
+
+  /**
     * \brief Process current MC event.
-    * \value Number of processed RichPoints
+    * \return Number of processed RichPoints.
     */
   Int_t ProcessMcEvent();
 
-  /*
-    * \brief Generate noise between events.
-    */
-  void GenerateNoiseBetweenEvents(Double_t oldEventTime, Double_t newEventTime);
+  /** Process CbmRichPoint. Main method which is called for all CbmRichPoints. */
+  void ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t eventNum, Int_t inputNum);
+
+  /** Add signal to signal buffer */
+  void AddSignalToBuffer(Int_t address, Double_t time, const CbmLink& link);
 
-  /*
-    *
+  /**
+    * \brief Add crosstalk assuming fCrossTalkProbability.
+    * Only add maximum one cross talk signal per MC point.
+    * Limited to the same PMT as the source MC point.
     */
-  void AddDigi(Int_t address, Double_t time, const CbmLink& link);
+  void AddCrossTalk(Int_t address, Double_t time, const CbmLink& link);
 
+  /**
+    * \brief Add additional signals to nearby pixels if a charged particle
+    * directly passes through the PMT, given fClusterSignalProbability and fClusterSize.
+    * Limited to the same PMT. Currently independant of mass, momentum, etc.
+    */
+  void AddChargedParticleCluster(Int_t address, Double_t time, Int_t eventNum, Int_t inputNum);
 
   /**
-    * \brief Copy constructor.
+    * \brief Add additional noise for each event based on fEventNoiseRate 
+    * and fEventNoiseInterval.
     */
-  CbmRichDigitizer(const CbmRichDigitizer&);
+  void AddEventNoise(Int_t eventNum, Int_t inputNum);
+
+  /** Add noise between events based on fDarkRatePerPixel */
+  void AddDarkRateNoise(Double_t oldEventTime, Double_t newEventTime);
 
   /**
-    * \brief Assignment operator.
+    * \brief Process signals in all buffers until processTime. 
+    * New Digis are only created until processTime - fPixelDeadTime,
+    * since potential links are not added to the buffer yet.
+    * Links are potentially added until processTime.
+    * \param processTime time in ns
+    * \return Number of Digis sent to DAQ 
     */
-  CbmRichDigitizer& operator=(const CbmRichDigitizer&);
+  Int_t ProcessBuffers(Double_t processTime);
 
-  ClassDef(CbmRichDigitizer, 2)
+  ClassDef(CbmRichDigitizer, 3)
 };
 
 #endif
diff --git a/sim/response/base/CbmDigitization.cxx b/sim/response/base/CbmDigitization.cxx
index 5cbc82cacaa7ac2c8e787e3f1bafa77464256747..20590bab06fec3b2f4670569841a6d181f5567f1 100644
--- a/sim/response/base/CbmDigitization.cxx
+++ b/sim/response/base/CbmDigitization.cxx
@@ -129,7 +129,7 @@ Int_t CbmDigitization::CreateDefaultDigitizers()
 {
   std::cout << "Create default digitisers" << std::endl;
 
-  stringstream ss;
+  std::stringstream ss;
 
   ss << fName << ": Create default digitisers: ";
   Int_t nDigis = 0;