/* 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); }