aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2024-10-08 15:25:45 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2024-10-08 15:25:45 +0200
commit1d83a2b247f8e83bbce802a272ffa165bbc6333f (patch)
tree116a24ec03eabfef4bd2dd73efeb97ecaad57d67
parent8736f6160aeafe7a177cb6143fea80157e174e52 (diff)
downloaddabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.tar.gz
dabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.tar.bz2
dabmod-1d83a2b247f8e83bbce802a272ffa165bbc6333f.zip
Get fixed_point working with USRP
-rw-r--r--src/DabMod.cpp26
-rw-r--r--src/DabModulator.cpp4
-rw-r--r--src/FormatConverter.cpp135
-rw-r--r--src/FormatConverter.h3
-rw-r--r--src/GuardIntervalInserter.cpp4
-rw-r--r--src/OutputMemory.cpp20
-rw-r--r--src/OutputMemory.h4
-rw-r--r--src/output/SDR.cpp1
-rw-r--r--src/output/SDR.h4
-rw-r--r--src/output/SDRDevice.h4
-rw-r--r--src/output/UHD.cpp23
-rw-r--r--src/output/UHD.h3
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>