2024-06-16 05:31:13 -04:00
|
|
|
/* lmath.c
|
|
|
|
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
|
|
|
|
Copyright (C) 2015, 2016, 2023 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 "bldr.hpp"
|
|
|
|
|
|
|
|
namespace WDSP {
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
BLDR::BLDR(int points, int ints)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
// for the create function, 'points' and 'ints' are the MAXIMUM values that will be encountered
|
2024-08-05 14:05:59 -04:00
|
|
|
catxy = new double[2 * points];
|
|
|
|
sx.resize(points);
|
|
|
|
sy.resize(points);
|
|
|
|
h .resize(ints);
|
|
|
|
p.resize(ints);
|
|
|
|
np.resize(ints);
|
|
|
|
taa.resize(ints);
|
|
|
|
tab.resize(ints);
|
|
|
|
tag.resize(ints);
|
|
|
|
tad.resize(ints);
|
|
|
|
tbb.resize(ints);
|
|
|
|
tbg.resize(ints);
|
|
|
|
tbd.resize(ints);
|
|
|
|
tgg.resize(ints);
|
|
|
|
tgd.resize(ints);
|
|
|
|
tdd.resize(ints);
|
2024-06-16 05:31:13 -04:00
|
|
|
int nsize = 3 * ints + 1;
|
|
|
|
int intp1 = ints + 1;
|
|
|
|
int intm1 = ints - 1;
|
2024-08-05 14:05:59 -04:00
|
|
|
A .resize(intp1 * intp1);
|
|
|
|
B .resize(intp1 * intp1);
|
|
|
|
C .resize(intp1 * intp1);
|
|
|
|
D .resize(intp1);
|
|
|
|
E .resize(intp1 * intp1);
|
|
|
|
F .resize(intm1 * intp1);
|
|
|
|
G .resize(intp1);
|
|
|
|
MAT.resize(nsize * nsize);
|
|
|
|
RHS.resize(nsize);
|
|
|
|
SLN.resize(nsize);
|
|
|
|
z .resize(intp1);
|
|
|
|
zp.resize(intp1);
|
|
|
|
wrk.resize(nsize);
|
|
|
|
ipiv.resize(nsize);
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
BLDR::~BLDR()
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
delete[]catxy;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
void BLDR::flush(int points)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
memset(catxy, 0, 2 * points * sizeof(double));
|
|
|
|
std::fill(sx.begin(), sx.end(), 0);
|
|
|
|
std::fill(sy.begin(), sy.end(), 0);
|
|
|
|
std::fill(h.begin(), h.end(), 0);
|
|
|
|
std::fill(p.begin(), p.end(), 0);
|
|
|
|
std::fill(np.begin(), np.end(), 0);
|
|
|
|
std::fill(taa.begin(), taa.end(), 0);
|
|
|
|
std::fill(tab.begin(), tab.end(), 0);
|
|
|
|
std::fill(tag.begin(), tag.end(), 0);
|
|
|
|
std::fill(tad.begin(), tad.end(), 0);
|
|
|
|
std::fill(tbb.begin(), tbb.end(), 0);
|
|
|
|
std::fill(tbg.begin(), tbg.end(), 0);
|
|
|
|
std::fill(tbd.begin(), tbd.end(), 0);
|
|
|
|
std::fill(tgg.begin(), tgg.end(), 0);
|
|
|
|
std::fill(tgd.begin(), tgd.end(), 0);
|
|
|
|
std::fill(tdd.begin(), tdd.end(), 0);
|
|
|
|
std::fill(A.begin(), A.end(), 0);
|
|
|
|
std::fill(B.begin(), B.end(), 0);
|
|
|
|
std::fill(C.begin(), C.end(), 0);
|
|
|
|
std::fill(D.begin(), D.end(), 0);
|
|
|
|
std::fill(E.begin(), E.end(), 0);
|
|
|
|
std::fill(F.begin(), F.end(), 0);
|
|
|
|
std::fill(G.begin(), G.end(), 0);
|
|
|
|
std::fill(MAT.begin(), MAT.end(), 0);
|
|
|
|
std::fill(RHS.begin(), RHS.end(), 0);
|
|
|
|
std::fill(SLN.begin(), SLN.end(), 0);
|
|
|
|
std::fill(z.begin(), z.end(), 0);
|
|
|
|
std::fill(zp.begin(), zp.end(), 0);
|
|
|
|
std::fill(wrk.begin(), wrk.end(), 0);
|
|
|
|
std::fill(ipiv.begin(), ipiv.end(), 0);
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int BLDR::fcompare(const void* a, const void* b)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
if (*(double*)a < *(double*)b)
|
2024-06-16 05:31:13 -04:00
|
|
|
return -1;
|
2024-08-05 14:05:59 -04:00
|
|
|
else if (*(double*)a == *(double*)b)
|
2024-06-16 05:31:13 -04:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
void BLDR::decomp(int n, std::vector<double>& a, std::vector<int>& piv, int* info, std::vector<double>& wrk)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
int i;
|
|
|
|
int j;
|
2024-06-16 05:31:13 -04:00
|
|
|
int t_piv;
|
2024-08-05 14:05:59 -04:00
|
|
|
double m_row;
|
|
|
|
double mt_row;
|
|
|
|
double m_col;
|
|
|
|
double mt_col;
|
2024-06-16 05:31:13 -04:00
|
|
|
*info = 0;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
piv[i] = i;
|
|
|
|
m_row = 0.0;
|
|
|
|
for (j = 0; j < n; j++)
|
|
|
|
{
|
|
|
|
mt_row = a[n * i + j];
|
|
|
|
if (mt_row < 0.0) mt_row = -mt_row;
|
|
|
|
if (mt_row > m_row) m_row = mt_row;
|
|
|
|
}
|
|
|
|
if (m_row == 0.0)
|
|
|
|
{
|
|
|
|
*info = i;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
wrk[i] = m_row;
|
|
|
|
}
|
2024-08-05 14:05:59 -04:00
|
|
|
for (int k = 0; k < n - 1; k++)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
j = k;
|
|
|
|
m_col = a[n * piv[k] + k] / wrk[piv[k]];
|
|
|
|
if (m_col < 0) m_col = -m_col;
|
|
|
|
for (i = k + 1; i < n; i++)
|
|
|
|
{
|
|
|
|
mt_col = a[n * piv[i] + k] / wrk[piv[k]];
|
|
|
|
if (mt_col < 0.0) mt_col = -mt_col;
|
|
|
|
if (mt_col > m_col)
|
|
|
|
{
|
|
|
|
m_col = mt_col;
|
|
|
|
j = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_col == 0)
|
|
|
|
{
|
|
|
|
*info = -k;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
t_piv = piv[k];
|
|
|
|
piv[k] = piv[j];
|
|
|
|
piv[j] = t_piv;
|
|
|
|
for (i = k + 1; i < n; i++)
|
|
|
|
{
|
|
|
|
a[n * piv[i] + k] /= a[n * piv[k] + k];
|
|
|
|
for (j = k + 1; j < n; j++)
|
|
|
|
a[n * piv[i] + j] -= a[n * piv[i] + k] * a[n * piv[k] + j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a[n * n - 1] == 0.0)
|
|
|
|
*info = -n;
|
|
|
|
cleanup:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
void BLDR::dsolve(int n, std::vector<double>& a, std::vector<int>& piv, std::vector<double>& b, std::vector<double>& x)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
int j;
|
|
|
|
int k;
|
|
|
|
double sum;
|
2024-06-16 05:31:13 -04:00
|
|
|
|
|
|
|
for (k = 0; k < n; k++)
|
|
|
|
{
|
|
|
|
sum = 0.0;
|
|
|
|
for (j = 0; j < k; j++)
|
|
|
|
sum += a[n * piv[k] + j] * x[j];
|
|
|
|
x[k] = b[piv[k]] - sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = n - 1; k >= 0; k--)
|
|
|
|
{
|
|
|
|
sum = 0.0;
|
|
|
|
for (j = k + 1; j < n; j++)
|
|
|
|
sum += a[n * piv[k] + j] * x[j];
|
|
|
|
x[k] = (x[k] - sum) / a[n * piv[k] + k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
void BLDR::cull(int* n, int ints, std::vector<double>& x, const double* t, double ptol)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
int k = 0;
|
|
|
|
int i = *n;
|
|
|
|
int ntopint;
|
|
|
|
int npx;
|
|
|
|
|
|
|
|
while (x[i - 1] > t[ints - 1])
|
|
|
|
i--;
|
|
|
|
ntopint = *n - i;
|
|
|
|
npx = (int)(ntopint * (1.0 - ptol));
|
|
|
|
i = *n;
|
|
|
|
while ((k < npx) && (x[--i] > t[ints]))
|
|
|
|
k++;
|
|
|
|
*n -= k;
|
|
|
|
}
|
|
|
|
|
2024-08-05 14:05:59 -04:00
|
|
|
void BLDR::execute(int points, const double* x, const double* y, int ints, const double* t, int* info, double* c, double ptol)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
double u;
|
|
|
|
double v;
|
|
|
|
double alpha;
|
|
|
|
double beta;
|
|
|
|
double gamma;
|
|
|
|
double delta;
|
2024-06-16 05:31:13 -04:00
|
|
|
int nsize = 3 * ints + 1;
|
|
|
|
int intp1 = ints + 1;
|
|
|
|
int intm1 = ints - 1;
|
2024-08-05 14:05:59 -04:00
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int k;
|
|
|
|
int m;
|
2024-06-16 05:31:13 -04:00
|
|
|
int dinfo;
|
2024-08-05 14:05:59 -04:00
|
|
|
flush(points);
|
2024-06-16 05:31:13 -04:00
|
|
|
for (i = 0; i < points; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
catxy[2 * i + 0] = x[i];
|
|
|
|
catxy[2 * i + 1] = y[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-08-05 14:05:59 -04:00
|
|
|
qsort(catxy, points, 2 * sizeof(double), fcompare);
|
2024-06-16 05:31:13 -04:00
|
|
|
for (i = 0; i < points; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
sx[i] = catxy[2 * i + 0];
|
|
|
|
sy[i] = catxy[2 * i + 1];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-08-05 14:05:59 -04:00
|
|
|
cull(&points, ints, sx, t, ptol);
|
|
|
|
if (points <= 0 || sx[points - 1] > t[ints])
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
|
|
|
*info = -1000;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
else *info = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < ints; j++)
|
2024-08-05 14:05:59 -04:00
|
|
|
h[j] = t[j + 1] - t[j];
|
|
|
|
p[0] = 0;
|
2024-06-16 05:31:13 -04:00
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < points; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
if (sx[i] <= t[j + 1])
|
|
|
|
np[j]++;
|
2024-06-16 05:31:13 -04:00
|
|
|
else
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
p[++j] = i;
|
|
|
|
while (sx[i] > t[j + 1])
|
|
|
|
p[++j] = i;
|
|
|
|
np[j] = 1;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < ints; i++)
|
2024-08-05 14:05:59 -04:00
|
|
|
for (j = p[i]; j < p[i] + np[i]; j++)
|
2024-06-16 05:31:13 -04:00
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
u = (sx[j] - t[i]) / h[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
v = u - 1.0;
|
|
|
|
alpha = (2.0 * u + 1.0) * v * v;
|
|
|
|
beta = u * u * (1.0 - 2.0 * v);
|
2024-08-05 14:05:59 -04:00
|
|
|
gamma = h[i] * u * v * v;
|
|
|
|
delta = h[i] * u * u * v;
|
|
|
|
taa[i] += alpha * alpha;
|
|
|
|
tab[i] += alpha * beta;
|
|
|
|
tag[i] += alpha * gamma;
|
|
|
|
tad[i] += alpha * delta;
|
|
|
|
tbb[i] += beta * beta;
|
|
|
|
tbg[i] += beta * gamma;
|
|
|
|
tbd[i] += beta * delta;
|
|
|
|
tgg[i] += gamma * gamma;
|
|
|
|
tgd[i] += gamma * delta;
|
|
|
|
tdd[i] += delta * delta;
|
|
|
|
D[i + 0] += 2.0 * sy[j] * alpha;
|
|
|
|
D[i + 1] += 2.0 * sy[j] * beta;
|
|
|
|
G[i + 0] += 2.0 * sy[j] * gamma;
|
|
|
|
G[i + 1] += 2.0 * sy[j] * delta;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0; i < ints; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
A[(i + 0) * intp1 + (i + 0)] += 2.0 * taa[i];
|
|
|
|
A[(i + 1) * intp1 + (i + 1)] = 2.0 * tbb[i];
|
|
|
|
A[(i + 0) * intp1 + (i + 1)] = 2.0 * tab[i];
|
|
|
|
A[(i + 1) * intp1 + (i + 0)] = 2.0 * tab[i];
|
|
|
|
B[(i + 0) * intp1 + (i + 0)] += 2.0 * tag[i];
|
|
|
|
B[(i + 1) * intp1 + (i + 1)] = 2.0 * tbd[i];
|
|
|
|
B[(i + 0) * intp1 + (i + 1)] = 2.0 * tbg[i];
|
|
|
|
B[(i + 1) * intp1 + (i + 0)] = 2.0 * tad[i];
|
|
|
|
E[(i + 0) * intp1 + (i + 0)] += 2.0 * tgg[i];
|
|
|
|
E[(i + 1) * intp1 + (i + 1)] = 2.0 * tdd[i];
|
|
|
|
E[(i + 0) * intp1 + (i + 1)] = 2.0 * tgd[i];
|
|
|
|
E[(i + 1) * intp1 + (i + 0)] = 2.0 * tgd[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0; i < intm1; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
C[i * intp1 + (i + 0)] = +3.0 * h[i + 1] / h[i];
|
|
|
|
C[i * intp1 + (i + 2)] = -3.0 * h[i] / h[i + 1];
|
|
|
|
C[i * intp1 + (i + 1)] = -C[i * intp1 + (i + 0)] - C[i * intp1 + (i + 2)];
|
|
|
|
F[i * intp1 + (i + 0)] = h[i + 1];
|
|
|
|
F[i * intp1 + (i + 1)] = 2.0 * (h[i] + h[i + 1]);
|
|
|
|
F[i * intp1 + (i + 2)] = h[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0, k = 0; i < intp1; i++, k++)
|
|
|
|
{
|
|
|
|
for (j = 0, m = 0; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = A[i * intp1 + j];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = intp1; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = B[j * intp1 + i];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = C[j * intp1 + i];
|
|
|
|
RHS[k] = D[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0, k = intp1; i < intp1; i++, k++)
|
|
|
|
{
|
|
|
|
for (j = 0, m = 0; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = B[i * intp1 + j];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = intp1; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = E[i * intp1 + j];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = F[j * intp1 + i];
|
|
|
|
RHS[k] = G[i];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0, k = 2 * intp1; i < intm1; i++, k++)
|
|
|
|
{
|
|
|
|
for (j = 0, m = 0; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = C[i * intp1 + j];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = intp1; j < intp1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = F[i * intp1 + j];
|
2024-06-16 05:31:13 -04:00
|
|
|
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
2024-08-05 14:05:59 -04:00
|
|
|
MAT[k * nsize + m] = 0.0;
|
|
|
|
RHS[k] = 0.0;
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
2024-08-05 14:05:59 -04:00
|
|
|
decomp(nsize, MAT, ipiv, &dinfo, wrk);
|
|
|
|
dsolve(nsize, MAT, ipiv, RHS, SLN);
|
2024-06-16 05:31:13 -04:00
|
|
|
if (dinfo != 0)
|
|
|
|
{
|
|
|
|
*info = dinfo;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i <= ints; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
z[i] = SLN[i];
|
|
|
|
zp[i] = SLN[i + ints + 1];
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
for (i = 0; i < ints; i++)
|
|
|
|
{
|
2024-08-05 14:05:59 -04:00
|
|
|
c[4 * i + 0] = z[i];
|
|
|
|
c[4 * i + 1] = zp[i];
|
|
|
|
c[4 * i + 2] = -3.0 / (h[i] * h[i]) * (z[i] - z[i + 1]) - 1.0 / h[i] * (2.0 * zp[i] + zp[i + 1]);
|
|
|
|
c[4 * i + 3] = 2.0 / (h[i] * h[i] * h[i]) * (z[i] - z[i + 1]) + 1.0 / (h[i] * h[i]) * (zp[i] + zp[i + 1]);
|
2024-06-16 05:31:13 -04:00
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace WDSP
|