1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-12-17 22:08:05 +00:00

feat: add multichannel support for ntlab adapter

This commit is contained in:
pedromiguelcp
2025-07-10 23:28:46 +01:00
parent ef01835b28
commit f1eaf5253e
6 changed files with 127 additions and 142 deletions

View File

@@ -28,13 +28,13 @@
using namespace std::string_literals;
MultiChannelTwoBitPackedFileSignalSource::MultiChannelTwoBitPackedFileSignalSource(
NTLabFileSignalSource::NTLabFileSignalSource(
const ConfigurationInterface* configuration,
const std::string& role,
unsigned int in_streams,
unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue)
: FileSourceBase(configuration, role, "ntlab_file_signal_source"s, queue, "byte"s),
: FileSourceBase(configuration, role, "NTLab_File_Signal_Source"s, queue, "byte"s),
sample_type_(configuration->property(role + ".sample_type", "real"s))
{
int default_n_channlels_ = 4;
@@ -43,6 +43,10 @@ MultiChannelTwoBitPackedFileSignalSource::MultiChannelTwoBitPackedFileSignalSour
{
n_channels_ = configuration->property(role + ".RF_channels", default_n_channlels_);
}
if ((n_channels_ != 1) && (n_channels_ != 2) && (n_channels_ != 4))
{
LOG(ERROR) << "Number of channels must be 1, 2 or 4 (got " << n_channels_ << ")";
}
if (in_streams > 0)
{
@@ -54,7 +58,7 @@ MultiChannelTwoBitPackedFileSignalSource::MultiChannelTwoBitPackedFileSignalSour
}
}
std::tuple<size_t, bool> MultiChannelTwoBitPackedFileSignalSource::itemTypeToSize()
std::tuple<size_t, bool> NTLabFileSignalSource::itemTypeToSize()
{
auto is_complex_t = false;
auto item_size = sizeof(char); // default
@@ -80,23 +84,23 @@ std::tuple<size_t, bool> MultiChannelTwoBitPackedFileSignalSource::itemTypeToSiz
return std::make_tuple(item_size, is_complex_t);
}
double MultiChannelTwoBitPackedFileSignalSource::packetsPerSample() const
double NTLabFileSignalSource::packetsPerSample() const
{
return 1.0;
}
gnss_shared_ptr<gr::block> MultiChannelTwoBitPackedFileSignalSource::source() const
gnss_shared_ptr<gr::block> NTLabFileSignalSource::source() const
{
return unpack_samples_;
}
void MultiChannelTwoBitPackedFileSignalSource::create_file_source_hook()
void NTLabFileSignalSource::create_file_source_hook()
{
unpack_samples_ = make_unpack_ntlab_2bit_samples(item_size(), n_channels_);
DLOG(INFO) << "unpack_byte_2bit_samples(" << unpack_samples_->unique_id() << ")";
}
void MultiChannelTwoBitPackedFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block)
void NTLabFileSignalSource::pre_connect_hook(gr::top_block_sptr top_block)
{
top_block->connect(file_source(), 0, unpack_samples_, 0);
DLOG(INFO) << "connected file source to samples unpacker";
@@ -108,7 +112,7 @@ void MultiChannelTwoBitPackedFileSignalSource::pre_connect_hook(gr::top_block_sp
}
}
void MultiChannelTwoBitPackedFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block)
void NTLabFileSignalSource::pre_disconnect_hook(gr::top_block_sptr top_block)
{
top_block->disconnect(file_source(), 0, unpack_samples_, 0);
DLOG(INFO) << "disconnected file source of samples unpacker";
@@ -120,13 +124,13 @@ void MultiChannelTwoBitPackedFileSignalSource::pre_disconnect_hook(gr::top_block
}
}
gr::basic_block_sptr MultiChannelTwoBitPackedFileSignalSource::get_left_block()
gr::basic_block_sptr NTLabFileSignalSource::get_left_block()
{
LOG(WARNING) << "Left block of a signal source should not be retrieved";
return gr::block_sptr();
}
gr::basic_block_sptr MultiChannelTwoBitPackedFileSignalSource::get_right_block()
gr::basic_block_sptr NTLabFileSignalSource::get_right_block()
{
return valve();
}

View File

@@ -40,14 +40,14 @@ class ConfigurationInterface;
* \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface
*/
class MultiChannelTwoBitPackedFileSignalSource : public FileSourceBase
class NTLabFileSignalSource : public FileSourceBase
{
public:
MultiChannelTwoBitPackedFileSignalSource(const ConfigurationInterface* configuration,
NTLabFileSignalSource(const ConfigurationInterface* configuration,
const std::string& role, unsigned int in_streams,
unsigned int out_streams, Concurrent_Queue<pmt::pmt_t>* queue);
~MultiChannelTwoBitPackedFileSignalSource() = default;
~NTLabFileSignalSource() = default;
gr::basic_block_sptr get_left_block() override;
gr::basic_block_sptr get_right_block() override;

View File

@@ -35,8 +35,7 @@ unpack_ntlab_2bit_samples::unpack_ntlab_2bit_samples(size_t item_size,
: sync_interpolator("unpack_ntlab_2bit_samples",
gr::io_signature::make(1, 1, item_size),
gr::io_signature::make(nchannels, nchannels, sizeof(float)),
1), // we make 4 floats out for every byte in
item_size_(item_size),
SAMPLES_PER_BYTE / nchannels),
nchannels_(nchannels)
{
}
@@ -47,41 +46,32 @@ int unpack_ntlab_2bit_samples::work(int noutput_items,
gr_vector_void_star &output_items)
{
auto const *in = reinterpret_cast<signed char const *>(input_items[0]);
int const nch = nchannels_;
float *out[4];
for (int n = 0; n < nchannels_; ++n)
std::vector<float *> out(nch);
for (int ch = 0; ch < nch; ++ch)
{
out[n] = static_cast<float *>(output_items[n]);
out[ch] = static_cast<float *>(output_items[ch]);
}
const int nbytes = noutput_items;
for (int i = 0; i < nbytes; ++i)
for (int i = 0; i < noutput_items; ++i)
{
// Unpack each of the four 2-bit samples in the byte 'b' into four real-valued outputs.
//
// The NTLAB format encodes samples as sign+magnitude pairs in each byte:
// bits 7-6 = [M0 S0] -> sample 0
// bits 5-4 = [M1 S1] -> sample 1
// bits 3-2 = [M2 S2] -> sample 2
// bits 1-0 = [M3 S3] -> sample 3
//
// Here we loop over channel index n = 0...3, compute the bit shift to extract
// the two bits for that channel (shift = 6,4,2,0), then:
// - M = magnitude bit (1->|sample|=3, 0->|sample|=1)
// - S = sign bit (1->positive, 0->negative)
// We reconstruct the signed sample value (+/-1 or +/-3) and store it in out[n][i].
uint8_t b = static_cast<uint8_t>(in[i]);
for (int n = 0; n < nchannels_; ++n)
auto b = static_cast<uint8_t>(in[i]);
int j = 0;
for (int n = 0; n < SAMPLES_PER_BYTE; ++n)
{
int shift = 2 * (3 - n); // 6, 4, 2, 0
int M = (b >> (shift + 1)) & 0x1; // magnitude bit
int S = (b >> shift) & 0x1; // sign bit
int mag = M ? 3 : 1;
int val = S ? +mag : -mag;
out[n][i] = static_cast<float>(val);
out[j][i] = static_cast<float>(val);
if (++j == nch) // iterate through each channel
j = 0;
}
}
return nbytes;
return noutput_items;
}

View File

@@ -41,6 +41,17 @@ unpack_ntlab_2bit_samples_sptr make_unpack_ntlab_2bit_samples(
/*!
* \brief This class implements conversion between byte packet multichannel samples
* to 2bit samples 1 byte = 4 2bit samples
*
* Unpack each of the four 2-bit samples in the byte 'b' into four real-valued outputs.
*
* The NTLAB format encodes samples as sign+magnitude pairs in each byte:
* bits 7-6 = [M0 S0] -> sample 0
* bits 5-4 = [M1 S1] -> sample 1
* bits 3-2 = [M2 S2] -> sample 2
* bits 1-0 = [M3 S3] -> sample 3
*
* M = magnitude bit (1->|sample|=3, 0->|sample|=1)
* S = sign bit (1->positive, 0->negative)
*/
class unpack_ntlab_2bit_samples : public gr::sync_interpolator
{
@@ -55,12 +66,12 @@ public:
gr_vector_void_star &output_items);
private:
static constexpr int SAMPLES_PER_BYTE = 4;
friend unpack_ntlab_2bit_samples_sptr make_unpack_ntlab_2bit_samples_sptr(
size_t item_size,
int nchannels);
std::vector<int8_t> work_buffer_;
size_t item_size_;
int nchannels_;
};