Skip to content
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@ endif (MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")

add_subdirectory(Core)
add_subdirectory(hermeslite)
add_subdirectory(libsddc)
add_subdirectory(unittest)
2 changes: 1 addition & 1 deletion Core/RadioHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ uint64_t RadioHandlerClass::TuneLO(uint64_t wishedFreq)
// we need shift the samples
int64_t offset = wishedFreq - actLo;
DbgPrintf("Offset freq %" PRIi64 "\n", offset);
float fc = r2iqCntrl->setFreqOffset(offset / (getSampleRate() / 2.0f));
float fc = r2iqCntrl->setFreqOffset(offset / (getSampleRate() / 2.0f), 0);
if (GetmodeRF() == VHFMODE)
fc = -fc; // sign change with sideband used
if (this->fc != fc)
Expand Down
5 changes: 3 additions & 2 deletions Core/dsp/ringbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>

const int default_count = 64;
Expand Down Expand Up @@ -80,7 +81,7 @@ class ringbufferbase {
std::unique_lock<std::mutex> lk(mutex);

emptyCount++;
nonemptyCV.wait(lk, [this] {
nonemptyCV.wait_for(lk, std::chrono::seconds(5), [this] {
return read_index != write_index;
});
}
Expand All @@ -98,7 +99,7 @@ class ringbufferbase {
{
std::unique_lock<std::mutex> lk(mutex);
fullCount++;
nonfullCV.wait(lk, [this] {
nonfullCV.wait_for(lk, std::chrono::seconds(5), [this] {
return (write_index + 1) % max_count != read_index;
});
}
Expand Down
55 changes: 39 additions & 16 deletions Core/fft_mt_r2iq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fft_mt_r2iq::fft_mt_r2iq() :
r2iqControlClass(),
filterHw(nullptr)
{
mtunebin = halfFft / 4;
memset(mtunebin, 0, sizeof(mtunebin));
mfftdim[0] = halfFft;
for (int i = 1; i < NDECIDX; i++)
{
Expand All @@ -59,8 +59,8 @@ fft_mt_r2iq::fft_mt_r2iq() :
{
float Bw = 64.0f / mratio;
int ntaps = KaiserWindow(0, Astop, relPass * Bw / 128.0f, relStop * Bw / 128.0f, nullptr);
printf("decimation %2d: KaiserWindow(Astop = %.1f dB, Fpass = %.3f,Fstop = %.3f, Bw %.3f @ %f ) => %d taps\n",
d, Astop, relPass * Bw, relStop * Bw, Bw, 128.0f, ntaps);
printf("decimation %2d: KaiserWindow(Astop = %.1f dB, Fpass = %.3f,Fstop = %.3f, Bw %.3f @ %f ) => %d taps (%c)\n",
d, Astop, relPass * Bw, relStop * Bw, Bw, 128.0f, ntaps, (ntaps < halfFft / 4 + 1)?' ':'*');
mratio = mratio * 2;
}
printf("***************************************************************************\n");
Expand Down Expand Up @@ -98,13 +98,18 @@ fft_mt_r2iq::~fft_mt_r2iq()
}


float fft_mt_r2iq::setFreqOffset(float offset)
float fft_mt_r2iq::setFreqOffset(float offset, int channel)
{
// align to 1/4 of halfft
this->mtunebin = int(offset * halfFft / 4) * 4; // mtunebin step 4 bin ?
float delta = ((float)this->mtunebin / halfFft) - offset;
if (channel > channel_num - 1)
{
return -1.0; // error
}

this->mtunebin[channel] = int(offset * halfFft / 4) * 4; // mtunebin step 4 bin ?
float delta = ((float)this->mtunebin[channel] / halfFft) - offset;
float ret = delta * getRatio(); // ret increases with higher decimation
DbgPrintf("offset %f mtunebin %d delta %f (%f)\n", offset, this->mtunebin, delta, ret);
DbgPrintf("Channel: %d offset %f mtunebin %d delta %f (%f)\n", channel, offset, this->mtunebin[channel], delta, ret);
return ret;
}

Expand All @@ -124,18 +129,37 @@ void fft_mt_r2iq::TurnOff(void) {
this->r2iqOn = false;

inputbuffer->Stop();
outputbuffer->Stop();
for(int i = 0; i< channel_num; i++)
{
outputbuffers[i]->Stop();
}
for (unsigned t = 0; t < processor_count; t++) {
r2iq_thread[t].join();
}
}

bool fft_mt_r2iq::IsOn(void) { return(this->r2iqOn); }

void fft_mt_r2iq::Init(float gain, ringbuffer<int16_t> *input, ringbuffer<float>* obuffers)
void fft_mt_r2iq::Init(float gain, ringbuffer<int16_t> *input, ringbuffer<float>* obuffer)
{
std::vector<ringbuffer<float>*> obuffers;

obuffers.push_back(obuffer);

Init(gain, input, obuffers);
}

void fft_mt_r2iq::Init(float gain, ringbuffer<int16_t> *input, std::vector<ringbuffer<float>*> obuffers)
{
if (obuffers.size() > MAX_CHANNELS)
return;

this->inputbuffer = input; // set to the global exported by main_loop
this->outputbuffer = obuffers; // set to the global exported by main_loop
for(size_t i = 0; i < obuffers.size(); i++)
{
this->outputbuffers[i] = obuffers[i]; // set to the global exported by main_loop
}
this->channel_num = obuffers.size();

this->GainScale = gain;

Expand All @@ -153,13 +177,12 @@ void fft_mt_r2iq::Init(float gain, ringbuffer<int16_t> *input, ringbuffer<float>

DbgPrintf((char *) "r2iqCntrl initialization\n");

// DbgPrintf((char *) "RandTable generated\n");

// DbgPrintf((char *) "RandTable generated\n");

// filters
fftwf_complex *pfilterht; // time filter ht
pfilterht = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*halfFft); // halfFft
filterHw = (fftwf_complex**)fftwf_malloc(sizeof(fftwf_complex*)*NDECIDX);
// filters
fftwf_complex *pfilterht; // time filter ht
pfilterht = (fftwf_complex *)fftwf_malloc(sizeof(fftwf_complex) * halfFft); // halfFft
filterHw = (fftwf_complex **)fftwf_malloc(sizeof(fftwf_complex *) * NDECIDX);
for (int d = 0; d < NDECIDX; d++)
{
filterHw[d] = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*halfFft); // halfFft
Expand Down
23 changes: 15 additions & 8 deletions Core/fft_mt_r2iq.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
#include "config.h"
#include <algorithm>
#include <string.h>
#include <vector>

// use up to this many threads
#define N_MAX_R2IQ_THREADS 1
#define PRINT_INPUT_RANGE 0

// We support 8 channels for now
#define MAX_CHANNELS 8

static const int halfFft = FFTN_R_ADC / 2; // half the size of the first fft at ADC 64Msps real rate (2048)
static const int fftPerBuf = transferSize / sizeof(short) / (3 * halfFft / 2) + 1; // number of ffts per buffer with 256|768 overlap

Expand All @@ -19,16 +23,17 @@ class fft_mt_r2iq : public r2iqControlClass
fft_mt_r2iq();
virtual ~fft_mt_r2iq();

float setFreqOffset(float offset);
float setFreqOffset(float offset, int channel = 0);

void Init(float gain, ringbuffer<int16_t>* buffers, ringbuffer<float>* obuffers);
void Init(float gain, ringbuffer<int16_t> *input, ringbuffer<float>* obuffer);
void Init(float gain, ringbuffer<int16_t> *input, std::vector<ringbuffer<float>*> obuffers);
void TurnOn();
void TurnOff(void);
bool IsOn(void);

protected:

template<bool rand> void convert_float(const int16_t *input, float* output, int size)
template<bool rand> void inline convert_float(const int16_t *input, float* output, int size)
{
for(int m = 0; m < size; m++)
{
Expand All @@ -45,7 +50,7 @@ class fft_mt_r2iq : public r2iqControlClass
}
}

void shift_freq(fftwf_complex* dest, const fftwf_complex* source1, const fftwf_complex* source2, int start, int end)
void inline shift_freq(fftwf_complex* dest, const fftwf_complex* source1, const fftwf_complex* source2, int start, int end)
{
for (int m = start; m < end; m++)
{
Expand All @@ -55,7 +60,7 @@ class fft_mt_r2iq : public r2iqControlClass
}
}

template<bool flip> void copy(fftwf_complex* dest, const fftwf_complex* source, int count)
template<bool flip> void inline copy(fftwf_complex* dest, const fftwf_complex* source, int count)
{
if (flip)
{
Expand All @@ -77,13 +82,15 @@ class fft_mt_r2iq : public r2iqControlClass

private:
ringbuffer<int16_t>* inputbuffer; // pointer to input buffers
ringbuffer<float>* outputbuffer; // pointer to ouput buffers
ringbuffer<float>* outputbuffers[MAX_CHANNELS]; // pointer to ouput buffers
int channel_num; // the number of channels

int bufIdx; // index to next buffer to be processed
r2iqThreadArg* lastThread;

float GainScale;
int mfftdim [NDECIDX]; // FFT N dimensions: mfftdim[k] = halfFft / 2^k
int mtunebin;
int mfftdim[NDECIDX]; // FFT N dimensions: mfftdim[k] = halfFft / 2^k
int mtunebin[MAX_CHANNELS];

void *r2iqThreadf(r2iqThreadArg *th); // thread function

Expand Down
Loading