1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
#include "Alignment/LaserAlignment/interface/LASProfileJudge.h"
// terminal colors
#define _R "\033[1;31m"
#define _B "\033[1;34m"
#define _G "\033[1;32m"
#define _N "\033[22;30m"
///
///
///
LASProfileJudge::LASProfileJudge() : overdriveThreshold(0) {
// switch on the zero filter by default
isZeroFilter = true;
}
///
/// Check if a LASModuleProfile indicates that the module has been hit,
/// i.e. contains a visible signal or is even distorted by too high laser amplitude.
/// This method doesn't care if the profile is usable for analysis.
///
bool LASProfileJudge::IsSignalIn(const LASModuleProfile& aProfile, double offset) {
profile = aProfile;
// need only approx values, so cast here to use integers throughout
const int approxOffset = static_cast<int>(offset);
const double negativity = GetNegativity(approxOffset);
const bool isPeaks = IsPeaksInProfile(approxOffset);
const bool isNegativePeaks = IsNegativePeaksInProfile(approxOffset);
bool result = (negativity < -1000.) || // if we see negativity, there was laser..
(isPeaks) || // if we see a peak, " " "
(isNegativePeaks); // same here
return (result);
}
///
/// Check if a LASModuleProfile is usable for being stored,
/// i.e. contains a visible signal & no baseline distortions
///
bool LASProfileJudge::JudgeProfile(const LASModuleProfile& aProfile, double offset = 0.) {
profile = aProfile;
// need only approx values, so cast here to use integers throughout
const int approxOffset = static_cast<int>(offset);
// run the tests
const double negativity = GetNegativity(approxOffset);
bool isPeaks;
if (!isZeroFilter)
isPeaks = true; // disable this test if set in cfg
else
isPeaks = IsPeaksInProfile(approxOffset);
const bool isNegativePeaks = IsNegativePeaksInProfile(approxOffset);
bool isOverdrive; // disable this test if set in cfg
if (!isZeroFilter)
isOverdrive = false;
else
isOverdrive = IsOverdrive(approxOffset);
bool result = (negativity > -1000.) && // < 1000. = distorted profile
(isPeaks) && // want to see a peak (zero filter)
!(isNegativePeaks) && // no negative peaks
!(isOverdrive); // no overdrive
return (result);
}
///
/// toggle the zero filter (passed from cfg file)
///
void LASProfileJudge::EnableZeroFilter(bool zeroFilter) {
if (!zeroFilter) {
std::cerr << " [LASProfileJudge::EnableZeroFilter] ** WARNING: Zero filter has been disabled." << std::endl;
}
isZeroFilter = zeroFilter;
}
///
/// set the threshold for overdriven profiles (passed from cfg file)
///
void LASProfileJudge::SetOverdriveThreshold(unsigned int aThreshold) { overdriveThreshold = aThreshold; }
///
/// In case of too high laser intensities, the APV baselines tend
/// to drop down. here, the strip amplitudes in the area around the
/// signal region are summed to return a variable which can indicate this.
///
double LASProfileJudge::GetNegativity(int offset) {
// here we could later run the sum only on the affected (pair of) APV
// expected beam position (in strips)
const unsigned int meanPosition = 256 + offset;
// backplane "alignment hole" (="signal region") approx. half size
const unsigned int halfWindowSize = 33;
// half size of range over which is summed (must be > halfWindowSize)
const unsigned int sumHalfRange = 128;
double neg = 0;
// need only x values, so cast here
for (unsigned int i = meanPosition - sumHalfRange; i < meanPosition - halfWindowSize; ++i) {
neg += profile.GetValue(i);
}
for (unsigned int i = meanPosition + halfWindowSize; i < meanPosition + sumHalfRange; ++i) {
neg += profile.GetValue(i);
}
return (neg);
}
///
/// If the laser intensity is too small, there's no peak at all.
/// Here we look if any strip is well above noise level.
///
bool LASProfileJudge::IsPeaksInProfile(int offset) {
// expected beam position (in strips)
const unsigned int meanPosition = 256 + offset;
// backplane "alignment hole" approx. half size (in strips)
const unsigned int halfWindowSize = 33;
bool returnValue = false;
// calculate average out-of-signal
double average = 0., counterD = 0.;
for (unsigned int strip = 0; strip < 512; ++strip) {
if (strip < meanPosition - halfWindowSize || strip > meanPosition + halfWindowSize) {
average += profile.GetValue(strip);
counterD += 1.;
}
}
average /= counterD;
// find peaks well above noise level
const double noiseLevel = 2.; // to be softcoded..
for (unsigned int strip = meanPosition - halfWindowSize; strip < meanPosition + halfWindowSize; ++strip) {
if (profile.GetValue(strip) > (average + 10. * noiseLevel)) {
returnValue = true;
thePeak.first = strip;
thePeak.second = profile.GetValue(strip);
break;
}
}
return (returnValue);
}
///
/// sometimes when the laser intensity is too high the APVs get confused
/// and a negative peak (dip) shows up. this is filtered here.
///
bool LASProfileJudge::IsNegativePeaksInProfile(int offset) {
// expected beam position in middle of module (in strips)
const unsigned int meanPosition = 256 + offset;
// backplane "alignment hole" approx. half size (in strips)
const unsigned int halfWindowSize = 33;
bool returnValue = false;
// calculate average out-of-signal
double average = 0., counterD = 0.;
for (unsigned int strip = 0; strip < 512; ++strip) {
if (strip < meanPosition - halfWindowSize || strip > meanPosition + halfWindowSize) {
average += profile.GetValue(strip);
counterD += 1.;
}
}
average /= counterD;
// find strips with negative amplitude way above noise level
const double noiseLevel = 2.;
for (unsigned int strip = 0; strip < 512; ++strip) {
if (profile.GetValue(strip) < (average - 10. * noiseLevel)) {
returnValue = true;
thePeak.first = strip;
thePeak.second = profile.GetValue(strip);
break;
}
}
return (returnValue);
}
///
/// check if peak in signal region is too high;
/// this can cause baseline distortions and therefore position bias
///
bool LASProfileJudge::IsOverdrive(int offset) {
// expected beam position in middle of module (in strips)
const unsigned int meanPosition = 256 + offset;
// backplane "alignment hole" approx. half size (in strips)
const unsigned int halfWindowSize = 33;
// find maximum strip amplitude in range
for (unsigned int strip = meanPosition - halfWindowSize; strip < meanPosition + halfWindowSize; ++strip) {
if (profile.GetValue(strip) > overdriveThreshold)
return true;
}
return false;
}
|