316 lines
8.3 KiB
C
316 lines
8.3 KiB
C
/* iqc.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
|
|
|
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.h"
|
|
|
|
void size_iqc (IQC a)
|
|
{
|
|
int i;
|
|
a->t = (double *) malloc0 ((a->ints + 1) * sizeof(double));
|
|
for (i = 0; i <= a->ints; i++)
|
|
a->t[i] = (double)i / (double)a->ints;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
a->cm[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
|
a->cc[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
|
a->cs[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
|
}
|
|
a->dog.cpi = (int *) malloc0 (a->ints * sizeof (int));
|
|
a->dog.count = 0;
|
|
a->dog.full_ints = 0;
|
|
}
|
|
|
|
void desize_iqc (IQC a)
|
|
{
|
|
int i;
|
|
_aligned_free (a->dog.cpi);
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
_aligned_free (a->cm[i]);
|
|
_aligned_free (a->cc[i]);
|
|
_aligned_free (a->cs[i]);
|
|
}
|
|
_aligned_free (a->t);
|
|
}
|
|
|
|
void calc_iqc (IQC a)
|
|
{
|
|
int i;
|
|
double delta, theta;
|
|
a->cset = 0;
|
|
a->count = 0;
|
|
a->state = 0;
|
|
a->busy = 0;
|
|
a->ntup = (int)(a->tup * a->rate);
|
|
a->cup = (double *) malloc0 ((a->ntup + 1) * sizeof (double));
|
|
delta = PI / (double)a->ntup;
|
|
theta = 0.0;
|
|
for (i = 0; i <= a->ntup; i++)
|
|
{
|
|
a->cup[i] = 0.5 * (1.0 - cos (theta));
|
|
theta += delta;
|
|
}
|
|
InitializeCriticalSectionAndSpinCount (&a->dog.cs, 2500);
|
|
size_iqc (a);
|
|
}
|
|
|
|
void decalc_iqc (IQC a)
|
|
{
|
|
desize_iqc (a);
|
|
DeleteCriticalSection (&a->dog.cs);
|
|
_aligned_free (a->cup);
|
|
}
|
|
|
|
IQC create_iqc (int run, int size, double* in, double* out, double rate, int ints, double tup, int spi)
|
|
{
|
|
IQC a = (IQC) malloc0 (sizeof (iqc));
|
|
a->run = run;
|
|
a->size = size;
|
|
a->in = in;
|
|
a->out = out;
|
|
a->rate = rate;
|
|
a->ints = ints;
|
|
a->tup = tup;
|
|
a->dog.spi = spi;
|
|
calc_iqc (a);
|
|
return a;
|
|
}
|
|
|
|
void destroy_iqc (IQC a)
|
|
{
|
|
decalc_iqc (a);
|
|
_aligned_free (a);
|
|
}
|
|
|
|
void flush_iqc (IQC a)
|
|
{
|
|
|
|
}
|
|
|
|
enum _iqcstate
|
|
{
|
|
RUN = 0,
|
|
BEGIN,
|
|
SWAP,
|
|
END,
|
|
DONE
|
|
};
|
|
|
|
void xiqc (IQC a)
|
|
{
|
|
if (_InterlockedAnd(&a->run, 1))
|
|
{
|
|
int i, k, cset, mset;
|
|
double I, Q, env, dx, ym, yc, ys, PRE0, PRE1;
|
|
for (i = 0; i < a->size; i++)
|
|
{
|
|
I = a->in[2 * i + 0];
|
|
Q = a->in[2 * i + 1];
|
|
env = sqrt (I * I + Q * Q);
|
|
if ((k = (int)(env * a->ints)) > a->ints - 1) k = a->ints - 1;
|
|
dx = env - a->t[k];
|
|
cset = a->cset;
|
|
ym = a->cm[cset][4 * k + 0] + dx * (a->cm[cset][4 * k + 1] + dx * (a->cm[cset][4 * k + 2] + dx * a->cm[cset][4 * k + 3]));
|
|
yc = a->cc[cset][4 * k + 0] + dx * (a->cc[cset][4 * k + 1] + dx * (a->cc[cset][4 * k + 2] + dx * a->cc[cset][4 * k + 3]));
|
|
ys = a->cs[cset][4 * k + 0] + dx * (a->cs[cset][4 * k + 1] + dx * (a->cs[cset][4 * k + 2] + dx * a->cs[cset][4 * k + 3]));
|
|
PRE0 = ym * (I * yc - Q * ys);
|
|
PRE1 = ym * (I * ys + Q * yc);
|
|
|
|
switch (a->state)
|
|
{
|
|
case RUN:
|
|
if (a->dog.cpi[k] != a->dog.spi)
|
|
if (++a->dog.cpi[k] == a->dog.spi)
|
|
a->dog.full_ints++;
|
|
if (a->dog.full_ints == a->ints)
|
|
{
|
|
EnterCriticalSection (&a->dog.cs);
|
|
++a->dog.count;
|
|
LeaveCriticalSection (&a->dog.cs);
|
|
a->dog.full_ints = 0;
|
|
memset (a->dog.cpi, 0, a->ints * sizeof (int));
|
|
}
|
|
break;
|
|
case BEGIN:
|
|
PRE0 = (1.0 - a->cup[a->count]) * I + a->cup[a->count] * PRE0;
|
|
PRE1 = (1.0 - a->cup[a->count]) * Q + a->cup[a->count] * PRE1;
|
|
if (a->count++ == a->ntup)
|
|
{
|
|
a->state = RUN;
|
|
a->count = 0;
|
|
InterlockedBitTestAndReset (&a->busy, 0);
|
|
}
|
|
break;
|
|
case SWAP:
|
|
mset = 1 - cset;
|
|
ym = a->cm[mset][4 * k + 0] + dx * (a->cm[mset][4 * k + 1] + dx * (a->cm[mset][4 * k + 2] + dx * a->cm[mset][4 * k + 3]));
|
|
yc = a->cc[mset][4 * k + 0] + dx * (a->cc[mset][4 * k + 1] + dx * (a->cc[mset][4 * k + 2] + dx * a->cc[mset][4 * k + 3]));
|
|
ys = a->cs[mset][4 * k + 0] + dx * (a->cs[mset][4 * k + 1] + dx * (a->cs[mset][4 * k + 2] + dx * a->cs[mset][4 * k + 3]));
|
|
PRE0 = (1.0 - a->cup[a->count]) * ym * (I * yc - Q * ys) + a->cup[a->count] * PRE0;
|
|
PRE1 = (1.0 - a->cup[a->count]) * ym * (I * ys + Q * yc) + a->cup[a->count] * PRE1;
|
|
if (a->count++ == a->ntup)
|
|
{
|
|
a->state = RUN;
|
|
a->count = 0;
|
|
InterlockedBitTestAndReset (&a->busy, 0);
|
|
}
|
|
break;
|
|
case END:
|
|
PRE0 = (1.0 - a->cup[a->count]) * PRE0 + a->cup[a->count] * I;
|
|
PRE1 = (1.0 - a->cup[a->count]) * PRE1 + a->cup[a->count] * Q;
|
|
if (a->count++ == a->ntup)
|
|
{
|
|
a->state = DONE;
|
|
a->count = 0;
|
|
InterlockedBitTestAndReset (&a->busy, 0);
|
|
}
|
|
break;
|
|
case DONE:
|
|
PRE0 = I;
|
|
PRE1 = Q;
|
|
break;
|
|
}
|
|
a->out[2 * i + 0] = PRE0;
|
|
a->out[2 * i + 1] = PRE1;
|
|
// print_iqc_values("iqc.txt", a->state, env, PRE0, PRE1, ym, yc, ys, 1.1);
|
|
}
|
|
}
|
|
else if (a->out != a->in)
|
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
|
}
|
|
|
|
void setBuffers_iqc (IQC a, double* in, double* out)
|
|
{
|
|
a->in = in;
|
|
a->out = out;
|
|
}
|
|
|
|
void setSamplerate_iqc (IQC a, int rate)
|
|
{
|
|
decalc_iqc (a);
|
|
a->rate = rate;
|
|
calc_iqc (a);
|
|
}
|
|
|
|
void setSize_iqc (IQC a, int size)
|
|
{
|
|
a->size = size;
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* TXA Properties *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
PORT
|
|
void GetTXAiqcValues (int channel, double* cm, double* cc, double* cs)
|
|
{
|
|
IQC a;
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
a = txa[channel].iqc.p0;
|
|
memcpy (cm, a->cm[a->cset], a->ints * 4 * sizeof (double));
|
|
memcpy (cc, a->cc[a->cset], a->ints * 4 * sizeof (double));
|
|
memcpy (cs, a->cs[a->cset], a->ints * 4 * sizeof (double));
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
}
|
|
|
|
PORT
|
|
void SetTXAiqcValues (int channel, double* cm, double* cc, double* cs)
|
|
{
|
|
IQC a;
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
a = txa[channel].iqc.p0;
|
|
a->cset = 1 - a->cset;
|
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
|
a->state = RUN;
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
}
|
|
|
|
PORT
|
|
void SetTXAiqcSwap (int channel, double* cm, double* cc, double* cs)
|
|
{
|
|
IQC a = txa[channel].iqc.p1;
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
a->cset = 1 - a->cset;
|
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
|
InterlockedBitTestAndSet (&a->busy, 0);
|
|
a->state = SWAP;
|
|
a->count = 0;
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
|
}
|
|
|
|
PORT
|
|
void SetTXAiqcStart (int channel, double* cm, double* cc, double* cs)
|
|
{
|
|
IQC a = txa[channel].iqc.p1;
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
a->cset = 0;
|
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
|
InterlockedBitTestAndSet (&a->busy, 0);
|
|
a->state = BEGIN;
|
|
a->count = 0;
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
InterlockedBitTestAndSet (&txa[channel].iqc.p1->run, 0);
|
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
|
}
|
|
|
|
PORT
|
|
void SetTXAiqcEnd (int channel)
|
|
{
|
|
IQC a = txa[channel].iqc.p1;
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
InterlockedBitTestAndSet (&a->busy, 0);
|
|
a->state = END;
|
|
a->count = 0;
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
|
InterlockedBitTestAndReset (&txa[channel].iqc.p1->run, 0);
|
|
}
|
|
|
|
void GetTXAiqcDogCount (int channel, int* count)
|
|
{
|
|
IQC a = txa[channel].iqc.p1;
|
|
EnterCriticalSection (&a->dog.cs);
|
|
*count = a->dog.count;
|
|
LeaveCriticalSection (&a->dog.cs);
|
|
}
|
|
|
|
void SetTXAiqcDogCount (int channel, int count)
|
|
{
|
|
IQC a = txa[channel].iqc.p1;
|
|
EnterCriticalSection (&a->dog.cs);
|
|
a->dog.count = count;
|
|
LeaveCriticalSection (&a->dog.cs);
|
|
}
|