int main(int argc, char **argv)
{
int nC;
int nRx;
int nTx;
int Tc;
if (argc != 5) {
cout << "Usage: cm nTx nRx nC Tc" << endl << "Example: cm 2 2 1 100000 (2x2 QPSK MIMO on slow fading channel)" << endl;
exit(1);
}
else {
sscanf(argv[1], "%i", &nTx);
sscanf(argv[2], "%i", &nRx);
sscanf(argv[3], "%i", &nC);
sscanf(argv[4], "%i", &Tc);
}
cout << "Initializing.. " << nTx << " TX antennas, " << nRx << " RX antennas, "
<< (1 << nC) << "-PAM per dimension, coherence time " << Tc << endl;
const vec EbN0db =
"-5:0.5:50";
const int Nmethods = 2;
const int Nbitsmax = 50000000;
const int Nu = 1000;
int Nbers, Nfers;
double BERmin, FERmin;
if (Tc == 1) {
BERmin = 0.001;
FERmin = 1.0e-10;
Nbers = 1000;
Nfers = 200;
}
else {
BERmin = 1.0e-15;
FERmin = 0.01;
Nbers = -1;
Nfers = 200;
}
Convolutional_Code code;
generator(0) = 0133;
generator(1) = 0165;
generator(2) = 0171;
double rate = 1.0 / 3.0;
code.set_generator_polynomials(generator, 7);
code.encode_tail(
randb(Nu), dummy);
const int Nctx = (int)(2 * nC * nTx *
ceil(
double(Nc) /
double(2 * nC * nTx)));
const int Nvec = Nctx / (2 * nC * nTx);
const int Nbitspvec = 2 * nC * nTx;
ND_UQAM chan;
chan.set_M(nTx, 1 << (2*nC));
cout << chan << endl;
Sequence_Interleaver<bin> sequence_interleaver_b(Nctx);
Sequence_Interleaver<int> sequence_interleaver_i(Nctx);
sequence_interleaver_b.randomize_interleaver_sequence();
sequence_interleaver_i.set_interleaver_sequence(sequence_interleaver_b.get_interleaver_sequence());
Array<cvec> Y(Nvec);
Array<cmat> H(Nvec / Tc + 1);
if (
pow(2.0, nC*2.0*nTx) > 256) {
Contflag(1) = 0;
}
if (nTx > nRx) {
Contflag(0) = 0;
}
cout << "Running methods: " << Contflag << endl;
cout.setf(ios::fixed, ios::floatfield);
cout.setf(ios::showpoint);
cout.precision(5);
for (
int nsnr = 0; nsnr <
length(EbN0db); nsnr++) {
const double Eb = 1.0;
const double N0 =
inv_dB(-EbN0db(nsnr));
const double sigma2 = N0;
const double Es = rate * 2 * nC * Eb;
const double Ess =
sqrt(Es);
Array<BERC> berc(Nmethods);
Array<BERC> bercu(Nmethods);
Array<BLERC> ferc(Nmethods);
for (int i = 0; i < Nmethods; i++) {
ferc(i).set_blocksize(Nu);
}
long int nbits = 0;
while (nbits < Nbitsmax) {
nbits += Nu;
code.encode_tail(inputbits, txbits);
txbits = sequence_interleaver_b.interleave(txbits);
for (int k = 0; k < Nvec; k++) {
if (k % Tc == 0) {
H(k / Tc) = Ess *
randn_c(nRx, nTx);
}
bvec bitstmp = txbits(k * 2 * nTx * nC, (k + 1) * 2 * nTx * nC - 1);
cvec x = chan.modulate_bits(bitstmp);
Y(k) = H(k / Tc) * x + e;
}
Array<QLLRvec> LLRin(Nmethods);
for (int i = 0; i < Nmethods; i++) {
}
for (int k = 0; k < Nvec; k++) {
if (Contflag(0)) {
chan.demodulate_soft_bits(Y(k), H(k / Tc), sigma2, llr_apr, llr_apost,
ND_UQAM::ZF_LOGMAP);
LLRin(0).set_subvector(k*Nbitspvec, llr_apost);
}
if (Contflag(1)) {
chan.demodulate_soft_bits(Y(k), H(k / Tc), sigma2, llr_apr, llr_apost);
LLRin(1).set_subvector(k*Nbitspvec, llr_apost);
}
}
for (int i = 0; i < Nmethods; i++) {
if (Contflag(i)) {
bercu(i).count(txbits(0, Nc - 1), LLRin(i)(0, Nc - 1) < 0);
LLRin(i) = sequence_interleaver_i.deinterleave(LLRin(i), 0);
vec llr = chan.get_llrcalc().to_double(LLRin(i).left(Nc));
code.decode_tail(llr, decoded_bits);
berc(i).count(inputbits(0, Nu - 1), decoded_bits(0, Nu - 1));
ferc(i).count(inputbits(0, Nu - 1), decoded_bits(0, Nu - 1));
}
}
int minber = 1000000;
int minfer = 1000000;
for (int i = 0; i < Nmethods; i++) {
if (Contflag(i)) {
minber =
min(minber,
round_i(berc(i).get_errors()));
minfer =
min(minfer,
round_i(ferc(i).get_errors()));
}
}
if (Nbers > 0 && minber > Nbers) { break;}
if (Nfers > 0 && minfer > Nfers) { break;}
}
cout << "-----------------------------------------------------" << endl;
cout << "Eb/N0: " << EbN0db(nsnr) << " dB. Simulated " << nbits << " bits." << endl;
cout << " Uncoded BER: " << bercu(0).get_errorrate() << " (ZF); " << bercu(1).get_errorrate() << " (ML)" << endl;
cout << " Coded BER: " << berc(0).get_errorrate() << " (ZF); " << berc(1).get_errorrate() << " (ML)" << endl;
cout << " Coded FER: " << ferc(0).get_errorrate() << " (ZF); " << ferc(1).get_errorrate() << " (ML)" << endl;
cout.flush();
int contflag = 0;
for (int i = 0; i < Nmethods; i++) {
if (Contflag(i)) {
if (berc(i).get_errorrate() > BERmin) { contflag = 1; }
else { Contflag(i) = 0; }
if (ferc(i).get_errorrate() > FERmin) { contflag = 1; }
else { Contflag(i) = 0; }
}
}
if (contflag) { continue; }
else {break; }
}
return 0;
}
Vec< double > vec
Definition of double vector type.
Vec< int > ivec
Definition of integer vector type.
Vec< bin > bvec
Definition of binary vector type.
Vec< std::complex< double > > cvec
Definition of complex<double> vector type.
vec pow(const double x, const vec &y)
Calculates x to the power of y (x^y)
double inv_dB(double x)
Inverse of decibel of x.
int length(const Vec< T > &v)
Length of vector.
T min(const Vec< T > &in)
Minimum value of vector.
vec sqrt(const vec &x)
Square root of the elements.
std::complex< double > randn_c(void)
Generates a random complex Gaussian (0,1) variable.
bin randb(void)
Generates a random bit (equally likely 0s and 1s)
ITPP_EXPORT ivec ones_i(int size)
A Int vector of ones.
ITPP_EXPORT ivec zeros_i(int size)
A Int vector of zeros.
Include file for the IT++ communications module.
ITPP_EXPORT int round_i(double x)
Round to nearest integer.
vec ceil(const vec &x)
Round to nearest upper integer.
const Array< T > concat(const Array< T > &a, const T &e)
Append element e to the end of the Array a.