1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-21 12:26:34 -04:00
sdrangel/wdsp/siphon.cpp
2024-08-03 11:05:12 +02:00

265 lines
7.2 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"
namespace WDSP {
void SIPHON::build_window()
{
int i;
double arg0;
double cosphi;
double sum;
float 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] = (float) (+ 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.0f / (float) 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);
idx = 0;
sipout.resize(sipsize * 2);
specout.resize(fftsize * 2);
sipplan = fftwf_plan_dft_1d (fftsize, (fftwf_complex *) sipout.data(), (fftwf_complex *) specout.data(), FFTW_FORWARD, FFTW_PATIENT);
window.resize(fftsize * 2);
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;
int second;
if (run && (position == pos) && (mode == 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;
}
}
}
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()
{
for (int 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] = 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] = sipout[2 * i + 0];
_out[2 * i + 1] = 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;
int j;
int mid;
int m;
int 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));
}
}
}
} // namespace WDSP