modulator.cpp
Go to the documentation of this file.
#include <itpp/comm/modulator.h>
#include <itpp/comm/commfunc.h>
#include <itpp/base/math/elem_math.h>
#include <itpp/base/specmat.h>
namespace itpp
{
//MSVC explicitely instantiate required template while building the shared library
template class ITPP_EXPORT Modulator<double>;
template class ITPP_EXPORT Modulator<std::complex<double> >;
// ----------------------------------------------------------------------
// QAM
// ----------------------------------------------------------------------
void QAM::set_M(int Mary)
{
k = levels2bits(Mary);
M = Mary;
it_assert((pow2i(k) == M) && (is_even(k)),
"QAM::set_M(): M = " << M << " is not an even power of 2");
L = round_i(std::sqrt(static_cast<double>(M)));
double average_energy = (M - 1) * 2.0 / 3.0;
scaling_factor = std::sqrt(average_energy);
symbols.set_size(M);
bitmap.set_size(M, k);
bits2symbols.set_size(M);
bmat gray_code = graycode(levels2bits(L));
for (int i = 0; i < L; i++) {
for (int j = 0; j < L; j++) {
symbols(i*L + j) = std::complex<double>(((L - 1) - j * 2) / scaling_factor,
((L - 1) - i * 2) / scaling_factor);
bitmap.set_row(i*L + j, concat(gray_code.get_row(i),
gray_code.get_row(j)));
bits2symbols(bin2dec(bitmap.get_row(i*L + j))) = i * L + j;
}
}
calculate_softbit_matrices();
setup_done = true;
}
void QAM::demodulate_bits(const cvec &signal, bvec &out) const
{
it_assert_debug(setup_done, "QAM::demodulate_bits(): Modulator not ready.");
out.set_size(k*signal.size(), false);
int temp_real, temp_imag;
for (int i = 0; i < signal.size(); i++) {
temp_real = round_i((L - 1) - (std::real(signal(i) * scaling_factor)
+ (L - 1)) / 2.0);
temp_imag = round_i((L - 1) - (std::imag(signal(i) * scaling_factor)
+ (L - 1)) / 2.0);
if (temp_real < 0)
temp_real = 0;
else if (temp_real > (L - 1))
temp_real = (L - 1);
if (temp_imag < 0)
temp_imag = 0;
else if (temp_imag > (L - 1))
temp_imag = (L - 1);
out.replace_mid(k*i, bitmap.get_row(temp_imag * L + temp_real));
}
}
bvec QAM::demodulate_bits(const cvec &signal) const
{
bvec out;
demodulate_bits(signal, out);
return out;
}
// ----------------------------------------------------------------------
// PSK
// ----------------------------------------------------------------------
void PSK::set_M(int Mary)
{
k = levels2bits(Mary);
M = Mary;
it_assert(pow2i(k) == M, "PSK::set_M(): M is not a power of 2");
symbols.set_size(M);
bitmap = graycode(k);
bits2symbols.set_size(M);
double delta = m_2pi / M;
double epsilon = delta / 10000.0;
std::complex<double> symb;
for (int i = 0; i < M; i++) {
symb = std::complex<double>(std::polar(1.0, delta * i));
if (std::fabs(std::real(symb)) < epsilon) {
symbols(i) = std::complex<double>(0.0, std::imag(symb));
}
else if (std::fabs(std::imag(symb)) < epsilon) {
symbols(i) = std::complex<double>(std::real(symb), 0.0);
}
else {
symbols(i) = symb;
}
bits2symbols(bin2dec(bitmap.get_row(i))) = i;
}
calculate_softbit_matrices();
setup_done = true;
}
void PSK::demodulate_bits(const cvec &signal, bvec &out) const
{
it_assert_debug(setup_done, "PSK::demodulate_bits(): Modulator not ready.");
int est_symbol;
double ang, temp;
out.set_size(k*signal.size(), false);
for (int i = 0; i < signal.size(); i++) {
ang = std::arg(signal(i));
temp = (ang < 0) ? (m_2pi + ang) : ang;
est_symbol = round_i(temp * (M >> 1) / pi) % M;
out.replace_mid(i*k, bitmap.get_row(est_symbol));
}
}
bvec PSK::demodulate_bits(const cvec &signal) const
{
bvec out;
demodulate_bits(signal, out);
return out;
}
// ----------------------------------------------------------------------
// QPSK
// ----------------------------------------------------------------------
void QPSK::demodulate_soft_bits(const cvec &rx_symbols, double N0,
vec &soft_bits, Soft_Method) const
{
soft_bits.set_size(k * rx_symbols.size());
std::complex<double> temp;
double factor = 2 * std::sqrt(2.0) / N0;
std::complex<double> exp_pi4 = std::complex<double>(std::cos(pi / 4),
std::sin(pi / 4));
for (int i = 0; i < rx_symbols.size(); i++) {
temp = rx_symbols(i) * exp_pi4;
soft_bits((i << 1) + 1) = std::real(temp) * factor;
soft_bits(i << 1) = std::imag(temp) * factor;
}
}
vec QPSK::demodulate_soft_bits(const cvec &rx_symbols, double N0,
Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, N0, out, method);
return out;
}
void QPSK::demodulate_soft_bits(const cvec &rx_symbols, const cvec &channel,
double N0, vec &soft_bits,
Soft_Method) const
{
soft_bits.set_size(2*rx_symbols.size(), false);
std::complex<double> temp;
double factor = 2 * std::sqrt(2.0) / N0;
std::complex<double> exp_pi4 = std::complex<double>(std::cos(pi / 4),
std::sin(pi / 4));
for (int i = 0; i < rx_symbols.size(); i++) {
temp = rx_symbols(i) * std::conj(channel(i)) * exp_pi4;
soft_bits((i << 1) + 1) = std::real(temp) * factor;
soft_bits(i << 1) = std::imag(temp) * factor;
}
}
vec QPSK::demodulate_soft_bits(const cvec &rx_symbols, const cvec &channel,
double N0, Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, channel, N0, out, method);
return out;
}
// ----------------------------------------------------------------------
// BPSK_c
// ----------------------------------------------------------------------
void BPSK_c::modulate_bits(const bvec &bits, cvec &out) const
{
out.set_size(bits.size(), false);
for (int i = 0; i < bits.size(); i++) {
out(i) = (bits(i) == 0 ? 1.0 : -1.0);
}
}
cvec BPSK_c::modulate_bits(const bvec &bits) const
{
cvec out(bits.size());
modulate_bits(bits, out);
return out;
}
void BPSK_c::demodulate_bits(const cvec &signal, bvec &out) const
{
out.set_size(signal.size(), false);
for (int i = 0; i < signal.length(); i++) {
out(i) = (std::real(signal(i)) > 0) ? bin(0) : bin(1);
}
}
bvec BPSK_c::demodulate_bits(const cvec &signal) const
{
bvec out(signal.size());
demodulate_bits(signal, out);
return out;
}
void BPSK_c::demodulate_soft_bits(const cvec &rx_symbols, double N0,
vec &soft_bits, Soft_Method) const
{
double factor = 4 / N0;
soft_bits.set_size(rx_symbols.size(), false);
for (int i = 0; i < rx_symbols.size(); i++) {
soft_bits(i) = factor * std::real(rx_symbols(i));
}
}
vec BPSK_c::demodulate_soft_bits(const cvec &rx_symbols, double N0,
Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, N0, out, method);
return out;
}
void BPSK_c::demodulate_soft_bits(const cvec &rx_symbols,
const cvec &channel,
double N0, vec &soft_bits,
Soft_Method) const
{
double factor = 4 / N0;
soft_bits.set_size(rx_symbols.size(), false);
for (int i = 0; i < rx_symbols.size(); i++) {
soft_bits(i) = factor * std::real(rx_symbols(i) * std::conj(channel(i)));
}
}
vec BPSK_c::demodulate_soft_bits(const cvec &rx_symbols, const cvec &channel,
double N0, Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, channel, N0, out, method);
return out;
}
// ----------------------------------------------------------------------
// BPSK
// ----------------------------------------------------------------------
void BPSK::modulate_bits(const bvec &bits, vec &out) const
{
out.set_size(bits.size(), false);
for (int i = 0; i < bits.size(); i++) {
out(i) = (bits(i) == 0 ? 1.0 : -1.0);
}
}
vec BPSK::modulate_bits(const bvec &bits) const
{
vec out(bits.size());
modulate_bits(bits, out);
return out;
}
void BPSK::demodulate_bits(const vec &signal, bvec &out) const
{
out.set_size(signal.size(), false);
for (int i = 0; i < signal.length(); i++) {
out(i) = (signal(i) > 0) ? bin(0) : bin(1);
}
}
bvec BPSK::demodulate_bits(const vec &signal) const
{
bvec out(signal.size());
demodulate_bits(signal, out);
return out;
}
void BPSK::demodulate_soft_bits(const vec &rx_symbols, double N0,
vec &soft_bits, Soft_Method) const
{
double factor = 4 / N0;
soft_bits.set_size(rx_symbols.size(), false);
for (int i = 0; i < rx_symbols.size(); i++) {
soft_bits(i) = factor * rx_symbols(i);
}
}
vec BPSK::demodulate_soft_bits(const vec &rx_symbols, double N0,
Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, N0, out, method);
return out;
}
void BPSK::demodulate_soft_bits(const vec &rx_symbols, const vec &channel,
double N0, vec &soft_bits,
Soft_Method) const
{
double factor = 4 / N0;
soft_bits.set_size(rx_symbols.size(), false);
for (int i = 0; i < rx_symbols.size(); i++) {
soft_bits(i) = factor * (rx_symbols(i) * channel(i));
}
}
vec BPSK::demodulate_soft_bits(const vec &rx_symbols, const vec &channel,
double N0, Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, channel, N0, out, method);
return out;
}
// ----------------------------------------------------------------------
// PAM_c
// ----------------------------------------------------------------------
void PAM_c::set_M(int Mary)
{
M = Mary;
k = levels2bits(M);
it_assert(pow2i(k) == M, "PAM_c::set_M(): M is not a power of 2");
symbols.set_size(M, false);
bits2symbols.set_size(M, false);
bitmap = graycode(k);
double average_energy = (sqr(M) - 1) / 3.0;
scaling_factor = std::sqrt(average_energy);
for (int i = 0; i < M; i++) {
symbols(i) = ((M - 1) - i * 2) / scaling_factor;
bits2symbols(bin2dec(bitmap.get_row(i))) = i;
}
calculate_softbit_matrices();
setup_done = true;
}
void PAM_c::demodulate_bits(const cvec &signal, bvec &out) const
{
it_assert_debug(setup_done, "PAM_c::demodulate_bits(): Modulator not ready.");
int est_symbol;
out.set_size(k*signal.size(), false);
for (int i = 0; i < signal.size(); i++) {
est_symbol = round_i((M - 1) - (std::real(signal(i)) * scaling_factor
+ (M - 1)) / 2);
if (est_symbol < 0)
est_symbol = 0;
else if (est_symbol > (M - 1))
est_symbol = M - 1;
out.replace_mid(i*k, bitmap.get_row(est_symbol));
}
}
bvec PAM_c::demodulate_bits(const cvec &signal) const
{
bvec temp(signal.size());
demodulate_bits(signal, temp);
return temp;
}
void PAM_c::demodulate_soft_bits(const cvec &rx_symbols, double N0,
vec &soft_bits, Soft_Method method) const
{
it_assert_debug(setup_done, "PAM_c::demodulate_soft_bits(): Modulator not ready.");
double P0, P1, d0min, d1min, temp;
vec metric(M);
soft_bits.set_size(k * rx_symbols.size());
if (method == LOGMAP) {
for (int l = 0; l < rx_symbols.size(); l++) {
for (int j = 0; j < M; j++) {
metric(j) = std::exp(-sqr(std::real(rx_symbols(l) - symbols(j)))
/ N0);
}
for (int i = 0; i < k; i++) {
P0 = P1 = 0;
for (int j = 0; j < (M >> 1); j++) {
P0 += metric(S0(i, j));
P1 += metric(S1(i, j));
}
soft_bits(l*k + i) = trunc_log(P0) - trunc_log(P1);
}
}
}
else { // method == APPROX
for (int l = 0; l < rx_symbols.size(); l++) {
for (int j = 0; j < M; j++) {
metric(j) = sqr(std::real(rx_symbols(l) - symbols(j)));
}
for (int i = 0; i < k; i++) {
d0min = d1min = std::numeric_limits<double>::max();
for (int j = 0; j < (M >> 1); j++) {
temp = metric(S0(i, j));
if (temp < d0min) { d0min = temp; }
temp = metric(S1(i, j));
if (temp < d1min) { d1min = temp; }
}
soft_bits(l*k + i) = (-d0min + d1min) / N0;
}
}
}
}
vec PAM_c::demodulate_soft_bits(const cvec &rx_symbols, double N0,
Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, N0, out, method);
return out;
}
void PAM_c::demodulate_soft_bits(const cvec &rx_symbols, const cvec &channel,
double N0, vec &soft_bits,
Soft_Method method) const
{
it_assert_debug(setup_done, "PAM_c::demodulate_soft_bits(): Modulator not ready.");
double P0, P1, d0min, d1min, temp;
vec metric(M);
soft_bits.set_size(k * rx_symbols.size());
if (method == LOGMAP) {
for (int l = 0; l < rx_symbols.size(); l++) {
for (int j = 0; j < M; j++) {
metric(j) = std::exp(-sqr(std::real(rx_symbols(l)
- channel(l) * symbols(j))) / N0);
}
for (int i = 0; i < k; i++) {
P0 = P1 = 0;
for (int j = 0; j < (M >> 1); j++) {
P0 += metric(S0(i, j));
P1 += metric(S1(i, j));
}
soft_bits(l*k + i) = trunc_log(P0) - trunc_log(P1);
}
}
}
else { // method == APPROX
for (int l = 0; l < rx_symbols.size(); l++) {
for (int j = 0; j < M; j++) {
metric(j) = sqr(std::real(rx_symbols(l) - channel(l) * symbols(j)));
}
for (int i = 0; i < k; i++) {
d0min = d1min = std::numeric_limits<double>::max();
for (int j = 0; j < (M >> 1); j++) {
temp = metric(S0(i, j));
if (temp < d0min) { d0min = temp; }
temp = metric(S1(i, j));
if (temp < d1min) { d1min = temp; }
}
soft_bits(l*k + i) = (-d0min + d1min) / N0;
}
}
}
}
vec PAM_c::demodulate_soft_bits(const cvec &rx_symbols, const cvec &channel,
double N0, Soft_Method method) const
{
vec out;
demodulate_soft_bits(rx_symbols, channel, N0, out, method);
return out;
}
// ----------------------------------------------------------------------
// PAM
// ----------------------------------------------------------------------
void PAM::set_M(int Mary)
{
M = Mary;
k = levels2bits(M);
it_assert(pow2i(k) == M, "PAM::set_M(): M is not a power of 2");
symbols.set_size(M, false);
bits2symbols.set_size(M, false);
bitmap = graycode(k);
double average_energy = (sqr(M) - 1) / 3.0;
scaling_factor = std::sqrt(average_energy);
for (int i = 0; i < M; i++) {
symbols(i) = ((M - 1) - i * 2) / scaling_factor;
bits2symbols(bin2dec(bitmap.get_row(i))) = i;
}
calculate_softbit_matrices();
setup_done = true;
}
void PAM::demodulate_bits(const vec &signal, bvec &out) const
{
it_assert_debug(setup_done, "PAM::demodulate_bits(): Modulator not ready.");
int est_symbol;
out.set_size(k*signal.size(), false);
for (int i = 0; i < signal.size(); i++) {
est_symbol = round_i((M - 1) - (signal(i) * scaling_factor + (M - 1)) / 2);
if (est_symbol < 0)
est_symbol = 0;
else if (est_symbol > (M - 1))
est_symbol = M - 1;
out.replace_mid(i*k, bitmap.get_row(est_symbol));
}
}
bvec PAM::demodulate_bits(const vec &signal) const
{
bvec temp(signal.size());
demodulate_bits(signal, temp);
return temp;
}
} // namespace itpp
itpp::Array
General array class.
Definition array.h:105
itpp::Array::size
int size() const
Returns the number of data elements in the array object.
Definition array.h:155
itpp::Array::set_size
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
itpp::Array::length
int length() const
Returns the number of data elements in the array object.
Definition array.h:157
itpp::BPSK_c::demodulate_soft_bits
virtual void demodulate_soft_bits(const cvec &rx_symbols, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channel.
Definition modulator.cpp:264
itpp::BPSK_c::modulate_bits
void modulate_bits(const bvec &bits, cvec &output) const
Modulate bits into BPSK symbols in complex domain.
Definition modulator.cpp:232
itpp::BPSK_c::demodulate_bits
void demodulate_bits(const cvec &signal, bvec &output) const
Demodulate noisy BPSK symbols in complex domain into bits.
Definition modulator.cpp:248
itpp::BPSK::modulate_bits
void modulate_bits(const bvec &bits, vec &output) const
Modulate bits into BPSK symbols in complex domain.
Definition modulator.cpp:310
itpp::BPSK::demodulate_soft_bits
virtual void demodulate_soft_bits(const vec &rx_symbols, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channel.
Definition modulator.cpp:342
itpp::BPSK::demodulate_bits
void demodulate_bits(const vec &signal, bvec &output) const
Demodulate noisy BPSK symbols in complex domain into bits.
Definition modulator.cpp:326
itpp::Modulator< std::complex< double > >::bitmap
bmat bitmap
Bit to symbol mapping table (size: M x k)
Definition modulator.h:241
itpp::Modulator< std::complex< double > >::symbols
Vec< std::complex< double > > symbols
Corresponding modulation symbols (size: M)
Definition modulator.h:245
itpp::Modulator< std::complex< double > >::k
int k
Number of bits per modulation symbol.
Definition modulator.h:237
itpp::Modulator< std::complex< double > >::bits2symbols
ivec bits2symbols
Bit to symbol mapping in decimal form (size: M)
Definition modulator.h:243
itpp::Modulator< std::complex< double > >::setup_done
bool setup_done
Setup indicator.
Definition modulator.h:235
itpp::Modulator< std::complex< double > >::S1
imat S1
Matrix where row k contains the constellation points with '1' in bit position k.
Definition modulator.h:251
itpp::Modulator< std::complex< double > >::M
int M
Number of modulation symbols.
Definition modulator.h:239
itpp::Modulator< std::complex< double > >::calculate_softbit_matrices
void calculate_softbit_matrices()
This function calculates the soft bit mapping matrices S0 and S1.
Definition modulator.h:530
itpp::Modulator< std::complex< double > >::S0
imat S0
Matrix where row k contains the constellation points with '0' in bit position k.
Definition modulator.h:248
itpp::PAM_c::demodulate_soft_bits
virtual void demodulate_soft_bits(const cvec &rx_symbols, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channels.
Definition modulator.cpp:435
itpp::PAM_c::set_M
void set_M(int M)
Set the size of the signal constellation.
Definition modulator.cpp:387
itpp::PAM_c::demodulate_bits
void demodulate_bits(const cvec &signal, bvec &output) const
Hard demodulation of PAM symbols in complex domain to bits.
Definition modulator.cpp:410
itpp::PAM_c::scaling_factor
double scaling_factor
Scaling factor used to normalize the average energy to 1.
Definition modulator.h:1080
itpp::PAM::set_M
void set_M(int M)
Set the size of the signal constellation.
Definition modulator.cpp:546
itpp::PAM::scaling_factor
double scaling_factor
Scaling factor used to normalize the average energy to 1.
Definition modulator.h:1123
itpp::PAM::demodulate_bits
void demodulate_bits(const vec &signal, bvec &output) const
Hard demodulation of PAM symbols in complex domain to bits.
Definition modulator.cpp:569
itpp::PSK::set_M
void set_M(int M)
Change the size of the signal constellation.
Definition modulator.cpp:117
itpp::PSK::demodulate_bits
void demodulate_bits(const cvec &signal, bvec &bits) const
Hard demodulation of bits.
Definition modulator.cpp:151
itpp::QAM::scaling_factor
double scaling_factor
Scaling factor of square QAM constellation (sqrt((M-1)*2/3))
Definition modulator.h:607
itpp::QAM::demodulate_bits
void demodulate_bits(const cvec &signal, bvec &bits) const
Hard demodulation of bits.
Definition modulator.cpp:81
itpp::QAM::L
int L
The square-root of M.
Definition modulator.h:605
itpp::QAM::set_M
void set_M(int M)
Change the size of the signal constellation.
Definition modulator.cpp:48
itpp::QPSK::demodulate_soft_bits
virtual void demodulate_soft_bits(const cvec &rx_symbols, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channel.
Definition modulator.cpp:179
itpp::Vec::set_size
void set_size(int size, bool copy=false)
Set length of vector. if copy = true then keeping the old values.
Definition vec.h:663
itpp::bin
Binary arithmetic (boolean) class.
Definition binary.h:57
commfunc.h
Definitions of some specific functions useful in communications.
elem_math.h
Elementary mathematical functions - header file.
it_assert_debug
#define it_assert_debug(t, s)
Abort if t is not true and NDEBUG is not defined.
Definition itassert.h:107
it_assert
#define it_assert(t, s)
Abort if t is not true.
Definition itassert.h:94
itpp::trunc_log
double trunc_log(double x)
Truncated natural logarithm function.
Definition log_exp.h:115
itpp::pow2i
int pow2i(int x)
Calculate two to the power of x (2^x); x is integer.
Definition log_exp.h:53
itpp::levels2bits
int levels2bits(int n)
Calculate the number of bits needed to represent n different values (levels).
Definition log_exp.h:92
itpp::graycode
bmat graycode(int m)
Generate Gray code of blocklength m.
Definition commfunc.cpp:39
itpp::is_even
bool is_even(int x)
Return true if x is an even integer.
Definition misc.h:122
itpp::sqr
vec sqr(const cvec &data)
Absolute square of elements.
Definition elem_math.cpp:36
itpp::Soft_Method
Soft_Method
Soft demodulation methods.
Definition modulator.h:47
itpp::LOGMAP
@ LOGMAP
Log-MAP full calculation.
Definition modulator.h:48
bmat
Mat< bin > bmat
bin matrix
Definition mat.h:508
modulator.h
One- and two-dimensional modulators - header file.
itpp
itpp namespace
Definition itmex.h:37
itpp::round_i
ITPP_EXPORT int round_i(double x)
Round to nearest integer.
itpp::m_2pi
const double m_2pi
Constant 2*Pi.
Definition misc.h:106
itpp::bin2dec
ITPP_EXPORT int bin2dec(const bvec &inbvec, bool msb_first=true)
Convert a bvec to decimal int with the first bit as MSB if msb_first == true.
itpp::concat
const Array< T > concat(const Array< T > &a, const T &e)
Append element e to the end of the Array a.
Definition array.h:486
itpp::gray_code
int gray_code(int x)
Convert to Gray Code.
Definition converters.h:421
itpp::pi
const double pi
Constant Pi.
Definition misc.h:103
specmat.h
Definitions of special vectors and matrices.

Generated on Mon Jun 10 2024 11:49:21 for IT++ by Doxygen 1.9.8