2024-06-16 09:31:13 +00:00
|
|
|
/* fcurve.c
|
|
|
|
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
|
|
|
|
Copyright (C) 2013, 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 "fcurve.hpp"
|
|
|
|
#include "fir.hpp"
|
|
|
|
|
|
|
|
namespace WDSP {
|
|
|
|
|
2024-06-25 01:50:48 +00:00
|
|
|
float* FCurve::fc_impulse (int nc, float f0, float f1, float g0, float, int curve, float samplerate, float scale, int ctfmode, int wintype)
|
2024-06-16 09:31:13 +00:00
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
float* A = new float[nc / 2 + 1]; // (float *) malloc0 ((nc / 2 + 1) * sizeof (float));
|
2024-06-16 09:31:13 +00:00
|
|
|
int i;
|
2024-06-25 01:50:48 +00:00
|
|
|
float fn, f;
|
|
|
|
float* impulse;
|
2024-06-16 09:31:13 +00:00
|
|
|
int mid = nc / 2;
|
2024-06-25 01:50:48 +00:00
|
|
|
float g0_lin = pow(10.0, g0 / 20.0);
|
2024-06-16 09:31:13 +00:00
|
|
|
if (nc & 1)
|
|
|
|
{
|
|
|
|
for (i = 0; i <= mid; i++)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
fn = (float)i / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
f = fn * samplerate / 2.0;
|
|
|
|
switch (curve)
|
|
|
|
{
|
|
|
|
case 0: // fm pre-emphasis
|
|
|
|
if (f0 > 0.0)
|
|
|
|
A[i] = scale * (g0_lin * f / f0);
|
|
|
|
else
|
|
|
|
A[i] = 0.0;
|
|
|
|
break;
|
|
|
|
case 1: // fm de-emphasis
|
|
|
|
if (f > 0.0)
|
|
|
|
A[i] = scale * (g0_lin * f0 / f);
|
|
|
|
else
|
|
|
|
A[i] = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < mid; i++)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
fn = ((float)i + 0.5) / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
f = fn * samplerate / 2.0;
|
|
|
|
switch (curve)
|
|
|
|
{
|
|
|
|
case 0: // fm pre-emphasis
|
|
|
|
if (f0 > 0.0)
|
|
|
|
A[i] = scale * (g0_lin * f / f0);
|
|
|
|
else
|
|
|
|
A[i] = 0.0;
|
|
|
|
break;
|
|
|
|
case 1: // fm de-emphasis
|
|
|
|
if (f > 0.0)
|
|
|
|
A[i] = scale * (g0_lin * f0 / f);
|
|
|
|
else
|
|
|
|
A[i] = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ctfmode == 0)
|
|
|
|
{
|
|
|
|
int k, low, high;
|
2024-06-25 01:50:48 +00:00
|
|
|
float lowmag, highmag, flow4, fhigh4;
|
2024-06-16 09:31:13 +00:00
|
|
|
if (nc & 1)
|
|
|
|
{
|
|
|
|
low = (int)(2.0 * f0 / samplerate * mid);
|
|
|
|
high = (int)(2.0 * f1 / samplerate * mid + 0.5);
|
|
|
|
lowmag = A[low];
|
|
|
|
highmag = A[high];
|
2024-06-25 01:50:48 +00:00
|
|
|
flow4 = pow((float)low / (float)mid, 4.0);
|
|
|
|
fhigh4 = pow((float)high / (float)mid, 4.0);
|
2024-06-16 09:31:13 +00:00
|
|
|
k = low;
|
|
|
|
while (--k >= 0)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
f = (float)k / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
lowmag *= (f * f * f * f) / flow4;
|
|
|
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
|
|
|
A[k] = lowmag;
|
|
|
|
}
|
|
|
|
k = high;
|
|
|
|
while (++k <= mid)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
f = (float)k / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
highmag *= fhigh4 / (f * f * f * f);
|
|
|
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
|
|
|
A[k] = highmag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
low = (int)(2.0 * f0 / samplerate * mid - 0.5);
|
|
|
|
high = (int)(2.0 * f1 / samplerate * mid - 0.5);
|
|
|
|
lowmag = A[low];
|
|
|
|
highmag = A[high];
|
2024-06-25 01:50:48 +00:00
|
|
|
flow4 = pow((float)low / (float)mid, 4.0);
|
|
|
|
fhigh4 = pow((float)high / (float)mid, 4.0);
|
2024-06-16 09:31:13 +00:00
|
|
|
k = low;
|
|
|
|
while (--k >= 0)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
f = (float)k / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
lowmag *= (f * f * f * f) / flow4;
|
|
|
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
|
|
|
A[k] = lowmag;
|
|
|
|
}
|
|
|
|
k = high;
|
|
|
|
while (++k < mid)
|
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
f = (float)k / (float)mid;
|
2024-06-16 09:31:13 +00:00
|
|
|
highmag *= fhigh4 / (f * f * f * f);
|
|
|
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
|
|
|
A[k] = highmag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nc & 1)
|
|
|
|
impulse = FIR::fir_fsamp_odd(nc, A, 1, 1.0, wintype);
|
|
|
|
else
|
|
|
|
impulse = FIR::fir_fsamp(nc, A, 1, 1.0, wintype);
|
|
|
|
// print_impulse ("emph.txt", size + 1, impulse, 1, 0);
|
|
|
|
delete[] (A);
|
|
|
|
return impulse;
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate mask for Overlap-Save Filter
|
2024-06-25 01:50:48 +00:00
|
|
|
float* FCurve::fc_mults (int size, float f0, float f1, float g0, float g1, int curve, float samplerate, float scale, int ctfmode, int wintype)
|
2024-06-16 09:31:13 +00:00
|
|
|
{
|
2024-06-25 01:50:48 +00:00
|
|
|
float* impulse = fc_impulse (size + 1, f0, f1, g0, g1, curve, samplerate, scale, ctfmode, wintype);
|
|
|
|
float* mults = FIR::fftcv_mults(2 * size, impulse);
|
2024-06-16 09:31:13 +00:00
|
|
|
delete[] (impulse);
|
|
|
|
return mults;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace WDSP
|