1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-08-31 18:08:00 +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

@@ -10,7 +10,7 @@
[GNSS-SDR] [GNSS-SDR]
;######### GLOBAL OPTIONS ################## ;######### GLOBAL OPTIONS ##################
GNSS-SDR.internal_fs_sps=39750000 GNSS-SDR.internal_fs_sps=9937500
GNSS-SDR.telecommand_enabled=true GNSS-SDR.telecommand_enabled=true
GNSS-SDR.telecommand_tcp_port=3333 GNSS-SDR.telecommand_tcp_port=3333
GNSS-SDR.osnma_enable=false GNSS-SDR.osnma_enable=false
@@ -33,41 +33,44 @@ GNSS-SDR.SUPL_CI=0x31b0
;######### SIGNAL_SOURCE CONFIG ############ ;######### SIGNAL_SOURCE CONFIG ############
SignalSource.implementation=NTLab_File_Signal_Source SignalSource.implementation=NTLab_File_Signal_Source
SignalSource.filename=./ntlab.bin ; <- PUT YOUR FILE HERE SignalSource.filename=ntlab.bin ; <- PUT YOUR FILE HERE
SignalSource.item_type=byte
SignalSource.big_endian_bytes=false
SignalSource.sample_type=real
SignalSource.sampling_frequency=79500000 SignalSource.sampling_frequency=79500000
SignalSource.samples=0 SignalSource.sample_type=real
SignalSource.repeat=false SignalSource.item_type=byte
SignalSource.dump=false
SignalSource.dump_filename=./signal_source.dat
SignalSource.RF_channels=4 SignalSource.RF_channels=4
SignalSource.enable_throttle_control=false SignalSource.dump=false
;######### SIGNAL_CONDITIONER CONFIG ############ ;######### SIGNAL_CONDITIONER CONFIG ############
; RF CHANNEL 0
SignalConditioner0.implementation=Signal_Conditioner SignalConditioner0.implementation=Signal_Conditioner
; RF CHANNEL 1
SignalConditioner1.implementation=Signal_Conditioner SignalConditioner1.implementation=Signal_Conditioner
; RF CHANNEL 2
SignalConditioner2.implementation=Signal_Conditioner SignalConditioner2.implementation=Signal_Conditioner
; RF CHANNEL 3
SignalConditioner3.implementation=Signal_Conditioner SignalConditioner3.implementation=Signal_Conditioner
;######### DATA_TYPE_ADAPTER CONFIG ############ ;######### DATA_TYPE_ADAPTER CONFIG ############
; RF CHANNEL 0
DataTypeAdapter0.implementation=Pass_Through DataTypeAdapter0.implementation=Pass_Through
DataTypeAdapter0.item_type=float DataTypeAdapter0.item_type=float
DataTypeAdapter0.inverted_spectrum=true DataTypeAdapter0.inverted_spectrum=true
; RF CHANNEL 1
DataTypeAdapter1.implementation=Pass_Through DataTypeAdapter1.implementation=Pass_Through
DataTypeAdapter1.item_type=float DataTypeAdapter1.item_type=float
; RF CHANNEL 2
DataTypeAdapter2.implementation=Pass_Through DataTypeAdapter2.implementation=Pass_Through
DataTypeAdapter2.item_type=float DataTypeAdapter2.item_type=float
DataTypeAdapter2.inverted_spectrum=true DataTypeAdapter2.inverted_spectrum=true
; RF CHANNEL 3
DataTypeAdapter3.implementation=Pass_Through DataTypeAdapter3.implementation=Pass_Through
DataTypeAdapter3.item_type=float DataTypeAdapter3.item_type=float
;######### INPUT_FILTER CONFIG ############ ;######### INPUT_FILTER CONFIG ############
; CHANNEL 0 ; RF CHANNEL 0
InputFilter0.implementation=Freq_Xlating_Fir_Filter InputFilter0.implementation=Freq_Xlating_Fir_Filter
InputFilter0.dump=false InputFilter0.dump=false
InputFilter0.input_item_type=float InputFilter0.input_item_type=float
@@ -88,9 +91,9 @@ InputFilter0.band2_error=1.0
InputFilter0.filter_type=bandpass InputFilter0.filter_type=bandpass
InputFilter0.grid_density=16 InputFilter0.grid_density=16
InputFilter0.sampling_frequency=79500000 InputFilter0.sampling_frequency=79500000
InputFilter0.IF=-14580000 InputFilter0.IF=14580000
InputFilter0.decimation_factor=2 InputFilter0.decimation_factor=8
; CHANNEL 1 ; RF CHANNEL 1
InputFilter1.implementation=Freq_Xlating_Fir_Filter InputFilter1.implementation=Freq_Xlating_Fir_Filter
InputFilter1.dump=false InputFilter1.dump=false
InputFilter1.input_item_type=float InputFilter1.input_item_type=float
@@ -111,9 +114,9 @@ InputFilter1.band2_error=1.0
InputFilter1.filter_type=bandpass InputFilter1.filter_type=bandpass
InputFilter1.grid_density=16 InputFilter1.grid_density=16
InputFilter1.sampling_frequency=79500000 InputFilter1.sampling_frequency=79500000
InputFilter1.IF=-14580000 InputFilter1.IF=0
InputFilter1.decimation_factor=2 InputFilter1.decimation_factor=8
; CHANNEL 2 ; RF CHANNEL 2
InputFilter2.implementation=Freq_Xlating_Fir_Filter InputFilter2.implementation=Freq_Xlating_Fir_Filter
InputFilter2.dump=false InputFilter2.dump=false
InputFilter2.input_item_type=float InputFilter2.input_item_type=float
@@ -134,9 +137,9 @@ InputFilter2.band2_error=1.0
InputFilter2.filter_type=bandpass InputFilter2.filter_type=bandpass
InputFilter2.grid_density=16 InputFilter2.grid_density=16
InputFilter2.sampling_frequency=79500000 InputFilter2.sampling_frequency=79500000
InputFilter2.IF=-23550000 InputFilter2.IF=23550000
InputFilter2.decimation_factor=2 InputFilter2.decimation_factor=8
; CHANNEL 3 ; RF CHANNEL 3
InputFilter3.implementation=Freq_Xlating_Fir_Filter InputFilter3.implementation=Freq_Xlating_Fir_Filter
InputFilter3.dump=false InputFilter3.dump=false
InputFilter3.input_item_type=float InputFilter3.input_item_type=float
@@ -157,108 +160,49 @@ InputFilter3.band2_error=1.0
InputFilter3.filter_type=bandpass InputFilter3.filter_type=bandpass
InputFilter3.grid_density=16 InputFilter3.grid_density=16
InputFilter3.sampling_frequency=79500000 InputFilter3.sampling_frequency=79500000
InputFilter3.IF=-2355000000 InputFilter3.IF=27600000
InputFilter3.decimation_factor=2 InputFilter3.decimation_factor=8
;######### RESAMPLER CONFIG ############ ;######### RESAMPLER CONFIG ############
; RF CHANNEL 0
Resampler0.implementation=Pass_Through Resampler0.implementation=Pass_Through
Resampler0.item_type=gr_complex Resampler0.item_type=gr_complex
; RF CHANNEL 1
Resampler1.implementation=Pass_Through Resampler1.implementation=Pass_Through
Resampler1.item_type=gr_complex Resampler1.item_type=gr_complex
; RF CHANNEL 2
Resampler2.implementation=Pass_Through Resampler2.implementation=Pass_Through
Resampler2.item_type=gr_complex Resampler2.item_type=gr_complex
; RF CHANNEL 3
Resampler3.implementation=Pass_Through Resampler3.implementation=Pass_Through
Resampler3.item_type=gr_complex Resampler3.item_type=gr_complex
;######### CHANNELS GLOBAL CONFIG ############ ;######### CHANNELS GLOBAL CONFIG ############
Channels_1C.count=8
Channels_1B.count=8
Channels_5X.count=8
Channels_L5.count=8
Channels.in_acquisition=1 Channels.in_acquisition=1
Channels_1C.count=8 ;# GPS L1
Channel0.RF_channel_ID=0 Channels_L5.count=8 ;# GPS L5
Channel1.RF_channel_ID=0 Channels_2S.count=8 ;# GPS L2C
Channel2.RF_channel_ID=0 Channels_1B.count=8 ;# Galileo E1b
Channel3.RF_channel_ID=0 Channels_5X.count=8 ;# Galileo E5a
Channel4.RF_channel_ID=0 Channels_B1.count=8 ;# Beidou B1I
Channel5.RF_channel_ID=0 ; RF CHANNEL MAPPING
Channel6.RF_channel_ID=0 Channels_1C.RF_channel_ID=0
Channel7.RF_channel_ID=0 Channels_L5.RF_channel_ID=2
Channels_2S.RF_channel_ID=3
Channel8.RF_channel_ID=2 Channels_1B.RF_channel_ID=0
Channel9.RF_channel_ID=2 Channels_5X.RF_channel_ID=2
Channel10.RF_channel_ID=2 Channels_B1.RF_channel_ID=0
Channel11.RF_channel_ID=2
Channel12.RF_channel_ID=2
Channel13.RF_channel_ID=2
Channel14.RF_channel_ID=2
Channel15.RF_channel_ID=2
Channel16.RF_channel_ID=0
Channel17.RF_channel_ID=0
Channel18.RF_channel_ID=0
Channel19.RF_channel_ID=0
Channel20.RF_channel_ID=0
Channel21.RF_channel_ID=0
Channel22.RF_channel_ID=0
Channel23.RF_channel_ID=0
Channel24.RF_channel_ID=2
Channel25.RF_channel_ID=2
Channel26.RF_channel_ID=2
Channel27.RF_channel_ID=2
Channel28.RF_channel_ID=2
Channel29.RF_channel_ID=2
Channel30.RF_channel_ID=2
Channel31.RF_channel_ID=2
;Channel0.signal=1C
;Channel1.signal=1C
;Channel2.signal=1C
;Channel3.signal=1C
;Channel4.signal=1C
;Channel5.signal=1C
;Channel6.signal=1C
;Channel7.signal=1C
;
;Channel8.signal=L5
;Channel9.signal=L5
;Channel10.signal=L5
;Channel11.signal=L5
;Channel12.signal=L5
;Channel13.signal=L5
;Channel14.signal=L5
;Channel15.signal=L5
;
;Channel16.signal=1B
;Channel17.signal=1B
;Channel18.signal=1B
;Channel19.signal=1B
;Channel20.signal=1B
;Channel21.signal=1B
;Channel22.signal=1B
;Channel23.signal=1B
;
;Channel24.signal=5X
;Channel25.signal=5X
;Channel26.signal=5X
;Channel27.signal=5X
;Channel28.signal=5X
;Channel29.signal=5X
;Channel30.signal=5X
;Channel31.signal=5X
;######### ACQUISITION CONFIG ############ ;######### ACQUISITION CONFIG ############
;# GPS L1 ;# GPS L1
Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition
Acquisition_1C.item_type=gr_complex Acquisition_1C.item_type=gr_complex
Acquisition_L5.threshold=2 Acquisition_1C.threshold=2
Acquisition_1C.doppler_max=5000 Acquisition_1C.doppler_max=5000
Acquisition_1C.doppler_step=500 Acquisition_1C.doppler_step=125
Acquisition_1C.dump=false Acquisition_1C.dump=false
Acquisition_1C.dump_filename=./acq_dump.dat Acquisition_1C.dump_filename=./acq_dump.dat
;# GPS L5 ;# GPS L5
@@ -268,6 +212,13 @@ Acquisition_L5.threshold=2
Acquisition_L5.doppler_max=5000 Acquisition_L5.doppler_max=5000
Acquisition_L5.doppler_step=125 Acquisition_L5.doppler_step=125
Acquisition_L5.dump=false Acquisition_L5.dump=false
;# GPS L2C
Acquisition_2S.implementation=GPS_L2_M_PCPS_Acquisition
Acquisition_2S.item_type=gr_complex
Acquisition_2S.threshold=2
Acquisition_2S.doppler_max=5000
Acquisition_2S.doppler_step=150
Acquisition_2S.dump=false
;# Galileo E1b ;# Galileo E1b
Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition Acquisition_1B.implementation=Galileo_E1_PCPS_Ambiguous_Acquisition
Acquisition_1B.item_type=gr_complex Acquisition_1B.item_type=gr_complex
@@ -282,6 +233,13 @@ Acquisition_5X.threshold=2
Acquisition_5X.doppler_max=5000 Acquisition_5X.doppler_max=5000
Acquisition_5X.doppler_step=125 Acquisition_5X.doppler_step=125
Acquisition_5X.dump=false Acquisition_5X.dump=false
;# Beidou B1
Acquisition_B1.implementation=BEIDOU_B1I_PCPS_Acquisition
Acquisition_B1.item_type=gr_complex
Acquisition_B1.threshold=2
Acquisition_B1.doppler_max=5000
Acquisition_B1.doppler_step=150
Acquisition_B1.dump=false
;######### TRACKING CONFIG ############ ;######### TRACKING CONFIG ############
@@ -289,12 +247,17 @@ Acquisition_5X.dump=false
Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking Tracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking
Tracking_1C.item_type=gr_complex Tracking_1C.item_type=gr_complex
Tracking_1C.dump=false Tracking_1C.dump=false
Tracking_1C.dump_filename=./epl_tracking_ch_ Tracking_1C.dump_mat=false
;# GPS L5 ;# GPS L5
Tracking_L5.implementation=GPS_L5_DLL_PLL_Tracking Tracking_L5.implementation=GPS_L5_DLL_PLL_Tracking
Tracking_L5.item_type=gr_complex Tracking_L5.item_type=gr_complex
Tracking_L5.dump=false Tracking_L5.dump=false
Tracking_L5.dump_mat=false Tracking_L5.dump_mat=false
;# GPS L2C
Tracking_2S.implementation=GPS_L2_M_DLL_PLL_Tracking
Tracking_2S.item_type=gr_complex
Tracking_2S.dump=false
Tracking_2S.dump_mat=false
;# Galileo E1b ;# Galileo E1b
Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking Tracking_1B.implementation=Galileo_E1_DLL_PLL_VEML_Tracking
Tracking_1B.item_type=gr_complex Tracking_1B.item_type=gr_complex
@@ -305,21 +268,38 @@ Tracking_5X.implementation=Galileo_E5a_DLL_PLL_Tracking
Tracking_5X.item_type=gr_complex Tracking_5X.item_type=gr_complex
Tracking_5X.dump=false Tracking_5X.dump=false
Tracking_5X.dump_mat=false Tracking_5X.dump_mat=false
;# Beidou B1
Tracking_B1.implementation=BEIDOU_B1I_DLL_PLL_Tracking
Tracking_B1.item_type=gr_complex
Tracking_B1.dump=false
Tracking_B1.dump_mat=false
;######### TELEMETRY DECODER CONFIG ############ ;######### TELEMETRY DECODER CONFIG ############
;# GPS L1
TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder
TelemetryDecoder_1C.dump=false TelemetryDecoder_1C.dump=false
TelemetryDecoder_1C.dump_mat=false TelemetryDecoder_1C.dump_mat=false
;# GPS L5
TelemetryDecoder_L5.implementation=GPS_L5_Telemetry_Decoder TelemetryDecoder_L5.implementation=GPS_L5_Telemetry_Decoder
TelemetryDecoder_L5.dump=false TelemetryDecoder_L5.dump=false
TelemetryDecoder_L5.dump_mat=false TelemetryDecoder_L5.dump_mat=false
;# GPS L2C
TelemetryDecoder_2S.implementation=GPS_L2C_Telemetry_Decoder
TelemetryDecoder_2S.dump=false
TelemetryDecoder_2S.dump_mat=false
;# Galileo E1b
TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder TelemetryDecoder_1B.implementation=Galileo_E1B_Telemetry_Decoder
TelemetryDecoder_1B.dump=false TelemetryDecoder_1B.dump=false
TelemetryDecoder_1B.dump_mat=false TelemetryDecoder_1B.dump_mat=false
;# Galileo E5a
TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder TelemetryDecoder_5X.implementation=Galileo_E5a_Telemetry_Decoder
TelemetryDecoder_5X.dump=false TelemetryDecoder_5X.dump=false
TelemetryDecoder_5X.dump_mat=false TelemetryDecoder_5X.dump_mat=false
;# Beidou B1
TelemetryDecoder_B1.implementation=BEIDOU_B1I_Telemetry_Decoder
TelemetryDecoder_B1.dump=false
TelemetryDecoder_B1.dump_mat=false
;######### OBSERVABLES CONFIG ############ ;######### OBSERVABLES CONFIG ############

View File

@@ -28,13 +28,13 @@
using namespace std::string_literals; using namespace std::string_literals;
MultiChannelTwoBitPackedFileSignalSource::MultiChannelTwoBitPackedFileSignalSource( NTLabFileSignalSource::NTLabFileSignalSource(
const ConfigurationInterface* configuration, const ConfigurationInterface* configuration,
const std::string& role, const std::string& role,
unsigned int in_streams, unsigned int in_streams,
unsigned int out_streams, unsigned int out_streams,
Concurrent_Queue<pmt::pmt_t>* queue) 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)) sample_type_(configuration->property(role + ".sample_type", "real"s))
{ {
int default_n_channlels_ = 4; int default_n_channlels_ = 4;
@@ -43,6 +43,10 @@ MultiChannelTwoBitPackedFileSignalSource::MultiChannelTwoBitPackedFileSignalSour
{ {
n_channels_ = configuration->property(role + ".RF_channels", default_n_channlels_); 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) 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 is_complex_t = false;
auto item_size = sizeof(char); // default 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); return std::make_tuple(item_size, is_complex_t);
} }
double MultiChannelTwoBitPackedFileSignalSource::packetsPerSample() const double NTLabFileSignalSource::packetsPerSample() const
{ {
return 1.0; return 1.0;
} }
gnss_shared_ptr<gr::block> MultiChannelTwoBitPackedFileSignalSource::source() const gnss_shared_ptr<gr::block> NTLabFileSignalSource::source() const
{ {
return unpack_samples_; 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_); unpack_samples_ = make_unpack_ntlab_2bit_samples(item_size(), n_channels_);
DLOG(INFO) << "unpack_byte_2bit_samples(" << unpack_samples_->unique_id() << ")"; 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); top_block->connect(file_source(), 0, unpack_samples_, 0);
DLOG(INFO) << "connected file source to samples unpacker"; 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); top_block->disconnect(file_source(), 0, unpack_samples_, 0);
DLOG(INFO) << "disconnected file source of samples unpacker"; 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"; LOG(WARNING) << "Left block of a signal source should not be retrieved";
return gr::block_sptr(); return gr::block_sptr();
} }
gr::basic_block_sptr MultiChannelTwoBitPackedFileSignalSource::get_right_block() gr::basic_block_sptr NTLabFileSignalSource::get_right_block()
{ {
return valve(); return valve();
} }

View File

@@ -40,14 +40,14 @@ class ConfigurationInterface;
* \brief Class that reads signals samples from a file * \brief Class that reads signals samples from a file
* and adapts it to a SignalSourceInterface * and adapts it to a SignalSourceInterface
*/ */
class MultiChannelTwoBitPackedFileSignalSource : public FileSourceBase class NTLabFileSignalSource : public FileSourceBase
{ {
public: public:
MultiChannelTwoBitPackedFileSignalSource(const ConfigurationInterface* configuration, NTLabFileSignalSource(const ConfigurationInterface* configuration,
const std::string& role, unsigned int in_streams, const std::string& role, unsigned int in_streams,
unsigned int out_streams, Concurrent_Queue<pmt::pmt_t>* queue); 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_left_block() override;
gr::basic_block_sptr get_right_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", : sync_interpolator("unpack_ntlab_2bit_samples",
gr::io_signature::make(1, 1, item_size), gr::io_signature::make(1, 1, item_size),
gr::io_signature::make(nchannels, nchannels, sizeof(float)), gr::io_signature::make(nchannels, nchannels, sizeof(float)),
1), // we make 4 floats out for every byte in SAMPLES_PER_BYTE / nchannels),
item_size_(item_size),
nchannels_(nchannels) nchannels_(nchannels)
{ {
} }
@@ -47,41 +46,32 @@ int unpack_ntlab_2bit_samples::work(int noutput_items,
gr_vector_void_star &output_items) gr_vector_void_star &output_items)
{ {
auto const *in = reinterpret_cast<signed char const *>(input_items[0]); auto const *in = reinterpret_cast<signed char const *>(input_items[0]);
int const nch = nchannels_;
float *out[4]; std::vector<float *> out(nch);
for (int n = 0; n < nchannels_; ++n) 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 < noutput_items; ++i)
for (int i = 0; i < nbytes; ++i)
{ {
// Unpack each of the four 2-bit samples in the byte 'b' into four real-valued outputs. auto b = static_cast<uint8_t>(in[i]);
// int j = 0;
// The NTLAB format encodes samples as sign+magnitude pairs in each byte: for (int n = 0; n < SAMPLES_PER_BYTE; ++n)
// 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)
{ {
int shift = 2 * (3 - n); // 6, 4, 2, 0 int shift = 2 * (3 - n); // 6, 4, 2, 0
int M = (b >> (shift + 1)) & 0x1; // magnitude bit int M = (b >> (shift + 1)) & 0x1; // magnitude bit
int S = (b >> shift) & 0x1; // sign bit int S = (b >> shift) & 0x1; // sign bit
int mag = M ? 3 : 1; int mag = M ? 3 : 1;
int val = S ? +mag : -mag; 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 * \brief This class implements conversion between byte packet multichannel samples
* to 2bit samples 1 byte = 4 2bit 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 class unpack_ntlab_2bit_samples : public gr::sync_interpolator
{ {
@@ -55,12 +66,12 @@ public:
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
private: private:
static constexpr int SAMPLES_PER_BYTE = 4;
friend unpack_ntlab_2bit_samples_sptr make_unpack_ntlab_2bit_samples_sptr( friend unpack_ntlab_2bit_samples_sptr make_unpack_ntlab_2bit_samples_sptr(
size_t item_size, size_t item_size,
int nchannels); int nchannels);
std::vector<int8_t> work_buffer_;
size_t item_size_;
int nchannels_; int nchannels_;
}; };

View File

@@ -323,7 +323,7 @@ std::unique_ptr<SignalSourceInterface> get_signal_source_block(
} }
else if (implementation == "NTLab_File_Signal_Source") else if (implementation == "NTLab_File_Signal_Source")
{ {
return std::make_unique<MultiChannelTwoBitPackedFileSignalSource>(configuration, role, in_streams, out_streams, queue); return std::make_unique<NTLabFileSignalSource>(configuration, role, in_streams, out_streams, queue);
} }
else if (implementation == "Spir_File_Signal_Source") else if (implementation == "Spir_File_Signal_Source")
{ {