diff --git a/core/data/sts/CbmStsHit.h b/core/data/sts/CbmStsHit.h
index c488edd1fe86c269f48b2c658cc91818a4190781..d8f0e9edc97e14bee67088c2e3f34acd5b99eae4 100644
--- a/core/data/sts/CbmStsHit.h
+++ b/core/data/sts/CbmStsHit.h
@@ -73,6 +73,14 @@ public:
      **/
   double GetDu() const { return fDu; }
 
+  /** @brief Error of coordinate across front-side strips
+     ** @value Coordinate error [cm]
+     **
+     ** Note that this error is defined only in the
+     ** local coordinate system of the sensor.
+     **/
+  void SetDu(Double_t du) { fDu = du; }
+
 
   /** @brief Error of coordinate across front-side strips
      ** @value Coordinate error [cm]
@@ -82,6 +90,14 @@ public:
      **/
   double GetDv() const { return fDv; }
 
+  /** @brief Error of coordinate across front-side strips
+     ** @value Coordinate error [cm]
+     **
+     ** Note that this error is defined only in the
+     ** local coordinate system of the sensor.
+     **/
+  void SetDv(Double_t dv) { fDv = dv; }
+
 
   /** Index of cluster at the front side
      ** @value  Front-side cluster index
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index 053f37eb32ca25d01b98c50ae72e5ddf3deddf38..4fa41786056ae729e9197d1b8943939ec4a4a91a 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -232,7 +232,7 @@ public:
   L1Algo* algo {nullptr};  // for access to L1 Algorithm from L1::Instance
 
   TString fMuchDigiFile {};  // Much digitization file name
-  bool fUseHitErrors {false};
+  bool fUseHitErrors {true};
   bool fMissingHits {false};
   L1Algo::TrackingMode fTrackingMode {L1Algo::TrackingMode::kSts};
 
diff --git a/reco/L1/L1Algo/L1Algo.h b/reco/L1/L1Algo/L1Algo.h
index 7cd96beee2fdacf5ac9781aeda2b8349cbde0590..a737c6583a4b6d9854e571e1fdc1e545ba7b39ad 100644
--- a/reco/L1/L1Algo/L1Algo.h
+++ b/reco/L1/L1Algo/L1Algo.h
@@ -256,7 +256,7 @@ public:
   L1Vector<int> fStripToTrackB {"L1Algo::fStripToTrackB"};  // back strip to track pointers
 
   int fNThreads {0};
-  bool fUseHitErrors {0};
+  bool fUseHitErrors {true};
   bool fMissingHits {0};
   TrackingMode fTrackingMode {kSts};
 
diff --git a/reco/detectors/sts/CMakeLists.txt b/reco/detectors/sts/CMakeLists.txt
index ef23952641d3d80c817ac9adfc703d803a1a7337..78c904eb80ac1a738a800e89eda9a6ac064884a2 100644
--- a/reco/detectors/sts/CMakeLists.txt
+++ b/reco/detectors/sts/CMakeLists.txt
@@ -17,6 +17,7 @@ CbmStsAlgoFindHitsOrtho.cxx
 CbmStsFindTracks.cxx
 CbmStsFindTracksEvents.cxx
 CbmStsRecoModule.cxx
+CbmRecoStsPixel.cxx
 CbmStsTrackFinderIdeal.cxx
 
 unpack/CbmStsUnpackAlgo.cxx
diff --git a/reco/detectors/sts/CbmRecoStsLinkDef.h b/reco/detectors/sts/CbmRecoStsLinkDef.h
index 2c014febe70b1801663ea606503360d4aa9193aa..a0d5a184b26a702aac5e22e8bdd94c337881bfc1 100644
--- a/reco/detectors/sts/CbmRecoStsLinkDef.h
+++ b/reco/detectors/sts/CbmRecoStsLinkDef.h
@@ -17,6 +17,9 @@
 #pragma link C++ class CbmStsFindTracksEvents + ;
 #pragma link C++ class CbmStsFindTracksQa + ;
 #pragma link C++ class CbmStsRecoModule + ;
+
+#pragma link C++ class CbmRecoStsPixel + ;
+
 #pragma link C++ class CbmStsTrackFinderIdeal + ;
 
 #pragma link C++ class CbmStsUnpackAlgo + ;
diff --git a/reco/detectors/sts/CbmRecoStsPixel.cxx b/reco/detectors/sts/CbmRecoStsPixel.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..54ea91ff37b5b521dc903de79a98e4a3987fb7fc
--- /dev/null
+++ b/reco/detectors/sts/CbmRecoStsPixel.cxx
@@ -0,0 +1,314 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/** @file CbmRecoStsPixel.cxx
+ ** @author Sergey Gorbunov
+ ** @since 09.12.2021
+ **/
+
+#include "CbmRecoStsPixel.h"
+
+#include "CbmAddress.h"
+#include "CbmDigiManager.h"
+#include "CbmEvent.h"
+#include "CbmMCDataArray.h"
+#include "CbmMCDataManager.h"
+#include "CbmStsDigi.h"
+#include "CbmStsModule.h"
+#include "CbmStsParSetModule.h"
+#include "CbmStsParSetSensor.h"
+#include "CbmStsParSetSensorCond.h"
+#include "CbmStsParSim.h"
+#include "CbmStsPoint.h"
+#include "CbmStsRecoModule.h"
+#include "CbmStsSetup.h"
+#include "CbmStsStation.h"
+
+#include <FairField.h>
+#include <FairRun.h>
+#include <FairRuntimeDb.h>
+
+#include <TClonesArray.h>
+#include <TGeoBBox.h>
+#include <TGeoPhysicalNode.h>
+#include <TRandom.h>
+
+#include <iomanip>
+
+using std::fixed;
+using std::left;
+using std::right;
+using std::setprecision;
+using std::setw;
+using std::stringstream;
+using std::vector;
+
+
+ClassImp(CbmRecoStsPixel)
+
+
+  // -----   Constructor   ---------------------------------------------------
+  CbmRecoStsPixel::CbmRecoStsPixel(ECbmRecoMode mode)
+  : FairTask("RecoStsPixel", 1)
+  , fMode(mode)
+{
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Destructor   ----------------------------------------------------
+CbmRecoStsPixel::~CbmRecoStsPixel() {}
+// -------------------------------------------------------------------------
+
+
+// -----   End-of-run action   ---------------------------------------------
+void CbmRecoStsPixel::Finish() {}
+// -------------------------------------------------------------------------
+
+
+// -----   Initialisation   ------------------------------------------------
+InitStatus CbmRecoStsPixel::Init()
+{
+
+  // --- Something for the screen
+  std::cout << std::endl;
+  LOG(info) << "==========================================================";
+  LOG(info) << GetName() << ": Initialising ";
+
+  // --- Check IO-Manager
+  FairRootManager* ioman = FairRootManager::Instance();
+  assert(ioman);
+
+  // --- In event mode: get input array (CbmEvent)
+  if (fMode == kCbmRecoEvent) {
+    LOG(info) << GetName() << ": Using event-by-event mode";
+    fEvents = dynamic_cast<TClonesArray*>(ioman->GetObject("CbmEvent"));
+    if (nullptr == fEvents) {
+      LOG(warn) << GetName() << ": Event mode selected but no event array found!";
+      return kFATAL;
+    }  //? Event branch not present
+  }    //? Event mode
+  else {
+    LOG(info) << GetName() << ": Using time-based mode";
+  }
+
+
+  // --- Digi Manager
+  fDigiManager = CbmDigiManager::Instance();
+  fDigiManager->Init();
+
+  // --- Check input array (StsDigis)
+  if (!fDigiManager->IsPresent(ECbmModuleId::kSts)) {
+    LOG(fatal) << GetName() << ": No StsDigi branch in input!";
+    return kERROR;
+  }
+
+  if (!fDigiManager->IsMatchPresent(ECbmModuleId::kSts)) {
+    LOG(error) << GetName() << " sts digi matches are not present";
+    return kERROR;
+  }
+
+  CbmMCDataManager* mcManager = (CbmMCDataManager*) ioman->GetObject("MCDataManager");
+  if (!mcManager) {
+    LOG(error) << GetName() << ": No CbmMCDataManager!";
+    return kERROR;
+  }
+
+  fStsPoints = mcManager->InitBranch("StsPoint");
+
+  if (!fStsPoints) {
+    LOG(fatal) << GetName() << ": No StsPoint branch in input!";
+    return kERROR;
+  }
+
+
+  // --- Register output array
+  fClusters = new TClonesArray("CbmStsCluster", 1);
+  ioman->Register("StsCluster", "Clusters in STS", fClusters, IsOutputBranchPersistent("StsCluster"));
+
+  // --- Register output array
+  fHits = new TClonesArray("CbmStsHit", 1);
+  ioman->Register("StsHit", "Hits in STS", fHits, IsOutputBranchPersistent("StsHit"));
+
+  // --- Simulation settings
+  assert(fParSim);
+  LOG(info) << GetName() << ": Sim settings " << fParSim->ToString();
+
+  // --- Module parameters
+  assert(fParSetModule);
+  LOG(info) << GetName() << ": Module parameters " << fParSetModule->ToString();
+
+  // --- Sensor parameters
+  assert(fParSetSensor);
+  LOG(info) << GetName() << ": Sensor parameters " << fParSetModule->ToString();
+
+  // --- Sensor conditions
+  assert(fParSetCond);
+  //assert(fParSetCond->IsSet());
+  LOG(info) << GetName() << ": Sensor conditions " << fParSetCond->ToString();
+
+  // --- Initialise STS setup
+  fSetup = CbmStsSetup::Instance();
+  if (!fSetup->IsInit()) { fSetup->Init(nullptr); }
+  if (!fSetup->IsModuleParsInit()) { fSetup->SetModuleParameters(fParSetModule); }
+  if (!fSetup->IsSensorParsInit()) { fSetup->SetSensorParameters(fParSetSensor); }
+  if (!fSetup->IsSensorCondInit()) { fSetup->SetSensorConditions(fParSetCond); }
+
+  // make sure that the STS digis were produced by the experimental Pixel digitiser
+  if (strcmp(fParSetSensor->getDescription(), "Experimental STS Pixels")) {
+    LOG(error) << GetName() << " STS digis must be produced by the CbmStsDigitizePixel digitizer";
+    return kERROR;
+  }
+
+  LOG(info) << GetName() << ": Initialisation successful.";
+  LOG(info) << "==========================================================";
+
+  return kSUCCESS;
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Task execution   ------------------------------------------------
+void CbmRecoStsPixel::Exec(Option_t*)
+{
+
+  // --- Clear hit output array
+  fHits->Delete();
+
+  // --- Reset cluster output array
+  fClusters->Delete();
+
+  if (fMode == kCbmRecoTimeslice) {
+    // --- Time-slice mode: process entire array
+    ProcessData(nullptr);
+  }
+  else {
+    // --- Event mode: loop over events
+    assert(fEvents);
+    for (Int_t iEvent = 0; iEvent < fEvents->GetEntriesFast(); iEvent++) {
+      CbmEvent* event = dynamic_cast<CbmEvent*>(fEvents->At(iEvent));
+      assert(event);
+      ProcessData(event);
+    }  //# events
+  }    //? event mode
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Process one time slice or event   -------------------------------
+void CbmRecoStsPixel::ProcessData(CbmEvent* event)
+{
+  if (!fDigiManager->IsMatchPresent(ECbmModuleId::kSts)) {
+    LOG(error) << GetName() << ": No StsDigi branch in input!";
+    return;
+  }
+
+  Int_t nDigis = (event ? event->GetNofData(ECbmDataType::kStsDigi) : fDigiManager->GetNofDigis(ECbmModuleId::kSts));
+  int nHits    = 0;
+
+  for (Int_t iDigi = 0; iDigi < nDigis; iDigi++) {
+
+    UInt_t digiIndex       = (event ? event->GetIndex(ECbmDataType::kStsDigi, iDigi) : iDigi);
+    const CbmStsDigi* digi = fDigiManager->Get<const CbmStsDigi>(digiIndex);
+    assert(digi);
+
+    // Check system ID. There are pulser digis in which will be ignored here.
+    Int_t systemId = CbmAddress::GetSystemId(digi->GetAddress());
+    if (systemId != ToIntegralType(ECbmModuleId::kSts)) { continue; }
+
+    const CbmMatch* match = fDigiManager->GetMatch(ECbmModuleId::kSts, digiIndex);
+    assert(match);
+
+    // make sure that the digi was produced by CbmStsDigitizePixel task
+    if (digi->GetChannel() != 0 || match->GetNofLinks() != 1) {
+      LOG(error) << GetName() << " sts digis were not produced by CbmStsDigitizePixel task";
+      break;
+    }
+
+    // the digi was produced by one MC point
+
+    const CbmLink& link = match->GetLink(0);
+    CbmStsPoint* pt     = dynamic_cast<CbmStsPoint*>(fStsPoints->Get(link.GetFile(), link.GetEntry(), link.GetIndex()));
+
+    // create one cluster and one hit per digi
+
+    UInt_t iCluster        = fClusters->GetEntriesFast();
+    CbmStsCluster* cluster = new ((*fClusters)[iCluster]) CbmStsCluster;
+    cluster->AddDigi(iDigi);
+    if (event) event->AddData(ECbmDataType::kStsCluster, iCluster);
+
+    UInt_t iHit    = fHits->GetEntriesFast();
+    CbmStsHit* hit = new ((*fHits)[iHit]) CbmStsHit;
+
+    hit->SetAddress(digi->GetAddress());
+    hit->SetFrontClusterId(iCluster);
+    hit->SetBackClusterId(iCluster);
+
+    int ista = CbmStsSetup::Instance()->GetStationNumber(hit->GetAddress());
+    if (ista < 0 || ista >= CbmStsSetup::Instance()->GetNofStations()) {
+      LOG(error) << "wrong Sts station number " << ista;
+      break;
+    }
+
+    CbmStsStation* station = CbmStsSetup::Instance()->GetStation(ista);
+    double staZ            = station->GetZ();
+
+    if (fabs(pt->GetZ() - staZ) > 1.) {
+      LOG(error) << "Sts point Z " << pt->GetZ() << " is far from the station Z " << staZ;
+      break;
+    }
+
+    double dx = pt->GetXOut() - pt->GetXIn();
+    double dy = pt->GetYOut() - pt->GetYIn();
+    double dz = pt->GetZOut() - pt->GetZIn();
+    if (fabs(dz) > 1.e-2) {
+      hit->SetX(pt->GetXIn() + dx * (staZ - pt->GetZIn()) / dz);
+      hit->SetY(pt->GetYIn() + dy * (staZ - pt->GetZIn()) / dz);
+      hit->SetZ(staZ);
+    }
+    else {
+      hit->SetX(pt->GetXIn());
+      hit->SetY(pt->GetYIn());
+      hit->SetZ(pt->GetZIn());
+    }
+
+    Double_t pitchX = station->GetSensorPitch(0);
+    Double_t pitchY = station->GetSensorPitch(1);
+
+    assert(pitchX > 1.e-5);
+    assert(pitchY > 1.e-5);
+
+    hit->SetX((floor(hit->GetX() / pitchX) + 0.5) * pitchX);
+    hit->SetY((floor(hit->GetY() / pitchY) + 0.5) * pitchY);
+
+    hit->SetDx(pitchX / sqrt(12.));
+    hit->SetDy(pitchY / sqrt(12.));
+    hit->SetDxy(0.);
+    hit->SetDu(hit->GetDx());
+    hit->SetDv(hit->GetDy());
+
+    hit->SetTime(digi->GetTime());
+    const CbmStsParModule& module = fParSetModule->GetParModule(digi->GetAddress());
+    const CbmStsParAsic& asic     = module.GetParAsic(0);
+    hit->SetTimeError(asic.GetTimeResol());
+
+    if (event) event->AddData(ECbmDataType::kStsHit, iHit);
+    nHits++;
+  }  // digis
+
+  LOG(info) << GetName() << " Processed " << nDigis << " digis, created " << nHits << " hits";
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Connect parameter container   -----------------------------------
+void CbmRecoStsPixel::SetParContainers()
+{
+  FairRuntimeDb* db = FairRun::Instance()->GetRuntimeDb();
+  fParSim           = dynamic_cast<CbmStsParSim*>(db->getContainer("CbmStsParSim"));
+  fParSetModule     = dynamic_cast<CbmStsParSetModule*>(db->getContainer("CbmStsParSetModule"));
+  fParSetSensor     = dynamic_cast<CbmStsParSetSensor*>(db->getContainer("CbmStsParSetSensor"));
+  fParSetCond       = dynamic_cast<CbmStsParSetSensorCond*>(db->getContainer("CbmStsParSetSensorCond"));
+}
+// -------------------------------------------------------------------------
diff --git a/reco/detectors/sts/CbmRecoStsPixel.h b/reco/detectors/sts/CbmRecoStsPixel.h
new file mode 100644
index 0000000000000000000000000000000000000000..d450bd2020b96862a7b1075a7f8150c3aba9d7fa
--- /dev/null
+++ b/reco/detectors/sts/CbmRecoStsPixel.h
@@ -0,0 +1,137 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/** @file CbmRecoStsPixel.h
+ ** @author Sergey Gorbunov
+ ** @since 09.12.2021
+ **/
+
+
+#ifndef CbmRecoStsPixel_H
+#define CbmRecoStsPixel_H 1
+
+#include "CbmRecoSts.h"
+
+#include <FairTask.h>
+
+#include <TStopwatch.h>
+
+
+class CbmDigiManager;
+class CbmEvent;
+class CbmStsElement;
+class CbmStsParAsic;
+class CbmStsParModule;
+class CbmStsParSensor;
+class CbmStsParSensorCond;
+class CbmStsParSetModule;
+class CbmStsParSetSensor;
+class CbmStsParSetSensorCond;
+class CbmStsParSim;
+class CbmStsRecoModule;
+class CbmStsSensor;
+class CbmStsSetup;
+class CbmMCDataArray;
+
+/** @class CbmRecoStsPixel
+ ** @brief Task class for local reconstruction in the STS Pixel detector
+ ** @author Sergey Gorbunov
+ ** @since 09.12.2021
+ ** @date 09.12.2021
+ **
+ ** Local reconstruction for the experimental STS Pixel detector
+ **
+ ** The STS digis must be produced by the CbmStsDigitizePixel task.
+ ** To run it, replace CbmRecoSts task by CbmRecoStsPixel task in the run_reco.C macro
+ **
+ **/
+class CbmRecoStsPixel : public FairTask {
+
+public:
+  /** @brief Constructor **/
+  CbmRecoStsPixel(ECbmRecoMode mode = kCbmRecoTimeslice);
+
+
+  /** @brief Copy constructor (disabled) **/
+  CbmRecoStsPixel(const CbmRecoStsPixel&) = delete;
+
+
+  /** @brief Assignment operator (disabled) **/
+  CbmRecoStsPixel operator=(const CbmRecoStsPixel&) = delete;
+
+
+  /** @brief Destructor  **/
+  ~CbmRecoStsPixel();
+
+
+  /** @brief Task execution **/
+  void Exec(Option_t* opt);
+
+
+  /** @brief End-of-run action **/
+  void Finish();
+
+
+  /** @brief Initialisation **/
+  InitStatus Init();
+
+
+  /** @brief Set event-by-event mode
+     ** @param choice  If true, event-by-event mode is used
+     **
+     ** In the event-by-event mode, the event objects in the input tree
+     ** are used, and events are processed one after the other.
+     ** An event builder has to be run before, creating the event objects.
+     ** By default, time-slice mode is applied.
+     **
+     ** Alternative to using SetMode.
+     **/
+  void SetEventMode(Bool_t choice = kTRUE) { fMode = (choice ? kCbmRecoEvent : kCbmRecoTimeslice); }
+
+
+  /** @brief Set execution mode
+     ** @param mode  Time-slice or event
+     **
+     ** In the time-slice mode, the entire time-slice (input arrays)
+     ** will be processed. In the event mode, events read from the event
+     ** branch are processed one after the other.
+     **/
+  void SetMode(ECbmRecoMode mode) { fMode = mode; }
+
+
+  /** @brief Define the needed parameter containers **/
+  void SetParContainers();
+
+
+private:
+  /** @brief Process one time slice or event
+     ** @param event  Pointer to CbmEvent object
+     **
+     ** If a null event pointer is given, the entire input array is processed.
+     **/
+  void ProcessData(CbmEvent* event = nullptr);
+
+private:
+  // --- I/O
+  TClonesArray* fEvents        = nullptr;  //! Input array of events
+  CbmDigiManager* fDigiManager = nullptr;  //! Interface to digi branch
+  CbmMCDataArray* fStsPoints {nullptr};
+  TClonesArray* fClusters = nullptr;  //! Output cluster array
+  TClonesArray* fHits     = nullptr;  //! Output hit array
+
+  // --- Setup and parameters
+  CbmStsSetup* fSetup                 = nullptr;  //! Instance of STS setup
+  CbmStsParSim* fParSim               = nullptr;  ///< Simulation settings
+  CbmStsParSetModule* fParSetModule   = nullptr;  ///< Module parameters
+  CbmStsParSetSensor* fParSetSensor   = nullptr;  ///< Sensor parameters
+  CbmStsParSetSensorCond* fParSetCond = nullptr;  ///< Sensor conditions
+
+
+  // --- Settings
+  ECbmRecoMode fMode = kCbmRecoEvent;  ///< Time-slice or event
+
+  ClassDef(CbmRecoStsPixel, 0);
+};
+
+#endif
diff --git a/sim/detectors/sts/CMakeLists.txt b/sim/detectors/sts/CMakeLists.txt
index 786c18bc3b84ae37cf9e15225fb0e8b6815c435f..656935a95a69371900fe2821a2d116617540308e 100644
--- a/sim/detectors/sts/CMakeLists.txt
+++ b/sim/detectors/sts/CMakeLists.txt
@@ -20,6 +20,8 @@ CbmStsSimSensorDssdOrtho.cxx
 CbmStsSimSensorDssdStereo.cxx
 CbmStsSimSensorFactory.cxx
 
+CbmStsDigitizePixel.cxx
+
 qa/CbmStsDigitizeQa.cxx
 qa/CbmStsDigitizeQaReport.cxx
 )
@@ -103,6 +105,7 @@ FILES CbmStsDigitize.h
 	  CbmStsSimSensorDssdOrtho.h
 	  CbmStsSimSensorFactory.h
 	  CbmStsTrackStatus.h
+	  CbmStsDigitizePixel.h
 DESTINATION include
 )
 # ---------------------------------------------------------
diff --git a/sim/detectors/sts/CbmStsDigitizePixel.cxx b/sim/detectors/sts/CbmStsDigitizePixel.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..19cfa8efcda35c51e096e63ff0075b9cc3b251e8
--- /dev/null
+++ b/sim/detectors/sts/CbmStsDigitizePixel.cxx
@@ -0,0 +1,301 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/** @file CbmStsDigitizePixel.cxx
+ ** @author Sergey Gorbunov
+ ** @date 09.12.2021
+ **/
+
+// Include class header
+#include "CbmStsDigitizePixel.h"
+
+// Includes from C++
+#include <cassert>
+#include <cstring>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+// Includes from ROOT
+#include "TClonesArray.h"
+#include "TGeoBBox.h"
+#include "TGeoMatrix.h"
+#include "TGeoPhysicalNode.h"
+#include "TGeoVolume.h"
+#include <TMCProcess.h>
+
+// Includes from FairRoot
+#include "FairEventHeader.h"
+#include "FairField.h"
+#include "FairLink.h"
+#include "FairMCEventHeader.h"
+#include "FairMCPoint.h"
+#include "FairRunAna.h"
+#include "FairRunSim.h"
+#include "FairRuntimeDb.h"
+#include <Logger.h>
+
+// Includes from CbmRoot
+#include "CbmStsDigi.h"
+#include "CbmStsParSetModule.h"
+#include "CbmStsPoint.h"
+#include "CbmStsSetup.h"
+
+// Includes from STS
+#include "CbmStsModule.h"
+#include "CbmStsParAsic.h"
+#include "CbmStsParModule.h"
+#include "CbmStsParSensor.h"
+#include "CbmStsParSensorCond.h"
+#include "CbmStsParSetModule.h"
+#include "CbmStsParSetSensor.h"
+#include "CbmStsParSetSensorCond.h"
+#include "CbmStsParSim.h"
+#include "CbmStsPhysics.h"
+#include "CbmStsSensor.h"
+#include "CbmStsSetup.h"
+#include "CbmStsSimSensorFactory.h"
+
+
+using std::fixed;
+using std::left;
+using std::right;
+using std::setprecision;
+using std::setw;
+using std::string;
+using std::stringstream;
+
+using namespace CbmSts;
+
+ClassImp(CbmStsDigitizePixel);
+
+// -----   Standard constructor   ------------------------------------------
+CbmStsDigitizePixel::CbmStsDigitizePixel(Double_t pitchXcm, Double_t pitchYcm, Double_t pitchTns)
+  : CbmDigitize<CbmStsDigi>("StsDigitizePixel")
+  , fPitchXcm(pitchXcm)
+  , fPitchYcm(pitchYcm)
+  , fPitchTns(pitchTns)
+{
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Destructor   ----------------------------------------------------
+CbmStsDigitizePixel::~CbmStsDigitizePixel() {}
+// -------------------------------------------------------------------------
+
+
+// -----   Finish run    ---------------------------------------------------
+void CbmStsDigitizePixel::Finish() {}
+// -------------------------------------------------------------------------
+
+
+// -----   Get parameter container from runtime DB   -----------------------
+void CbmStsDigitizePixel::SetParContainers()
+{
+  assert(FairRunAna::Instance());
+  FairRuntimeDb* rtdb = FairRunAna::Instance()->GetRuntimeDb();
+  fParSim             = static_cast<CbmStsParSim*>(rtdb->getContainer("CbmStsParSim"));
+  fParSetModule       = static_cast<CbmStsParSetModule*>(rtdb->getContainer("CbmStsParSetModule"));
+  fParSetSensor       = static_cast<CbmStsParSetSensor*>(rtdb->getContainer("CbmStsParSetSensor"));
+  fParSetCond         = static_cast<CbmStsParSetSensorCond*>(rtdb->getContainer("CbmStsParSetSensorCond"));
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Initialisation    -----------------------------------------------
+InitStatus CbmStsDigitizePixel::Init()
+{
+
+  // --- Instantiate StsPhysics
+  CbmStsPhysics::Instance();
+
+  // Initialise the STS setup interface from TGeoManager
+  fSetup = CbmStsSetup::Instance();
+  if (!fSetup->IsInit()) { fSetup->Init(nullptr); }
+
+  // --- Initialise parameters
+  InitParams();
+
+  // --- Get FairRootManager instance
+  FairRootManager* ioman = FairRootManager::Instance();
+  assert(ioman);
+
+  // --- Get input array (CbmStsPoint)
+  fPoints = (TClonesArray*) ioman->GetObject("StsPoint");
+  assert(fPoints);
+
+  // always create matches
+
+  SetCreateMatches(kTRUE);
+
+  RegisterOutput();
+
+  return kSUCCESS;
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Private method ReInit   -----------------------------------------
+InitStatus CbmStsDigitizePixel::ReInit() { return Init(); }
+// -------------------------------------------------------------------------
+
+
+// -----   Task execution   ------------------------------------------------
+void CbmStsDigitizePixel::Exec(Option_t* /*opt*/)
+{
+  TStopwatch timer;
+
+  // ---  Get current event time.
+  GetEventInfo();
+
+  // -----   Process points from MC event    ---------------------------------
+
+  assert(fPoints);
+
+  std::vector<std::pair<double, int>> sortedPoints;
+  sortedPoints.reserve(fPoints->GetEntriesFast());
+
+  for (Int_t iPoint = 0; iPoint < fPoints->GetEntriesFast(); iPoint++) {
+    const CbmStsPoint* point = (const CbmStsPoint*) fPoints->At(iPoint);
+    sortedPoints.push_back(std::make_pair(point->GetTime(), iPoint));
+  }
+
+  std::sort(sortedPoints.begin(), sortedPoints.end(),
+            [](std::pair<double, int>& left, std::pair<double, int>& right) { return left.first < right.first; });
+
+  for (UInt_t iSorted = 0; iSorted < sortedPoints.size(); iSorted++) {
+    Int_t iPoint             = sortedPoints[iSorted].second;
+    const CbmStsPoint* point = (const CbmStsPoint*) fPoints->At(iPoint);
+
+    UInt_t address   = static_cast<UInt_t>(point->GetDetectorID());
+    UShort_t channel = 0;
+    double timef     = fCurrentEventTime + point->GetTime();
+    timef            = (floor(timef / fPitchTns) + 0.5) * fPitchTns;
+    Long64_t time    = Long64_t(round(timef));
+    UShort_t adc     = 30;
+    assert(time >= 0);
+
+    // Create digi and (if required) match and send them to DAQ
+    // The time is sent separately from the digi in double precision.
+    // It will be set in the digi later, when creating the timestamp for the time slice.
+
+    CbmStsDigi* digi    = new CbmStsDigi(address, channel, 0, adc);
+    CbmMatch* digiMatch = nullptr;
+    if (fCreateMatches) {
+      digiMatch = new CbmMatch;
+      digiMatch->AddLink(CbmLink(1., iPoint, fCurrentMCEntry, fCurrentInput));
+    }
+    SendData(time, digi, digiMatch);
+  }
+
+  timer.Stop();
+  if (fCreateMatches) { std::cout << "create matches" << std::endl; }
+  // --- Event log
+  LOG(info) << left << setw(15) << GetName() << "[" << fixed << setprecision(3) << timer.RealTime() << " s]"
+            << " Points processed " << fPoints->GetEntriesFast();
+}
+// -------------------------------------------------------------------------
+
+
+// -----   Initialise parameters   -----------------------------------------
+void CbmStsDigitizePixel::InitParams()
+{
+
+  // --- The parameter containers are completely initialised here.
+  // --- Any contents possibly obtained from the runtimeDb are ignored
+  // --- and overwritten.
+
+  // --- Simulation settings
+  assert(fParSim);
+
+  // --- Simulation settings
+  {
+    fParSim->SetEventMode(fEventMode);         // from CbmDigitizeBase
+    fParSim->SetGenerateNoise(fProduceNoise);  // from CbmDigitizeBase
+    if (fEventMode) fParSim->SetGenerateNoise(kFALSE);
+    fParSim->setChanged();
+    fParSim->setInputVersion(-2, 1);
+    LOG(info) << GetName() << "--- Settings: " << fParSim->ToString();
+  }
+
+
+  {  // --- Module parameters
+
+    UInt_t nChannels     = 2048;  // Number of module readout channels
+    UInt_t nAsicChannels = 128;   // Number of readout channels per ASIC
+
+    // --- ASIC parameters
+    UShort_t nAdc      = 32;                     // Number of ADC channels (5 bit)
+    Double_t dynRange  = 75000.;                 // Dynamic range [e]
+    Double_t threshold = 3000.;                  // Threshold [e]
+    Double_t timeResol = fPitchTns / sqrt(12.);  // Time resolution [ns]
+    Double_t deadTime  = 800.;                   // Channel dead time [ns]
+    Double_t noiseRms  = 1000.;                  // RMS of noise [e]
+    Double_t znr       = 3.9789e-3;              // Zero-crossing noise rate [1/ns]
+    CbmStsParAsic userParAsic(nAsicChannels, nAdc, dynRange, threshold, timeResol, deadTime, noiseRms, znr);
+
+    CbmStsParModule userParModule(nChannels, nAsicChannels);
+    userParModule.SetAllAsics(userParAsic);
+
+    assert(fParSetModule);
+    fParSetModule->clear();
+    for (Int_t iModule = 0; iModule < fSetup->GetNofModules(); iModule++) {
+      UInt_t address = fSetup->GetModule(iModule)->GetAddress();
+      fParSetModule->SetParModule(address, userParModule);
+    }
+
+    fParSetModule->setChanged();
+    fParSetModule->setInputVersion(-2, 1);
+    LOG(info) << GetName() << "--- Using global ASIC parameters: \n       " << userParAsic.ToString();
+    LOG(info) << GetName() << "--- Module parameters: " << fParSetModule->ToString();
+  }
+
+  // --- Sensor parameters
+  {
+    assert(fParSetSensor);
+    fParSetSensor->clear();
+
+    // --- Sensor parameters
+
+    for (Int_t iSensor = 0; iSensor < fSetup->GetNofSensors(); iSensor++) {
+      CbmStsSensor* sensor = fSetup->GetSensor(iSensor);
+      UInt_t address       = sensor->GetAddress();
+      TGeoBBox* box        = dynamic_cast<TGeoBBox*>(sensor->GetPnode()->GetShape());
+      assert(box);
+      Double_t lX = 2. * box->GetDX();
+      Double_t lY = 2. * box->GetDY();
+      Double_t lZ = 2. * box->GetDZ();
+      Double_t dY = lY;
+
+      // Create a sensor parameter object and add it to the container
+      CbmStsParSensor par(CbmStsSensorClass::kDssdStereo);
+
+      // sensor parameters currently not used by the tracker
+
+      par.SetPar(0, lX);     // Extension in x
+      par.SetPar(1, lY);     // Extension in y
+      par.SetPar(2, lZ);     // Extension in z
+      par.SetPar(3, dY);     // Active size in y
+      par.SetPar(4, 1024.);  // Number of strips front side
+      par.SetPar(5, 1024.);  // Number of strips back side
+
+      // sensor parameters used by the tracker
+
+      par.SetPar(6, fPitchXcm);  // Strip pitch front side
+      par.SetPar(7, fPitchYcm);  // Strip pitch back side
+      par.SetPar(8, 0.);         // Stereo angle front side [deg]
+      par.SetPar(9, 90);         // Stereo angle back side [deg]
+
+      fParSetSensor->SetParSensor(address, par);
+    }
+
+    LOG(info) << GetName() << "--- Sensor parameters: " << fParSetSensor->ToString();
+    fParSetSensor->setChanged();
+    fParSetSensor->setInputVersion(-2, 1);
+    fParSetSensor->setDescription("Experimental STS Pixels");
+  }
+}
+// -------------------------------------------------------------------------
diff --git a/sim/detectors/sts/CbmStsDigitizePixel.h b/sim/detectors/sts/CbmStsDigitizePixel.h
new file mode 100644
index 0000000000000000000000000000000000000000..dee43b80af14d6a838a1a17ba41c981f0ef4fe4c
--- /dev/null
+++ b/sim/detectors/sts/CbmStsDigitizePixel.h
@@ -0,0 +1,130 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov [committer] */
+
+/** @file CbmStsDigitizePixel.h
+ ** @author Sergey Gorbunov
+ ** @date 09.12.2021
+ **/
+
+#ifndef CbmStsDigitizePixel_H
+#define CbmStsDigitizePixel_H 1
+
+#include "CbmDefs.h"
+#include "CbmDigitize.h"
+#include "CbmMatch.h"
+#include "CbmStsDefs.h"
+#include "CbmStsDigi.h"
+#include "CbmStsPhysics.h"
+#include "CbmStsSimModule.h"
+#include "CbmStsSimSensor.h"
+
+#include "TStopwatch.h"
+
+#include <map>
+
+class TClonesArray;
+class CbmStsPoint;
+class CbmStsParAsic;
+class CbmStsParModule;
+class CbmStsParSensor;
+class CbmStsParSensorCond;
+class CbmStsParSetModule;
+class CbmStsParSetSensor;
+class CbmStsParSetSensorCond;
+class CbmStsParSim;
+class CbmStsSetup;
+class CbmStsSimSensorFactory;
+
+
+/** @class CbmStsDigitizePixel
+ **
+ ** @brief Task class for simulating the detector response of the experimental STS Pixel setup
+ ** @author Sergey Gorbunov
+ ** @since 09.12.2021
+ **
+ ** A digitiser for the experimental STS Pixel detector
+ **
+ ** To run it, add the following line to run_digi.C macro:
+ **
+ ** run.SetDigitizer(ECbmModuleId::kSts, new CbmStsDigitizePixel);
+ **
+ **/
+class CbmStsDigitizePixel : public CbmDigitize<CbmStsDigi> {
+
+public:
+  /** Constructor **/
+  CbmStsDigitizePixel(Double_t pitchXcm = 0.0010, Double_t pitchYcm = 0.0010, Double_t pitchTns = 20);
+
+
+  /** Destructor **/
+  virtual ~CbmStsDigitizePixel();
+
+
+  /** @brief Detector system ID
+   ** @return kSts
+   **/
+  ECbmModuleId GetSystemId() const { return ECbmModuleId::kSts; }
+
+  /**
+    * \brief Inherited from FairTask.
+    */
+  virtual void SetParContainers();
+
+
+  /** Execution **/
+  virtual void Exec(Option_t* opt);
+
+
+  /** Re-initialisation **/
+  virtual InitStatus ReInit();
+
+  /** End-of-run action **/
+  virtual void Finish();
+
+
+  /** Initialisation **/
+  virtual InitStatus Init();
+
+  /// set pitch X [cm]
+  void SetPitchX(double pitchXcm) { fPitchXcm = pitchXcm; }
+
+  /// set pitch Y [cm]
+  void SetPitchY(double pitchYcm) { fPitchYcm = pitchYcm; }
+
+  /// set pitch Time [ns]
+  void SetPitchT(double pitchTns) { fPitchTns = pitchTns; }
+
+private:
+  Bool_t fIsInitialised;  ///< kTRUE if Init() was called
+
+  //std::map<Int_t, CbmStsDigitizeParameters*> fModuleParameterMap; ///< Individual module parameter map
+  CbmStsSetup* fSetup;              //! STS setup interface
+  TClonesArray* fPoints {nullptr};  ///< Input array of CbmStsPoint
+
+  // --- Module and sensor parameters for runtime DB output
+  CbmStsParSim* fParSim               = nullptr;  ///< Simulation settings
+  CbmStsParSetModule* fParSetModule   = nullptr;  ///< Module parameter
+  CbmStsParSetSensor* fParSetSensor   = nullptr;  ///< Sensor parameters
+  CbmStsParSetSensorCond* fParSetCond = nullptr;  ///< Sensor conditions
+
+  // data members
+
+  Double_t fPitchXcm {0.0058};  // pitch in X [cm]
+  Double_t fPitchYcm {0.0058};  // pitch in Y [cm]
+  Double_t fPitchTns {20};      // pitch in time [ns]
+
+  /** @brief Initialise the parameters **/
+  void InitParams();
+
+  /** Process StsPoints from MCEvent **/
+  void ProcessMCEvent();
+
+  /** Prevent usage of copy constructor and assignment operator **/
+  CbmStsDigitizePixel(const CbmStsDigitizePixel&);
+  CbmStsDigitizePixel operator=(const CbmStsDigitizePixel&);
+
+  ClassDef(CbmStsDigitizePixel, 0);
+};
+
+#endif
diff --git a/sim/detectors/sts/CbmStsSimLinkDef.h b/sim/detectors/sts/CbmStsSimLinkDef.h
index 17ed0b7552897372309e8ae435130e84202194ab..281d7ca5105a65696af89fa49478cfcbf1d6410b 100644
--- a/sim/detectors/sts/CbmStsSimLinkDef.h
+++ b/sim/detectors/sts/CbmStsSimLinkDef.h
@@ -21,5 +21,6 @@
 #pragma link C++ class CbmStsSimSensorDssdStereo + ;
 #pragma link C++ class CbmStsSimSensorDssdOrtho + ;
 #pragma link C++ class CbmStsSimSensorFactory + ;
+#pragma link C++ class CbmStsDigitizePixel + ;
 
 #endif /* __CINT__ */