Files
gr-ieee802-11/lib/frame_equalizer_impl.cc
Bastian Bloessl 4d1befbc05 fix formatting
2021-07-19 08:50:53 +02:00

375 lines
12 KiB
C++

/*
* Copyright (C) 2016 Bastian Bloessl <bloessl@ccs-labs.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "equalizer/base.h"
#include "equalizer/comb.h"
#include "equalizer/lms.h"
#include "equalizer/ls.h"
#include "equalizer/sta.h"
#include "frame_equalizer_impl.h"
#include "utils.h"
#include <gnuradio/io_signature.h>
namespace gr {
namespace ieee802_11 {
frame_equalizer::sptr
frame_equalizer::make(Equalizer algo, double freq, double bw, bool log, bool debug)
{
return gnuradio::get_initial_sptr(
new frame_equalizer_impl(algo, freq, bw, log, debug));
}
frame_equalizer_impl::frame_equalizer_impl(
Equalizer algo, double freq, double bw, bool log, bool debug)
: gr::block("frame_equalizer",
gr::io_signature::make(1, 1, 64 * sizeof(gr_complex)),
gr::io_signature::make(1, 1, 48)),
d_current_symbol(0),
d_log(log),
d_debug(debug),
d_equalizer(NULL),
d_freq(freq),
d_bw(bw),
d_frame_bytes(0),
d_frame_symbols(0),
d_freq_offset_from_synclong(0.0)
{
message_port_register_out(pmt::mp("symbols"));
d_bpsk = constellation_bpsk::make();
d_qpsk = constellation_qpsk::make();
d_16qam = constellation_16qam::make();
d_64qam = constellation_64qam::make();
d_frame_mod = d_bpsk;
set_tag_propagation_policy(block::TPP_DONT);
set_algorithm(algo);
}
frame_equalizer_impl::~frame_equalizer_impl() {}
void frame_equalizer_impl::set_algorithm(Equalizer algo)
{
gr::thread::scoped_lock lock(d_mutex);
delete d_equalizer;
switch (algo) {
case COMB:
dout << "Comb" << std::endl;
d_equalizer = new equalizer::comb();
break;
case LS:
dout << "LS" << std::endl;
d_equalizer = new equalizer::ls();
break;
case LMS:
dout << "LMS" << std::endl;
d_equalizer = new equalizer::lms();
break;
case STA:
dout << "STA" << std::endl;
d_equalizer = new equalizer::sta();
break;
default:
throw std::runtime_error("Algorithm not implemented");
}
}
void frame_equalizer_impl::set_bandwidth(double bw)
{
gr::thread::scoped_lock lock(d_mutex);
d_bw = bw;
}
void frame_equalizer_impl::set_frequency(double freq)
{
gr::thread::scoped_lock lock(d_mutex);
d_freq = freq;
}
void frame_equalizer_impl::forecast(int noutput_items,
gr_vector_int& ninput_items_required)
{
ninput_items_required[0] = noutput_items;
}
int frame_equalizer_impl::general_work(int noutput_items,
gr_vector_int& ninput_items,
gr_vector_const_void_star& input_items,
gr_vector_void_star& output_items)
{
gr::thread::scoped_lock lock(d_mutex);
const gr_complex* in = (const gr_complex*)input_items[0];
uint8_t* out = (uint8_t*)output_items[0];
int i = 0;
int o = 0;
gr_complex symbols[48];
gr_complex current_symbol[64];
dout << "FRAME EQUALIZER: input " << ninput_items[0] << " output " << noutput_items
<< std::endl;
while ((i < ninput_items[0]) && (o < noutput_items)) {
get_tags_in_window(tags, 0, i, i + 1, pmt::string_to_symbol("wifi_start"));
// new frame
if (tags.size()) {
d_current_symbol = 0;
d_frame_symbols = 0;
d_frame_mod = d_bpsk;
d_freq_offset_from_synclong =
pmt::to_double(tags.front().value) * d_bw / (2 * M_PI);
d_epsilon0 = pmt::to_double(tags.front().value) * d_bw / (2 * M_PI * d_freq);
d_er = 0;
dout << "epsilon: " << d_epsilon0 << std::endl;
}
// not interesting -> skip
if (d_current_symbol > (d_frame_symbols + 2)) {
i++;
continue;
}
std::memcpy(current_symbol, in + i * 64, 64 * sizeof(gr_complex));
// compensate sampling offset
for (int i = 0; i < 64; i++) {
current_symbol[i] *= exp(gr_complex(0,
2 * M_PI * d_current_symbol * 80 *
(d_epsilon0 + d_er) * (i - 32) / 64));
}
gr_complex p = equalizer::base::POLARITY[(d_current_symbol - 2) % 127];
double beta;
if (d_current_symbol < 2) {
beta = arg(current_symbol[11] - current_symbol[25] + current_symbol[39] +
current_symbol[53]);
} else {
beta = arg((current_symbol[11] * p) + (current_symbol[39] * p) +
(current_symbol[25] * p) + (current_symbol[53] * -p));
}
double er = arg((conj(d_prev_pilots[0]) * current_symbol[11] * p) +
(conj(d_prev_pilots[1]) * current_symbol[25] * p) +
(conj(d_prev_pilots[2]) * current_symbol[39] * p) +
(conj(d_prev_pilots[3]) * current_symbol[53] * -p));
er *= d_bw / (2 * M_PI * d_freq * 80);
if (d_current_symbol < 2) {
d_prev_pilots[0] = current_symbol[11];
d_prev_pilots[1] = -current_symbol[25];
d_prev_pilots[2] = current_symbol[39];
d_prev_pilots[3] = current_symbol[53];
} else {
d_prev_pilots[0] = current_symbol[11] * p;
d_prev_pilots[1] = current_symbol[25] * p;
d_prev_pilots[2] = current_symbol[39] * p;
d_prev_pilots[3] = current_symbol[53] * -p;
}
// compensate residual frequency offset
for (int i = 0; i < 64; i++) {
current_symbol[i] *= exp(gr_complex(0, -beta));
}
// update estimate of residual frequency offset
if (d_current_symbol >= 2) {
double alpha = 0.1;
d_er = (1 - alpha) * d_er + alpha * er;
}
// do equalization
d_equalizer->equalize(
current_symbol, d_current_symbol, symbols, out + o * 48, d_frame_mod);
// signal field
if (d_current_symbol == 2) {
if (decode_signal_field(out + o * 48)) {
pmt::pmt_t dict = pmt::make_dict();
dict = pmt::dict_add(
dict, pmt::mp("frame bytes"), pmt::from_uint64(d_frame_bytes));
dict = pmt::dict_add(
dict, pmt::mp("encoding"), pmt::from_uint64(d_frame_encoding));
dict = pmt::dict_add(
dict, pmt::mp("snr"), pmt::from_double(d_equalizer->get_snr()));
dict = pmt::dict_add(
dict, pmt::mp("nominal frequency"), pmt::from_double(d_freq));
dict = pmt::dict_add(dict,
pmt::mp("frequency offset"),
pmt::from_double(d_freq_offset_from_synclong));
dict = pmt::dict_add(dict, pmt::mp("beta"), pmt::from_double(beta));
std::vector<gr_complex> csi = d_equalizer->get_csi();
dict = pmt::dict_add(
dict, pmt::mp("csi"), pmt::init_c32vector(csi.size(), csi));
pmt::pmt_t pairs = pmt::dict_items(dict);
for (int i = 0; i < pmt::length(pairs); i++) {
pmt::pmt_t pair = pmt::nth(i, pairs);
add_item_tag(0,
nitems_written(0) + o,
pmt::car(pair),
pmt::cdr(pair),
alias_pmt());
}
}
}
if (d_current_symbol > 2) {
o++;
pmt::pmt_t pdu = pmt::make_dict();
message_port_pub(
pmt::mp("symbols"),
pmt::cons(pmt::make_dict(), pmt::init_c32vector(48, symbols)));
}
i++;
d_current_symbol++;
}
consume(0, i);
return o;
}
bool frame_equalizer_impl::decode_signal_field(uint8_t* rx_bits)
{
static ofdm_param ofdm(BPSK_1_2);
static frame_param frame(ofdm, 0);
deinterleave(rx_bits);
uint8_t* decoded_bits = d_decoder.decode(&ofdm, &frame, d_deinterleaved);
return parse_signal(decoded_bits);
}
void frame_equalizer_impl::deinterleave(uint8_t* rx_bits)
{
for (int i = 0; i < 48; i++) {
d_deinterleaved[i] = rx_bits[interleaver_pattern[i]];
}
}
bool frame_equalizer_impl::parse_signal(uint8_t* decoded_bits)
{
int r = 0;
d_frame_bytes = 0;
bool parity = false;
for (int i = 0; i < 17; i++) {
parity ^= decoded_bits[i];
if ((i < 4) && decoded_bits[i]) {
r = r | (1 << i);
}
if (decoded_bits[i] && (i > 4) && (i < 17)) {
d_frame_bytes = d_frame_bytes | (1 << (i - 5));
}
}
if (parity != decoded_bits[17]) {
dout << "SIGNAL: wrong parity" << std::endl;
return false;
}
switch (r) {
case 11:
d_frame_encoding = 0;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)24);
d_frame_mod = d_bpsk;
dout << "Encoding: 3 Mbit/s ";
break;
case 15:
d_frame_encoding = 1;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)36);
d_frame_mod = d_bpsk;
dout << "Encoding: 4.5 Mbit/s ";
break;
case 10:
d_frame_encoding = 2;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)48);
d_frame_mod = d_qpsk;
dout << "Encoding: 6 Mbit/s ";
break;
case 14:
d_frame_encoding = 3;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)72);
d_frame_mod = d_qpsk;
dout << "Encoding: 9 Mbit/s ";
break;
case 9:
d_frame_encoding = 4;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)96);
d_frame_mod = d_16qam;
dout << "Encoding: 12 Mbit/s ";
break;
case 13:
d_frame_encoding = 5;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)144);
d_frame_mod = d_16qam;
dout << "Encoding: 18 Mbit/s ";
break;
case 8:
d_frame_encoding = 6;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)192);
d_frame_mod = d_64qam;
dout << "Encoding: 24 Mbit/s ";
break;
case 12:
d_frame_encoding = 7;
d_frame_symbols = (int)ceil((16 + 8 * d_frame_bytes + 6) / (double)216);
d_frame_mod = d_64qam;
dout << "Encoding: 27 Mbit/s ";
break;
default:
dout << "unknown encoding" << std::endl;
return false;
}
mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") % d_frame_encoding %
d_frame_bytes % d_frame_symbols);
return true;
}
const int frame_equalizer_impl::interleaver_pattern[48] = {
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,
1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46,
2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47
};
} /* namespace ieee802_11 */
} /* namespace gr */