aff3ct / my_project_with_aff3ct

Small code examples using AFF3CT as a library.
MIT License
15 stars 16 forks source link

How to set up a basic polar encoder/decoder by using the bootstrap example #5

Closed ibarron9216 closed 3 years ago

ibarron9216 commented 4 years ago

Hi,

I have forked my_project_with_aff3ct and modified the bootsrap example to try and implement a simple example of polar encoding/decoding. The following is my main function:

int main(int argc, char** argv)
{

    params p;  init_params (p   ); // create and initialize the parameters defined by the user
    modules m; init_modules(p, m); // create and initialize the modules
    buffers b; init_buffers(p, b); // create and initialize the buffers required by the modules
    utils u;   init_utils  (m, u); // create and initialize the utils

    // Create Frozen Bits Generator GA
    tools::Frozenbits_generator_GA         frozenBitsGeneratorGA(p.K,p.N);

    // Compute the noise (sigma)
    float SNR_max  =  10.01f;
        const auto esn0  = tools::ebn0_to_esn0 (SNR_max, p.R);
        const auto sigma = tools::esn0_to_sigma(esn0);
        u.noise->set_noise(sigma, SNR_max, esn0);

    // Set the noise for the Frozen Bits Generator GA
    frozenBitsGeneratorGA.set_noise(*u.noise);

    // Generate the frozen bits
    frozenBitsGeneratorGA.generate(b.frozen_bits);

    // Create Polar Encoder
    module::Encoder_polar<> polarEncoder(p.K, p.N, b.frozen_bits);

    // Generate Random bits
    m.source ->generate(b.ref_bits);

    // Encode the bits
    polarEncoder.encode(b.ref_bits,b.enc_bits);

    // Create Polar Decoder
    module::Decoder_polar_SC_naive<> polarDecoder(p.K, p.N, b.frozen_bits);

    // Convert the vector<int> to vector<float> such that it can be used in the decoder
    std::vector<float> encodedBits(b.enc_bits.begin(), b.enc_bits.end());

    // Decode the encoded bits
    polarDecoder.decode_siho(encodedBits,b.dec_bits);

    return 0;
}

where b.frozen_bits = std::vector<bool >(p.N). The problem I am facing is that after decoding (polarDecoder.decode_siho(encodedBits,b.dec_bits)), the decoded message (b.dec_bits) is full of zeros. The result is obviously wrong since there is no noise and the encoded message is passed directly to the decoder. My implementation was based on what I read from the documentation and on the bootstrap example so I do not know if there is something wrong with my approach.

SubtleMuffin commented 4 years ago

Hi @ibarron9216 ,

Do you mind post all of your program? It might be the issues of init_params functions.

Besides, I am also working on using aff3ct as a library in Python, so please let me know if you have any success on this.

SubtleMuffin commented 4 years ago

@ibarron9216 I think the problem is probably [0, 1] -> [-1, +1] mapping, i.e.,

std::vector<float> encodedBits(b.enc_bits.begin(), b.enc_bits.end());

Please consider map the bits to BPSK symbols, maybe using std::transform.

Please find the attached code I am using.

#include "codec.hpp"

template <typename T> auto print_vector(std::vector<T> vec) {
  std::for_each(vec.begin(), vec.end(),
                [&](const auto i) { std::cout << i << ' '; });
  std::cout << std::endl;
}

int main() {
  int k = 401;
  int n = 512;
  float snr_max = 20;
  auto frozen_bits = generate_frozen_bits(k, n, snr_max);

  auto source =
      std::unique_ptr<module::Source_random<>>(new module::Source_random<>(k));
  std::vector<int> info_bits(k);
  source->generate(info_bits);

  auto encoded_bits = polar_encode(k, n, frozen_bits, info_bits);

  std::vector<float> received;
  std::transform(encoded_bits.begin(), encoded_bits.end(),
                 std::back_inserter(received),
                 [&](const int i) -> float { return i * 2 - 1; });

  auto decoded_bits = polar_decode(k, n, frozen_bits, received);

  print_vector(info_bits);
  print_vector(decoded_bits);

  for (auto i = 0; i < k-1; i++) {
    if (decoded_bits[i] != info_bits[i]) {
      std::cout << i << ' ';
    }
  }
}

and

#include <iostream>
#include <string>
#include <vector>

#include <aff3ct.hpp>

using namespace aff3ct;

/**
 * @brief Generate frozen bits for a specific SNR
 *
 * @param k The number of information bits
 * @param n The codeword length
 * @param snr_max Estimated SNR (in dB)
 * @return auto std::vector<bool> of frozen bits
 */
auto generate_frozen_bits(const int k, const int n, const float snr_max) {
  auto r = static_cast<float>(k * 1.0 / n);
  const auto esn0 = tools::ebn0_to_esn0(snr_max, r);
  const auto sigma = tools::esn0_to_sigma(esn0);

  tools::Frozenbits_generator_GA frozen_bits_generator(k, n);
  auto noise = std::unique_ptr<tools::Sigma<>>(new tools::Sigma<>());
  noise->set_noise(sigma, snr_max, esn0);

  std::vector<bool> frozen_bits(n);
  frozen_bits_generator.set_noise(*noise);
  frozen_bits_generator.generate(frozen_bits);

  return frozen_bits;
}

/**
 * @brief Polar encoder
 *
 * @param k The number of information bits
 * @param n The codeword length
 * @param frozen_bits std::vector<bool>, frozen bits (length k)
 * @param info_bits std::vector<int>, information bits (length k)
 * @return auto Encoded codewords, std::vector<int> of length n
 */
auto polar_encode(const int k, const int n,
                  const std::vector<bool> &frozen_bits,
                  const std::vector<int> &info_bits) {
  std::vector<int> encoded_bits(n);
  module::Encoder_polar<int> polar_encoder(k, n, frozen_bits);
  polar_encoder.encode(info_bits, encoded_bits);
  return encoded_bits;
}

/**
 * @brief Polar decoder
 *
 * @param k The number of information bits
 * @param n The codeword length
 * @param frozen_bits std::vector<bool>, frozen bits (length k)
 * @param received std::vector<float> soft symbols, BPSK, length n
 * @return auto Decoded information bits, std::vector<int> of length k
 */
auto polar_decode(const int k, const int n,
                  const std::vector<bool> &frozen_bits,
                  const std::vector<float> &received) {
  std::vector<int> decoded_bits(k);
  module::Decoder_polar_SC_naive<int> polar_decoder(k, n, frozen_bits);
  polar_decoder.decode_siho(received, decoded_bits);
  return decoded_bits;
}
ibarron9216 commented 4 years ago

Hi @ibarron9216 ,

Do you mind post all of your program? It might be the issues of init_params functions.

Besides, I am also working on using aff3ct as a library in Python, so please let me know if you have any success on this.

Hi,

First, thank you so much for your reply. I actually continued trying different things to make a simple example of the polar encoder/decoder. Indeed, as you mentioned in your newest response, I used BPSK symbols. I am able to get some results from my new implementation, however there is still something wrong, which I have not been able to solve. The following is my full code:


#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>
#include <math.h>
#include <stack>          // std::stack
#include <cmath>       /* log */
#include <sstream>      // std::stringstream
#include <fstream>
#include <iomanip>      // std::setprecision
#include <random>
#include <chrono>

#include <aff3ct.hpp>

using namespace std;
using namespace aff3ct;

void runPolarExample(int K, int N, int L, int n_frames, float p)
{
    srand((unsigned)time(0));

    int messageBits[K];
    int encodedBits[N];
    double bpsk[N];
    double BSC_bpsk[N];
    float receivedSignal[N];
    float BSC_receivedSignal[N];
    int decodedMessageBits[K];
    int BSC_decodedMessageBits[K];
    std::vector<bool> frozen_bits(N,0);
    std::vector<bool> GA_frozen_bits(N,0);
    int tmp = 0;
    float BER = 0;
    float BSC_BER = 0;
    int flippedBits = 0;
    float rate = (float)K/N;

    std::unique_ptr<tools::Sigma<>> noise;
    noise = std::unique_ptr<tools::Sigma<>>(new tools::Sigma<>());

    // Create Frozen Bits Generator GA
    tools::Frozenbits_generator_GA frozenBitsGeneratorGA(K,N);
    //tools::Frozenbits_generator frozenBitsGeneratorGA(K,N);

    // Compute the noise (sigma)
    //float SNR_max  =  10.01f;
    float SNR_max  =  0.01f;
    const auto esn0  = tools::ebn0_to_esn0 (SNR_max, rate);
    const auto sigma = tools::esn0_to_sigma(esn0);
    noise->set_noise(sigma, SNR_max, esn0);

    // Set the noise for the Frozen Bits Generator GA
    frozenBitsGeneratorGA.set_noise(*noise);

    // Generate the frozen bits
    frozenBitsGeneratorGA.generate(GA_frozen_bits);

    // Generate random message bits and initilize decodedMessageBits/BSC_decodedMessageBits
    for(int i = 0; i < K; ++ i ){
        messageBits[i] = (int) (rand() % 2);
        decodedMessageBits[i] = 0;
        BSC_decodedMessageBits[i] = 0;
    }

    // Set encoded bits to 0
    for(int i = 0; i < N; ++ i ){
        encodedBits[i] = 0;
    }

    // Set frozen bits
    // IB Check frozen bits generator from Aff3ct
    for (int i=0; i<N-K; i++){
        frozen_bits.at(i) = 1;
    }

    aff3ct::module::Encoder_polar<int> polarEncoder (K, N, frozen_bits, n_frames);
    //aff3ct::module::Encoder_polar<int> polarEncoder (K, N, GA_frozen_bits, n_frames);

    polarEncoder.encode(messageBits, encodedBits);

    // Use BPSK modulation to modulate the encoded bits
    for(int i = 0; i < N; ++ i ) {

        // Noiseless channel
        bpsk[i] = 2.0f * ((double) encodedBits[i]) - 1.0f;
        receivedSignal[i] = (float) bpsk[i];

        // BSC
        if ((rand() % 100) < (p*100))
        {

            if (encodedBits[i] == 1)
            {
                tmp = 0;
            }
            else
            {
                tmp = 1;
            }
            BSC_bpsk[i] = 2.0f * ((double) tmp) - 1.0f;
            flippedBits = flippedBits+1;

        }
        else
            BSC_bpsk[i] = 2.0f * ((double) encodedBits[i]) - 1.0f;
        BSC_receivedSignal[i] = (float) BSC_bpsk[i];

    }

    aff3ct::module::Decoder_polar_SCL_naive<int, float> polarDecoder(K, N, L, frozen_bits, n_frames);

    polarDecoder.decode_siho(receivedSignal, decodedMessageBits,1);

    polarDecoder.decode_siho(BSC_receivedSignal, BSC_decodedMessageBits,1);

    for(int i = 0; i < K; ++ i ){
        if (BSC_decodedMessageBits[i]!=messageBits[i])
            BSC_BER = BSC_BER+1;
    }

    for(int i = 0; i < K; ++ i ){
        if (decodedMessageBits[i]!=messageBits[i])
            BER = BER+1;
    }

    BER = (float)BER/K;
    BSC_BER = (float)BSC_BER/K;

    cout << "BER=" << BER << ", BSCBER=" << BSC_BER << endl;

//    cout << "The first 15 bits from the original message and the decoded message" << endl;
//    for (int i=0; i<15; i++){
//        cout << "(" << messageBits[i] << ", " << decodedMessageBits[i] << ")" << endl;
//    }
//
//    cout << "The first 15 bits from the original message and the decoded message (BSC)" << endl;
//    for (int i=0; i<15; i++){
//        cout << "(" << messageBits[i] << ", " << BSC_decodedMessageBits[i] << ")" << endl;
//    }

}

int main()
{

    const int K = 128;
    const int N = 256;
    //const int K = 1723;
    //const int N = 2048;

    //int L = 8; //power of 2: [1,2,4,8]
    int L = 32;

    int n_frames = 1;

    // BSC probaility
    //float p = 0.5;
    //float p = 0.01;
    //float p = 0.05;
    float p = 0;

    runPolarExample(K, N, L, n_frames, p);

    return 0;
}

My program always gets 1 bit in error. As you can see, I am manually initializing the frozen bits, which I think is a big problem. I also tried to use the frozen bits generator from aff3ct but was not able to do it. At this moment, I am going to look at your example and see if I can figure things out. However, I just want to highlight again that indeed the main error from my previous approach was the lack of mapping from bits to BPSK symbols. I will get to work in my code and get an update as soon as possible. Once again, thank you

SubtleMuffin commented 4 years ago

[Previous reply] No problem. Your 1 bit error mostly come from the very last bit I think. I am also seeing this problem. Please refer to my code where I compare everything except for the last bit. This is strange but one can get away with it by adding one more information bit and avoid using the last output.

I think I have found the reason. The mapping should be [0, 1] -> [+1, -1]. Please check if your program has the same issue.

Here is the listing of code I am using.

#include <iostream>
#include <memory>
#include <vector>
#include <string>

#include <aff3ct.hpp>
#include "cxxopts.hpp"

using namespace aff3ct;

struct params
{
    int   K         ; // number of information bits
    int   N         ; // codeword size
    int   fe        ; // number of frame errors
    int   seed      ; // PRNG seed for the AWGN channel
    float ebn0_min  ; // minimum SNR value
    float ebn0_max  ; // maximum SNR value
    float ebn0_step ; // SNR step
    float R         ; // code rate (R=K/N)
};

struct modules
{
    std::unique_ptr<module::Source_random<>>          source;
    std::unique_ptr<tools::Frozenbits_generator_GA>   frozen;
    std::unique_ptr<module::Encoder_polar<>>          encoder;
    std::unique_ptr<module::Modem_BPSK<>>             modem;
    std::unique_ptr<module::Channel_AWGN_LLR<>>       channel;
    std::unique_ptr<module::Decoder_polar_SC_naive<>> decoder;
    std::unique_ptr<module::Monitor_BFER<>>           monitor;
};

struct buffers
{
    std::vector<int  > ref_bits;
    std::vector<bool > frozen_bits;
    std::vector<int  > enc_bits;
    std::vector<float> symbols;
    std::vector<float> noisy_symbols;
    std::vector<float> LLRs;
    std::vector<int  > dec_bits;
};

struct utils
{
    std::unique_ptr<tools::Sigma<>>               noise;     // a sigma noise type
    std::vector<std::unique_ptr<tools::Reporter>> reporters; // list of reporters dispayed in the terminal
    std::unique_ptr<tools::Terminal_std>          terminal;  // manage the output text in the terminal
};

void init_params(params &p, cxxopts::ParseResult &opts)
{
    p.K         = opts["k"].as<int> ();
    p.N         = opts["n"].as<int> ();
    p.fe        = opts["fe"].as<int> ();
    p.seed      = opts["seed"].as<int> ();
    p.ebn0_min  = opts["ebn0min"].as<float> ();
    p.ebn0_max  = opts["ebn0max"].as<float> ();
    p.ebn0_step = opts["ebn0step"].as<float> ();
    if (opts.count("r"))
    {
        p.R = opts["r"].as<float> ();
        p.K = (int) (p.N * 1.0 * p.R);
    }
    else
    {
        p.R = (float)p.K / (float)p.N;
    }

    std::cout << "# * Simulation parameters: "              << std::endl;
    std::cout << "#    ** Frame errors   = " << p.fe        << std::endl;
    std::cout << "#    ** Noise seed     = " << p.seed      << std::endl;
    std::cout << "#    ** Info. bits (K) = " << p.K         << std::endl;
    std::cout << "#    ** Frame size (N) = " << p.N         << std::endl;
    std::cout << "#    ** Code rate  (R) = " << p.R         << std::endl;
    std::cout << "#    ** SNR min   (dB) = " << p.ebn0_min  << std::endl;
    std::cout << "#    ** SNR max   (dB) = " << p.ebn0_max  << std::endl;
    std::cout << "#    ** SNR step  (dB) = " << p.ebn0_step << std::endl;
    std::cout << "#"                                        << std::endl;
}

void init_modules(const params &p, modules &m, buffers &b)
{
    m.source  = std::unique_ptr<module::Source_random         <>>(new module::Source_random         <>(p.K                    ));
    m.frozen  = std::unique_ptr<tools::Frozenbits_generator_GA>  (new tools::Frozenbits_generator_GA  (p.K, p.N               ));
    // m.encoder = std::unique_ptr<module::Encoder_polar         <>>(new module::Encoder_polar         <>(p.K, p.N, b.frozen_bits));
    m.modem   = std::unique_ptr<module::Modem_BPSK            <>>(new module::Modem_BPSK            <>(p.N                    ));
    m.channel = std::unique_ptr<module::Channel_AWGN_LLR      <>>(new module::Channel_AWGN_LLR      <>(p.N, p.seed            ));
    // m.decoder = std::unique_ptr<module::Decoder_polar_SC_naive<>>(new module::Decoder_polar_SC_naive<>(p.K, p.N, b.frozen_bits));
    m.monitor = std::unique_ptr<module::Monitor_BFER          <>>(new module::Monitor_BFER          <>(p.K, p.fe              ));
};

void init_buffers(const params &p, buffers &b)
{
    b.ref_bits      = std::vector<int  >(p.K);
    b.frozen_bits   = std::vector<bool >(p.N);
    b.enc_bits      = std::vector<int  >(p.N);
    b.symbols       = std::vector<float>(p.N);
    b.noisy_symbols = std::vector<float>(p.N);
    b.LLRs          = std::vector<float>(p.N);
    b.dec_bits      = std::vector<int  >(p.K);
}

void init_utils(const modules &m, utils &u)
{
    // create a sigma noise type
    u.noise = std::unique_ptr<tools::Sigma<>>(new tools::Sigma<>());
    // report the noise values (Es/N0 and Eb/N0)
    u.reporters.push_back(std::unique_ptr<tools::Reporter>(new tools::Reporter_noise<>(*u.noise)));
    // report the bit/frame error rates
    u.reporters.push_back(std::unique_ptr<tools::Reporter>(new tools::Reporter_BFER<>(*m.monitor)));
    // report the simulation throughputs
    u.reporters.push_back(std::unique_ptr<tools::Reporter>(new tools::Reporter_throughput<>(*m.monitor)));
    // create a terminal that will display the collected data from the reporters
    u.terminal = std::unique_ptr<tools::Terminal_std>(new tools::Terminal_std(u.reporters));
}

template <typename T> auto print_vector(std::vector<T> vec) {
  std::for_each(vec.begin(), vec.end(),
                [&](const auto i) { std::cout << i << ' '; });
  std::cout << std::endl;
}

int main(int argc, char** argv)
{
    // parse the command line options
    cxxopts::Options options(argv[0], "A Polar Code Codec Simlator");
    options.positional_help("[optional args]").show_positional_help();

    options.allow_unrecognised_options().add_options()
        ("k,linfo", "The number of information bits", cxxopts::value<int>()->default_value("400"), "k")
        ("n,lcode", "The codeword size", cxxopts::value<int>()->default_value("512"), "n")
        ("r,coderate", "The code rate. If this presents, k is ignored.", cxxopts::value<float>()->default_value("0.8"), "r")
        ("fe", "The number of frame error", cxxopts::value<int>()->default_value("100"), "fe")
        ("seed", "Pseudorandom generator seed", cxxopts::value<int>()->default_value("0"), "seed")
        ("ebn0min", "The minimum Eb/N0", cxxopts::value<float>()->default_value("0.0"), "ebn0min")
        ("ebn0max", "The maximum Eb/N0", cxxopts::value<float>()->default_value("5.01"), "ebn0max")
        ("ebn0step", "The step of Eb/N0", cxxopts::value<float>()->default_value("0.25"), "ebn0step")
        ("help", "Print help");
    options.parse_positional({"input", "output", "positional"});

    auto opts = options.parse(argc, argv);
    if (opts.count("help"))
    {
        std::cout << options.help({"", "Group"}) << std::endl;
        exit(0);
    }

    // get the AFF3CT version
    const std::string v = "v" + std::to_string(tools::version_major()) + "." +
                                std::to_string(tools::version_minor()) + "." +
                                std::to_string(tools::version_release());

    std::cout << "#-----------------------------------------------------------------"        << std::endl;
    std::cout << "# This is a Polar Code simulator using the AFF3CT library (" << v << ")" << std::endl;
    std::cout << "#-----------------------------------------------------------------"        << std::endl;
    std::cout << "#"                                                                       << std::endl;

    params p;  init_params (p, opts); // create and initialize the parameters defined by the user
    buffers b; init_buffers(p, b   ); // create and initialize the buffers required by the modules
    modules m; init_modules(p, m, b); // create and initialize the modules
    utils u;   init_utils  (m, u   ); // create and initialize the utils

    // display the legend in the terminal
    u.terminal->legend();

    // loop over the various SNRs
    for (auto ebn0 = p.ebn0_min; ebn0 < p.ebn0_max; ebn0 += p.ebn0_step)
    {
        // compute the current sigma for the channel noise
        const auto esn0  = tools::ebn0_to_esn0 (ebn0, p.R);
        const auto sigma = tools::esn0_to_sigma(esn0     );

        u.noise->set_noise(sigma, ebn0, esn0);

        // update the sigma of the modem, the channel and the frozen bits
        m.modem  ->set_noise(*u.noise);
        m.channel->set_noise(*u.noise);
        m.frozen ->set_noise(*u.noise);

        // generate frozen bits for current SNR settings
        m.frozen ->generate(b.frozen_bits);

        // update the Polar encoder and decoder's frozen bits
        m.encoder = std::unique_ptr<module::Encoder_polar<>>(new module::Encoder_polar<>(p.K, p.N, b.frozen_bits));
        m.decoder = std::unique_ptr<module::Decoder_polar_SC_naive<>>(new module::Decoder_polar_SC_naive<>(p.K, p.N, b.frozen_bits));

        // display the performance (BER and FER) in real time (in a separate thread)
        u.terminal->start_temp_report();

        // run the simulation chain
        while (!m.monitor->fe_limit_achieved() && !u.terminal->is_interrupt())
        {
            m.source ->generate    (                 b.ref_bits     );
            m.encoder->encode      (b.ref_bits,      b.enc_bits     );
            m.modem  ->modulate    (b.enc_bits,      b.symbols      );
            m.channel->add_noise   (b.symbols,       b.noisy_symbols);
            m.modem  ->demodulate  (b.noisy_symbols, b.LLRs         );
            m.decoder->decode_siho (b.LLRs,          b.dec_bits     );
            m.monitor->check_errors(b.dec_bits,      b.ref_bits     );
        }

        // display the performance (BER and FER) in the terminal
        u.terminal->final_report();

        // reset the monitor for the next SNR
        m.monitor->reset();
        u.terminal->reset();

        // if user pressed Ctrl+c twice, exit the SNRs loop
        if (u.terminal->is_over()) break;
    }

    std::cout << "# End of the simulation" << std::endl;

    return 0;
}
ibarron9216 commented 4 years ago

Hi @SubtleMuffin

Once again thanks for the help! Indeed changing 2.0f * ((double) tmp) - 1.0f to -(2.0f * ((double) tmp) - 1.0f) for the BPSK modulation allowed the polar code to be successfully encoded and decoded in a noiseless channel.

However, there was still one major issue. In my code, I have a BSC and if I assign p=0.001 then the message is not correctly decoded. In other words, after the BSC my decoded message have some error bits. Even at the extreme case when I only flip a single bit (which can be seen in my code), the decoder is not able to correct the error. Yet, after using the frozen bits generator, now I am able to decode for p=0.05! I am going to do further testing and some code cleaning and then I will submit here the result and close the issue.

Let me know if there is anything I can help you with or if you have questions.

ibarron9216 commented 3 years ago

Hi @SubtleMuffin

I apologize for taking so long to reply back. I had other commitments and worked on the background on this code, but I got the code to work with polar encoding/decoding aided by CRC.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>
#include <math.h>
#include <stack>          // std::stack
#include <cmath>       /* log */
#include <sstream>      // std::stringstream
#include <fstream>
#include <iomanip>      // std::setprecision
#include <random>
#include <chrono>

#include <aff3ct.hpp>

using namespace std;
using namespace aff3ct;

void initializeIntegerArrayToRandom(int* arr, int length)
{
   for(int i = 0; i < length; ++ i ){
        arr[i] = (int) (rand() % 2);
    }
}

float computeBER(int* messageBits, int* decodedBits, int length)
{
    float BER = 0;
    for(int i = 0; i < length; ++ i ){
        if (decodedBits[i]!=messageBits[i])
            BER = BER+1;
    }

    BER = (float)BER/length;
    return BER;
}

int useBSC(int* inputBits, int* outputBits, int length, float p)
{

    int flippedBits = 0;
    for(int i = 0; i < length; ++ i )
    {
     if ((rand() % 100) < (p*100))
     {
        if (inputBits[i] == 1)
        {
            outputBits[i] = 0;
        }
        else
        {
            outputBits[i] = 1;
        }
        flippedBits = flippedBits+1;
     }
     else
        outputBits[i] = inputBits[i];
    }
    return flippedBits;

}

void performBPSK(int* encodedMessageBits, float* encodedMessageBitsBPSK, int length)
{
    double bpskValue;

    // Use BPSK modulation to modulate the encoded bits
    for(int i = 0; i < length; ++ i ) {
        bpskValue = -(2.0f * ((double) encodedMessageBits[i]) - 1.0f);
        encodedMessageBitsBPSK[i] = (float) bpskValue;
    }
}

void runPolarEncoderDecoderCRCExample(int K, int N, int L, int n_frames, float p, int crcSize)
{
    srand((unsigned)time(0));

    int messageBits[K-crcSize];
    int messageBitsWithCRC[K];
    initializeIntegerArrayToRandom(messageBits,(K-crcSize));

    int encodedBits[N];
    int BSC_encodedBits[N];

    float receivedSignal[N];

    int decodedMessageBits[K];

    std::vector<bool> frozeBits(N,0);
    float BER = 0;
    int flippedBits = 0;
    float rate = (float)K/N;

    std::unique_ptr<tools::Sigma<>> noise;
    noise = std::unique_ptr<tools::Sigma<>>(new tools::Sigma<>());
    // Compute and set the noise (sigma)
    float SNR_max  =  5.01f;
    const auto esn0  = tools::ebn0_to_esn0 (SNR_max, rate);
    const auto sigma = tools::esn0_to_sigma(esn0);
    noise->set_noise(sigma, SNR_max, esn0);

    // Create Frozen Bits Generator
    tools::Frozenbits_generator_5G frozenBitsGenerator(K,N);
    // Set the noise for the Frozen Bits Generator GA
    frozenBitsGenerator.set_noise(*noise);
    // Generate the frozen bits
    frozenBitsGenerator.generate(frozeBits);

    aff3ct::module::CRC_polynomial<int> crcObject((K-crcSize),"0x04C11DB7",crcSize);
    crcObject.build(messageBits,messageBitsWithCRC);

    aff3ct::module::Encoder_polar_sys<int> polarEncoder(K, N, frozeBits, n_frames);
    polarEncoder.encode(messageBitsWithCRC, encodedBits);

    // Simulate communication trough BSC and by using BPSK modulation
    flippedBits = useBSC(encodedBits,BSC_encodedBits,N,p);
    performBPSK(BSC_encodedBits,receivedSignal,N);

    aff3ct::module::Decoder_polar_SCL_naive_CA_sys<int, float> polarDecoder(K,N,L,frozeBits,crcObject);
    polarDecoder.decode_siho(receivedSignal,decodedMessageBits,n_frames);
    bool isCorrect = crcObject.check(decodedMessageBits);

    BER = computeBER(messageBitsWithCRC, decodedMessageBits, K);

    cout << "BER = " << BER << endl;
    cout << "Flipped Bits: " << flippedBits << endl;

}

int main()
{
    const int K = 256;
    const int N = 512;

    const int crcSize = 32;

    int L = 32;

    int n_frames = 1;

    float p = 0.1;

    runPolarEncoderDecoderCRCExample(K, N, L, n_frames, p, crcSize);

    return 0;
}

This code is not quite using the bootstrap example but it does show how you can use the aff3ct modules to use individual components.

SubtleMuffin commented 3 years ago

Hi @ibarron9216 , I am glad that you figured it out!

ibarron9216 commented 3 years ago

Hi @SubtleMuffin

Thanks! I have one question for you, since I have seen that you have also been trying several components of aff3ct. Have you used the polar puncturer successfully? I have been trying to use it but so far I have had no success.