1883 lines
52 KiB
C
1883 lines
52 KiB
C
/* analyzer.c
|
|
|
|
This file is part of a program that implements a Spectrum Analyzer
|
|
used in conjunction with software-defined-radio hardware.
|
|
|
|
Copyright (C) 2012, 2013, 2014, 2016, 2023, 2025 Warren Pratt, NR0V
|
|
Copyright (C) 2012 David McQuate, WA8YWQ - Kaiser window & Bessel function added.
|
|
|
|
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"
|
|
|
|
DP pdisp[dMAX_DISPLAYS];
|
|
|
|
double bessi0(double x)
|
|
{
|
|
double ax,ans;
|
|
double y;
|
|
|
|
if ((ax=fabs(x)) < 3.75) {
|
|
y = x / 3.75, y = y * y;
|
|
ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y* (1.2067492
|
|
+ y * (0.2659732 + y * (0.360768e-1 + y * 0.45813e-2)))));
|
|
} else {
|
|
y = 3.75 / ax;
|
|
ans = (exp(ax) / sqrt(ax)) * (0.39894228 + y * (0.1328592e-1
|
|
+ y * (0.225319e-2 + y * (-0.157565e-2 + y * (0.916281e-2
|
|
+ y * (-0.2057706e-1 + y * (0.2635537e-1 + y * (-0.1647633e-1
|
|
+ y * 0.392377e-2))))))));
|
|
}
|
|
return ans;
|
|
}
|
|
|
|
void new_window(int disp, int type, int size, double PiAlpha)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i;
|
|
double arg0, arg1, cgsum, igsum;
|
|
switch (type)
|
|
{
|
|
case 0: // rectangular window
|
|
{
|
|
a->inv_coherent_gain = 1.0;
|
|
igsum = (double)size;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] = a->inv_coherent_gain * 1.0;
|
|
break;
|
|
}
|
|
case 1: // blackman-harris window (4 term)
|
|
{
|
|
arg0 = 2.0 * PI / ((double)size - 1.0);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
arg1 = arg0 * (double)i;
|
|
a->window[i] = 0.35875 - 0.48829 * cos(arg1) + 0.14128 * cos(2.0 * arg1) - 0.01168 * cos(3.0 * arg1);
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
case 2: // hann window
|
|
{
|
|
arg0 = 2.0 * PI / ((double)size - 1.0);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
a->window[i] = 0.5 * (1.0 - cos((double)i * arg0));
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
case 3: // flat-top window
|
|
{
|
|
arg0 = 2.0 * PI / ((double)size - 1.0);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
arg1 = arg0 * (double)i;
|
|
a->window[i] = 0.21557895 - 0.41663158 * cos(arg1) + 0.277263158 * cos(2.0 * arg1) - 0.083578947 * cos(3.0 * arg1) + 0.006947368 * cos (4.0 * arg1);
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
case 4: // hamming window
|
|
{
|
|
arg0 = 2.0 * PI / ((double)size - 1.0);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
a->window[i] = (0.54 - 0.46 * cos((double)i * arg0));
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
case 5: // Kaiser window
|
|
{ arg0 = bessi0(PiAlpha);
|
|
arg1 = (double)(size - 1);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; ++i)
|
|
{
|
|
a->window[i] = bessi0(PiAlpha * sqrt(1.0 - pow(2.0 * (double)i / arg1 - 1.0, 2))) / arg0;
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
case 6: // Blackman-Harris window (7-term)
|
|
default:
|
|
{
|
|
arg0 = 2.0 * PI / ((double)size - 1.0);
|
|
cgsum = 0.0;
|
|
igsum = 0.0;
|
|
for (i = 0; i < size; ++i)
|
|
{
|
|
arg1 = cos (arg0 * (double)i);
|
|
a->window[i] = + 6.3964424114390378e-02
|
|
+ arg1 * ( - 2.3993864599352804e-01
|
|
+ arg1 * ( + 3.5015956323820469e-01
|
|
+ arg1 * ( - 2.4774111897080783e-01
|
|
+ arg1 * ( + 8.5438256055858031e-02
|
|
+ arg1 * ( - 1.2320203369293225e-02
|
|
+ arg1 * ( + 4.3778825791773474e-04 ))))));
|
|
cgsum += a->window[i];
|
|
igsum += a->window[i] * a->window[i];
|
|
}
|
|
a->inv_coherent_gain = (double)size / cgsum;
|
|
for (i = 0; i < size; i++)
|
|
a->window[i] *= a->inv_coherent_gain;
|
|
break;
|
|
}
|
|
}
|
|
a->inherent_power_gain = igsum / (double)size;
|
|
a->inv_enb = 1.0 / (a->inherent_power_gain * a->inv_coherent_gain * a->inv_coherent_gain);
|
|
// print_window_gain ("windows.txt", type, a->inv_coherent_gain, a->inherent_power_gain);
|
|
}
|
|
|
|
// spur elimination, REAL input data
|
|
void eliminate(int disp, int ss, int LO)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i, k, begin, end, ilim;
|
|
double mag;
|
|
|
|
if (ss == a->begin_ss)
|
|
begin = a->fscL + a->clip;
|
|
else
|
|
begin = a->clip;
|
|
if (ss == a->end_ss)
|
|
end = a->out_size - 1 -a->clip - a->fscH;
|
|
else
|
|
end = a->out_size - 1 - a->clip;
|
|
|
|
ilim = a->out_size - 1;
|
|
|
|
if (a->flip[LO])
|
|
for (i = ilim - begin, k = 0; i > ilim - end; i--, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
else
|
|
for (i = begin, k = 0; i < end; i++, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
a->ss_bins[ss] = k;
|
|
}
|
|
|
|
// spur elimination, COMPLEX input data
|
|
void Celiminate(int disp, int ss, int LO)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i, k, begin0, end0, begin1, end1, ilim;
|
|
double mag;
|
|
|
|
if (ss == a->begin_ss)
|
|
{
|
|
begin0 = a->out_size / 2 + 1 + a->clip + a->fscL;
|
|
if (begin0 > a->out_size)
|
|
begin1 = begin0 - a->out_size;
|
|
else
|
|
begin1 = 0;
|
|
}
|
|
else
|
|
{
|
|
begin0 = a->out_size / 2 + 1 + a->clip;
|
|
begin1 = 0;
|
|
}
|
|
if (ss == a->end_ss)
|
|
{
|
|
end1 = a->out_size / 2 - a->clip - a->fscH;
|
|
if (end1 < 0)
|
|
end0 = a->out_size + end1;
|
|
else
|
|
end0 = a->out_size;
|
|
}
|
|
else
|
|
{
|
|
end0 = a->out_size;
|
|
end1 = a->out_size / 2 - a->clip;
|
|
}
|
|
|
|
ilim = a->out_size - 1;
|
|
|
|
if (a->flip[LO])
|
|
{
|
|
for (i = ilim - begin0, k = 0; i > ilim - end0; i--, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
for (i = ilim - begin1; i > ilim - end1; i--, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = begin0, k = 0; i < end0; i++, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
for (i = begin1; i < end1; i++, k++)
|
|
{
|
|
mag = (a->fft_out[ss][LO])[i][0] * (a->fft_out[ss][LO])[i][0] + (a->fft_out[ss][LO])[i][1] * (a->fft_out[ss][LO])[i][1];
|
|
if ((a->spec_flag[ss] == 0) || (mag < (a->result[ss])[k]))
|
|
(a->result[ss])[k] = mag;
|
|
}
|
|
}
|
|
a->ss_bins[ss] = k;
|
|
}
|
|
|
|
void detector ( int det_type, // detector type
|
|
int m, // number of bins
|
|
int num_pixels, // number of output pixels
|
|
double pix_per_bin, // pixels per bin
|
|
double bin_per_pix, // bins per pixel
|
|
double* bins, // input buffer
|
|
double* pixels, // output buffer
|
|
double inv_enb, // inverse equivalent noise bandwidth
|
|
double fsclipL,
|
|
double fsclipH,
|
|
double det_offset
|
|
)
|
|
{
|
|
int i, imin, ilim;
|
|
int pix_count = 0;
|
|
int rose, fell, next_pix_count, bcount, last_pix_count;
|
|
double prev_maxi, mini, maxi, psum;
|
|
if (pix_per_bin <= 1.0)
|
|
{
|
|
if (fsclipL == floor(fsclipL)) imin = 0;
|
|
else imin = 1;
|
|
if (fsclipH == floor(fsclipH)) ilim = m;
|
|
else ilim = m - 1;
|
|
switch (det_type)
|
|
{
|
|
|
|
case 0: // positive peak
|
|
for (i = 0; i < num_pixels; i++)
|
|
pixels[i] = - 1.0e300;
|
|
|
|
for (i = imin; i < ilim; i++)
|
|
{
|
|
pix_count = (int)(det_offset + (double)i * pix_per_bin);
|
|
if (pix_count >= num_pixels) pix_count = num_pixels - 1;
|
|
if (bins[i] > pixels[pix_count])
|
|
pixels[pix_count] = bins[i];
|
|
}
|
|
break;
|
|
|
|
case 1: // rosenfell
|
|
rose = 0;
|
|
fell = 0;
|
|
mini = + 1.0e300;
|
|
maxi = - 1.0e300;
|
|
prev_maxi = - 1.0e300;
|
|
|
|
for (i = imin; i < ilim; i++) // for each FFT bin
|
|
{
|
|
// determine the pixel number that this FFT bin goes into
|
|
pix_count = (int)(det_offset + (double)i * pix_per_bin);
|
|
if (pix_count >= num_pixels) pix_count = num_pixels - 1;
|
|
// determine the pixel number for the NEXT FFT bin
|
|
next_pix_count = (int)((double)(i + 1) * pix_per_bin);
|
|
// update the minimum and maximum of the set of bins within the pixel
|
|
if (bins[i] < mini) mini = bins[i];
|
|
if (bins[i] > maxi) maxi = bins[i];
|
|
// if the next bin is also within the pixel && there is a next bin,
|
|
// compare its value with the current bin and update rose and fell
|
|
if (next_pix_count == pix_count && i < ilim - 1)
|
|
{
|
|
// NOTE: when next_pix_count != pix_count, rose and fell do not get updated;
|
|
// that's OK because we do NOT need to know if there's a rise or fall across bins
|
|
if (bins[i + 1] > bins[i]) rose = 1;
|
|
if (bins[i + 1] < bins[i]) fell = 1;
|
|
}
|
|
// if the next bin is NOT within the pixel || there is no next bin, finalize the pixel
|
|
// value and reset parameters
|
|
else
|
|
{
|
|
if (rose && fell)
|
|
if (pix_count & 1) // odd pixel
|
|
pixels[pix_count] = max (prev_maxi, maxi);
|
|
else // even pixel
|
|
pixels[pix_count] = mini;
|
|
else
|
|
pixels[pix_count] = maxi;
|
|
rose = 0;
|
|
fell = 0;
|
|
prev_maxi = maxi;
|
|
mini = + 1.0e300;
|
|
maxi = - 1.0e300;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2: // average - adjusted for window's equivalent noise bandwidth
|
|
psum = 0.0;
|
|
bcount = 0;
|
|
for (i = imin; i < ilim; i++)
|
|
{
|
|
last_pix_count = pix_count;
|
|
pix_count = (int)(det_offset + (double)i * pix_per_bin);
|
|
if (pix_count >= num_pixels) pix_count = num_pixels - 1;
|
|
if (pix_count == last_pix_count)
|
|
{
|
|
psum += bins[i];
|
|
bcount++;
|
|
}
|
|
else
|
|
{
|
|
pixels[last_pix_count] = psum / (double)bcount * inv_enb;
|
|
psum = bins[i];
|
|
bcount = 1;
|
|
}
|
|
if (i == ilim - 1)
|
|
{
|
|
pixels[pix_count] = psum / (double)bcount * inv_enb;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3: // sample - adjusted for window's equivalent noise bandwidth
|
|
bcount = 0;
|
|
for (i = imin; i < ilim; i++)
|
|
{
|
|
last_pix_count = pix_count;
|
|
pix_count = (int)(det_offset + (double)i * pix_per_bin);
|
|
if (pix_count >= num_pixels) pix_count = num_pixels - 1;
|
|
if (pix_count == last_pix_count)
|
|
{
|
|
bcount++;
|
|
}
|
|
else
|
|
{
|
|
pixels[last_pix_count] = bins[i - bcount / 2 - 1] * inv_enb;
|
|
bcount = 1;
|
|
}
|
|
if (i == ilim - 1)
|
|
{
|
|
pixels[pix_count] = bins[i - bcount / 2] * inv_enb;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4: // rms
|
|
psum = 0.0;
|
|
bcount = 0;
|
|
for (i = imin; i < ilim; i++)
|
|
{
|
|
last_pix_count = pix_count;
|
|
pix_count = (int)(det_offset + (double)i * pix_per_bin);
|
|
if (pix_count >= num_pixels) pix_count = num_pixels - 1;
|
|
if (pix_count == last_pix_count)
|
|
{
|
|
psum += bins[i] * bins[i];
|
|
bcount++;
|
|
}
|
|
else
|
|
{
|
|
pixels[last_pix_count] = sqrt (psum / (double)bcount) * inv_enb;
|
|
psum = bins[i] * bins[i];
|
|
bcount = 1;
|
|
}
|
|
if (i == ilim - 1)
|
|
{
|
|
pixels[pix_count] = sqrt (psum / (double)bcount) * inv_enb;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double frac;
|
|
double pix_pos = fsclipL - floor(fsclipL);
|
|
int ampl_comp = (det_type == 2) || (det_type == 3) || (det_type == 4);
|
|
for (i = 1; i < m; i++)
|
|
{
|
|
while (pix_pos < ((double)i + 1.0e-06) && pix_count < num_pixels)
|
|
{
|
|
frac = pix_pos - (double)(i - 1);
|
|
pixels[pix_count] = bins[i - 1] * (1.0 - frac) + bins[i] * frac;
|
|
if (ampl_comp) pixels[pix_count] *= inv_enb;
|
|
pix_count++;
|
|
pix_pos += bin_per_pix;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void avenger ( int av_mode, // averaging mode
|
|
int num_pixels, // number of pixels
|
|
int* avail_frames, // number of available frames for window averaging
|
|
int num_average, // number of frames to average within a window
|
|
int* av_in_idx, // in index for av_buff
|
|
int* av_out_idx, // out index for av_buff
|
|
double av_backmult, // multiplier for recursive averaging
|
|
double scale, // scale factor
|
|
double* t_pixels, // input buffer
|
|
double* av_sum, // history buffer for averaging
|
|
double** av_buff, // frame buffer for window averaging
|
|
double* cd, // correction factor buffer
|
|
int norm, // if TRUE, normalize to one Hz bandwidth
|
|
double norm_oneHz, // normalization factor to add
|
|
dOUTREAL* pixels // output buffer
|
|
)
|
|
{
|
|
int i;
|
|
double factor;
|
|
switch (av_mode)
|
|
{
|
|
case -1: // peak-hold
|
|
{
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
if (t_pixels[i] > av_sum[i])
|
|
av_sum[i] = t_pixels[i];
|
|
pixels[i] = (dOUTREAL)(10.0 * mlog10(scale * cd[i] * av_sum[i] + 1.0e-60));
|
|
}
|
|
break;
|
|
}
|
|
case 0: // no averaging
|
|
default:
|
|
{
|
|
for (i = 0; i < num_pixels; i++)
|
|
pixels[i] = (dOUTREAL)(10.0 * mlog10(scale * cd[i] * t_pixels[i] + 1.0e-60));
|
|
break;
|
|
}
|
|
case 1: // weighted averaging of linear data
|
|
{
|
|
double onem_avb = 1.0 - av_backmult;
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
av_sum[i] = av_backmult * av_sum[i] + onem_avb * t_pixels[i];
|
|
pixels[i] = (dOUTREAL)(10.0 * mlog10(scale * cd[i] * av_sum[i] + 1.0e-60));
|
|
}
|
|
break;
|
|
}
|
|
case 2: // window averaging of linear data
|
|
{
|
|
if (*avail_frames < num_average)
|
|
{
|
|
factor = scale / (double)++(*avail_frames);
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
av_sum[i] += t_pixels[i];
|
|
av_buff[*av_in_idx][i] = t_pixels[i];
|
|
pixels[i] = (dOUTREAL)(10.0 * mlog10(cd[i] * av_sum[i] * factor + 1.0e-60));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
factor = scale / (double)(*avail_frames);
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
av_sum[i] += t_pixels[i] - (av_buff[*av_out_idx])[i];
|
|
av_buff[*av_in_idx][i] = t_pixels[i];
|
|
pixels[i] = (dOUTREAL)(10.0 * mlog10(cd[i] * av_sum[i] * factor + 1.0e-60));
|
|
}
|
|
if (++(*av_out_idx) == dMAX_AVERAGE)
|
|
*av_out_idx = 0;
|
|
}
|
|
if (++(*av_in_idx) == dMAX_AVERAGE)
|
|
*av_in_idx = 0;
|
|
break;
|
|
}
|
|
case 3: // weighted averaging of log data - looks nice, not accurate for time-varying signals
|
|
{
|
|
double onem_avb = 1.0 - av_backmult;
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
av_sum[i] = av_backmult * av_sum[i] + onem_avb * (10.0 * mlog10(scale * cd[i] * t_pixels[i] + 1e-60));
|
|
pixels[i] = (dOUTREAL)av_sum[i];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (norm)
|
|
for (i = 0; i < num_pixels; i++)
|
|
pixels[i] += (dOUTREAL)norm_oneHz;
|
|
}
|
|
|
|
void stitch(int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i, j, k, n, m;
|
|
double* ptr;
|
|
|
|
// stitch
|
|
m = 0;
|
|
ptr = a->pre_av_out;
|
|
for (n = a->begin_ss; n <= a->end_ss; n++)
|
|
{
|
|
memcpy(ptr, a->result[n], a->ss_bins[n] * sizeof(double));
|
|
ptr += a->ss_bins[n];
|
|
m += a->ss_bins[n];
|
|
}
|
|
for (i = 0; i < a->num_pixout; i++) // for each output
|
|
{
|
|
EnterCriticalSection(&a->ResampleSection);
|
|
// if a detection of the same 'det_type' has already been done, use that result
|
|
j = i - 1;
|
|
k = i;
|
|
while (j >= 0)
|
|
{
|
|
if (a->det_type[i] == a->det_type[j])
|
|
k = j;
|
|
j--;
|
|
}
|
|
if (k == i)
|
|
// detect
|
|
detector (a->det_type[i], m, a->num_pixels, a->pix_per_bin, a->bin_per_pix, a->pre_av_out,
|
|
a->t_pixels[i], a->inv_enb, a->fsclipL, a->fsclipH, a->det_offset);
|
|
else
|
|
memcpy (a->t_pixels[i], a->t_pixels[k], a->num_pixels * sizeof (double));
|
|
// average & convert to dBm
|
|
avenger (a->av_mode[i], a->num_pixels, &a->avail_frames[i], a->num_average[i], &a->av_in_idx[i], &a->av_out_idx[i],
|
|
a->av_backmult[i], a->scale, a->t_pixels[i], a->av_sum[i], a->av_buff[i], a->cd, a->normalize[i], a->norm_oneHz,
|
|
a->pixels[i][a->w_pix_buff[i]]);
|
|
LeaveCriticalSection(&a->ResampleSection);
|
|
|
|
EnterCriticalSection(&a->PB_ControlsSection[i]);
|
|
a->last_pix_buff[i] = a->w_pix_buff[i];
|
|
while ((a->w_pix_buff[i] = (a->w_pix_buff[i] + 1) % dNUM_PIXEL_BUFFS) == a->r_pix_buff[i]);
|
|
LeaveCriticalSection(&a->PB_ControlsSection[i]);
|
|
InterlockedBitTestAndSet(&(a->pb_ready[i][a->last_pix_buff[i]]), 0);
|
|
}
|
|
}
|
|
|
|
DWORD WINAPI spectra (void *pargs)
|
|
{
|
|
int i, j;
|
|
int disp = ((int)(uintptr_t)pargs) >> 12;
|
|
int ss = (((int)(uintptr_t)pargs) >> 4) & 255;
|
|
int LO = ((int)(uintptr_t)pargs) & 15;
|
|
DP a = pdisp[disp];
|
|
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
|
|
if ((ss >= a->begin_ss) && (ss <= a->end_ss))
|
|
{
|
|
for (i = 0; i < a->size; i++)
|
|
{
|
|
(a->fft_in[ss][LO])[i] = a->window[i] * (double)((a->I_samples[ss][LO])[a->IQO_idx[ss][LO]]);
|
|
if(++a->IQO_idx[ss][LO] >= a->bsize)
|
|
a->IQO_idx[ss][LO] -= a->bsize;
|
|
}
|
|
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
fftw_execute (a->plan[ss][LO]);
|
|
}
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
|
|
EnterCriticalSection(&(a->EliminateSection[ss]));
|
|
if ((ss >= a->begin_ss) && (ss <= a->end_ss))
|
|
eliminate(disp, ss, LO);
|
|
a->spec_flag[ss] |= 1 << LO;
|
|
|
|
if (a->spec_flag[ss] == ((1 << a->num_fft) - 1))
|
|
{
|
|
a->spec_flag[ss] = 0;
|
|
LeaveCriticalSection (&(a->EliminateSection[ss]));
|
|
|
|
EnterCriticalSection (&a->StitchSection);
|
|
a->stitch_flag |= ((uint64_t)1) << ss;
|
|
|
|
if (a->stitch_flag == ((((uint64_t)1) << a->num_stitch) - 1))
|
|
{
|
|
a->stitch_flag = 0;
|
|
LeaveCriticalSection(&a->StitchSection);
|
|
for (j = 0; j < dMAX_STITCH; j++)
|
|
for (i = 0; i < dMAX_NUM_FFT; i++)
|
|
InterlockedBitTestAndReset(&(a->input_busy[j][i]), 0);
|
|
stitch(disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->StitchSection);
|
|
}
|
|
else
|
|
LeaveCriticalSection (&(a->EliminateSection[ss]));
|
|
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 1;
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* BEGIN CODE TO GET MAX FFT_BIN WITHIN A FREQ RANGE *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
// Call in XCreateAnalyzer(...)
|
|
// This gets initialized for each 'disp' that is set up.
|
|
void Init_DetectMaxBin(int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
InitializeCriticalSectionAndSpinCount(&a->cs_dmb, 2500);
|
|
a->dmb_run = 0;
|
|
a->dmb_disp = disp;
|
|
a->dmb_ss = 0;
|
|
a->dmb_LO = 0;
|
|
a->dmb_rate = 48000.0;
|
|
a->dmb_fLow = 0.0;
|
|
a->dmb_fHigh = 0.0;
|
|
a->dmb_begin0 = 0;
|
|
a->dmb_end0 = -1;
|
|
a->dmb_begin1 = 0;
|
|
a->dmb_end1 = -1;
|
|
a->dmb_max_dB = -400.0;
|
|
}
|
|
|
|
// Call in DestroyAnalyzer(...)
|
|
void Destroy_DetectMaxBin(int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
DeleteCriticalSection(&a->cs_dmb);
|
|
}
|
|
|
|
// Called from SetupDetectMaxBin(...) AND anytime 'size' changes, e.g., in SetAnalyzer(...)
|
|
void calc_dmb(int disp, int size)
|
|
{
|
|
DP a = pdisp[disp];
|
|
double bin_spacing, min_freq, max_freq;
|
|
bin_spacing = a->dmb_rate / size;
|
|
min_freq = -a->dmb_rate * (double)((size / 2 - 1)) / (double)size;
|
|
max_freq = -min_freq;
|
|
if (a->dmb_fLow < min_freq) a->dmb_fLow = min_freq;
|
|
if (a->dmb_fLow > max_freq) a->dmb_fLow = max_freq;
|
|
if (a->dmb_fHigh < min_freq) a->dmb_fHigh = min_freq;
|
|
if (a->dmb_fHigh > max_freq) a->dmb_fHigh = max_freq;
|
|
|
|
if (a->dmb_fLow < 0.0 && a->dmb_fHigh < 0.0)
|
|
{
|
|
a->dmb_begin0 = size - (int)ceil(-a->dmb_fLow / bin_spacing);
|
|
// Example: 1024, 48K, -2700 => 966
|
|
// Example: 1024, 48K, -23953.125==min_freq => 513
|
|
// NOTE: since dmb_fLow < 0.0, begin0 will never be greater than a->size - 1
|
|
a->dmb_end0 = size - (int)ceil(-a->dmb_fHigh / bin_spacing);
|
|
// Example: 1024, 48K, -300 => 1017
|
|
a->dmb_begin1 = 0;
|
|
a->dmb_end1 = -1;
|
|
}
|
|
else if (a->dmb_fLow >= 0.0 && a->dmb_fHigh >= 0.0)
|
|
{
|
|
a->dmb_begin0 = (int)round(a->dmb_fLow / bin_spacing);
|
|
// Example: 1024, 48K, +300 => 6
|
|
a->dmb_end0 = (int)round(a->dmb_fHigh / bin_spacing);
|
|
// Example: 1024, 48K, +2700 => 58
|
|
// Example: 1024, 48K, 23953.125==max_freq => 511
|
|
a->dmb_begin1 = 0;
|
|
a->dmb_end1 = -1;
|
|
}
|
|
else // fLow < 0.0 && fHigh >= 0.0
|
|
{
|
|
a->dmb_begin0 = size - (int)ceil(-a->dmb_fLow / bin_spacing);
|
|
a->dmb_end0 = size - 1;
|
|
a->dmb_begin1 = 0;
|
|
a->dmb_end1 = (int)round(a->dmb_fHigh / bin_spacing);
|
|
}
|
|
if (a->dmb_tau > 0.0 && a->dmb_frame_rate > 0)
|
|
a->dmb_decay = exp(-1.0 / (a->dmb_tau * (double)a->dmb_frame_rate));
|
|
else
|
|
a->dmb_decay = 0.0;
|
|
a->dmb_max_dB = -400.0;
|
|
}
|
|
|
|
|
|
// Call from console, for each 'disp' for which this function is desired.
|
|
// Call for initial setup and anytime one of the parameters changes.
|
|
// run: Set to '1' if this is being used; cycles can be saved by setting to
|
|
// '0' if this is not currently in use.
|
|
// disp: Display identifier number.
|
|
// ss: Set to '0' for Thetis use.
|
|
// LO: Set to '0' for Thetis use.
|
|
// rate: Sample_rate of display data, e.g., '192000.0'.
|
|
// fLow: Lowest frequency of frequency range to evaluate, referenced to center_frequency
|
|
// to which DDC is tuned. For example, for LSB, not using CTUN, this might be
|
|
// '-3000.0'.
|
|
// fHigh: Highest frequency of frequency range to evaluate, referenced to center_frequency
|
|
// to which DDC is tuned. Example, LSB: '-300.0'.
|
|
// tau: Metering time constant in seconds. E.g., '0.5'.
|
|
// frame_rate: Display frame_rate currently in use. E.g., '60'.
|
|
PORT
|
|
void SetupDetectMaxBin(int run, int disp, int ss, int LO, double rate,
|
|
double fLow, double fHigh, double tau, int frame_rate)
|
|
{
|
|
// We only allow setup for one (ss,LO) pair at a time for each 'disp'.
|
|
DP a = pdisp[disp];
|
|
|
|
a->dmb_run = run;
|
|
a->dmb_disp = disp;
|
|
a->dmb_ss = ss;
|
|
a->dmb_LO = LO;
|
|
a->dmb_rate = rate;
|
|
a->dmb_fLow = fLow;
|
|
a->dmb_fHigh = fHigh;
|
|
a->dmb_tau = tau;
|
|
a->dmb_frame_rate = frame_rate;
|
|
|
|
calc_dmb(a->dmb_disp, a->size);
|
|
}
|
|
|
|
// Call this function in 'Cspectra(...)', after the FFT.
|
|
void DetectMaxBin(int disp, int ss, int LO)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i;
|
|
double mag, dmb_max;
|
|
double dmb_max_dB;
|
|
// If 'run' is set and the FFT Output is from the correct disp, ss, LO ...
|
|
if (a->dmb_run && disp == a->dmb_disp && ss == a->dmb_ss && LO == a->dmb_LO)
|
|
{
|
|
fftw_complex* fft_out = a->fft_out[ss][LO];
|
|
dmb_max = 1.0e-60;
|
|
EnterCriticalSection(&a->cs_dmb);
|
|
for (i = a->dmb_begin0; i <= a->dmb_end0; i++)
|
|
{
|
|
mag = fft_out[i][0] * fft_out[i][0] + fft_out[i][1] * fft_out[i][1];
|
|
if (mag > dmb_max) dmb_max = mag;
|
|
}
|
|
for (i = a->dmb_begin1; i <= a->dmb_end1; i++)
|
|
{
|
|
mag = fft_out[i][0] * fft_out[i][0] + fft_out[i][1] * fft_out[i][1];
|
|
if (mag > dmb_max) dmb_max = mag;
|
|
}
|
|
|
|
a->dmb_max_dB -= fabs((1.0 - a->dmb_decay) * a->dmb_max_dB);
|
|
dmb_max_dB = 10.0 * mlog10(a->scale * dmb_max);
|
|
if (dmb_max_dB > a->dmb_max_dB) a->dmb_max_dB = dmb_max_dB;
|
|
LeaveCriticalSection(&a->cs_dmb);
|
|
// for test only.
|
|
// printf("Max Bin = %.5e\n", a->dmb_max_dB);
|
|
}
|
|
}
|
|
|
|
// Call from console, for each 'disp' for which this function is desired.
|
|
// Always returns the value from the most recent display frame.
|
|
PORT
|
|
double GetDetectMaxBin(int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
double dmb_max_dB;
|
|
EnterCriticalSection(&a->cs_dmb);
|
|
dmb_max_dB = a->dmb_max_dB;
|
|
LeaveCriticalSection(&a->cs_dmb);
|
|
return dmb_max_dB;
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* END CODE TO GET MAXIMUM FFT_BIN WITHIN A FREQ RANGE *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
DWORD WINAPI Cspectra (void *pargs)
|
|
{
|
|
int i, j;
|
|
int disp = ((int)(uintptr_t)pargs) >> 12;
|
|
int ss = (((int)(uintptr_t)pargs) >> 4) & 255;
|
|
int LO = ((int)(uintptr_t)pargs) & 15;
|
|
DP a = pdisp[disp];
|
|
int trans_size = a->size * sizeof(double);
|
|
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
|
|
if ((ss >= a->begin_ss) && (ss <= a->end_ss))
|
|
{
|
|
for (i = 0; i < a->size; i++)
|
|
{
|
|
(a->Cfft_in[ss][LO])[i][0] = a->window[i] * (double)((a->I_samples[ss][LO])[a->IQO_idx[ss][LO]]);
|
|
(a->Cfft_in[ss][LO])[i][1] = a->window[i] * (double)((a->Q_samples[ss][LO])[a->IQO_idx[ss][LO]]);
|
|
if(++a->IQO_idx[ss][LO] >= a->bsize)
|
|
a->IQO_idx[ss][LO] -= a->bsize;
|
|
}
|
|
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
fftw_execute (a->Cplan[ss][LO]);
|
|
|
|
// Detect value of Max FFT Bin in a freq range
|
|
DetectMaxBin(disp, ss, LO);
|
|
//
|
|
|
|
}
|
|
|
|
if (a->stop)
|
|
{
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 0;
|
|
}
|
|
|
|
if (InterlockedBitTestAndReset(&(a->snap[ss][LO]), 0))
|
|
{
|
|
memcpy((char *)(a->snap_buff[ss][LO]), (char *)(a->fft_out[ss][LO]) + trans_size, trans_size);
|
|
memcpy((char *)(a->snap_buff[ss][LO]) + trans_size, (char *)(a->fft_out[ss][LO]), trans_size);
|
|
SetEvent(a->hSnapEvent[ss][LO]);
|
|
}
|
|
|
|
EnterCriticalSection(&(a->EliminateSection[ss]));
|
|
if ((ss >= a->begin_ss) && (ss <= a->end_ss))
|
|
Celiminate(disp, ss, LO);
|
|
a->spec_flag[ss] |= 1 << LO;
|
|
|
|
if (a->spec_flag[ss] == ((1 << a->num_fft) - 1))
|
|
{
|
|
a->spec_flag[ss] = 0;
|
|
LeaveCriticalSection (&(a->EliminateSection[ss]));
|
|
|
|
EnterCriticalSection (&a->StitchSection);
|
|
a->stitch_flag |= ((uint64_t)1) << ss;
|
|
|
|
if (a->stitch_flag == ((((uint64_t)1) << a->num_stitch) - 1))
|
|
{
|
|
a->stitch_flag = 0;
|
|
LeaveCriticalSection(&a->StitchSection);
|
|
for (j = 0; j < dMAX_STITCH; j++)
|
|
for (i = 0; i < dMAX_NUM_FFT; i++)
|
|
InterlockedBitTestAndReset(&(a->input_busy[j][i]), 0);
|
|
stitch(disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->StitchSection);
|
|
}
|
|
else
|
|
LeaveCriticalSection (&(a->EliminateSection[ss]));
|
|
|
|
InterlockedDecrement(a->pnum_threads);
|
|
return 1;
|
|
}
|
|
|
|
void interpolate(int disp, int set, double fmin, double fmax, int num_pixels)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i;
|
|
double f;
|
|
int n = a->n_freqs[set];
|
|
int k;
|
|
int kmin = 0;
|
|
int kmax = n - 1;
|
|
int kdelta;
|
|
double dx;
|
|
double mag;
|
|
|
|
for (i = 0; i < num_pixels; i++)
|
|
{
|
|
f = fmin + (double)i * (fmax - fmin) / (double)(num_pixels - 1);
|
|
|
|
if (f < (a->freqs[set])[0])
|
|
k = 0;
|
|
else if (f > (a->freqs[set])[n - 1])
|
|
k = n - 2;
|
|
else
|
|
{
|
|
kdelta = 1;
|
|
|
|
while (f < (a->freqs[set])[kmin])
|
|
{
|
|
kmin = max(0, kmin - kdelta);
|
|
kdelta += kdelta;
|
|
}
|
|
while (f > (a->freqs[set])[kmax])
|
|
{
|
|
kmax = min(n - 1, kmax + kdelta);
|
|
kdelta += kdelta;
|
|
}
|
|
k = (kmin + kmax) / 2;
|
|
while ((kmax - kmin) > 1)
|
|
{
|
|
k = (kmin + kmax) / 2;
|
|
if (f > (a->freqs[set])[k])
|
|
kmin = k;
|
|
else
|
|
kmax = k--;
|
|
}
|
|
}
|
|
|
|
dx = f - (a->freqs[set])[k];
|
|
|
|
mag = (((a->ac3[set][0])[k] * dx + (a->ac2[set][0])[k]) * dx + (a->ac1[set][0])[k]) * dx + (a->ac0[set][0])[k];
|
|
a->cd[i] = mag * mag;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int build_interpolants(int disp, int set, int n, int m, double *x, double (*y)[dMAX_M])
|
|
{
|
|
DP a = pdisp[disp];
|
|
double dx[dMAX_N];
|
|
double idx[dMAX_N];
|
|
double dmain[dMAX_N];
|
|
double dsub[dMAX_N];
|
|
double dsup[dMAX_N];
|
|
double d[dMAX_N][dMAX_M];
|
|
double S[dMAX_N][dMAX_M];
|
|
double b[dMAX_N];
|
|
double v[dMAX_N][dMAX_M];
|
|
double tmp;
|
|
int i, j;
|
|
if (n < 3) return -1;
|
|
for (i = 0; i < n - 1; i++)
|
|
{
|
|
dx[i] = x[i + 1] - x[i];
|
|
|
|
if (dx[i] < 1e-30)
|
|
return -1;
|
|
idx[i] = 1.0 / dx[i];
|
|
}
|
|
|
|
for (i = 1; i <= n - 2; i++)
|
|
{
|
|
if (i == 1)
|
|
{
|
|
dsub[i] = 0.0;
|
|
dmain[i] = 3.0 * dx[i - 1] + 2.0 * dx[i];
|
|
dsup[i] = dx[i];
|
|
}
|
|
else if (i == (n - 2))
|
|
{
|
|
dsub[i] = dx[i - 1];
|
|
dmain[i] = 2.0 * dx[i - 1] + 3.0 * dx[i];
|
|
dsup[i] = 0.0;
|
|
}
|
|
else
|
|
{
|
|
dsub[i] = dx[i - 1];
|
|
dmain[i] = 2.0 * (dx[i - 1] + dx[i]);
|
|
dsup[i] = dx[i];
|
|
}
|
|
for (j = 0; j < m; j++)
|
|
d[i][j] = 6.0 * ((y[i + 1][j] - y[i][j]) * idx[i] - (y[i][j] - y[i - 1][j]) * idx[i - 1]);
|
|
}
|
|
|
|
b[1] = dmain[1];
|
|
for (j = 0; j < m; j++)
|
|
v[1][j] = d[1][j];
|
|
|
|
for (i = 2; i <= n - 2; i++)
|
|
{
|
|
tmp = dsub[i] / b[i - 1];
|
|
b[i] = dmain[i] - tmp * dsup[i - 1];
|
|
for (j = 0; j < m; j++)
|
|
v[i][j] = d[i][j] - tmp * v[i - 1][j];
|
|
}
|
|
|
|
for (j = 0; j < m; j++)
|
|
S[n - 2][j] = v[n - 2][j] / b[n - 2];
|
|
|
|
for (i = n - 3; i >= 1; i--)
|
|
for (j = 0; j < m; j++)
|
|
S[i][j] = (v[i][j] - dsup[i] * S[i + 1][j]) / b[i];
|
|
|
|
for (j = 0; j < m; j++)
|
|
{
|
|
S[0][j] = S[1][j];
|
|
S[n - 1][j] = S[n - 2][j];
|
|
}
|
|
|
|
for (i = 0; i < n - 1; i++)
|
|
for (j = 0; j < m; j++)
|
|
{
|
|
(a->ac3[set][j])[i] = (S[i + 1][j] - S[i][j]) / (6.0 * dx[i]);
|
|
(a->ac2[set][j])[i] = 0.5 * S[i][j];
|
|
(a->ac1[set][j])[i] = (y[i + 1][j] - y[i][j]) * idx[i] - (2.0 * dx[i] * S[i][j] + dx[i] * S[i + 1][j]) / 6.0;
|
|
(a->ac0[set][j])[i] = y[i][j];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void __cdecl sendbuf(void *arg)
|
|
{
|
|
DP a = pdisp[(int)(uintptr_t)arg];
|
|
while(!a->end_dispatcher)
|
|
{
|
|
for (a->ss = 0; a->ss < a->num_stitch; a->ss++)
|
|
for (a->LO = 0; a->LO < a->num_fft; a->LO++)
|
|
{
|
|
if (!_InterlockedAnd(&(a->input_busy[a->ss][a->LO]), 1) && _InterlockedAnd(&(a->buff_ready[a->ss][a->LO]), 1))
|
|
{
|
|
InterlockedBitTestAndSet(&(a->input_busy[a->ss][a->LO]), 0);
|
|
|
|
a->IQO_idx[a->ss][a->LO] = a->IQout_index[a->ss][a->LO];
|
|
|
|
InterlockedIncrement(a->pnum_threads);
|
|
if (a->type == 0)
|
|
QueueUserWorkItem(spectra, (void *)(((uintptr_t)arg << 12) + (a->ss << 4) + a->LO), 0);
|
|
else
|
|
QueueUserWorkItem(Cspectra, (void *)(((uintptr_t)arg << 12) + (a->ss << 4) + a->LO), 0);
|
|
|
|
if((a->IQout_index[a->ss][a->LO] += a->incr) >= a->bsize)
|
|
a->IQout_index[a->ss][a->LO] -= a->bsize;
|
|
|
|
EnterCriticalSection(&(a->BufferControlSection[a->ss][a->LO]));
|
|
if ((a->have_samples[a->ss][a->LO] -= a->incr) < a->size)
|
|
InterlockedBitTestAndReset(&(a->buff_ready[a->ss][a->LO]), 0);
|
|
LeaveCriticalSection(&(a->BufferControlSection[a->ss][a->LO]));
|
|
}
|
|
}
|
|
Sleep(1);
|
|
}
|
|
InterlockedBitTestAndReset(&a->dispatcher, 0);
|
|
_endthread();
|
|
}
|
|
|
|
void CalcBandwidthNormalization (DP a)
|
|
{
|
|
double bin_width;
|
|
if (a->sample_rate <= 0 || a->size <= 0) { a->norm_oneHz = 0.0; return; }
|
|
bin_width = (double)a->sample_rate / (double)a->size;
|
|
if (bin_width <= 0.0) { a->norm_oneHz = 0.0; return; }
|
|
a->norm_oneHz = 10.0 * mlog10 (1.0 / bin_width);
|
|
}
|
|
|
|
PORT
|
|
void ResetPixelBuffers(int disp)
|
|
{
|
|
//[2.10.2]MW0LGE reset all the pixel and average buffers
|
|
DP a = pdisp[disp];
|
|
int i, j, k;
|
|
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
EnterCriticalSection(&a->ResampleSection);
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
{
|
|
for (j = 0; j < dMAX_PIXELS; j++)
|
|
a->t_pixels[i][j] = 0.0;
|
|
for (j = 0; j < dMAX_AVERAGE; j++)
|
|
for (k = 0; k < dMAX_PIXELS; k++)
|
|
a->av_buff[i][j][k] = 0.0f;
|
|
switch (a->av_mode[i])
|
|
{
|
|
case 1:
|
|
for (j = 0; j < dMAX_PIXELS; j++)
|
|
a->av_sum[i][j] = 1.0e-12;
|
|
break;
|
|
case 2:
|
|
//done below
|
|
//a->avail_frames[i] = 0;
|
|
//a->av_in_idx[i] = 0;
|
|
//a->av_out_idx[i] = 0;
|
|
break;
|
|
case 3:
|
|
for (j = 0; j < dMAX_PIXELS; j++)
|
|
a->av_sum[i][j] = -160.0;
|
|
break;
|
|
default:
|
|
memset((void*)a->av_sum[i], 0, sizeof(double) * dMAX_PIXELS);
|
|
break;
|
|
}
|
|
a->avail_frames[i] = 0;
|
|
a->av_in_idx[i] = 0;
|
|
a->av_out_idx[i] = 0;
|
|
EnterCriticalSection(&a->PB_ControlsSection[i]);
|
|
a->w_pix_buff[i] = 0;
|
|
a->r_pix_buff[i] = 0;
|
|
a->last_pix_buff[i] = 0;
|
|
for (j = 0; j < dNUM_PIXEL_BUFFS; j++)
|
|
a->pb_ready[i][j] = 0;
|
|
LeaveCriticalSection(&a->PB_ControlsSection[i]);
|
|
}
|
|
memset((void*)a->pre_av_out, 0, sizeof(double) * a->max_size * a->max_stitch);
|
|
LeaveCriticalSection(&a->ResampleSection);
|
|
EnterCriticalSection(&a->StitchSection);
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
a->input_busy[i][j] = 0;
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
a->spec_flag[i] = 0;
|
|
a->stitch_flag = 0;
|
|
a->ss = 0;
|
|
a->LO = 0;
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
{
|
|
EnterCriticalSection(&(a->BufferControlSection[i][j]));
|
|
a->buff_ready[i][j] = 0;
|
|
a->have_samples[i][j] = 0;
|
|
a->IQin_index[i][j] = 0;
|
|
a->IQout_index[i][j] = 0;
|
|
LeaveCriticalSection(&(a->BufferControlSection[i][j]));
|
|
}
|
|
LeaveCriticalSection(&a->StitchSection);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
|
|
PORT
|
|
void SetAnalyzer ( int disp, // display identifier
|
|
int n_pixout, // pixel output identifier
|
|
int n_fft, // number of LO frequencies = number of ffts used in elimination
|
|
int typ, // 0 for real input data (I only); 1 for complex input data (I & Q)
|
|
int *flp, // vector with one elt for each LO frequency, 1 if high-side LO, 0 otherwise
|
|
int sz, // size of the fft, i.e., number of input samples
|
|
int bf_sz, // number of samples transferred for each OpenBuffer()/CloseBuffer()
|
|
int win_type, // integer specifying which window function to use
|
|
double pi, // PiAlpha parameter for Kaiser window
|
|
int ovrlp, // number of samples each fft (other than the first) is to re-use from the previous
|
|
int clp, // number of fft output bins to be clipped from EACH side of each sub-span
|
|
double fscLin, // number of bins to clip from low end of entire span
|
|
double fscHin, // number of bins to clip from high end of entire span
|
|
int n_pix, // number of pixel values to return. may be either <= or > number of bins
|
|
int n_stch, // number of sub-spans to concatenate to form a complete span
|
|
int calset, // identifier of which set of calibration data to use
|
|
double fmin, // frequency at first pixel value
|
|
double fmax, // frequency at last pixel value
|
|
int max_w
|
|
)
|
|
{
|
|
WDSP_FPE_GUARD;
|
|
DP a = pdisp[disp];
|
|
int i, j;
|
|
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
a->end_dispatcher = 1;
|
|
while (InterlockedAnd(&a->dispatcher, 1))
|
|
Sleep(1);
|
|
a->stop = 1;
|
|
while (_InterlockedAnd(a->pnum_threads, 1023))
|
|
Sleep(1);
|
|
a->num_pixout = n_pixout;
|
|
a->num_fft = n_fft;
|
|
a->type = typ;
|
|
a->buff_size = bf_sz;
|
|
for (i = 0; i < a->num_fft; i++)
|
|
a->flip[i] = *(flp + i);
|
|
a->overlap = ovrlp;
|
|
a->clip = clp;
|
|
a->fsclipL = fscLin;
|
|
a->fsclipH = fscHin;
|
|
a->num_stitch = n_stch;
|
|
|
|
if (sz != a->size)
|
|
{
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
if (a->plan[i][j]) fftw_destroy_plan (a->plan[i][j]);
|
|
if (a->Cplan[i][j]) fftw_destroy_plan (a->Cplan[i][j]);
|
|
a->plan[i][j] = fftw_plan_dft_r2c_1d(sz, a->fft_in[i][j], a->fft_out[i][j], FFTW_PATIENT);
|
|
a->Cplan[i][j] = fftw_plan_dft_1d(sz, a->Cfft_in[i][j], a->fft_out[i][j], FFTW_FORWARD, FFTW_PATIENT);
|
|
}
|
|
|
|
// Setup DetectMaxBin for a 'size' change.
|
|
calc_dmb(disp, sz);
|
|
//
|
|
|
|
}
|
|
|
|
if ((sz != a->size) || (win_type != a->window_type) || (pi != a->PiAlpha))
|
|
new_window(disp, win_type, sz, pi);
|
|
|
|
a->size = sz;
|
|
a->window_type = win_type;
|
|
a->PiAlpha = pi;
|
|
a->max_writeahead = max_w;
|
|
CalcBandwidthNormalization (a);
|
|
if (((fmin != a->f_min) || (fmax != a->f_max)) && ((fmin == 0.0) && (fmax == 0.0)))
|
|
for (i = 0; i < dMAX_PIXELS; i++)
|
|
a->cd[i] = 1.0;
|
|
|
|
if (((fmax != 0.0) || (fmin != 0.0)) && ((n_pix != a->num_pixels) || (fmin != a->f_min) || (fmax != a->f_max) || (calset != a->cal_set) || a->cal_changed))
|
|
interpolate(disp, calset, fmin, fmax, n_pix);
|
|
|
|
a->incr = a->size - a->overlap;
|
|
a->num_pixels = n_pix;
|
|
a->f_min = fmin;
|
|
a->f_max = fmax;
|
|
a->cal_set = calset;
|
|
a->cal_changed = 0;
|
|
|
|
if (a->type == 0)
|
|
{
|
|
a->out_size = a->size / 2 + 1;
|
|
a->scale = 4.0 / ((double)a->size * (double)a->size);
|
|
}
|
|
else
|
|
{
|
|
a->out_size = a->size;
|
|
a->scale = 1.0 / ((double)a->size * (double)a->size);
|
|
}
|
|
|
|
a->begin_ss = 0;
|
|
a->end_ss = a->num_stitch - 1;
|
|
a->fscL = (int)a->fsclipL;
|
|
a->fscH = (int)a->fsclipH;
|
|
while (a->fscL >= (a->out_size - 1 - 2 * a->clip))
|
|
{
|
|
a->fscL -= a->out_size - 1 - 2 * a->clip;
|
|
a->ss_bins[a->begin_ss] = 0;
|
|
a->begin_ss++;
|
|
}
|
|
while (a->fscH >= (a->out_size - 1 - 2 * a->clip))
|
|
{
|
|
a->fscH -= a->out_size - 1 - 2 * a->clip;
|
|
a->ss_bins[a->end_ss] = 0;
|
|
a->end_ss--;
|
|
}
|
|
|
|
a->pix_per_bin = (double)a->num_pixels / ((double)(a->num_stitch * (a->out_size - 1 - 2 * a->clip)) - a->fsclipL - a->fsclipH - 1.0);
|
|
a->det_offset = -a->pix_per_bin * (a->fsclipL - floor(a->fsclipL));
|
|
a->bin_per_pix = ((double)(a->num_stitch * (a->out_size - 1 - 2 * a->clip)) - 1.0 - a->fsclipL - a->fsclipH) / ((double)a->num_pixels - 1.0);
|
|
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
a->input_busy[i][j] = 0;
|
|
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
a->spec_flag[i] = 0;
|
|
a->stitch_flag = 0;
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
{
|
|
a->w_pix_buff[i] = 0;
|
|
a->r_pix_buff[i] = 0;
|
|
a->last_pix_buff[i] = 0;
|
|
for (j = 0; j < dNUM_PIXEL_BUFFS; j++)
|
|
a->pb_ready[i][j] = 0;
|
|
}
|
|
a->ss = 0;
|
|
a->LO = 0;
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
{
|
|
a->buff_ready[i][j] = 0;
|
|
a->have_samples[i][j] = 0;
|
|
a->IQin_index[i][j] = 0;
|
|
a->IQout_index[i][j] = 0;
|
|
}
|
|
|
|
a->stop = 0;
|
|
a->end_dispatcher = 0;
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
|
|
PORT
|
|
void XCreateAnalyzer( int disp,
|
|
int *success,
|
|
int m_size,
|
|
int m_num_fft,
|
|
int m_stitch,
|
|
char *app_data_path
|
|
)
|
|
{
|
|
WDSP_FPE_GUARD;
|
|
int i, j;
|
|
DP a = (DP) malloc0 (sizeof(dp));
|
|
pdisp[disp] = a;
|
|
|
|
a->max_size = m_size;
|
|
a->max_num_fft = m_num_fft;
|
|
a->max_stitch = m_stitch;
|
|
|
|
a->pnum_threads = (LONG*) malloc0 (sizeof (LONG));
|
|
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
a->hSnapEvent[i][j] = CreateEvent(NULL, FALSE, FALSE, TEXT("snap"));
|
|
a->snap[i][j] = 0;
|
|
}
|
|
InitializeCriticalSectionAndSpinCount(&a->ResampleSection, 0);
|
|
InitializeCriticalSectionAndSpinCount(&a->SetAnalyzerSection, 0);
|
|
InitializeCriticalSectionAndSpinCount(&a->StitchSection, 0);
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
InitializeCriticalSectionAndSpinCount(&a->PB_ControlsSection[i], 0);
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
{
|
|
InitializeCriticalSectionAndSpinCount(&(a->EliminateSection[i]), 0);
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
InitializeCriticalSectionAndSpinCount(&(a->BufferControlSection[i][j]), 0);
|
|
}
|
|
|
|
a->window = (double*) malloc0 (sizeof(double) * a->max_size);
|
|
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
{
|
|
a->result[i] = (double*) malloc0 (sizeof(double) * a->max_size);
|
|
|
|
}
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
a->plan[i][j] = 0;
|
|
a->Cplan[i][j] = 0;
|
|
a->fft_in[i][j] = (double*) malloc0 (sizeof(double) * a->max_size);
|
|
a->Cfft_in[i][j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * a->max_size);
|
|
a->fft_out[i][j] = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * a->max_size);
|
|
}
|
|
a->pre_av_out = (double*) malloc0 (sizeof(double) * a->max_size * a->max_stitch);
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
{
|
|
a->det_type[i] = 0;
|
|
a->av_mode[i] = 0;
|
|
a->av_sum[i] = (double*) malloc0 (sizeof(double) * dMAX_PIXELS);
|
|
for (j = 0; j < dMAX_AVERAGE; j++)
|
|
a->av_buff[i][j] = (double*) malloc0 (sizeof(double) * dMAX_PIXELS);
|
|
a->t_pixels[i] = (double*) malloc0 (sizeof(double) * dMAX_PIXELS);
|
|
for (j = 0; j < dNUM_PIXEL_BUFFS; j++)
|
|
a->pixels[i][j] = (dOUTREAL*) malloc0 (sizeof(dOUTREAL) * dMAX_PIXELS);
|
|
}
|
|
|
|
a->cd = (double*) malloc0 (sizeof(double) * dMAX_PIXELS);
|
|
for (j = 0; j < dMAX_PIXELS; j++)
|
|
a->cd[j] = 1.0;
|
|
for (i = 0; i < dMAX_CAL_SETS; i++)
|
|
{
|
|
a->freqs[i] = (double*) malloc0 (sizeof(double) * dMAX_N);
|
|
for (j = 0; j < dMAX_M; j++)
|
|
{
|
|
a->ac3[i][j] = (double*) malloc0 (sizeof(double) * dMAX_N);
|
|
a->ac2[i][j] = (double*) malloc0 (sizeof(double) * dMAX_N);
|
|
a->ac1[i][j] = (double*) malloc0 (sizeof(double) * dMAX_N);
|
|
a->ac0[i][j] = (double*) malloc0 (sizeof(double) * dMAX_N);
|
|
}
|
|
}
|
|
|
|
a->size = -1;
|
|
a->window_type = -1;
|
|
a->num_pixels = -1;
|
|
a->cal_set = -1;
|
|
a->f_min = -1.0;
|
|
a->f_max = -1.0;
|
|
|
|
a->bsize = a->max_size * dSAMP_BUFF_MULT;
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
a->I_samples[i][j] = (dINREAL*) malloc0 (sizeof(dINREAL) * a->bsize);
|
|
a->Q_samples[i][j] = (dINREAL*) malloc0 (sizeof(dINREAL) * a->bsize);
|
|
}
|
|
|
|
// Initialize DetectMaxBin functionality
|
|
Init_DetectMaxBin(disp);
|
|
// for test only.
|
|
// SetupDetectMaxBin(1, 0, 0, 0, 192000.0, -3000.0, -300.0, 0.5, 60);
|
|
//
|
|
|
|
*success = 0;
|
|
}
|
|
|
|
PORT
|
|
void DestroyAnalyzer(int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i, j;
|
|
|
|
a->end_dispatcher = 1;
|
|
while (InterlockedAnd(&a->dispatcher, 1))
|
|
Sleep(1);
|
|
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
_aligned_free (a->I_samples[i][j]);
|
|
_aligned_free (a->Q_samples[i][j]);
|
|
}
|
|
|
|
for (i = 0; i < dMAX_CAL_SETS; i++)
|
|
{
|
|
_aligned_free (a->freqs[i]);
|
|
for (j = 0; j < dMAX_M; j++)
|
|
{
|
|
_aligned_free (a->ac3[i][j]);
|
|
_aligned_free (a->ac2[i][j]);
|
|
_aligned_free (a->ac1[i][j]);
|
|
_aligned_free (a->ac0[i][j]);
|
|
}
|
|
}
|
|
_aligned_free (a->cd);
|
|
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
{
|
|
for (j = 0; j < dNUM_PIXEL_BUFFS; j++)
|
|
_aligned_free (a->pixels[i][j]);
|
|
_aligned_free (a->t_pixels[i]);
|
|
for (j = 0; j < dMAX_AVERAGE; j++)
|
|
_aligned_free (a->av_buff[i][j]);
|
|
_aligned_free (a->av_sum[i]);
|
|
}
|
|
|
|
_aligned_free (a->pre_av_out);
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
{
|
|
fftw_destroy_plan (a->plan[i][j]);
|
|
fftw_destroy_plan (a->Cplan[i][j]);
|
|
fftw_free (a->Cfft_in[i][j]);
|
|
_aligned_free (a->fft_in[i][j]);
|
|
fftw_free (a->fft_out[i][j]);
|
|
}
|
|
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
_aligned_free (a->result[i]);
|
|
_aligned_free (a->window);
|
|
|
|
for (i = 0; i < dMAX_STITCH; i++)
|
|
{
|
|
DeleteCriticalSection(&(a->EliminateSection[i]));
|
|
for (j = 0; j < dMAX_NUM_FFT; j++)
|
|
DeleteCriticalSection(&(a->BufferControlSection[i][j]));
|
|
}
|
|
for (i = 0; i < dMAX_PIXOUTS; i++)
|
|
DeleteCriticalSection(&a->PB_ControlsSection[i]);
|
|
DeleteCriticalSection(&a->StitchSection);
|
|
DeleteCriticalSection(&a->SetAnalyzerSection);
|
|
DeleteCriticalSection(&a->ResampleSection);
|
|
|
|
for (i = 0; i < a->max_stitch; i++)
|
|
for (j = 0; j < a->max_num_fft; j++)
|
|
CloseHandle(a->hSnapEvent[i][j]);
|
|
|
|
_aligned_free ((void *) a->pnum_threads);
|
|
|
|
// Destroy DetectMaxBin functionality.
|
|
Destroy_DetectMaxBin(disp);
|
|
//
|
|
|
|
_aligned_free (a);
|
|
}
|
|
|
|
PORT
|
|
void GetPixels ( int disp,
|
|
int pixout,
|
|
dOUTREAL *pix, //if new pixel values avail, copies to pix and sets flag = 1
|
|
int *flag //else, returns 0 (try again later)
|
|
)
|
|
{
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->PB_ControlsSection[pixout]);
|
|
a->r_pix_buff[pixout] = a->last_pix_buff[pixout];
|
|
LeaveCriticalSection(&a->PB_ControlsSection[pixout]);
|
|
|
|
if (_InterlockedAnd(&(a->pb_ready[pixout][a->r_pix_buff[pixout]]), 1))
|
|
{
|
|
memcpy (pix, a->pixels[pixout][a->r_pix_buff[pixout]], a->num_pixels * sizeof(dOUTREAL));
|
|
*flag = 1;
|
|
InterlockedBitTestAndReset(&(a->pb_ready[pixout][a->r_pix_buff[pixout]]), 0);
|
|
}
|
|
else
|
|
*flag = 0;
|
|
}
|
|
|
|
PORT
|
|
void SnapSpectrum( int disp,
|
|
int ss,
|
|
int LO,
|
|
double *snap_buff)
|
|
{
|
|
DP a = pdisp[disp];
|
|
a->snap_buff[ss][LO] = snap_buff;
|
|
InterlockedBitTestAndSet(&(a->snap[ss][LO]), 0);
|
|
WaitForSingleObject(a->hSnapEvent[ss][LO], INFINITE);
|
|
}
|
|
|
|
PORT
|
|
void SnapSpectrumTimeout( int disp,
|
|
int ss,
|
|
int LO,
|
|
double* snap_buff,
|
|
DWORD timeout,
|
|
int* flag)
|
|
{
|
|
DP a = pdisp[disp];
|
|
a->snap_buff[ss][LO] = snap_buff;
|
|
ResetEvent(a->hSnapEvent[ss][LO]);
|
|
InterlockedBitTestAndSet(&(a->snap[ss][LO]), 0);
|
|
if (!WaitForSingleObject(a->hSnapEvent[ss][LO], timeout))
|
|
*flag = 1;
|
|
else
|
|
{
|
|
InterlockedBitTestAndReset(&(a->snap[ss][LO]), 0);
|
|
*flag = 0;
|
|
}
|
|
}
|
|
|
|
int calcompare (const void * a, const void * b)
|
|
{
|
|
if (*(double*)a < *(double*)b)
|
|
return -1;
|
|
else if (*(double*)a == *(double*)b)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
PORT
|
|
void SetCalibration ( int disp,
|
|
int set_num, //identifier for this calibration data set
|
|
int n_points, //number of calibration points in the set
|
|
double (*cal)[dMAX_M+1] //pointer to the calibration table, first
|
|
) // column is frequency, add'l columns are
|
|
// data for variables being calibrated
|
|
{
|
|
DP a = pdisp[disp];
|
|
int i, j;
|
|
int k = 0;
|
|
double y [dMAX_N][dMAX_M];
|
|
|
|
qsort (cal, n_points, (dMAX_M+1) * sizeof(double), calcompare);
|
|
|
|
for (i = 0; i < n_points; i++)
|
|
{
|
|
if ((i == n_points - 1) || (cal[i][0] != cal[i + 1][0]))
|
|
{
|
|
(a->freqs[set_num])[k] = cal[i][0];
|
|
for (j = 0; j < dMAX_M; j++)
|
|
y[k][j] = cal[i][j + 1];
|
|
k++;
|
|
}
|
|
}
|
|
|
|
a->n_freqs[set_num] = k;
|
|
|
|
build_interpolants(disp, set_num, a->n_freqs[set_num], dMAX_M, a->freqs[set_num], y);
|
|
a->cal_changed = 1;
|
|
}
|
|
|
|
PORT
|
|
void OpenBuffer(int disp, int ss, int LO, void **Ipointer, void **Qpointer)
|
|
{
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
*Ipointer = &((a->I_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
*Qpointer = &((a->Q_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
|
|
PORT
|
|
void CloseBuffer(int disp, int ss, int LO)
|
|
{
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
EnterCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if (a->have_samples[ss][LO] > a->max_writeahead)
|
|
{
|
|
//if we're receiving samples too much faster than we're consuming them, skip some
|
|
if ((a->IQout_index[ss][LO] += a->have_samples[ss][LO] - a->max_writeahead) >= a->bsize)
|
|
a->IQout_index[ss][LO] -= a->bsize;
|
|
a->have_samples[ss][LO] = a->max_writeahead;
|
|
}
|
|
if ((a->have_samples[ss][LO] += a->buff_size) >= a->size)
|
|
InterlockedBitTestAndSet(&(a->buff_ready[ss][LO]), 0);
|
|
LeaveCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if((a->IQin_index[ss][LO] += a->buff_size) >= a->bsize) //REQUIRES buff_size IS A SUB-MULTIPLE OF SIZE OF INPUT SAMPLE BUFFS!
|
|
a->IQin_index[ss][LO] = 0;
|
|
|
|
if (!InterlockedAnd(&a->dispatcher, 1))
|
|
{
|
|
InterlockedBitTestAndSet (&a->dispatcher, 0);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
_beginthread(sendbuf, 0, (void *)(uintptr_t)disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
|
|
PORT
|
|
void Spectrum(int disp, int ss, int LO, dINREAL* pI, dINREAL* pQ)
|
|
{
|
|
dINREAL *Ipointer;
|
|
dINREAL *Qpointer;
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
Ipointer = &((a->I_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
Qpointer = &((a->Q_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
|
|
memcpy(Ipointer, pI, a->buff_size * sizeof(dINREAL));
|
|
memcpy(Qpointer, pQ, a->buff_size * sizeof(dINREAL));
|
|
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
EnterCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if (a->have_samples[ss][LO] > a->max_writeahead)
|
|
{
|
|
//if we're receiving samples too much faster than we're consuming them, skip some
|
|
if ((a->IQout_index[ss][LO] += a->have_samples[ss][LO] - a->max_writeahead) >= a->bsize)
|
|
a->IQout_index[ss][LO] -= a->bsize;
|
|
a->have_samples[ss][LO] = a->max_writeahead;
|
|
}
|
|
if ((a->have_samples[ss][LO] += a->buff_size) >= a->size)
|
|
InterlockedBitTestAndSet(&(a->buff_ready[ss][LO]), 0);
|
|
LeaveCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if((a->IQin_index[ss][LO] += a->buff_size) >= a->bsize) //REQUIRES buff_size IS A SUB-MULTIPLE OF SIZE OF INPUT SAMPLE BUFFS!
|
|
a->IQin_index[ss][LO] = 0;
|
|
|
|
if (!InterlockedAnd(&a->dispatcher, 1))
|
|
{
|
|
InterlockedBitTestAndSet(&a->dispatcher, 0);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
_beginthread(sendbuf, 0, (void *)(uintptr_t)disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
|
|
PORT
|
|
void Spectrum2(int run, int disp, int ss, int LO, dINREAL* pbuff)
|
|
{
|
|
if (run)
|
|
{
|
|
int i;
|
|
dINREAL *Ipointer;
|
|
dINREAL *Qpointer;
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
Ipointer = &((a->I_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
Qpointer = &((a->Q_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
|
|
for (i = 0; i < a->buff_size; i++)
|
|
{
|
|
Ipointer[i] = pbuff[2 * i + 1];
|
|
Qpointer[i] = pbuff[2 * i + 0];
|
|
}
|
|
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
EnterCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if (a->have_samples[ss][LO] > a->max_writeahead)
|
|
{
|
|
//if we're receiving samples too much faster than we're consuming them, skip some
|
|
if ((a->IQout_index[ss][LO] += a->have_samples[ss][LO] - a->max_writeahead) >= a->bsize)
|
|
a->IQout_index[ss][LO] -= a->bsize;
|
|
a->have_samples[ss][LO] = a->max_writeahead;
|
|
}
|
|
if ((a->have_samples[ss][LO] += a->buff_size) >= a->size)
|
|
InterlockedBitTestAndSet(&(a->buff_ready[ss][LO]), 0);
|
|
LeaveCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if((a->IQin_index[ss][LO] += a->buff_size) >= a->bsize) //REQUIRES buff_size IS A SUB-MULTIPLE OF SIZE OF INPUT SAMPLE BUFFS!
|
|
a->IQin_index[ss][LO] = 0;
|
|
|
|
if (!InterlockedAnd(&a->dispatcher, 1))
|
|
{
|
|
InterlockedBitTestAndSet(&a->dispatcher, 0);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
_beginthread(sendbuf, 0, (void *)(uintptr_t)disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void Spectrum0(int run, int disp, int ss, int LO, double* pbuff)
|
|
{
|
|
if (run)
|
|
{
|
|
int i;
|
|
dINREAL *Ipointer;
|
|
dINREAL *Qpointer;
|
|
DP a = pdisp[disp];
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
Ipointer = &((a->I_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
Qpointer = &((a->Q_samples[ss][LO])[a->IQin_index[ss][LO]]);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
|
|
for (i = 0; i < a->buff_size; i++)
|
|
{
|
|
Ipointer[i] = (dINREAL)pbuff[2 * i + 1];
|
|
Qpointer[i] = (dINREAL)pbuff[2 * i + 0];
|
|
}
|
|
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
EnterCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if (a->have_samples[ss][LO] > a->max_writeahead)
|
|
{
|
|
//if we're receiving samples too much faster than we're consuming them, skip some
|
|
if ((a->IQout_index[ss][LO] += a->have_samples[ss][LO] - a->max_writeahead) >= a->bsize)
|
|
a->IQout_index[ss][LO] -= a->bsize;
|
|
a->have_samples[ss][LO] = a->max_writeahead;
|
|
}
|
|
if ((a->have_samples[ss][LO] += a->buff_size) >= a->size)
|
|
InterlockedBitTestAndSet(&(a->buff_ready[ss][LO]), 0);
|
|
LeaveCriticalSection(&(a->BufferControlSection[ss][LO]));
|
|
if((a->IQin_index[ss][LO] += a->buff_size) >= a->bsize) //REQUIRES buff_size IS A SUB-MULTIPLE OF SIZE OF INPUT SAMPLE BUFFS!
|
|
a->IQin_index[ss][LO] = 0;
|
|
|
|
if (!InterlockedAnd(&a->dispatcher, 1))
|
|
{
|
|
InterlockedBitTestAndSet(&a->dispatcher, 0);
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
_beginthread(sendbuf, 0, (void *)(uintptr_t)disp);
|
|
}
|
|
else
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplayDetectorMode (int disp, int pixout, int mode)
|
|
{
|
|
DP a = pdisp[disp];
|
|
if (a->det_type[pixout] != mode)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->det_type[pixout] = mode;
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplayAverageMode (int disp, int pixout, int mode)
|
|
{
|
|
int i;
|
|
DP a = pdisp[disp];
|
|
if (a->av_mode[pixout] != mode)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->av_mode[pixout] = mode;
|
|
switch (mode)
|
|
{
|
|
case 1:
|
|
for (i = 0; i < dMAX_PIXELS; i++)
|
|
a->av_sum[pixout][i] = 1.0e-12;
|
|
break;
|
|
case 2:
|
|
a->avail_frames[pixout] = 0;
|
|
a->av_in_idx[pixout] = 0;
|
|
a->av_out_idx[pixout] = 0;
|
|
break;
|
|
case 3:
|
|
for (i = 0; i < dMAX_PIXELS; i++)
|
|
a->av_sum[pixout][i] = -160.0;
|
|
break;
|
|
default:
|
|
memset ((void *)a->av_sum[pixout], 0, sizeof(double) * dMAX_PIXELS);
|
|
break;
|
|
}
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplayNumAverage (int disp, int pixout, int num)
|
|
{
|
|
DP a = pdisp[disp];
|
|
if (a->num_average[pixout] != num)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->num_average[pixout] = num;
|
|
a->avail_frames[pixout] = 0;
|
|
a->av_in_idx[pixout] = 0;
|
|
a->av_out_idx[pixout] = 0;
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplayAvBackmult (int disp, int pixout, double mult)
|
|
{
|
|
DP a = pdisp[disp];
|
|
if (a->av_backmult[pixout] != mult)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->av_backmult[pixout] = mult;
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplaySampleRate (int disp, int rate)
|
|
{
|
|
DP a = pdisp[disp];
|
|
if (a->sample_rate != rate)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->sample_rate = rate;
|
|
CalcBandwidthNormalization (a);
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetDisplayNormOneHz (int disp, int pixout, int norm)
|
|
{
|
|
DP a = pdisp[disp];
|
|
if (a->normalize[pixout] != norm)
|
|
{
|
|
EnterCriticalSection (&a->ResampleSection);
|
|
a->normalize[pixout] = norm;
|
|
LeaveCriticalSection (&a->ResampleSection);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
double GetDisplayENB (int disp)
|
|
{
|
|
DP a = pdisp[disp];
|
|
double enb;
|
|
EnterCriticalSection(&a->SetAnalyzerSection);
|
|
enb = 1.0 / a->inv_enb;
|
|
LeaveCriticalSection(&a->SetAnalyzerSection);
|
|
return enb;
|
|
}
|