2024-06-16 05:31:13 -04:00
|
|
|
/* siphon.c
|
|
|
|
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
|
|
|
|
Copyright (C) 2013 Warren Pratt, NR0V
|
|
|
|
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
The author can be reached by email at
|
|
|
|
|
|
|
|
warren@wpratt.com
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "comm.hpp"
|
|
|
|
#include "meterlog10.hpp"
|
|
|
|
#include "siphon.hpp"
|
|
|
|
#include "RXA.hpp"
|
|
|
|
#include "TXA.hpp"
|
|
|
|
|
|
|
|
namespace WDSP {
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::build_window()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
int i;
|
2024-07-30 16:52:21 -04:00
|
|
|
double arg0, cosphi;
|
|
|
|
double sum, scale;
|
|
|
|
arg0 = 2.0 * PI / ((double) fftsize - 1.0);
|
2024-06-16 05:31:13 -04:00
|
|
|
sum = 0.0;
|
2024-07-30 16:52:21 -04:00
|
|
|
for (i = 0; i < fftsize; i++)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-06-24 21:50:48 -04:00
|
|
|
cosphi = cos (arg0 * (float)i);
|
2024-07-30 16:52:21 -04:00
|
|
|
window[i] = + 6.3964424114390378e-02
|
2024-06-16 05:31:13 -04:00
|
|
|
+ cosphi * ( - 2.3993864599352804e-01
|
|
|
|
+ cosphi * ( + 3.5015956323820469e-01
|
|
|
|
+ cosphi * ( - 2.4774111897080783e-01
|
|
|
|
+ cosphi * ( + 8.5438256055858031e-02
|
|
|
|
+ cosphi * ( - 1.2320203369293225e-02
|
|
|
|
+ cosphi * ( + 4.3778825791773474e-04 ))))));
|
2024-07-30 16:52:21 -04:00
|
|
|
sum += window[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
scale = 1.0 / sum;
|
2024-07-30 16:52:21 -04:00
|
|
|
for (i = 0; i < fftsize; i++)
|
|
|
|
window[i] *= scale;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
SIPHON::SIPHON(
|
|
|
|
int _run,
|
|
|
|
int _position,
|
|
|
|
int _mode,
|
|
|
|
int _disp,
|
|
|
|
int _insize,
|
|
|
|
float* _in,
|
|
|
|
int _sipsize,
|
|
|
|
int _fftsize,
|
|
|
|
int _specmode
|
2024-06-16 05:31:13 -04:00
|
|
|
)
|
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
run = _run;
|
|
|
|
position = _position;
|
|
|
|
mode = _mode;
|
|
|
|
disp = _disp;
|
|
|
|
insize = _insize;
|
|
|
|
in = _in;
|
|
|
|
sipsize = _sipsize; // NOTE: sipsize MUST BE A POWER OF TWO!!
|
|
|
|
fftsize = _fftsize;
|
|
|
|
specmode = _specmode;
|
|
|
|
sipbuff.resize(sipsize * 2); // (float *) malloc0 (sipsize * sizeof (complex));
|
|
|
|
idx = 0;
|
|
|
|
sipout.resize(sipsize * 2); // (float *) malloc0 (sipsize * sizeof (complex));
|
|
|
|
specout.resize(fftsize * 2); // (float *) malloc0 (fftsize * sizeof (complex));
|
|
|
|
sipplan = fftwf_plan_dft_1d (fftsize, (fftwf_complex *) sipout.data(), (fftwf_complex *) specout.data(), FFTW_FORWARD, FFTW_PATIENT);
|
|
|
|
window.resize(fftsize * 2); // (float *) malloc0 (fftsize * sizeof (complex));
|
|
|
|
build_window();
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
SIPHON::~SIPHON()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
fftwf_destroy_plan (sipplan);
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::flush()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
std::fill(sipbuff.begin(), sipbuff.end(), 0);
|
|
|
|
std::fill(sipout.begin(), sipout.end(), 0);
|
|
|
|
std::fill(specout.begin(), specout.end(), 0);
|
|
|
|
idx = 0;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::execute(int pos)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
int first, second;
|
2024-07-13 17:59:46 -04:00
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
if (run && position == pos)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
switch (mode)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
case 0:
|
2024-07-30 16:52:21 -04:00
|
|
|
if (insize >= sipsize)
|
|
|
|
std::copy(&(in[2 * (insize - sipsize)]), &(in[2 * (insize - sipsize)]) + sipsize * 2, sipbuff.begin());
|
2024-06-16 05:31:13 -04:00
|
|
|
else
|
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
if (insize > (sipsize - idx))
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
first = sipsize - idx;
|
|
|
|
second = insize - first;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
first = insize;
|
2024-06-16 05:31:13 -04:00
|
|
|
second = 0;
|
|
|
|
}
|
2024-07-30 16:52:21 -04:00
|
|
|
std::copy(in, in + first * 2, sipbuff.begin() + 2 * idx);
|
|
|
|
std::copy(in + 2 * first, in + 2 * first + second * 2, sipbuff.begin());
|
|
|
|
if ((idx += insize) >= sipsize) idx -= sipsize;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
2024-07-30 16:52:21 -04:00
|
|
|
// Spectrum0 (1, disp, 0, 0, in);
|
2024-06-16 05:31:13 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setBuffers(float* _in)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
in = _in;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSamplerate(int)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
flush();
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSize(int size)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
insize = size;
|
|
|
|
flush();
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::suck()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
if (outsize <= sipsize)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
int mask = sipsize - 1;
|
|
|
|
int j = (idx - outsize) & mask;
|
|
|
|
int size = sipsize - j;
|
|
|
|
if (size >= outsize)
|
|
|
|
std::copy(&(sipbuff[2 * j]), &(sipbuff[2 * j]) + outsize * 2, sipout.begin());
|
2024-06-16 05:31:13 -04:00
|
|
|
else
|
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
std::copy(&(sipbuff[2 * j]), &(sipbuff[2 * j]) + size * 2, sipout.begin());
|
|
|
|
std::copy(sipbuff.begin(), sipbuff.begin() + (outsize - size) * 2, &(sipout[2 * size]));
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::sip_spectrum()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
int i;
|
2024-07-30 16:52:21 -04:00
|
|
|
for (i = 0; i < fftsize; i++)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
sipout[2 * i + 0] *= window[i];
|
|
|
|
sipout[2 * i + 1] *= window[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-07-30 16:52:21 -04:00
|
|
|
fftwf_execute (sipplan);
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************************
|
|
|
|
* *
|
|
|
|
* RXA Properties *
|
|
|
|
* *
|
|
|
|
********************************************************************************************************/
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::getaSipF(float* _out, int _size)
|
2024-06-16 05:31:13 -04:00
|
|
|
{ // return raw samples as floats
|
2024-07-30 16:52:21 -04:00
|
|
|
outsize = _size;
|
|
|
|
suck ();
|
2024-07-13 17:59:46 -04:00
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
for (int i = 0; i < _size; i++) {
|
|
|
|
_out[i] = (float) sipout[2 * i + 0];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::getaSipF1(float* _out, int _size)
|
2024-06-16 05:31:13 -04:00
|
|
|
{ // return raw samples as floats
|
2024-07-30 16:52:21 -04:00
|
|
|
outsize = _size;
|
|
|
|
suck();
|
2024-07-13 17:59:46 -04:00
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
for (int i = 0; i < _size; i++)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
_out[2 * i + 0] = (float) sipout[2 * i + 0];
|
|
|
|
_out[2 * i + 1] = (float) sipout[2 * i + 1];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************************
|
|
|
|
* *
|
|
|
|
* TXA Properties *
|
|
|
|
* *
|
|
|
|
********************************************************************************************************/
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSipPosition(int _pos)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
position = _pos;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSipMode(int _mode)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
mode = _mode;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSipDisplay(int _disp)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
disp = _disp;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::setSipSpecmode(int _mode)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
if (_mode == 0)
|
|
|
|
specmode = 0;
|
2024-06-16 05:31:13 -04:00
|
|
|
else
|
2024-07-30 16:52:21 -04:00
|
|
|
specmode = 1;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
void SIPHON::getSpecF1(float* _out)
|
2024-06-16 05:31:13 -04:00
|
|
|
{ // return spectrum magnitudes in dB
|
|
|
|
int i, j, mid, m, n;
|
2024-07-30 16:52:21 -04:00
|
|
|
outsize = fftsize;
|
|
|
|
suck();
|
|
|
|
sip_spectrum();
|
|
|
|
mid = fftsize / 2;
|
2024-07-13 17:59:46 -04:00
|
|
|
|
2024-07-30 16:52:21 -04:00
|
|
|
if (specmode != 1)
|
2024-07-13 17:59:46 -04:00
|
|
|
{
|
2024-06-16 05:31:13 -04:00
|
|
|
// swap the halves of the spectrum
|
|
|
|
for (i = 0, j = mid; i < mid; i++, j++)
|
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
_out[i] = (float)(10.0 * MemLog::mlog10 (specout[2 * j + 0] * specout[2 * j + 0] + specout[2 * j + 1] * specout[2 * j + 1] + 1.0e-60));
|
|
|
|
_out[j] = (float)(10.0 * MemLog::mlog10 (specout[2 * i + 0] * specout[2 * i + 0] + specout[2 * i + 1] * specout[2 * i + 1] + 1.0e-60));
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-07-13 17:59:46 -04:00
|
|
|
}
|
2024-06-16 05:31:13 -04:00
|
|
|
else
|
2024-07-13 17:59:46 -04:00
|
|
|
{
|
2024-06-16 05:31:13 -04:00
|
|
|
// mirror each half of the spectrum in-place
|
2024-07-30 16:52:21 -04:00
|
|
|
for (i = 0, j = mid - 1, m = mid, n = fftsize - 1; i < mid; i++, j--, m++, n--)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-07-30 16:52:21 -04:00
|
|
|
_out[i] = (float)(10.0 * MemLog::mlog10 (specout[2 * j + 0] * specout[2 * j + 0] + specout[2 * j + 1] * specout[2 * j + 1] + 1.0e-60));
|
|
|
|
_out[m] = (float)(10.0 * MemLog::mlog10 (specout[2 * n + 0] * specout[2 * n + 0] + specout[2 * n + 1] * specout[2 * n + 1] + 1.0e-60));
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-07-13 17:59:46 -04:00
|
|
|
}
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************************
|
|
|
|
* *
|
|
|
|
* CALLS FOR EXTERNAL USE *
|
|
|
|
* *
|
|
|
|
********************************************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
#define MAX_EXT_SIPHONS (2) // maximum number of Siphons called from outside wdsp
|
|
|
|
__declspec (align (16)) SIPHON psiphon[MAX_EXT_SIPHONS]; // array of pointers for Siphons used EXTERNAL to wdsp
|
|
|
|
|
|
|
|
|
|
|
|
PORT
|
|
|
|
void create_siphonEXT (int id, int run, int insize, int sipsize, int fftsize, int specmode)
|
|
|
|
{
|
|
|
|
psiphon[id] = create_siphon (run, 0, 0, 0, insize, 0, sipsize, fftsize, specmode);
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT
|
|
|
|
void destroy_siphonEXT (int id)
|
|
|
|
{
|
|
|
|
destroy_siphon (psiphon[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT
|
|
|
|
void flush_siphonEXT (int id)
|
|
|
|
{
|
|
|
|
flush_siphon (psiphon[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT
|
2024-06-24 21:50:48 -04:00
|
|
|
void xsiphonEXT (int id, float* buff)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
SIPHON a = psiphon[id];
|
|
|
|
a->in = buff;
|
|
|
|
xsiphon (a, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT
|
|
|
|
void GetaSipF1EXT (int id, float* out, int size)
|
|
|
|
{ // return raw samples as floats
|
|
|
|
SIPHON a = psiphon[id];
|
|
|
|
int i;
|
|
|
|
a->update.lock();
|
|
|
|
a->outsize = size;
|
|
|
|
suck (a);
|
|
|
|
a->update.unlock();
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
out[2 * i + 0] = (float)a->sipout[2 * i + 0];
|
|
|
|
out[2 * i + 1] = (float)a->sipout[2 * i + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PORT
|
|
|
|
void SetSiphonInsize (int id, int size)
|
|
|
|
{
|
|
|
|
SIPHON a = psiphon[id];
|
|
|
|
a->update.lock();
|
|
|
|
a->insize = size;
|
|
|
|
a->update.unlock();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
} // namespace WDSP
|
|
|
|
|