1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-14 04:11:48 -05:00
sdrangel/wdsp/cfir.cpp

285 lines
7.8 KiB
C++
Raw Normal View History

2024-06-16 05:31:13 -04:00
/* cfir.c
This file is part of a program that implements a Software-Defined Radio.
Copyright (C) 2014, 2016, 2021 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 "cfir.hpp"
#include "fir.hpp"
#include "fircore.hpp"
2024-06-16 05:31:13 -04:00
#include "TXA.hpp"
namespace WDSP {
2024-08-07 15:14:09 -04:00
void CFIR::calc()
2024-06-16 05:31:13 -04:00
{
2024-06-24 21:50:48 -04:00
float* impulse;
2024-08-07 15:14:09 -04:00
scale = 1.0 / (float)(2 * size);
impulse = cfir_impulse (nc, DD, R, Pairs, runrate, cicrate, cutoff, xtype, xbw, 1, scale, wintype);
p = new FIRCORE(size, in, out, nc, mp, impulse);
delete[] impulse;
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::decalc()
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
delete p;
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
CFIR::CFIR(
int _run,
int _size,
int _nc,
int _mp,
float* _in,
float* _out,
int _runrate,
int _cicrate,
int _DD,
int _R,
int _Pairs,
double _cutoff,
int _xtype,
double _xbw,
int _wintype
2024-07-19 02:10:54 -04:00
)
2024-06-16 05:31:13 -04:00
// run: 0 - no action; 1 - operate
// size: number of complex samples in an input buffer to the CFIR filter
// nc: number of filter coefficients
// mp: minimum phase flag
// in: pointer to the input buffer
// out: pointer to the output buffer
// rate: samplerate
// DD: differential delay of the CIC to be compensated (usually 1 or 2)
// R: interpolation factor of CIC
// Pairs: number of comb-integrator pairs in the CIC
// cutoff: cutoff frequency
// xtype: 0 - fourth power transition; 1 - raised cosine transition; 2 - brick wall
// xbw: width of raised cosine transition
{
2024-08-07 15:14:09 -04:00
run = _run;
size = _size;
nc = _nc;
mp = _mp;
in = _in;
out = _out;
runrate = _runrate;
cicrate = _cicrate;
DD = _DD;
R = _R;
Pairs = _Pairs;
cutoff = _cutoff;
xtype = _xtype;
xbw = _xbw;
wintype = _wintype;
calc();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
CFIR::~CFIR()
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
decalc();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::flush()
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
p->flush();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::execute()
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
if (run)
p->execute();
else if (in != out)
std::copy( in, in + size * 2, out);
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::setBuffers(float* _in, float* _out)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
decalc();
in = _in;
out = _out;
calc();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::setSamplerate(int rate)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
decalc();
runrate = rate;
calc();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::setSize(int _size)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
decalc();
size = _size;
calc();
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::setOutRate(int rate)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
decalc();
cicrate = rate;
calc();
2024-06-16 05:31:13 -04:00
}
2024-07-19 02:10:54 -04:00
float* CFIR::cfir_impulse (
2024-08-07 15:14:09 -04:00
int _N,
int _DD,
int _R,
int _Pairs,
double _runrate,
double _cicrate,
double _cutoff,
int _xtype,
double _xbw,
int _rtype,
double _scale,
int _wintype
2024-07-19 02:10:54 -04:00
)
2024-06-16 05:31:13 -04:00
{
// N: number of impulse response samples
// DD: differential delay used in the CIC filter
// R: interpolation / decimation factor of the CIC
// Pairs: number of comb-integrator pairs in the CIC
// runrate: sample rate at which this filter is to run (assumes there may be flat interp. between this filter and the CIC)
// cicrate: sample rate at interface to CIC
// cutoff: cutoff frequency
// xtype: transition type, 0 for 4th-power rolloff, 1 for raised cosine, 2 for brick wall
// xbw: transition bandwidth for raised cosine
// rtype: 0 for real output, 1 for complex output
// scale: scale factor to be applied to the output
2024-08-07 15:14:09 -04:00
int i;
int j;
double tmp;
double local_scale;
double ri;
double mag = 0;
double fn;
2024-06-24 21:50:48 -04:00
float* impulse;
2024-08-07 15:14:09 -04:00
std::vector<float> A(_N);
double ft = _cutoff / _cicrate; // normalized cutoff frequency
int u_samps = (_N + 1) / 2; // number of unique samples, OK for odd or even N
int c_samps = (int)(_cutoff / _runrate * _N) + (_N + 1) / 2 - _N / 2; // number of unique samples within bandpass, OK for odd or even N
auto x_samps = (int)(_xbw / _runrate * _N); // number of unique samples in transition region, OK for odd or even N
double offset = 0.5 - 0.5 * (double)((_N + 1) / 2 - _N / 2); // sample offset from center, OK for odd or even N
std::vector<double> xistion(x_samps + 1);
double delta = PI / (double)x_samps;
double L = _cicrate / _runrate;
double _phs = 0.0;
2024-06-16 05:31:13 -04:00
for (i = 0; i <= x_samps; i++)
{
2024-08-07 15:14:09 -04:00
xistion[i] = 0.5 * (cos (_phs) + 1.0);
_phs += delta;
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
if ((tmp = _DD * _R * sin (PI * ft / _R) / sin (PI * _DD * ft)) < 0.0) //normalize by peak gain
2024-06-16 05:31:13 -04:00
tmp = -tmp;
2024-08-07 15:14:09 -04:00
local_scale = _scale / pow (tmp, _Pairs);
if (_xtype == 0)
2024-06-16 05:31:13 -04:00
{
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
{
2024-08-07 15:14:09 -04:00
fn = ri / (L * (double) _N);
2024-06-16 05:31:13 -04:00
if (fn <= ft)
{
2024-07-19 02:10:54 -04:00
if (fn == 0.0)
tmp = 1.0;
2024-08-07 15:14:09 -04:00
else if ((tmp = _DD * _R * sin (PI * fn / _R) / sin (PI * _DD * fn)) < 0.0)
2024-06-16 05:31:13 -04:00
tmp = -tmp;
2024-08-07 15:14:09 -04:00
mag = pow (tmp, _Pairs) * local_scale;
2024-06-16 05:31:13 -04:00
}
else
mag *= (ft * ft * ft * ft) / (fn * fn * fn * fn);
2024-08-07 15:14:09 -04:00
A[i] = (float) mag;
2024-06-16 05:31:13 -04:00
}
}
2024-08-07 15:14:09 -04:00
else if (_xtype == 1)
2024-06-16 05:31:13 -04:00
{
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
{
2024-08-07 15:14:09 -04:00
fn = ri / (L *(double) _N);
2024-06-16 05:31:13 -04:00
if (i < c_samps)
{
if (fn == 0.0) tmp = 1.0;
2024-08-07 15:14:09 -04:00
else if ((tmp = _DD * _R * sin (PI * fn / _R) / sin (PI * _DD * fn)) < 0.0)
2024-06-16 05:31:13 -04:00
tmp = -tmp;
2024-08-07 15:14:09 -04:00
mag = pow (tmp, _Pairs) * local_scale;
A[i] = (float) mag;
2024-06-16 05:31:13 -04:00
}
else if ( i >= c_samps && i <= c_samps + x_samps)
2024-08-07 15:14:09 -04:00
A[i] = (float) (mag * xistion[i - c_samps]);
2024-06-16 05:31:13 -04:00
else
A[i] = 0.0;
}
}
2024-08-07 15:14:09 -04:00
else if (_xtype == 2)
2024-06-16 05:31:13 -04:00
{
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
{
2024-08-07 15:14:09 -04:00
fn = ri / (L * (double) _N);
2024-06-16 05:31:13 -04:00
if (fn <= ft)
{
if (fn == 0.0) tmp = 1.0;
2024-08-07 15:14:09 -04:00
else if ((tmp = _DD * _R * sin(PI * fn / _R) / sin(PI * _DD * fn)) < 0.0)
2024-06-16 05:31:13 -04:00
tmp = -tmp;
2024-08-07 15:14:09 -04:00
mag = pow (tmp, _Pairs) * local_scale;
2024-06-16 05:31:13 -04:00
}
else
mag = 0.0;
2024-08-07 15:14:09 -04:00
A[i] = (float) mag;
2024-06-16 05:31:13 -04:00
}
}
2024-08-07 15:14:09 -04:00
if (_N & 1)
for (i = u_samps, j = 2; i < _N; i++, j++)
2024-06-16 05:31:13 -04:00
A[i] = A[u_samps - j];
else
2024-08-07 15:14:09 -04:00
for (i = u_samps, j = 1; i < _N; i++, j++)
2024-06-16 05:31:13 -04:00
A[i] = A[u_samps - j];
2024-08-07 15:14:09 -04:00
impulse = FIR::fir_fsamp (_N, A.data(), _rtype, 1.0, _wintype);
2024-06-16 05:31:13 -04:00
return impulse;
}
/********************************************************************************************************
* *
* TXA Properties *
* *
********************************************************************************************************/
2024-08-07 15:14:09 -04:00
void CFIR::setRun(int _run)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
run = _run;
2024-06-16 05:31:13 -04:00
}
2024-08-07 15:14:09 -04:00
void CFIR::setNC(int _nc)
2024-06-16 05:31:13 -04:00
{
// NOTE: 'nc' must be >= 'size'
2024-07-13 17:59:46 -04:00
2024-08-07 15:14:09 -04:00
if (nc != _nc)
2024-06-16 05:31:13 -04:00
{
2024-08-07 15:14:09 -04:00
nc = _nc;
decalc();
calc();
2024-06-16 05:31:13 -04:00
}
}
} // namespace WDSP