Skip to content

Commit a4ba0c1

Browse files
Calculate veto signals baseline without outliers (#146)
* Calculate veto signals baseline without outliers * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 2f69a48 commit a4ba0c1

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

inc/TRestRawSignal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class TRestRawSignal {
4141

4242
void CalculateBaseLineSigmaIQR(Int_t startBin, Int_t endBin);
4343

44+
void CalculateBaseLineSigmaExcludeOutliers(Int_t startBin, Int_t endBin);
45+
4446
std::vector<Float_t> GetSignalSmoothed_ExcludeOutliers(Int_t averagingPoints);
4547

4648
protected:
@@ -198,6 +200,8 @@ class TRestRawSignal {
198200

199201
void CalculateBaseLineMedian(Int_t startBin, Int_t endBin);
200202

203+
void CalculateBaseLineMedianExcludeOutliers(Int_t startBin, Int_t endBin);
204+
201205
void CalculateBaseLine(Int_t startBin, Int_t endBin, const std::string& option = "");
202206

203207
void GetBaseLineCorrected(TRestRawSignal* smoothedSignal, Int_t averagingPoints);

src/TRestRawPeaksFinderProcess.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ TRestEvent* TRestRawPeaksFinderProcess::ProcessEvent(TRestEvent* inputEvent) {
9797
} else if (channelType == "veto") {
9898
// For veto signals the baseline is calculated over the whole range, as we don´t know where the
9999
// signal will be.
100-
signal->CalculateBaseLine(0, 511, "robust");
100+
signal->CalculateBaseLine(0, 511, "OUTLIERS");
101101
// For veto signals the threshold is selected by the user.
102102
const auto peaks =
103103
signal->GetPeaksVeto(signal->GetBaseLine() + fThresholdOverBaseline, fDistance);

src/TRestRawSignal.cxx

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,50 @@ void TRestRawSignal::CalculateBaseLineMedian(Int_t startBin, Int_t endBin) {
784784
}
785785
}
786786

787+
///////////////////////////////////////////////
788+
/// \brief This method is called by CalculateBaseLine with the "OUTLIERS"-option and is used to determine the
789+
/// value of the baseline as the median of the data points found in the range defined between startBin and
790+
/// endBin after excluding the outliers. The median is calculated using only the values in the 25-75% removing
791+
/// big and small outliers.
792+
///
793+
void TRestRawSignal::CalculateBaseLineMedianExcludeOutliers(Int_t startBin, Int_t endBin) {
794+
if (endBin - startBin <= 0) {
795+
fBaseLine = 0.;
796+
return;
797+
} else if (endBin > static_cast<int>(fSignalData.size())) {
798+
cout << "TRestRawSignal::CalculateBaseLine. Error! Baseline range exceeds the rawdata depth!!"
799+
<< endl;
800+
endBin = fSignalData.size();
801+
} else {
802+
// Extract the data within the interval
803+
std::vector<Short_t> data(fSignalData.begin() + startBin, fSignalData.begin() + endBin);
804+
std::sort(data.begin(), data.end());
805+
806+
// Calculate Q1 and Q3 for IQR
807+
size_t dataSize = data.size();
808+
Short_t Q1 = data[dataSize / 4];
809+
Short_t Q3 = data[(3 * dataSize) / 4];
810+
Double_t lowerBound = Q1;
811+
Double_t upperBound = Q3;
812+
813+
// Filter out the outliers
814+
std::vector<Short_t> filteredData;
815+
for (const auto& value : data) {
816+
if (value >= lowerBound && value <= upperBound) {
817+
filteredData.emplace_back(value);
818+
}
819+
}
820+
821+
// Calculate median of filtered data
822+
if (filteredData.empty()) {
823+
fBaseLine = TMath::Median(data.size(),
824+
&data[0]); // Fall back to original median if all values are outliers
825+
} else {
826+
fBaseLine = TMath::Median(filteredData.size(), &filteredData[0]);
827+
}
828+
}
829+
}
830+
787831
///////////////////////////////////////////////
788832
/// \brief This method calculates the average and fluctuation of the baseline in the
789833
/// specified range and writes the values to fBaseLine and fBaseLineSigma respectively.
@@ -792,12 +836,16 @@ void TRestRawSignal::CalculateBaseLineMedian(Int_t startBin, Int_t endBin) {
792836
///
793837
/// \param option By setting this option to "ROBUST", the average is calculated as median,
794838
/// and the fluctuation as interquartile range (IQR), which are less affected by outliers (e.g. a signal
795-
/// pulse).
839+
/// pulse). By setting it to "OUTLIERS" the median and sigma will only take into account the
840+
/// 25-75% values of the interval.
796841
///
797842
void TRestRawSignal::CalculateBaseLine(Int_t startBin, Int_t endBin, const std::string& option) {
798843
if (ToUpper(option) == "ROBUST") {
799844
CalculateBaseLineMedian(startBin, endBin);
800845
CalculateBaseLineSigmaIQR(startBin, endBin);
846+
} else if (ToUpper(option) == "OUTLIERS") {
847+
CalculateBaseLineMedianExcludeOutliers(startBin, endBin);
848+
CalculateBaseLineSigmaExcludeOutliers(startBin, endBin);
801849
} else {
802850
CalculateBaseLineMean(startBin, endBin);
803851
CalculateBaseLineSigmaSD(startBin, endBin);
@@ -842,6 +890,54 @@ void TRestRawSignal::CalculateBaseLineSigmaIQR(Int_t startBin, Int_t endBin) {
842890
}
843891
}
844892

893+
///////////////////////////////////////////////
894+
/// \brief This method is called by CalculateBaseLine with the "OUTLIERS"-option to
895+
/// determine the value of the baseline
896+
/// fluctuation as the standard deviation in the baseline range provided excluding outliers.
897+
/// Since outliers are strongly suppressed there is no need to use the IQR.
898+
///
899+
void TRestRawSignal::CalculateBaseLineSigmaExcludeOutliers(Int_t startBin, Int_t endBin) {
900+
if (endBin - startBin <= 0) {
901+
fBaseLineSigma = 0.;
902+
return;
903+
} else if (endBin > static_cast<int>(fSignalData.size())) {
904+
cout << "TRestRawSignal::CalculateBaseLineSigma. Error! Range exceeds the rawdata depth!!" << endl;
905+
endBin = fSignalData.size();
906+
} else {
907+
// Extract the data within the interval
908+
std::vector<Short_t> data(fSignalData.begin() + startBin, fSignalData.begin() + endBin);
909+
std::sort(data.begin(), data.end());
910+
911+
// Calculate Q1 and Q3 for IQR
912+
size_t dataSize = data.size();
913+
Short_t Q1 = data[dataSize / 4];
914+
Short_t Q3 = data[(3 * dataSize) / 4];
915+
Double_t lowerBound = Q1;
916+
Double_t upperBound = Q3;
917+
918+
// Filter out the outliers
919+
std::vector<Short_t> filteredData;
920+
for (const auto& value : data) {
921+
if (value >= lowerBound && value <= upperBound) {
922+
filteredData.emplace_back(value);
923+
}
924+
}
925+
926+
// Calculate standard deviation of filtered data
927+
if (filteredData.empty()) {
928+
fBaseLineSigma = 0.; // If all values are outliers, set sigma to zero
929+
} else {
930+
double mean =
931+
std::accumulate(filteredData.begin(), filteredData.end(), 0.0) / filteredData.size();
932+
double variance = 0.0;
933+
for (const auto& value : filteredData) {
934+
variance += std::pow(value - mean, 2);
935+
}
936+
fBaseLineSigma = std::sqrt(variance / filteredData.size()); // Standard deviation
937+
}
938+
}
939+
}
940+
845941
///////////////////////////////////////////////
846942
/// \brief This method adds an offset to the signal data
847943
///

0 commit comments

Comments
 (0)