Skip to content

Commit f7f5b4a

Browse files
Added BI_AWGN channel.
1 parent 9afa202 commit f7f5b4a

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

blocks.hpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,44 @@ class SDMEC : public details::SameTypeProcessor<SDMEC<T>, T> {
275275
*/
276276
T operator()(const T& in) noexcept;
277277

278+
/**
279+
* @brief Calculate channel capacity in bits per symbol
280+
* @return Channel capacity C in bits per symbol
281+
*
282+
* Computes the Shannon capacity of the SDMEC channel using the formula for q-ary
283+
* symmetric channels with optional erasures. The capacity represents the maximum
284+
* achievable rate of reliable communication through this channel.
285+
*
286+
* **Mathematical Formula**:
287+
*
288+
* For errors-only channel (px = 0):
289+
* - C = log₂(q) + (1-pe)·log₂(1-pe) + pe·log₂(pe) - pe·log₂(q-1)
290+
*
291+
* For errors-and-erasures channel:
292+
* - C = (1-px) · C_error
293+
* - where C_error uses the conditional error probability pe/(1-px)
294+
*
295+
* For erasures-only channel:
296+
* - C = (1-px)·log₂(q)
297+
*
298+
* **Implementation Notes**:
299+
* - Uses internal error probability pe/(1-px) from error_dist.p()
300+
* - Handles edge cases pe=0 and pe=1 using limit: lim_{x→0} x·log₂(x) = 0
301+
* - For CECCO_ERASURE_SUPPORT, scales result by (1-px) to account for erasures
302+
* - Returns capacity in bits per channel use (symbol)
303+
*
304+
* **Usage Example**:
305+
* @code{.cpp}
306+
* SDMEC<F4> channel(0.05, 0.1); // 5% errors, 10% erasures over F₄
307+
* double capacity = channel.get_capacity();
308+
* std::cout << "Channel capacity: " << capacity << " bits/symbol" << std::endl;
309+
* // Result: approximately 1.52 bits/symbol (for F₄ with these parameters)
310+
* @endcode
311+
*
312+
* @note Returned value is in bits (log base 2).
313+
*/
314+
double get_capacity() const noexcept;
315+
278316
private:
279317
std::geometric_distribution<unsigned int> error_dist;
280318
unsigned int error_trials{0};
@@ -338,6 +376,24 @@ T SDMEC<T>::operator()(const T& in) noexcept {
338376
return res;
339377
}
340378

379+
template <FiniteFieldType T>
380+
double SDMEC<T>::get_capacity() const noexcept {
381+
const double pe = error_dist.p();
382+
const double q = static_cast<double>(T::get_size());
383+
384+
// Handle edge cases: lim_{x→0} x·log₂(x) = 0
385+
const double term1 = (pe > 0.0 && pe < 1.0) ? pe * log2(pe) : 0.0;
386+
const double term2 = (pe > 0.0 && pe < 1.0) ? (1 - pe) * log2(1 - pe) : 0.0;
387+
388+
double res = log2(q) + term2 + term1 - pe * log2(q - 1);
389+
390+
#ifdef CECCO_ERASURE_SUPPORT
391+
const double px = erasure_dist.p();
392+
res *= (1 - px);
393+
#endif
394+
return res;
395+
}
396+
341397
/**
342398
* @brief Symmetric Discrete Memoryless Channel (SDMC)
343399
* @tparam T Finite field type for channel input/output symbols
@@ -699,6 +755,73 @@ double AWGN::calculate_pe(double Eb, double constellation_distance, double EbNod
699755
return 0.5 * erfc(sqrt(constellation_snr));
700756
}
701757

758+
759+
/**
760+
* @brief Binary Input - Additive White Gaussian Noise (BI-AWGN) channel
761+
*
762+
* Combines NRZ modulation and AWGN transmission into a single block that maps binary inputs
763+
* to noisy complex-valued channel outputs. Compatible with NRZDecoder for hard decisions
764+
* or LLRCalculator for soft decisions.
765+
*
766+
* **Usage Example**:
767+
* @code{.cpp}
768+
* // BPSK-AWGN at 6 dB (default parameters)
769+
* BI_AWGN channel(6.0); // BPSK: a=0, b=2
770+
* Vector<Fp<2>> c = {1, 0, 1, 0};
771+
* Vector<std::complex<double>> y;
772+
* Vector<Fp<2>> r;
773+
* c >> channel >> y >> NRZDecoder(channel.get_encoder()) >> r;
774+
*
775+
* // Custom NRZ constellation
776+
* BI_AWGN ook(8.0, 1.0, 2.0); // OOK: a=1, b=2
777+
* @endcode
778+
*
779+
* @note Default parameters implement BPSK (a=0, b=2)
780+
* @see @ref CECCO::NRZEncoder for constellation parameters
781+
* @see @ref CECCO::AWGN for transmission/noise model
782+
* @see @ref CECCO::NRZDecoder for hard-decision
783+
* @see @ref CECCO::LLRCalculator for soft-decision
784+
*/
785+
class BI_AWGN : public details::BlockProcessor<BI_AWGN, Fp<2>, std::complex<double>> {
786+
public:
787+
using details::BlockProcessor<BI_AWGN, Fp<2>, std::complex<double>>::operator();
788+
789+
/**
790+
* @brief Construct BI-AWGN channel with SNR and optional NRZ parameters
791+
* @param EbN0dB Signal-to-noise ratio (Eb/N0) in decibels
792+
* @param a DC offset parameter for NRZ encoder (default: 0.0 for BPSK)
793+
* @param b Constellation distance parameter for NRZ encoder (default: 2.0 for BPSK)
794+
*
795+
* Default parameters (a=0, b=2) implement BPSK modulation with constellation {-1, +1}.
796+
* For other modulation schemes (e.g., OOK with a=1, b=2), specify custom parameters.
797+
*/
798+
BI_AWGN(double EbN0dB, double a = 0.0, double b = 2.0)
799+
: encoder(a, b), transmission(encoder.get_Eb(), encoder.get_constellation_distance(), EbN0dB) {}
800+
801+
/**
802+
* @brief Process single bit through BI-AWGN channel
803+
* @param in Input bit
804+
* @return Noisy complex-valued channel output
805+
*/
806+
std::complex<double> operator()(const Fp<2>& in) noexcept { return transmission(encoder(in)); }
807+
808+
/**
809+
* @brief Get theoretical bit error probability for hard decisions
810+
* @return Pe for this channel configuration
811+
*/
812+
double get_pe() const noexcept { return transmission.get_pe(); }
813+
814+
/**
815+
* @brief Get reference to internal NRZ encoder
816+
* @return Const reference to NRZ encoder (needed for NRZDecoder construction)
817+
*/
818+
const NRZEncoder& get_encoder() const noexcept { return encoder; }
819+
820+
private:
821+
NRZEncoder encoder;
822+
AWGN transmission;
823+
};
824+
702825
/**
703826
* @brief Non-Return-to-Zero (NRZ) hard-decision decoder
704827
*

0 commit comments

Comments
 (0)