1515
1616// / The data is sent by the CRU as 256+16 bit words. The CMV data layout is as follows:
1717// / - 256-bit Header: [version:8][packetID:8][errorCode:8][magicWord:8][heartbeatOrbit:32][heartbeatBC:16][padding:176]
18- // / - 16-bit CMV value: [CMV:16]
18+ // / - 16-bit CMV value: [sign:1][I8F7:15] where bit 15 is the sign (1=positive, 0=negative) and the lower 15 bits are a fixed point I8F7 value (8 integer bits, 7 fractional bits)
19+ // / Float conversion: sign ? (value & 0x7FFF) / 128.0 : -(value & 0x7FFF) / 128.0
1920
2021#ifndef ALICEO2_DATAFORMATSTPC_CMV_H
2122#define ALICEO2_DATAFORMATSTPC_CMV_H
2223
2324#include < cstdint>
25+ #include < cmath>
2426
2527namespace o2 ::tpc::cmv
2628{
2729
2830static constexpr uint32_t NTimeBinsPerPacket = 3564 ; // /< number of time bins (covering 8 heartbeats)
2931static constexpr uint32_t NPacketsPerTFPerCRU = 4 ; // /< 4 packets per timeframe
3032static constexpr uint32_t NTimeBinsPerTF = NTimeBinsPerPacket * NPacketsPerTFPerCRU; // /< maximum number of timebins per timeframe (14256)
31- static constexpr uint32_t SignificantBits = 2 ; // /< number of bits used for floating point precision
32- static constexpr float FloatConversion = 1 .f / float (1 << SignificantBits); // /< conversion factor from integer representation to float
3333
3434// / Header definition of the CMVs
3535struct Header {
@@ -83,18 +83,25 @@ struct Header {
8383
8484// / CMV single data container
8585struct Data {
86- uint16_t CMV{0 }; // /< 16bit ADC value
86+ uint16_t CMV{0 }; // /< 16-bit signed fixed point value: bit 15 = sign (1=positive, 0=negative), bits 14-0 = I8F7 magnitude
8787
88- // Raw integer accessors
89- uint16_t getCMV () const { return CMV; }
90- void setCMV (uint16_t value) { CMV = value; }
88+ uint16_t getCMV () const { return CMV; } // /< raw 16-bit integer representation
89+ void setCMV (uint16_t value) { CMV = value; } // /< set raw 16-bit integer representation
9190
92- // Float helpers using SignificantBits for fixed-point conversion
93- float getCMVFloat () const { return static_cast <float >(CMV) * FloatConversion; }
91+ // Decode to float: sign-magnitude with 7 fractional bits, range ±255.992
92+ float getCMVFloat () const
93+ {
94+ const bool positive = (CMV >> 15 ) & 1 ; // bit 15: sign (1=positive, 0=negative)
95+ const float magnitude = (CMV & 0x7FFF ) / 128 .f ; // lower 15 bits, shift right by 7 (divide by 2^7)
96+ return positive ? magnitude : -magnitude;
97+ }
98+
99+ // Encode from float: clamps magnitude to 15 bits, range ±255.992
94100 void setCMVFloat (float value)
95101 {
96- // round to nearest representable fixed-point value
97- setCMV (uint32_t ((value + 0 .5f * FloatConversion) / FloatConversion));
102+ const bool positive = (value >= 0 .f );
103+ const uint16_t magnitude = static_cast <uint16_t >(std::abs (value) * 128 .f + 0 .5f ) & 0x7FFF ;
104+ CMV = (positive ? 0x8000 : 0x0000 ) | magnitude;
98105 }
99106};
100107
@@ -110,7 +117,7 @@ struct Container {
110117 const Data* getData () const { return data; }
111118 Data* getData () { return data; }
112119
113- // Per-time-bin CMV accessors
120+ // Per timebin CMV accessors
114121 uint16_t getCMV (uint32_t timeBin) const { return data[timeBin].getCMV (); }
115122 void setCMV (uint32_t timeBin, uint16_t value) { data[timeBin].setCMV (value); }
116123
0 commit comments