1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-21 12:26:34 -04:00
sdrangel/wdsp/siphon.cpp
2024-07-30 22:52:21 +02:00

332 lines
9.3 KiB
C++

/* 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 {
void SIPHON::build_window()
{
int i;
double arg0, cosphi;
double sum, scale;
arg0 = 2.0 * PI / ((double) fftsize - 1.0);
sum = 0.0;
for (i = 0; i < fftsize; i++)
{
cosphi = cos (arg0 * (float)i);
window[i] = + 6.3964424114390378e-02
+ cosphi * ( - 2.3993864599352804e-01
+ cosphi * ( + 3.5015956323820469e-01
+ cosphi * ( - 2.4774111897080783e-01
+ cosphi * ( + 8.5438256055858031e-02
+ cosphi * ( - 1.2320203369293225e-02
+ cosphi * ( + 4.3778825791773474e-04 ))))));
sum += window[i];
}
scale = 1.0 / sum;
for (i = 0; i < fftsize; i++)
window[i] *= scale;
}
SIPHON::SIPHON(
int _run,
int _position,
int _mode,
int _disp,
int _insize,
float* _in,
int _sipsize,
int _fftsize,
int _specmode
)
{
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();
}
SIPHON::~SIPHON()
{
fftwf_destroy_plan (sipplan);
}
void SIPHON::flush()
{
std::fill(sipbuff.begin(), sipbuff.end(), 0);
std::fill(sipout.begin(), sipout.end(), 0);
std::fill(specout.begin(), specout.end(), 0);
idx = 0;
}
void SIPHON::execute(int pos)
{
int first, second;
if (run && position == pos)
{
switch (mode)
{
case 0:
if (insize >= sipsize)
std::copy(&(in[2 * (insize - sipsize)]), &(in[2 * (insize - sipsize)]) + sipsize * 2, sipbuff.begin());
else
{
if (insize > (sipsize - idx))
{
first = sipsize - idx;
second = insize - first;
}
else
{
first = insize;
second = 0;
}
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;
}
break;
case 1:
// Spectrum0 (1, disp, 0, 0, in);
break;
}
}
}
void SIPHON::setBuffers(float* _in)
{
in = _in;
}
void SIPHON::setSamplerate(int)
{
flush();
}
void SIPHON::setSize(int size)
{
insize = size;
flush();
}
void SIPHON::suck()
{
if (outsize <= sipsize)
{
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());
else
{
std::copy(&(sipbuff[2 * j]), &(sipbuff[2 * j]) + size * 2, sipout.begin());
std::copy(sipbuff.begin(), sipbuff.begin() + (outsize - size) * 2, &(sipout[2 * size]));
}
}
}
void SIPHON::sip_spectrum()
{
int i;
for (i = 0; i < fftsize; i++)
{
sipout[2 * i + 0] *= window[i];
sipout[2 * i + 1] *= window[i];
}
fftwf_execute (sipplan);
}
/********************************************************************************************************
* *
* RXA Properties *
* *
********************************************************************************************************/
void SIPHON::getaSipF(float* _out, int _size)
{ // return raw samples as floats
outsize = _size;
suck ();
for (int i = 0; i < _size; i++) {
_out[i] = (float) sipout[2 * i + 0];
}
}
void SIPHON::getaSipF1(float* _out, int _size)
{ // return raw samples as floats
outsize = _size;
suck();
for (int i = 0; i < _size; i++)
{
_out[2 * i + 0] = (float) sipout[2 * i + 0];
_out[2 * i + 1] = (float) sipout[2 * i + 1];
}
}
/********************************************************************************************************
* *
* TXA Properties *
* *
********************************************************************************************************/
void SIPHON::setSipPosition(int _pos)
{
position = _pos;
}
void SIPHON::setSipMode(int _mode)
{
mode = _mode;
}
void SIPHON::setSipDisplay(int _disp)
{
disp = _disp;
}
void SIPHON::setSipSpecmode(int _mode)
{
if (_mode == 0)
specmode = 0;
else
specmode = 1;
}
void SIPHON::getSpecF1(float* _out)
{ // return spectrum magnitudes in dB
int i, j, mid, m, n;
outsize = fftsize;
suck();
sip_spectrum();
mid = fftsize / 2;
if (specmode != 1)
{
// swap the halves of the spectrum
for (i = 0, j = mid; i < mid; i++, j++)
{
_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));
}
}
else
{
// mirror each half of the spectrum in-place
for (i = 0, j = mid - 1, m = mid, n = fftsize - 1; i < mid; i++, j--, m++, n--)
{
_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));
}
}
}
/********************************************************************************************************
* *
* 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
void xsiphonEXT (int id, float* buff)
{
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