mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -05:00
246 lines
6.6 KiB
C++
246 lines
6.6 KiB
C++
/* icfir.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2018 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@pratt.one
|
|
|
|
*/
|
|
|
|
#include <vector>
|
|
|
|
#include "comm.hpp"
|
|
#include "fircore.hpp"
|
|
#include "fir.hpp"
|
|
#include "icfir.hpp"
|
|
|
|
namespace WDSP {
|
|
|
|
void ICFIR::calc()
|
|
{
|
|
std::vector<float> impulse;
|
|
scale = 1.0f / (float)(2 * size);
|
|
icfir_impulse (impulse, nc, DD, R, Pairs, (float) runrate, (float) cicrate, cutoff, xtype, xbw, 1, scale, wintype);
|
|
p = new FIRCORE(size, in, out, mp, impulse);
|
|
}
|
|
|
|
void ICFIR::decalc()
|
|
{
|
|
delete p;
|
|
}
|
|
|
|
ICFIR::ICFIR(
|
|
int _run,
|
|
int _size,
|
|
int _nc,
|
|
int _mp,
|
|
float* _in,
|
|
float* _out,
|
|
int _runrate,
|
|
int _cicrate,
|
|
int _DD,
|
|
int _R,
|
|
int _Pairs,
|
|
float _cutoff,
|
|
int _xtype,
|
|
float _xbw,
|
|
int _wintype
|
|
)
|
|
// 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
|
|
// xbw: width of raised cosine transition
|
|
{
|
|
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();
|
|
}
|
|
|
|
ICFIR::~ICFIR()
|
|
{
|
|
decalc();
|
|
}
|
|
|
|
void ICFIR::flush()
|
|
{
|
|
p->flush();
|
|
}
|
|
|
|
void ICFIR::execute()
|
|
{
|
|
if (run)
|
|
p->execute();
|
|
else if (in != out)
|
|
std::copy( in, in + size * 2, out);
|
|
}
|
|
|
|
void ICFIR::setBuffers(float* _in, float* _out)
|
|
{
|
|
decalc();
|
|
in = _in;
|
|
out = _out;
|
|
calc();
|
|
}
|
|
|
|
void ICFIR::setSamplerate(int _rate)
|
|
{
|
|
decalc();
|
|
runrate = _rate;
|
|
calc();
|
|
}
|
|
|
|
void ICFIR::setSize(int _size)
|
|
{
|
|
decalc();
|
|
size = _size;
|
|
calc();
|
|
}
|
|
|
|
void ICFIR::setOutRate(int _rate)
|
|
{
|
|
decalc();
|
|
cicrate = _rate;
|
|
calc();
|
|
}
|
|
|
|
void ICFIR::icfir_impulse (
|
|
std::vector<float>& _impulse,
|
|
int _N,
|
|
int _DD,
|
|
int _R,
|
|
int _Pairs,
|
|
float _runrate,
|
|
float _cicrate,
|
|
float _cutoff,
|
|
int _xtype,
|
|
float _xbw,
|
|
int _rtype,
|
|
float _scale,
|
|
int _wintype
|
|
)
|
|
{
|
|
// 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
|
|
// xbw: transition bandwidth for raised cosine
|
|
// rtype: 0 for real output, 1 for complex output
|
|
// scale: scale factor to be applied to the output
|
|
int i;
|
|
int j;
|
|
double tmp;
|
|
double local_scale;
|
|
double ri;
|
|
double mag = 0;
|
|
double fn;
|
|
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.5f - 0.5f * (float)((_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 / (float)x_samps;
|
|
double L = _cicrate / _runrate;
|
|
double phs = 0.0;
|
|
for (i = 0; i <= x_samps; i++)
|
|
{
|
|
xistion[i] = 0.5 * (cos (phs) + 1.0);
|
|
phs += delta;
|
|
}
|
|
if ((tmp = _DD * _R * sin (PI * ft / _R) / sin (PI * _DD * ft)) < 0.0) //normalize by peak gain
|
|
tmp = -tmp;
|
|
local_scale = _scale / pow (tmp, _Pairs);
|
|
if (_xtype == 0)
|
|
{
|
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
|
{
|
|
fn = ri / (L * (float)_N);
|
|
if (fn <= ft)
|
|
{
|
|
if (fn == 0.0) tmp = 1.0;
|
|
else if ((tmp = sin (PI * _DD * fn) / (_DD * _R * sin (PI * fn / _R))) < 0.0)
|
|
tmp = -tmp;
|
|
mag = pow (tmp, _Pairs) * local_scale;
|
|
}
|
|
else
|
|
mag *= (ft * ft * ft * ft) / (fn * fn * fn * fn);
|
|
A[i] = (float) mag;
|
|
}
|
|
}
|
|
else if (_xtype == 1)
|
|
{
|
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
|
{
|
|
fn = ri / (L *(float)_N);
|
|
if (i < c_samps)
|
|
{
|
|
if (fn == 0.0) tmp = 1.0;
|
|
else if ((tmp = sin (PI * _DD * fn) / (_DD * _R * sin (PI * fn / _R))) < 0.0)
|
|
tmp = -tmp;
|
|
mag = pow (tmp, _Pairs) * local_scale;
|
|
A[i] = (float) mag;
|
|
}
|
|
else if ( i >= c_samps && i <= c_samps + x_samps)
|
|
A[i] = (float) (mag * xistion[i - c_samps]);
|
|
else
|
|
A[i] = 0.0;
|
|
}
|
|
}
|
|
if (_N & 1)
|
|
for (i = u_samps, j = 2; i < _N; i++, j++)
|
|
A[i] = A[u_samps - j];
|
|
else
|
|
for (i = u_samps, j = 1; i < _N; i++, j++)
|
|
A[i] = A[u_samps - j];
|
|
_impulse.resize(2 * _N);
|
|
FIR::fir_fsamp (_impulse, _N, A.data(), _rtype, 1.0, _wintype);
|
|
}
|
|
|
|
|
|
} // namespace WDSP
|