# Gnuradio BER block <details> <summary>BER Block.cc</summary> ``` /* -*- c++ -*- */ /* * Copyright 2013-2014 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* 如果定義了 HAVE_CONFIG_H,則包含 config.h 配置文件,這是自動化工具(如autotools)生成的配置頭文件 */ #include "ber_bf_impl.h" #include <gnuradio/io_signature.h> #include <volk/volk.h> #include <boost/format.hpp> #include <cmath> /* 包含必要的頭文件: - ber_bf_impl.h: 本模組的聲明 - io_signature.h: GNU Radio用於描述block端口的數據類型和大小 - volk.h: 用於SIMD優化的數學函數 - format.hpp: Boost庫的格式化工具,用於輸出格式化文本 - cmath: 標準數學函數庫 */ namespace gr { namespace fec { ber_bf::sptr ber_bf::make(bool test_mode, int berminerrors, float ber_limit) { return gnuradio::make_block_sptr<ber_bf_impl>(test_mode, berminerrors, ber_limit); } ber_bf_impl::ber_bf_impl(bool test_mode, int berminerrors, float ber_limit) : block("fec_ber_bf", io_signature::make(2, 2, sizeof(unsigned char)), io_signature::make(1, 1, sizeof(float))), d_total_errors(0), d_total(0), d_test_mode(test_mode), d_berminerrors(berminerrors), d_ber_limit(ber_limit) { } inline float ber_bf_impl::calculate_log_ber() const { return log10(((double)d_total_errors) / (d_total * 8.0)); } inline void ber_bf_impl::update_counters(const int items, const unsigned char* inbuffer0, const unsigned char* inbuffer1) { uint32_t ret; for (int i = 0; i < items; i++) { volk_32u_popcnt(&ret, static_cast<uint32_t>(inbuffer0[i] ^ inbuffer1[i])); d_total_errors += ret; } d_total += items; } /* 更新錯誤數和總數據數 - 逐個比較兩個輸入緩衝區的數據 - 使用 VOLK 函數計算 Hamming 距離(即位錯誤數) */ ber_bf_impl::~ber_bf_impl() {} int ber_bf_impl::general_work(int noutput_items, gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { unsigned char* inbuffer0 = (unsigned char*)input_items[0]; unsigned char* inbuffer1 = (unsigned char*)input_items[1]; float* outbuffer = (float*)output_items[0]; int items = ninput_items[0] <= ninput_items[1] ? ninput_items[0] : ninput_items[1]; /* general_work 函數處理數據塊 - 比較兩個輸入緩衝區,計算BER,並將結果輸出到 outbuffer */ if (d_test_mode) { // 如果在測試模式下,當錯誤數達到設定的最小值時停止 if (d_total_errors >= d_berminerrors) { return WORK_DONE; // 完成工作 } else { if (items > 0) { update_counters(items, inbuffer0, inbuffer1); } consume_each(items); if (d_total_errors >= d_berminerrors) { outbuffer[0] = calculate_log_ber(); GR_LOG_INFO(d_logger, boost::format(" %1% over %2% --> %3%") % d_total_errors % (d_total * 8) % outbuffer[0]); return 1; } // 在高信噪比模擬中檢查總錯誤數以防止過早停止 else if (calculate_log_ber() < d_ber_limit && d_total_errors > 0) { GR_LOG_INFO(d_logger, " Min. BER limit reached"); outbuffer[0] = d_ber_limit; d_total_errors = d_berminerrors + 1; return 1; } else { return 0; } } } else { // 流模式下,持續處理 if (items > 0) { update_counters(items, inbuffer0, inbuffer1); outbuffer[0] = calculate_log_ber(); consume_each(items); return 1; } else { return 0; } } } } /* namespace fec */ } /* namespace gr */ ``` </details> <details> <summary>BER Block.h</summary> ``` /* -*- c++ -*- */ /* * Copyright 2013-2014 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifndef INCLUDED_FEC_BER_BF_IMPL_H #define INCLUDED_FEC_BER_BF_IMPL_H #include <gnuradio/fec/ber_bf.h> namespace gr { namespace fec { class FEC_API ber_bf_impl : public ber_bf { private: long d_total_errors; long d_total; bool d_test_mode; int d_berminerrors; float d_ber_limit; inline float calculate_log_ber() const; inline void update_counters(const int items, const unsigned char* inbuffer0, const unsigned char* inbuffer1); public: ber_bf_impl(bool d_test_mode = false, int berminerrors = 100, float ber_limit = -7.0); ~ber_bf_impl() override; int general_work(int noutput_items, gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) override; long total_errors() override { return d_total_errors; }; }; } /* namespace fec */ } /* namespace gr */ #endif /* INCLUDED_FEC_BER_BF_IMPL_H */ ``` </details> ### update_counters 1. inbuffer0[i] ^ inbuffer1[i]: 對兩個緩衝區中的相同位置的數據進行 XOR 運算。XOR 運算的結果是如果相應的位相同,則結果為0;如果不同,則結果為1。 2. static_cast<uint32_t>(): 將 XOR 的結果轉型為 uint32_t 型。 3. volk_32u_popcnt(): 計算轉型後的 uint32_t 數值中1的個數,也就是計算兩個字節間的漢明距離(Hamming distance)。漢明距離即不同位的數量,這裡也就是位錯誤數。 ``` inline void ber_bf_impl::update_counters(const int items, const unsigned char* inbuffer0, const unsigned char* inbuffer1) { uint32_t ret; for (int i = 0; i < items; i++) { volk_32u_popcnt(&ret, static_cast<uint32_t>(inbuffer0[i] ^ inbuffer1[i])); d_total_errors += ret; } d_total += items; } ``` ### items ninput_items[0] 和 ninput_items[1] 分別是兩個輸入緩衝區中可用的數據項的數量。這段程式碼使用了 C++ 的條件運算符(也稱為三元運算符)? :,其格式為 [條件 ? 表達式1 : 表達式2:] 如果條件為真(在這裡是檢查 ninput_items[0] 是否小於或等於 ninput_items[1]),則表達式的結果是 表達式1(ninput_items[0])。 如果條件為假,則結果是 表達式2(ninput_items[1])。 因此,items 變量被賦值為兩個輸入中可用數據項最小的那個數量。這樣做可以保證在接下來的處理中,不會讀取任一輸入緩衝區中不存在的數據,從而避免越界錯誤。 ``` int items = ninput_items[0] <= ninput_items[1] ? ninput_items[0] : ninput_items[1]; ``` ### calculate_log_ber (d_total * 8.0):這部分代表總比特數。d_total 變量應該是指處理過的數據項的總數(例如字節數)。因為每個數據項(假設為字節)包含 8 個比特,所以這裡乘以 8 將字節轉換成比特。 ((double)d_total_errors) / (d_total * 8.0):這個表達式計算的是位錯誤率(BER),即總錯誤比特數除以總比特數。d_total_errors 是錯誤比特的計數,這裡被顯式轉換成 double 類型,以確保進行浮點除法,從而得到準確的 BER 值。 ``` inline float ber_bf_impl::calculate_log_ber() const { return log10(((double)d_total_errors) / (d_total * 8.0)); } ```