diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-10-08 15:25:45 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2024-10-08 15:25:45 +0200 |
commit | 1d83a2b247f8e83bbce802a272ffa165bbc6333f (patch) | |
tree | 116a24ec03eabfef4bd2dd73efeb97ecaad57d67 | |
parent | 8736f6160aeafe7a177cb6143fea80157e174e52 (diff) | |
download | dabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.tar.gz dabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.tar.bz2 dabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.zip |
Get fixed_point working with USRP
-rw-r--r-- | src/DabMod.cpp | 26 | ||||
-rw-r--r-- | src/DabModulator.cpp | 4 | ||||
-rw-r--r-- | src/FormatConverter.cpp | 135 | ||||
-rw-r--r-- | src/FormatConverter.h | 3 | ||||
-rw-r--r-- | src/GuardIntervalInserter.cpp | 4 | ||||
-rw-r--r-- | src/OutputMemory.cpp | 20 | ||||
-rw-r--r-- | src/OutputMemory.h | 4 | ||||
-rw-r--r-- | src/output/SDR.cpp | 1 | ||||
-rw-r--r-- | src/output/SDR.h | 4 | ||||
-rw-r--r-- | src/output/SDRDevice.h | 4 | ||||
-rw-r--r-- | src/output/UHD.cpp | 23 | ||||
-rw-r--r-- | src/output/UHD.h | 3 |
12 files changed, 129 insertions, 102 deletions
diff --git a/src/DabMod.cpp b/src/DabMod.cpp index 5f8412b..739fef1 100644 --- a/src/DabMod.cpp +++ b/src/DabMod.cpp @@ -72,10 +72,12 @@ * samples can have peaks up to about 48000. The value of 50000 * should guarantee that with a digital gain of 1.0, UHD never clips * our samples. + * + * This only applies when fixed_point == false. */ static const float normalise_factor = 50000.0f; -//Empirical normalisation factors used to normalise the samples to amplitude 1. +// Empirical normalisation factors used to normalise the samples to amplitude 1. static const float normalise_factor_file_fix = 81000.0f; static const float normalise_factor_file_var = 46000.0f; static const float normalise_factor_file_max = 46000.0f; @@ -249,16 +251,12 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) { shared_ptr<ModOutput> output; - if (s.fixedPoint) { - if (s.useFileOutput) { + if (s.useFileOutput) { + if (s.fixedPoint) { + // Intentionally ignore fileOutputFormat, it is always sc16 output = make_shared<OutputFile>(s.outputName, s.fileOutputShowMetadata); } - else { - throw runtime_error("Fixed point only works with file output"); - } - } - else if (s.useFileOutput) { - if (s.fileOutputFormat == "complexf") { + else if (s.fileOutputFormat == "complexf") { output = make_shared<OutputFile>(s.outputName, s.fileOutputShowMetadata); } else if (s.fileOutputFormat == "complexf_normalised") { @@ -294,6 +292,7 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) else if (s.useUHDOutput) { s.normalise = 1.0f / normalise_factor; s.sdr_device_config.sampleRate = s.outputRate; + s.sdr_device_config.fixedPoint = s.fixedPoint; auto uhddevice = make_shared<Output::UHD>(s.sdr_device_config); output = make_shared<Output::SDR>(s.sdr_device_config, uhddevice); rcs.enrol((Output::SDR*)output.get()); @@ -304,6 +303,7 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) /* We normalise the same way as for the UHD output */ s.normalise = 1.0f / normalise_factor; s.sdr_device_config.sampleRate = s.outputRate; + if (s.fixedPoint) throw runtime_error("soapy fixed_point unsupported"); auto soapydevice = make_shared<Output::Soapy>(s.sdr_device_config); output = make_shared<Output::SDR>(s.sdr_device_config, soapydevice); rcs.enrol((Output::SDR*)output.get()); @@ -313,6 +313,7 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) else if (s.useDexterOutput) { /* We normalise specifically range [-32768; 32767] */ s.normalise = 32767.0f / normalise_factor; + if (s.fixedPoint) throw runtime_error("dexter fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto dexterdevice = make_shared<Output::Dexter>(s.sdr_device_config); output = make_shared<Output::SDR>(s.sdr_device_config, dexterdevice); @@ -323,6 +324,7 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) else if (s.useLimeOutput) { /* We normalise the same way as for the UHD output */ s.normalise = 1.0f / normalise_factor; + if (s.fixedPoint) throw runtime_error("limesdr fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto limedevice = make_shared<Output::Lime>(s.sdr_device_config); output = make_shared<Output::SDR>(s.sdr_device_config, limedevice); @@ -333,6 +335,7 @@ static shared_ptr<ModOutput> prepare_output(mod_settings_t& s) else if (s.useBladeRFOutput) { /* We normalise specifically for the BladeRF output : range [-2048; 2047] */ s.normalise = 2047.0f / normalise_factor; + if (s.fixedPoint) throw runtime_error("bladerf fixed_point unsupported"); s.sdr_device_config.sampleRate = s.outputRate; auto bladerfdevice = make_shared<Output::BladeRF>(s.sdr_device_config); output = make_shared<Output::SDR>(s.sdr_device_config, bladerfdevice); @@ -443,7 +446,10 @@ int launch_modulator(int argc, char* argv[]) } std::string output_format; - if (mod_settings.useFileOutput and + if (mod_settings.fixedPoint) { + output_format = "fixedpoint"; + } + else if (mod_settings.useFileOutput and (mod_settings.fileOutputFormat == "s8" or mod_settings.fileOutputFormat == "u8" or mod_settings.fileOutputFormat == "s16")) { diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index d48f1a2..9e9d017 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -258,8 +258,8 @@ int DabModulator::process(Buffer* dataOut) } if (not m_format.empty()) { - if (m_settings.fixedPoint) throw std::runtime_error("fixed point doesn't support format converter"); - + // This handles both complexf and fixedpoint: + // Convert from complexfix to interleaved int16_t I/Q m_formatConverter = make_shared<FormatConverter>(m_format); } diff --git a/src/FormatConverter.cpp b/src/FormatConverter.cpp index e8e76ed..9e59a4a 100644 --- a/src/FormatConverter.cpp +++ b/src/FormatConverter.cpp @@ -39,6 +39,14 @@ FormatConverter::FormatConverter(const std::string& format) : m_format(format) { } +FormatConverter::~FormatConverter() +{ + etiLog.level(debug) << "FormatConverter: " + << m_num_clipped_samples.load() << + " clipped samples"; +} + + /* Expect the input samples to be in the correct range for the required format */ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) { @@ -47,71 +55,101 @@ int FormatConverter::process(Buffer* const dataIn, Buffer* dataOut) size_t num_clipped_samples = 0; - size_t sizeIn = dataIn->getLength() / sizeof(float); - float* in = reinterpret_cast<float*>(dataIn->getData()); - - if (m_format == "s16") { - dataOut->setLength(sizeIn * sizeof(int16_t)); - int16_t* out = reinterpret_cast<int16_t*>(dataOut->getData()); - - for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT16_MIN) { - out[i] = INT16_MIN; - num_clipped_samples++; - } - else if (in[i] > INT16_MAX) { - out[i] = INT16_MAX; - num_clipped_samples++; - } - else { - out[i] = in[i]; + bool source_is_complexf = m_format != "fixedpoint"; + + if (source_is_complexf) { + size_t sizeIn = dataIn->getLength() / sizeof(float); + float* in = reinterpret_cast<float*>(dataIn->getData()); + + if (m_format == "s16") { + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast<int16_t*>(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT16_MIN) { + out[i] = INT16_MIN; + num_clipped_samples++; + } + else if (in[i] > INT16_MAX) { + out[i] = INT16_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } } - } - else if (m_format == "u8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - uint8_t* out = reinterpret_cast<uint8_t*>(dataOut->getData()); + else if (m_format == "u8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + uint8_t* out = reinterpret_cast<uint8_t*>(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + const auto samp = in[i] + 128.0f; + if (samp < 0) { + out[i] = 0; + num_clipped_samples++; + } + else if (samp > UINT8_MAX) { + out[i] = UINT8_MAX; + num_clipped_samples++; + } + else { + out[i] = samp; + } - for (size_t i = 0; i < sizeIn; i++) { - const auto samp = in[i] + 128.0f; - if (samp < 0) { - out[i] = 0; - num_clipped_samples++; } - else if (samp > UINT8_MAX) { - out[i] = UINT8_MAX; - num_clipped_samples++; - } - else { - out[i] = samp; + } + else if (m_format == "s8") { + dataOut->setLength(sizeIn * sizeof(int8_t)); + int8_t* out = reinterpret_cast<int8_t*>(dataOut->getData()); + + for (size_t i = 0; i < sizeIn; i++) { + if (in[i] < INT8_MIN) { + out[i] = INT8_MIN; + num_clipped_samples++; + } + else if (in[i] > INT8_MAX) { + out[i] = INT8_MAX; + num_clipped_samples++; + } + else { + out[i] = in[i]; + } } - } + else { + throw std::runtime_error("FormatConverter: Invalid format " + m_format); + } + } - else if (m_format == "s8") { - dataOut->setLength(sizeIn * sizeof(int8_t)); - int8_t* out = reinterpret_cast<int8_t*>(dataOut->getData()); + else { + // Output is always sc16, because that's what UHD accepts + + using fixed_t = complexfix::value_type; + size_t sizeIn = dataIn->getLength() / sizeof(fixed_t); + fixed_t* in = reinterpret_cast<fixed_t*>(dataIn->getData()); + + dataOut->setLength(sizeIn * sizeof(int16_t)); + int16_t* out = reinterpret_cast<int16_t*>(dataOut->getData()); for (size_t i = 0; i < sizeIn; i++) { - if (in[i] < INT8_MIN) { - out[i] = INT8_MIN; + const auto v = (in[i] * 2).raw_value(); + + if (v < INT16_MIN) { + out[i] = INT16_MIN; num_clipped_samples++; } - else if (in[i] > INT8_MAX) { - out[i] = INT8_MAX; + else if (v > INT16_MAX) { + out[i] = INT16_MAX; num_clipped_samples++; } else { - out[i] = in[i]; + out[i] = (int16_t)v; } } } - else { - throw std::runtime_error("FormatConverter: Invalid format " + m_format); - } m_num_clipped_samples.store(num_clipped_samples); - return dataOut->getLength(); } @@ -129,7 +167,10 @@ size_t FormatConverter::get_num_clipped_samples() const size_t FormatConverter::get_format_size(const std::string& format) { // Returns 2*sizeof(SAMPLE_TYPE) because we have I + Q - if (format == "s16") { + if (format == "fixedpoint") { + return 4; + } + else if (format == "s16") { return 4; } else if (format == "u8") { diff --git a/src/FormatConverter.h b/src/FormatConverter.h index 05511c0..27ca0b1 100644 --- a/src/FormatConverter.h +++ b/src/FormatConverter.h @@ -33,10 +33,8 @@ #endif #include "ModPlugin.h" -#include <complex> #include <atomic> #include <string> -#include <cstdint> class FormatConverter : public ModCodec { @@ -45,6 +43,7 @@ class FormatConverter : public ModCodec // Allowed formats: s8, u8 and s16 FormatConverter(const std::string& format); + virtual ~FormatConverter(); int process(Buffer* const dataIn, Buffer* dataOut); const char* name(); diff --git a/src/GuardIntervalInserter.cpp b/src/GuardIntervalInserter.cpp index 0b39de8..4e22367 100644 --- a/src/GuardIntervalInserter.cpp +++ b/src/GuardIntervalInserter.cpp @@ -112,8 +112,6 @@ int do_process(const GuardIntervalInserter::Params& p, Buffer* const dataIn, Buf PDEBUG("GuardIntervalInserter do_process(dataIn: %p, dataOut: %p)\n", dataIn, dataOut); - std::lock_guard<std::mutex> lock(p.windowMutex); - // Every symbol overlaps over a length of windowOverlap with // the previous symbol, and with the next symbol. First symbol // receives no prefix window, because we don't remember the @@ -141,7 +139,7 @@ int do_process(const GuardIntervalInserter::Params& p, Buffer* const dataIn, Buf // TODO remember the end of the last TF so that we can do some // windowing too. - + std::lock_guard<std::mutex> lock(p.windowMutex); if (p.windowOverlap) { if constexpr (std::is_same_v<complexf, T>) { { // Handle Null symbol separately because it is longer diff --git a/src/OutputMemory.cpp b/src/OutputMemory.cpp index ac8a67b..f673555 100644 --- a/src/OutputMemory.cpp +++ b/src/OutputMemory.cpp @@ -26,20 +26,14 @@ #include "OutputMemory.h" #include "PcDebug.h" -#include "Log.h" -#include "TimestampDecoder.h" - -#include <stdexcept> -#include <string.h> -#include <math.h> - +#include <cmath> OutputMemory::OutputMemory(Buffer* dataOut) : ModOutput() { PDEBUG("OutputMemory::OutputMemory(%p) @ %p\n", dataOut, this); - myDataOut = dataOut; + m_dataOut = dataOut; #if OUTPUT_MEM_HISTOGRAM myMax = 0.0f; @@ -49,7 +43,6 @@ OutputMemory::OutputMemory(Buffer* dataOut) #endif } - OutputMemory::~OutputMemory() { #if OUTPUT_MEM_HISTOGRAM @@ -66,13 +59,12 @@ OutputMemory::~OutputMemory() PDEBUG("OutputMemory::~OutputMemory() @ %p\n", this); } - int OutputMemory::process(Buffer* dataIn) { PDEBUG("OutputMemory::process(dataIn: %p)\n", dataIn); - *myDataOut = *dataIn; + *m_dataOut = *dataIn; #if OUTPUT_MEM_HISTOGRAM const float* in = (const float*)dataIn->getData(); @@ -87,17 +79,17 @@ int OutputMemory::process(Buffer* dataIn) } #endif - return myDataOut->getLength(); + return m_dataOut->getLength(); } meta_vec_t OutputMemory::process_metadata(const meta_vec_t& metadataIn) { - myMetadata = metadataIn; + m_metadata = metadataIn; return {}; } meta_vec_t OutputMemory::get_latest_metadata() { - return myMetadata; + return m_metadata; } diff --git a/src/OutputMemory.h b/src/OutputMemory.h index e7252d3..299d31d 100644 --- a/src/OutputMemory.h +++ b/src/OutputMemory.h @@ -62,8 +62,8 @@ public: meta_vec_t get_latest_metadata(void); protected: - Buffer* myDataOut; - meta_vec_t myMetadata; + Buffer* m_dataOut; + meta_vec_t m_metadata; #if OUTPUT_MEM_HISTOGRAM // keep track of max value diff --git a/src/output/SDR.cpp b/src/output/SDR.cpp index 594171f..22398c7 100644 --- a/src/output/SDR.cpp +++ b/src/output/SDR.cpp @@ -34,6 +34,7 @@ #include "RemoteControl.h" #include "Utils.h" +#include <chrono> #include <cmath> #include <iostream> #include <assert.h> diff --git a/src/output/SDR.h b/src/output/SDR.h index 960de0c..86bf295 100644 --- a/src/output/SDR.h +++ b/src/output/SDR.h @@ -34,16 +34,12 @@ DESCRIPTION: # include <config.h> #endif -#include <chrono> #include "ModPlugin.h" -#include "EtiReader.h" #include "output/SDRDevice.h" #include "output/Feedback.h" namespace Output { -using complexf = std::complex<float>; - class SDR : public ModOutput, public ModMetadata, public RemoteControllable { public: SDR(SDRDeviceConfig& config, std::shared_ptr<SDRDevice> device); diff --git a/src/output/SDRDevice.h b/src/output/SDRDevice.h index 378829c..ec9373d 100644 --- a/src/output/SDRDevice.h +++ b/src/output/SDRDevice.h @@ -38,9 +38,7 @@ DESCRIPTION: #include <string> #include <vector> #include <complex> -#include <variant> #include <optional> -#include <unordered_map> #include "TimestampDecoder.h" @@ -59,6 +57,8 @@ struct SDRDeviceConfig { std::string tx_antenna; std::string rx_antenna; + bool fixedPoint = false; + long masterClockRate = 32768000; unsigned sampleRate = 2048000; double frequency = 0.0; diff --git a/src/output/UHD.cpp b/src/output/UHD.cpp index e097692..b30f9e1 100644 --- a/src/output/UHD.cpp +++ b/src/output/UHD.cpp @@ -31,10 +31,7 @@ //#define MDEBUG(fmt, args...) fprintf(LOG, fmt , ## args) #define MDEBUG(fmt, args...) -#include "PcDebug.h" #include "Log.h" -#include "RemoteControl.h" -#include "Utils.h" #include <thread> #include <iomanip> @@ -52,14 +49,12 @@ # include <uhd/utils/thread_priority.hpp> #endif - -#include <cmath> #include <iostream> -#include <assert.h> +#include <cmath> +#include <cassert> #include <stdexcept> -#include <stdio.h> +#include <cstdio> #include <time.h> -#include <errno.h> #include <unistd.h> #include <pthread.h> @@ -235,7 +230,8 @@ UHD::UHD(SDRDeviceConfig& config) : m_usrp->set_rx_gain(m_conf.rxgain); etiLog.log(debug, "OutputUHD:Actual RX Gain: %f", m_usrp->get_rx_gain()); - const uhd::stream_args_t stream_args("fc32"); //complex floats + const uhd::stream_args_t stream_args( + m_conf.fixedPoint ? "sc16" : "fc32"); m_rx_stream = m_usrp->get_rx_stream(stream_args); m_tx_stream = m_usrp->get_tx_stream(stream_args); @@ -319,8 +315,9 @@ double UHD::get_bandwidth(void) const void UHD::transmit_frame(struct FrameData&& frame) { const double tx_timeout = 20.0; - const size_t sizeIn = frame.buf.size() / sizeof(complexf); - const complexf* in_data = reinterpret_cast<const complexf*>(&frame.buf[0]); + + const size_t sample_size = m_conf.fixedPoint ? (2 * sizeof(int16_t)) : sizeof(complexf); + const size_t sizeIn = frame.buf.size() / sample_size; uhd::tx_metadata_t md_tx; @@ -353,9 +350,9 @@ void UHD::transmit_frame(struct FrameData&& frame) samps_to_send <= usrp_max_num_samps ); m_require_timestamp_refresh = false; - //send a single packet + // send a single packet size_t num_tx_samps = m_tx_stream->send( - &in_data[num_acc_samps], + frame.buf.data() + sample_size * num_acc_samps, samps_to_send, md_tx, tx_timeout); etiLog.log(trace, "UHD,sent %zu of %zu", num_tx_samps, samps_to_send); diff --git a/src/output/UHD.h b/src/output/UHD.h index 9891c7a..c4f1a45 100644 --- a/src/output/UHD.h +++ b/src/output/UHD.h @@ -45,12 +45,9 @@ DESCRIPTION: #include <atomic> #include <thread> -#include "Log.h" #include "output/SDR.h" #include "output/USRPTime.h" #include "TimestampDecoder.h" -#include "RemoteControl.h" -#include "ThreadsafeQueue.h" #include <stdio.h> #include <sys/types.h> |