sdrangel/wdsp/firopt.cpp

207 wiersze
5.3 KiB
C++

/* firmin.c
This file is part of a program that implements a Software-Defined Radio.
Copyright (C) 2016 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 "fir.hpp"
#include "firopt.hpp"
namespace WDSP {
/********************************************************************************************************
* *
* Standalone Partitioned Overlap-Save Bandpass *
* *
********************************************************************************************************/
2024-08-10 07:59:42 +00:00
void FIROPT::plan()
{
// must call for change in 'nc', 'size', 'out'
2024-08-10 07:59:42 +00:00
nfor = nc / size;
buffidx = 0;
idxmask = nfor - 1;
fftin.resize(2 * size * 2);
fftout.resize(nfor);
fmask.resize(nfor);
maskgen.resize(2 * size * 2);
pcfor.resize(nfor);
maskplan.resize(nfor);
for (int i = 0; i < nfor; i++)
{
2024-08-10 07:59:42 +00:00
fftout[i].resize(2 * size * 2);
fmask[i].resize(2 * size * 2);
pcfor[i] = fftwf_plan_dft_1d(
2 * size,
(fftwf_complex *)fftin.data(),
(fftwf_complex *)fftout[i].data(),
FFTW_FORWARD,
FFTW_PATIENT
);
2024-08-10 07:59:42 +00:00
maskplan[i] = fftwf_plan_dft_1d(
2 * size,
(fftwf_complex *)maskgen.data(),
(fftwf_complex *)fmask[i].data(),
FFTW_FORWARD,
FFTW_PATIENT
);
}
2024-08-10 07:59:42 +00:00
accum.resize(2 * size * 2);
crev = fftwf_plan_dft_1d(
2 * size,
(fftwf_complex *)accum.data(),
(fftwf_complex *)out,
FFTW_BACKWARD,
FFTW_PATIENT
);
}
2024-08-10 07:59:42 +00:00
void FIROPT::calc()
{
// call for change in frequency, rate, wintype, gain
// must also call after a call to plan_firopt()
std::vector<float> impulse;
2024-08-10 07:59:42 +00:00
FIR::fir_bandpass (impulse, nc, f_low, f_high, samplerate, wintype, 1, gain);
buffidx = 0;
for (int i = 0; i < nfor; i++)
{
// I right-justified the impulse response => take output from left side of output buff, discard right side
// Be careful about flipping an asymmetrical impulse response.
2024-08-10 07:59:42 +00:00
std::copy(&(impulse[2 * size * i]), &(impulse[2 * size * i]) + size * 2, &(maskgen[2 * size]));
fftwf_execute (maskplan[i]);
}
}
2024-08-10 07:59:42 +00:00
FIROPT::FIROPT(
int _run,
int _position,
int _size,
float* _in,
float* _out,
int _nc,
float _f_low,
float _f_high,
int _samplerate,
int _wintype,
float _gain
)
{
2024-08-10 07:59:42 +00:00
run = _run;
position = _position;
size = _size;
in = _in;
out = _out;
nc = _nc;
f_low = _f_low;
f_high = _f_high;
samplerate = (float) _samplerate;
wintype = _wintype;
gain = _gain;
plan();
calc();
}
2024-08-10 07:59:42 +00:00
void FIROPT::deplan()
{
2024-08-10 07:59:42 +00:00
fftwf_destroy_plan (crev);
for (int i = 0; i < nfor; i++)
{
2024-08-10 07:59:42 +00:00
fftwf_destroy_plan (pcfor[i]);
fftwf_destroy_plan (maskplan[i]);
}
}
2024-08-10 07:59:42 +00:00
FIROPT::~FIROPT()
{
2024-08-10 07:59:42 +00:00
deplan();
}
2024-08-10 07:59:42 +00:00
void FIROPT::flush()
{
2024-08-10 07:59:42 +00:00
std::fill(fftin.begin(), fftin.end(), 0);
for (int i = 0; i < nfor; i++)
std::fill(fftout[i].begin(), fftout[i].end(), 0);
buffidx = 0;
}
2024-08-10 07:59:42 +00:00
void FIROPT::execute(int pos)
{
2024-08-10 07:59:42 +00:00
if (run && (position == pos))
{
int k;
2024-08-10 07:59:42 +00:00
std::copy(in, in + size * 2, &(fftin[2 * size]));
fftwf_execute (pcfor[buffidx]);
k = buffidx;
std::fill(accum.begin(), accum.end(), 0);
for (int j = 0; j < nfor; j++)
{
2024-08-10 07:59:42 +00:00
for (int i = 0; i < 2 * size; i++)
{
2024-08-10 07:59:42 +00:00
accum[2 * i + 0] += fftout[k][2 * i + 0] * fmask[j][2 * i + 0] - fftout[k][2 * i + 1] * fmask[j][2 * i + 1];
accum[2 * i + 1] += fftout[k][2 * i + 0] * fmask[j][2 * i + 1] + fftout[k][2 * i + 1] * fmask[j][2 * i + 0];
}
2024-08-10 07:59:42 +00:00
k = (k + idxmask) & idxmask;
}
2024-08-10 07:59:42 +00:00
buffidx = (buffidx + 1) & idxmask;
fftwf_execute (crev);
std::copy(&(fftin[2 * size]), &(fftin[2 * size]) + size * 2, fftin.begin());
}
2024-08-10 07:59:42 +00:00
else if (in != out)
std::copy( in, in + size * 2, out);
}
2024-08-10 07:59:42 +00:00
void FIROPT::setBuffers(float* _in, float* _out)
{
2024-08-10 07:59:42 +00:00
in = _in;
out = _out;
deplan();
plan();
calc();
}
2024-08-10 07:59:42 +00:00
void FIROPT::setSamplerate(int _rate)
{
2024-08-10 07:59:42 +00:00
samplerate = (float) _rate;
calc();
}
2024-08-10 07:59:42 +00:00
void FIROPT::setSize(int _size)
{
2024-08-10 07:59:42 +00:00
size = _size;
deplan();
plan();
calc();
}
2024-08-10 07:59:42 +00:00
void FIROPT::setFreqs(float _f_low, float _f_high)
{
2024-08-10 07:59:42 +00:00
f_low = _f_low;
f_high = _f_high;
calc();
}
} // namespace WDSP