Belle II Software development
ECLRawDataHadron.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <ecl/utility/ECLRawDataHadron.h>
10
11#ifdef ECL_RAW_DATA_HADRON_STANDALONE_BUILD
12#include <cstdio> // printf
13#include <cstdlib> // exit
14#else
15#include <framework/logging/Logger.h>
16#endif
17
21
23
24 /* Amplitude */
25 /* ------------------------------------------------------------------------ */
26
27 unsigned long long packAmplitude(long long peak_amp)
28 {
29 // amplitude packing (from 18 bits int to 14 bits float)
30 // sign -- not used, 0 bits
31 // exponent -- 3 bits
32 // fraction -- 11 bits
33 if (peak_amp < 0) {
34#ifdef ECL_RAW_DATA_HADRON_STANDALONE_BUILD
35 printf("\n\033[31m");
36 printf("%s:%d: Error! Amplitude can never be negative, you have to call this function as packAmplitude(peak_amp + 128).\n",
37 __FILE__, __LINE__);
38 printf("\033[0m\n");
39 exit(1);
40#else
41 B2FATAL("Amplitude can never be negative, you have to call this function as packAmplitude(peak_amp + 128).");
42#endif
43 }
44 unsigned long long exponent;
45 unsigned long long fraction;
46 unsigned long long amp_packed = 0;
47
48 exponent = 0;
49 fraction = peak_amp;
50
51 if ((fraction & 0x20000) != 0)
52 exponent = 7;
53 else if ((fraction & 0x10000) != 0)
54 exponent = 6;
55 else if ((fraction & 0x08000) != 0)
56 exponent = 5;
57 else if ((fraction & 0x04000) != 0)
58 exponent = 4;
59 else if ((fraction & 0x02000) != 0)
60 exponent = 3;
61 else if ((fraction & 0x01000) != 0)
62 exponent = 2;
63 else if ((fraction & 0x00800) != 0)
64 exponent = 1;
65 else
66 exponent = 0;
67
68 if (exponent > 0) {
69 if (exponent > 1) {
70 fraction += 1 << (exponent - 2);
71 fraction = (fraction >> (exponent - 1)) - (1 << 11);
72 }
73 }
74 //###############################################
75 // ACCOUNTING FOR OVERFLOW
76 //###############################################
77 // See the comments in packTime function
78 // for the explanation
79 //###############################################
80 if ((fraction & 0x00800) != 0)
81 fraction -= 1;
82
83 amp_packed = (exponent << 11) | fraction;
84 return amp_packed;
85 }
86
87 unsigned long long unpackAmplitude(unsigned long long amp_packed)
88 {
89 unsigned int exponent = (amp_packed >> 11) & 0b111;
90 unsigned int fraction = (amp_packed) & 0b11111111111;
91 if (exponent == 0) {
92 return fraction - 128;
93 } else {
94 return (1 << (10 + exponent)) + fraction * (1 << (exponent - 1)) - 128;
95 }
96 }
97
98 /* Time */
99 /* ------------------------------------------------------------------------ */
100
101 int packTime(int peak_time)
102 {
103 // time packing (from 12 bits int to 11 bits float) as per IEEE 754
104 // https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64
105 // sign -- 1 bit
106 // exponent -- 2 bits
107 // fraction -- 8 bits
108 unsigned int exponent = 0;
109 unsigned int sign = 0;
110 int fraction = peak_time; // time from -2048 to 2047
111 if ((fraction & 0x800) != 0) {
112 sign = 1;
113 fraction = -fraction;
114 }
115
116 if ((fraction & 0x400) != 0)
117 exponent = 3;
118 else if ((fraction & 0x200) != 0)
119 exponent = 2;
120 else if ((fraction & 0x100) != 0)
121 exponent = 1;
122 else
123 exponent = 0;
124
125
126 if (exponent > 0) {
127 if (exponent > 1) {
128 // Adjust initial value so that the value is rounded to
129 // closest possible number.
130 fraction += 1 << (exponent - 2);
131 }
132 fraction = (fraction >> (exponent - 1)) - (1 << 8);
133 //###############################################
134 // ACCOUNTING FOR OVERFLOW
135 //###############################################
136 // In several specific cases, rounding can cause
137 // the value to overflow, this has to be handled.
138 // (for example:
139 // We would like to compress 63 from 5 bits to 3 bits.
140 // Thus, we divide 63 by 2^(5-3) == 4
141 // 63 + (4 / 2) == 65 # apply rounding
142 // 65 / 4 == 16 # divide by 2^(5-3)
143 // And 16 will exceed the bit width of 3!
144 // So we need to account for such cases
145 //###############################################
146 if ((fraction & 0x100) != 0)
147 fraction -= 1;
148 }
149
150 int peak_time_packed = (sign << 10) | (exponent << 8) | fraction;
151 return peak_time_packed;
152 }
153
154 int unpackTime(int time_packed)
155 {
156 unsigned int sign = (time_packed >> 10) & 0b1;
157 unsigned int exponent = (time_packed >> 8) & 0b11;
158 unsigned int fraction = (time_packed) & 0b11111111;
159
160 int result;
161
162 if (exponent == 0)
163 result = fraction;
164 else
165 result = ((1 << (7 + exponent)) + fraction * (1 << (exponent - 1)));
166 if (sign == 1)
167 result = -result;
168 return result;
169 }
170
171 /* Hadron fraction */
172 /* ------------------------------------------------------------------------ */
173
216 int integer_division_32(int dividend, int divisor)
217 {
218 if (divisor < 32)
219 // Division can be done for divisor < 32 but it is meaningless:
220 // hadron component fit is meaningless for amp < 32
221 return 0;
222
223 if (dividend >= (1 << 18) || dividend < 0) {
224 fprintf(stderr, "\n\033[31m");
225 fprintf(stderr, "%s:%d: Error! Dividend outside of expected range: %d\n", __FILE__, __LINE__, dividend);
226 fprintf(stderr, "\033[0m\n");
227 return 0; // exit(1);
228 }
229 if (divisor >= (1 << 19)) {
230 fprintf(stderr, "\n\033[31m");
231 fprintf(stderr, "%s:%d: Error! Divisor outside of expected range: %d\n", __FILE__, __LINE__, divisor);
232 fprintf(stderr, "\033[0m\n");
233 return 0; // exit(1);
234 }
235
236 // while divisor < 32:
237 // dividend *= 2
238 // divisor *= 2
239 //###############################################
240 // GET CORRECT BITSHIFT
241 //###############################################
242 int i = 18;
243 int p = i - 5;
244 while (i >= 5) {
245 if ((divisor & (1 << i)) != 0) {
246 p = (i - 5);
247 break;
248 }
249 i = i - 1;
250 }
251 //#######################
252 // Equivalent math expression:
253 //
254 // i = ⎣ log2(divisor) ⎦
255 // p = i - 5
256 //
257 //#######################
258 // Equivalent code (same as a while loop above)
259 // if (divisor & 0x40000) != 0:
260 // p = 13
261 // elif (divisor & 0x20000) != 0:
262 // p = 12
263 // elif (divisor & 0x10000) != 0:
264 // p = 11
265 // elif (divisor & 0x08000) != 0:
266 // p = 10
267 // ...
268 // elif (divisor & 0x00020) != 0:
269 // p = 0
270 //#######################
271
272 // NOTE: Because of this multiplication, dividend requires 23 bits.
273 // The code can be rewritten to manage with 18 bits.
274 dividend = dividend << 5;
275
276 int n_S = dividend >> p;
277 int m_S = divisor >> p;
278
279 // The values of round((2^16) / m_S), where m_S is in 32..63 range
280 const int precalculated_constants[] = {
281 // round(2**16 / (x+0.5)) for x in range(32, 64)
282 // ===>
283 2016, 1956, 1900, 1846, 1796, 1748, 1702, 1659,
284 1618, 1579, 1542, 1507, 1473, 1440, 1409, 1380,
285 1351, 1324, 1298, 1273, 1248, 1225, 1202, 1181,
286 1160, 1140, 1120, 1101, 1083, 1066, 1049, 1032
287 };
288
289 // n ⎛ 16 ⎞
290 // n S ⎜ 2 ⎟ 1
291 // ─ = ── = n ∙ ⎜ ─── ⎟ ∙ ───
292 // m m S ⎜ m ⎟ 16
293 // S ⎝ S ⎠ 2
294
295 return ((n_S + m_S / 2) * precalculated_constants[m_S - 32]) >> 16;
296 }
297
298 int packHadronFraction(int A_hadron, int A_total)
299 {
300 // The actual expression is ( (A_hadron / A_total + 0.25) / 0.75 ) * 32
301 // (for the firmware, dividend and divisor are multiplied by 4 to simplify calculations)
302 int dividend = 4 * A_hadron + A_total;
303 if (dividend < 0) return 0;
304 int packed_fraction = integer_division_32(dividend, 3 * A_total);
305 return packed_fraction;
306 }
307
308 double unpackHadronFraction(int fraction_packed)
309 {
310 return fraction_packed / 32.0 * 0.75 - 0.25;
311 }
312}
313
This is a set of function for packing/unpacking the data produced by the new ShaperDSP firmware that ...
int packHadronFraction(int A_hadron, int A_total)
Hadron fraction packing.
int integer_division_32(int dividend, int divisor)
Basically the fastest algorithm for approximate integer division (with the precision (1/32)).
unsigned long long packAmplitude(long long peak_amp)
Amplitude packing.
int packTime(int peak_time)
Time packing.
int unpackTime(int time_packed)
Time unpacking (from 11 bits float to 12 bits int)
unsigned long long unpackAmplitude(unsigned long long amp_packed)
Amplitude unpacking (from 14 bits float to 18 bit int)
double unpackHadronFraction(int fraction_packed)
Hadron fraction unpacking.