File indexing completed on 2025-08-06 08:17:21
0001
0002
0003
0004
0005
0006
0007
0008 #include "MicromegasBcoMatchingInformation_v2.h"
0009
0010 #include <Event/packet.h>
0011
0012 #include <algorithm>
0013 #include <vector>
0014
0015 namespace
0016 {
0017
0018
0019
0020
0021 template <class T>
0022 std::ostream& operator<<(std::ostream& o, const std::list<T>& list)
0023 {
0024 if (list.empty())
0025 {
0026 o << "{}";
0027 }
0028 else
0029 {
0030 const bool is_hex = (o.flags() & std::ios_base::hex);
0031 o << "{ ";
0032 bool first = true;
0033 for (const auto& value : list)
0034 {
0035 if (!first)
0036 {
0037 o << ", ";
0038 }
0039 if (is_hex)
0040 {
0041 o << "0x";
0042 }
0043 o << value;
0044 first = false;
0045 }
0046 o << " }";
0047 }
0048 return o;
0049 }
0050
0051 template <class T>
0052 std::ostream& operator<<(std::ostream& o, const std::vector<T>& list)
0053 {
0054 if (list.empty())
0055 {
0056 o << "{}";
0057 }
0058 else
0059 {
0060 const bool is_hex = (o.flags() & std::ios_base::hex);
0061 o << "{ ";
0062 bool first = true;
0063 for (const auto& value : list)
0064 {
0065 if (!first)
0066 {
0067 o << ", ";
0068 }
0069 if (is_hex)
0070 {
0071 o << "0x";
0072 }
0073 o << value;
0074 first = false;
0075 }
0076 o << " }";
0077 }
0078 return o;
0079 }
0080
0081
0082 template <class T>
0083 inline static constexpr T get_bco_diff(const T& first, const T& second)
0084 {
0085 return first < second ? (second - first) : (first - second);
0086 }
0087
0088
0089 static constexpr unsigned int m_max_fee_bco_diff = 10;
0090
0091
0092 static constexpr unsigned int m_max_matching_data_size = 50;
0093
0094
0095 static constexpr int m_nchannels_fee = 256;
0096
0097
0098 enum SampaDataType
0099 {
0100 HEARTBEAT_T = 0b000,
0101 TRUNCATED_DATA_T = 0b001,
0102 TRUNCATED_TRIG_EARLY_DATA_T = 0b011,
0103 NORMAL_DATA_T = 0b100,
0104 LARGE_DATA_T = 0b101,
0105 TRIG_EARLY_DATA_T = 0b110,
0106 TRIG_EARLY_LARGE_DATA_T = 0b111,
0107 };
0108
0109
0110 enum ModeBitType
0111 {
0112 BX_COUNTER_SYNC_T = 0b001,
0113 ELINK_HEARTBEAT_T = 0b010
0114 };
0115 }
0116
0117
0118 bool MicromegasBcoMatchingInformation_v2::m_multiplier_is_set = false;
0119 double MicromegasBcoMatchingInformation_v2::m_multiplier = 0;
0120
0121
0122 bool MicromegasBcoMatchingInformation_v2::m_multiplier_adjustment_enabled = true;
0123
0124
0125
0126 unsigned int MicromegasBcoMatchingInformation_v2::m_max_multiplier_adjustment_count = 200;
0127
0128
0129 unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100;
0130
0131
0132 std::optional<uint32_t> MicromegasBcoMatchingInformation_v2::get_predicted_fee_bco(uint64_t gtm_bco) const
0133 {
0134
0135 if (!is_verified())
0136 {
0137 return std::nullopt;
0138 }
0139
0140
0141 const uint64_t gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first);
0142
0143
0144 const uint64_t fee_bco_predicted = m_fee_bco_first + get_adjusted_multiplier() * gtm_bco_difference;
0145 return uint32_t(fee_bco_predicted & 0xFFFFFU);
0146 }
0147
0148
0149 void MicromegasBcoMatchingInformation_v2::print_gtm_bco_information() const
0150 {
0151 if (!m_gtm_bco_list.empty())
0152 {
0153 std::cout
0154 << "MicromegasBcoMatchingInformation_v2::print_gtm_bco_information -"
0155 << " gtm_bco: " << std::hex << m_gtm_bco_list << std::dec
0156 << std::endl;
0157
0158
0159 if (is_verified())
0160 {
0161 std::list<uint32_t> fee_bco_predicted_list;
0162 std::transform(
0163 m_gtm_bco_list.begin(),
0164 m_gtm_bco_list.end(),
0165 std::back_inserter(fee_bco_predicted_list),
0166 [this](const uint64_t& gtm_bco)
0167 { return get_predicted_fee_bco(gtm_bco).value(); });
0168
0169 std::cout
0170 << "MicromegasBcoMatchingInformation_v2::print_gtm_bco_information -"
0171 << " fee_bco_predicted: " << std::hex << fee_bco_predicted_list << std::dec
0172 << std::endl;
0173 }
0174 }
0175 }
0176
0177
0178 void MicromegasBcoMatchingInformation_v2::save_gtm_bco_information(int , const MicromegasBcoMatchingInformation_v2::gtm_payload& payload)
0179 {
0180 if ( payload.is_lvl1)
0181 {
0182
0183
0184 const auto& gtm_bco = payload.bco;
0185 m_gtm_bco_list.push_back(gtm_bco);
0186
0187 } else if( payload.is_endat ) {
0188
0189
0190 const auto& gtm_bco = payload.bco;
0191
0192
0193 if( m_gtm_bco_list.empty() || (gtm_bco-m_gtm_bco_list.back()) > 10 )
0194 { m_gtm_bco_list.push_back(gtm_bco); }
0195
0196 } else if( payload.is_modebit ) {
0197
0198
0199 const auto& modebits = payload.modebits;
0200 if (modebits == ELINK_HEARTBEAT_T)
0201 {
0202 const auto& gtm_bco = payload.bco;
0203 m_gtm_bco_list.push_back(gtm_bco);
0204 }
0205 }
0206 }
0207
0208
0209 bool MicromegasBcoMatchingInformation_v2::find_reference_from_modebits(const MicromegasBcoMatchingInformation_v2::gtm_payload& payload)
0210 {
0211 if( payload.is_modebit )
0212 {
0213
0214 const auto& modebits = payload.modebits;
0215 if (modebits == BX_COUNTER_SYNC_T)
0216 {
0217 std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_modebits"
0218 << " found reference from modebits"
0219 << std::endl;
0220
0221
0222 const auto& gtm_bco = payload.bco;
0223 m_gtm_bco_first = gtm_bco;
0224 m_fee_bco_first = 0;
0225 m_verified_from_modebits = true;
0226 return true;
0227 }
0228 }
0229 return false;
0230 }
0231
0232
0233 bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_payload& payload)
0234 {
0235
0236 std::vector<uint64_t> gtm_bco_list;
0237 std::vector<uint64_t> gtm_bco_diff_list;
0238 for (const auto& gtm_bco : m_gtm_bco_list)
0239 {
0240 if (!gtm_bco_list.empty())
0241 {
0242
0243
0244 const uint64_t gtm_bco_difference = (gtm_bco >= gtm_bco_list.back()) ? (gtm_bco - gtm_bco_list.back()) : (gtm_bco + (1ULL << 40U) - gtm_bco_list.back());
0245
0246 gtm_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference);
0247 }
0248
0249
0250 gtm_bco_list.push_back(gtm_bco);
0251 }
0252
0253
0254 if (verbosity())
0255 {
0256 std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - gtm_bco_diff_list: " << gtm_bco_diff_list << std::endl;
0257 }
0258
0259
0260 if( payload.type == HEARTBEAT_T)
0261 {
0262 return false;
0263 }
0264
0265
0266 if( payload.channel >= m_nchannels_fee)
0267 {
0268 return false;
0269 }
0270
0271
0272 const auto& fee_bco = payload.bx_timestamp;
0273 if (!m_has_fee_bco_prev)
0274 {
0275 m_fee_bco_prev = fee_bco;
0276 m_has_fee_bco_prev = true;
0277 }
0278
0279
0280 const uint64_t fee_bco_diff = get_bco_diff(fee_bco, m_fee_bco_prev);
0281
0282
0283 if (fee_bco_diff < m_max_fee_bco_diff)
0284 {
0285 return false;
0286 }
0287
0288 std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - fee_bco_diff: " << fee_bco_diff << std::endl;
0289
0290
0291 for (size_t i = 0; i < gtm_bco_diff_list.size(); ++i)
0292 {
0293 uint64_t sum = 0;
0294 for (size_t j = i; j < gtm_bco_diff_list.size(); ++j)
0295 {
0296 sum += gtm_bco_diff_list[j];
0297 if (get_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff)
0298 {
0299 m_verified_from_data = true;
0300 m_gtm_bco_first = gtm_bco_list[i];
0301 m_fee_bco_first = m_fee_bco_prev;
0302
0303 if (verbosity())
0304 {
0305 std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - matching is verified" << std::endl;
0306 std::cout
0307 << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -"
0308 << " m_gtm_bco_first: " << std::hex << m_gtm_bco_first << std::dec
0309 << std::endl;
0310 std::cout
0311 << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -"
0312 << " m_fee_bco_first: " << std::hex << m_fee_bco_first << std::dec
0313 << std::endl;
0314 }
0315 return true;
0316 }
0317 }
0318 }
0319
0320
0321 m_fee_bco_prev = fee_bco;
0322 return false;
0323 }
0324
0325
0326 std::optional<uint64_t> MicromegasBcoMatchingInformation_v2::find_gtm_bco(int packet_id, unsigned int fee_id, uint32_t fee_bco)
0327 {
0328
0329 if (!is_verified())
0330 {
0331 return std::nullopt;
0332 }
0333
0334
0335 const auto bco_matching_iter = std::find_if(
0336 m_bco_matching_list.begin(),
0337 m_bco_matching_list.end(),
0338 [fee_bco](const m_bco_matching_pair_t& pair)
0339 { return get_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; });
0340
0341 if (bco_matching_iter != m_bco_matching_list.end())
0342 {
0343 return bco_matching_iter->second;
0344 }
0345 else
0346 {
0347
0348 const auto iter = std::find_if(
0349 m_gtm_bco_list.begin(),
0350 m_gtm_bco_list.end(),
0351 [this, fee_bco](const uint64_t& gtm_bco)
0352 { return get_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; });
0353
0354
0355 if (iter != m_gtm_bco_list.end())
0356 {
0357 const auto gtm_bco = *iter;
0358 if (verbosity())
0359 {
0360 const auto fee_bco_predicted = get_predicted_fee_bco(gtm_bco).value();
0361 const auto fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco);
0362
0363 std::cout << "MicromegasBcoMatchingInformation_v2::find_gtm_bco -"
0364 << " packet_id: " << packet_id
0365 << " fee_id: " << fee_id
0366 << std::hex
0367 << " fee_bco: 0x" << fee_bco
0368 << " predicted: 0x" << fee_bco_predicted
0369 << " gtm_bco: 0x" << gtm_bco
0370 << std::dec
0371 << " difference: " << fee_bco_diff
0372 << std::endl;
0373 }
0374
0375
0376 m_bco_matching_list.emplace_back(fee_bco, gtm_bco);
0377
0378
0379 m_gtm_bco_list.erase(iter);
0380
0381
0382 if( m_multiplier_adjustment_enabled )
0383 { update_multiplier_adjustment(gtm_bco, fee_bco); }
0384
0385 return gtm_bco;
0386 }
0387 else
0388 {
0389 if (m_orphans.insert(fee_bco).second)
0390 {
0391 if (verbosity())
0392 {
0393
0394 const auto iter2 = std::min_element(
0395 m_gtm_bco_list.begin(),
0396 m_gtm_bco_list.end(),
0397 [this, fee_bco](const uint64_t& first, const uint64_t& second)
0398 { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); });
0399
0400 const int fee_bco_diff = (iter2 != m_gtm_bco_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1;
0401
0402 std::cout << "MicromegasBcoMatchingInformation_v2::find_gtm_bco -"
0403 << " packet_id: " << packet_id
0404 << " fee_id: " << fee_id
0405 << std::hex
0406 << " fee_bco: 0x" << fee_bco
0407 << std::dec
0408 << " gtm_bco: none"
0409 << " difference: " << fee_bco_diff
0410 << std::endl;
0411 }
0412 }
0413 return std::nullopt;
0414 }
0415 }
0416
0417
0418 return std::nullopt;
0419 }
0420
0421
0422 void MicromegasBcoMatchingInformation_v2::cleanup()
0423 {
0424
0425 while (m_gtm_bco_list.size() > m_max_matching_data_size)
0426 {
0427 m_gtm_bco_list.pop_front();
0428 }
0429 while (m_bco_matching_list.size() > m_max_matching_data_size)
0430 {
0431 m_bco_matching_list.pop_front();
0432 }
0433
0434
0435 m_orphans.clear();
0436 }
0437
0438
0439 void MicromegasBcoMatchingInformation_v2::cleanup(uint64_t ref_bco)
0440 {
0441
0442 m_gtm_bco_list.erase( std::remove_if( m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [ref_bco](const uint64_t& bco) { return bco<=ref_bco; }), m_gtm_bco_list.end() );
0443
0444
0445 m_bco_matching_list.erase( std::remove_if( m_bco_matching_list.begin(), m_bco_matching_list.end(), [ref_bco](const m_bco_matching_pair_t& pair) { return pair.second<=ref_bco; }), m_bco_matching_list.end() );
0446
0447
0448 m_orphans.clear();
0449 }
0450
0451
0452 double MicromegasBcoMatchingInformation_v2::get_adjusted_multiplier() const
0453 {
0454 return m_multiplier + m_multiplier_adjustment;
0455 }
0456
0457
0458 void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t gtm_bco, uint32_t fee_bco)
0459 {
0460
0461 if (!is_verified())
0462 {
0463 return;
0464 }
0465
0466
0467 if (gtm_bco == m_gtm_bco_first)
0468 {
0469 return;
0470 }
0471
0472 const uint32_t fee_bco_predicted = get_predicted_fee_bco(gtm_bco).value();
0473 const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted);
0474 const double gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first);
0475
0476 m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco;
0477 m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference;
0478 ++m_multiplier_adjustment_count;
0479
0480 if (verbosity())
0481 {
0482 const auto default_precision{std::cout.precision()};
0483 std::cout << "MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment -"
0484 << " m_multiplier_adjustment_count: " << m_multiplier_adjustment_count
0485 << std::setprecision(10)
0486 << " m_multiplier: " << get_adjusted_multiplier()
0487 << " adjustment: " << m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator
0488 << " m_multiplier_adjusted: " << get_adjusted_multiplier() + m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator
0489 << std::setprecision(default_precision)
0490 << std::endl;
0491 }
0492
0493
0494 if (m_multiplier_adjustment_count > m_max_multiplier_adjustment_count)
0495 {
0496 m_multiplier_adjustment += m_multiplier_adjustment_numerator / m_multiplier_adjustment_denominator;
0497 m_multiplier_adjustment_numerator = 0;
0498 m_multiplier_adjustment_denominator = 0;
0499 m_multiplier_adjustment_count = 0;
0500 }
0501 }