Closed ibarron9216 closed 3 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.
@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;
}
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
[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;
}
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.
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.
Hi @ibarron9216 , I am glad that you figured it out!
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.
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:
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.