Skip to content

Commit

Permalink
Add Optional Encoding for Simulation
Browse files Browse the repository at this point in the history
- enabled if suitable generator matrix is provided
- the simulator encodes a random information word
and compares the decoded word to the initial codeword
  • Loading branch information
heat1q committed Nov 10, 2020
1 parent 5a6385d commit 6f67ed4
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 52 deletions.
21 changes: 13 additions & 8 deletions src/core/ldpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ namespace ldpc
{

ldpc_code::ldpc_code(const std::string &pcFileName)
: mMaxDC(0)
: mMaxDC(0),
mH(),
mG()
{
try
{
Expand All @@ -21,14 +23,17 @@ namespace ldpc
ldpc_code::ldpc_code(const std::string &pcFileName, const std::string &genFileName)
: ldpc_code(pcFileName)
{
try
if (!genFileName.empty())
{
read_G(genFileName);
}
catch (std::exception &e)
{
std::cout << "Error: ldpc_code(): " << e.what() << std::endl;
exit(EXIT_FAILURE);
try
{
read_G(genFileName);
}
catch (std::exception &e)
{
std::cout << "Error: ldpc_code(): " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/core/ldpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ namespace ldpc
const vec_u64 &shorten() const { return mShorten; };
// Maximum check node degree
u64 max_dc() const { return mMaxDC; };
// Index position of transmitted bits
const vec_u64 &bit_pos() const { return mBitPos; }
// Parity-check matrix
const sparse_csr<bits_t> &H() const { return mH; }
Expand Down
1 change: 1 addition & 0 deletions src/core/sparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace ldpc
const std::vector<std::vector<node>> &col_neighbor() const { return colN; }
const std::vector<std::vector<node>> &row_neighbor() const { return rowN; }
const std::vector<edge<T>> &nz_entry() const { return nonZeroVals; }
bool empty() const { return ((numCols == 0) && (numRows == 0)); }

private:
int numCols; // number of columns
Expand Down
3 changes: 3 additions & 0 deletions src/decoding/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ namespace ldpc
const vec_double_t &lc2v() const { return mLc2v; }
const vec_double_t &llr_out() const { return mLLROut; }

// The current estimated codeword
const vec_bits_t &estimate() const { return mCO; }

static inline constexpr int sign(const double x);
static inline constexpr double jacobian(const double x, const double y);
static inline constexpr double minsum(const double x, const double y);
Expand Down
79 changes: 45 additions & 34 deletions src/sim/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ namespace ldpc
channel::channel(const std::shared_ptr<ldpc_code> &code, std::shared_ptr<ldpc_decoder> decoder, const u64 seed)
: mLdpcCode(code),
mLdpcDecoder(decoder),
mRNGSeed(seed),
mRNGEngine(std::mt19937_64(seed))
mRNG(seed),
mRandInfoWord(std::bind(std::bernoulli_distribution(0.5), std::mt19937_64(seed << 1))),
mInfoWord(vec_bits_t(code->kc(), 0)),
mCodeWord(vec_bits_t(code->nc(), 0))
{
}

void channel::set_channel_param(const double channelParam) {}
void channel::encode_and_map() {}
void channel::simulate() {}
void channel::calculate_llrs() {}

Expand All @@ -20,38 +23,43 @@ namespace ldpc
mY(vec_double_t(code->nct())),
mSNR(snr),
mSigma2(pow(10, -snr / 10)),
mRandNormal(std::normal_distribution<double>(0., sqrt(mSigma2)))
mRandNormal(std::bind(std::normal_distribution<double>(0., sqrt(mSigma2)), mRNG))
{
}

/**
* @brief Update the noise variance and reinitialize the RNG.
*
* @param channelParam SNR defined as E_s / \sigma^2, E_s = 1.
*/
void channel_awgn::set_channel_param(const double channelParam)
{
mSNR = channelParam;
mSigma2 = pow(10, -mSNR / 10);
mRandNormal = std::normal_distribution<double>(0., sqrt(mSigma2));
mRandNormal = std::bind(std::normal_distribution<double>(0., sqrt(mSigma2)), mRNG);
}

void channel_awgn::encode_and_map()
{
for (auto &u : mInfoWord)
{
u = mRandInfoWord();
}

mLdpcCode->G().multiply_left(mInfoWord, mCodeWord);

// only select transmitted codeword bits
for (int i = 0; i < mLdpcCode->nct(); ++i)
{
// 0 --> +1
// 1 --> -1
mX[i] = 1 - (2 * mCodeWord[mLdpcCode->bit_pos()[i]].value);
}
}

/**
* @brief Simulate the binary-input (biAWGN) channel with noise variance \sigma^2.
*
*/
void channel_awgn::simulate()
{
for (int i = 0; i < mLdpcCode->nct(); ++i)
{
mY[i] = mRandNormal(mRNGEngine) + mX[i]; // x \in {-1,+1}
mY[i] = mRandNormal() + mX[i]; // x \in {-1,+1}
}
}

/**
* @brief Calculate the LLR values for the biAWGN channel.
*
*/
void channel_awgn::calculate_llrs()
{
//puncturing & shortening
Expand Down Expand Up @@ -82,37 +90,40 @@ namespace ldpc
mX(vec_bits_t(code->nct(), 0)), // initialize to all zero cw
mY(vec_bits_t(code->nct())),
mEpsilon(epsilon),
mRandBernoulli(std::bernoulli_distribution(epsilon))
mRandBernoulli(std::bind(std::bernoulli_distribution(epsilon), mRNG))
{
}

/**
* @brief Update the crossover probability and reinitialize the RNG.
*
* @param channelParam \espilon < 0.5
*/
void channel_bsc::encode_and_map()
{
for (auto &u : mInfoWord)
{
u = mRandInfoWord();
}

mLdpcCode->G().multiply_left(mInfoWord, mCodeWord);

// only select transmitted codeword bits
for (int i = 0; i < mLdpcCode->nct(); ++i)
{
mX[i] = mCodeWord[mLdpcCode->bit_pos()[i]];
}
}

void channel_bsc::set_channel_param(const double channelParam)
{
mEpsilon = channelParam;
mRandBernoulli = std::bernoulli_distribution(mEpsilon);
mRandBernoulli = std::bind(std::bernoulli_distribution(mEpsilon), mRNG);
}

/**
* @brief Simulate the Binary Symmetric Channel (BSC) with crossover probability \epsilon.
*
*/
void channel_bsc::simulate()
{
for (int i = 0; i < mLdpcCode->nct(); ++i)
{
mY[i] = mRandBernoulli(mRNGEngine); // generate a 1 with probability epsilon
mY[i] = mX[i] + mRandBernoulli(); // flip bit with probability epsilon
}
}

/**
* @brief Calculate the LLR values for the BSC.
*
*/
void channel_bsc::calculate_llrs()
{
const double delta = log((1 - mEpsilon) / mEpsilon);
Expand Down
70 changes: 64 additions & 6 deletions src/sim/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,32 @@ namespace ldpc
// set param and update rng stream
virtual void set_channel_param(const double channelParam);

virtual void encode_and_map();
virtual void simulate();
virtual void calculate_llrs();

// Current transmitted codeword
const vec_bits_t &codeword() const { return mCodeWord; }

// Current encoded information word
const vec_bits_t &infoword() const { return mInfoWord; }

protected:
// ptr to const ldpc_code for parameters
std::shared_ptr<ldpc_code> mLdpcCode;

// hold the unique decoder for this channel
// Holds the unique decoder for this channel
std::shared_ptr<ldpc_decoder> mLdpcDecoder;

// rng params
const u64 mRNGSeed;
std::mt19937_64 mRNGEngine;
// RNG engine
std::mt19937_64 mRNG;

// RNG for encoding information word
std::function<bool()> mRandInfoWord;

// Information word
vec_bits_t mInfoWord;
vec_bits_t mCodeWord;
};

class channel_awgn : public channel
Expand All @@ -35,10 +49,32 @@ namespace ldpc
channel_awgn(const std::shared_ptr<ldpc_code> &code, std::shared_ptr<ldpc_decoder> decoder, const u64 seed, const double snr);
virtual ~channel_awgn() = default;

/**
* @brief Update the noise variance and reinitialize the RNG.
*
* @param channelParam SNR defined as E_s / sigma^2, E_s = 1.
*/
void set_channel_param(const double channelParam) override;

/**
* @brief Encodes an randomly chosen information word and maps
* it to the channel input.
*
*/
void encode_and_map() override;

/**
* @brief Simulate the binary-input (biAWGN) channel with noise variance sigma^2.
*
*/
void simulate() override;

/**
* @brief Calculate the LLR values for the biAWGN channel.
*
*/
void calculate_llrs() override;

private:
//channel i/o
vec_double_t mX;
Expand All @@ -48,7 +84,7 @@ namespace ldpc
double mSNR;
double mSigma2;

std::normal_distribution<double> mRandNormal;
std::function<double()> mRandNormal;
};

class channel_bsc : public channel
Expand All @@ -58,10 +94,32 @@ namespace ldpc
channel_bsc(const std::shared_ptr<ldpc_code> &code, std::shared_ptr<ldpc_decoder> decoder, const u64 seed, const double epsilon);
virtual ~channel_bsc() = default;

/**
* @brief Update the crossover probability and reinitialize the RNG.
*
* @param channelParam espilon < 0.5
*/
void set_channel_param(const double channelParam) override;

/**
* @brief Encodes an randomly chosen information word and maps
* it to the channel input.
*
*/
void encode_and_map() override;

/**
* @brief Simulate the Binary Symmetric Channel (BSC) with crossover probability \epsilon.
*
*/
void simulate() override;

/**
* @brief Calculate the LLR values for the BSC.
*
*/
void calculate_llrs() override;

private:
//channel i/o
vec_bits_t mX;
Expand All @@ -70,6 +128,6 @@ namespace ldpc
// crossover probability
double mEpsilon;

std::bernoulli_distribution mRandBernoulli;
std::function<bool()> mRandBernoulli;
};
} // namespace ldpc
10 changes: 8 additions & 2 deletions src/sim/ldpcsim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ namespace ldpc

do
{
if (!mLdpcCode->G().empty())
{
mChannel[tid]->encode_and_map();
}

// calculate the channel transitions
mChannel[tid]->simulate();

Expand All @@ -171,10 +176,11 @@ namespace ldpc
#pragma omp atomic update
++frames;

// count the bit errors
bec_tmp = 0;
for (int j = 0; j < mLdpcCode->nc(); ++j)
for (auto ci : mLdpcCode->bit_pos())
{
bec_tmp += (mLdpcDecoder[tid]->llr_out()[j] <= 0);
bec_tmp += (mLdpcDecoder[tid]->estimate()[ci] != mChannel[tid]->codeword()[ci]);
}

if (bec_tmp > 0)
Expand Down
7 changes: 5 additions & 2 deletions src/sim_cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ int main(int argc, char *argv[])
parser.add_argument("output-file").help("Results output file.");
parser.add_argument("snr-range").help("{MIN} {MAX} {STEP}").nargs(3).action([](const std::string &s) { return std::stod(s); });

parser.add_argument("-G", "--gen-matrix").help("Generator matrix file, compressed sparse row (CSR) format.").default_value(std::string(""));

parser.add_argument("-i", "--num-iterations").help("Number of iterations for decoding. (Default: 50)").default_value(unsigned(50)).action([](const std::string &s) { return static_cast<unsigned>(std::stoul(s)); });
parser.add_argument("-s", "--seed").help("RNG seed. (Default: 0)").default_value(ldpc::u64(0)).action([](const std::string &s) { return std::stoul(s); });
parser.add_argument("-t", "--num-threads").help("Number of frames to be decoded in parallel. (Default: 1)").default_value(unsigned(1)).action([](const std::string &s) { return static_cast<unsigned>(std::stoul(s)); });
Expand All @@ -26,9 +28,10 @@ int main(int argc, char *argv[])
auto snr = parser.get<ldpc::vec_double_t>("snr-range");
if (snr[0] > snr[1]) throw std::runtime_error("snr min > snr max");

std::shared_ptr<ldpc::ldpc_code> code(new ldpc::ldpc_code(parser.get<std::string>("codefile")));
auto code = std::make_shared<ldpc::ldpc_code>(parser.get<std::string>("codefile"), parser.get<std::string>("-G"));
std::cout << "========================================================================================" << std::endl;
std::cout << "codefile: " << parser.get<std::string>("codefile") << std::endl;
std::cout << "Parity-Check Matrix: " << parser.get<std::string>("codefile") << std::endl;
std::cout << "Generator Matrix: " << parser.get<std::string>("-G") << std::endl;
std::cout << *code << std::endl;
std::cout << "========================================================================================" << std::endl;

Expand Down

0 comments on commit 6f67ed4

Please sign in to comment.