/* emnr.c This file is part of a program that implements a Software-Defined Radio. Copyright (C) 2015, 2025 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 */ #define _CRT_SECURE_NO_WARNINGS #include "comm.h" #include "calculus.h" #include "zetaHat.h" #include "FDnoiseIQ.h" /******************************************************************************************************** * * * Special Functions * * * ********************************************************************************************************/ // MODIFIED BESSEL FUNCTIONS OF THE 0TH AND 1ST ORDERS, Polynomial Approximations // M. Abramowitz and I. Stegun, Eds., "Handbook of Mathematical Functions." Washington, DC: National // Bureau of Standards, 1964. // Shanjie Zhang and Jianming Jin, "Computation of Special Functions." New York, NY, John Wiley and Sons, // Inc., 1996. [Sample code given in FORTRAN] double bessI0 (double x) { double res, p; if (x == 0.0) res = 1.0; else { if (x < 0.0) x = -x; if (x <= 3.75) { p = x / 3.75; p = p * p; res = ((((( 0.0045813 * p + 0.0360768) * p + 0.2659732) * p + 1.2067492) * p + 3.0899424) * p + 3.5156229) * p + 1.0; } else { p = 3.75 / x; res = exp (x) / sqrt (x) * (((((((( + 0.00392377 * p - 0.01647633) * p + 0.02635537) * p - 0.02057706) * p + 0.00916281) * p - 0.00157565) * p + 0.00225319) * p + 0.01328592) * p + 0.39894228); } } return res; } double bessI1 (double x) { double res, p; if (x == 0.0) res = 0.0; else { if (x < 0.0) x = -x; if (x <= 3.75) { p = x / 3.75; p = p * p; res = x * (((((( 0.00032411 * p + 0.00301532) * p + 0.02658733) * p + 0.15084934) * p + 0.51498869) * p + 0.87890594) * p + 0.5); } else { p = 3.75 / x; res = exp (x) / sqrt (x) * (((((((( - 0.00420059 * p + 0.01787654) * p - 0.02895312) * p + 0.02282967) * p - 0.01031555) * p + 0.00163801) * p - 0.00362018) * p - 0.03988024) * p + 0.39894228); } } return res; } // EXPONENTIAL INTEGRAL, E1(x) // M. Abramowitz and I. Stegun, Eds., "Handbook of Mathematical Functions." Washington, DC: National // Bureau of Standards, 1964. // Shanjie Zhang and Jianming Jin, "Computation of Special Functions." New York, NY, John Wiley and Sons, // Inc., 1996. [Sample code given in FORTRAN] double e1xb (double x) { double e1, ga, r, t, t0; int k, m; if (x == 0.0) e1 = 1.0e300; else if (x <= 1.0) { e1 = 1.0; r = 1.0; for (k = 1; k <= 25; k++) { r = -r * k * x / ((k + 1.0)*(k + 1.0)); e1 = e1 + r; if ( fabs (r) <= fabs (e1) * 1.0e-15 ) break; } ga = 0.5772156649015328; e1 = - ga - log (x) + x * e1; } else { m = 20 + (int)(80.0 / x); t0 = 0.0; for (k = m; k >= 1; k--) t0 = (double)k / (1.0 + k / (x + t0)); t = 1.0 / (x + t0); e1 = exp (- x) * t; } return e1; } /******************************************************************************************************** * * * Main Body of Code * * * ********************************************************************************************************/ void calc_window (EMNR a) { int i; double arg, sum, inv_coherent_gain; switch (a->wintype) { case 0: arg = 2.0 * PI / (double)a->fsize; sum = 0.0; for (i = 0; i < a->fsize; i++) { a->window[i] = sqrt (0.54 - 0.46 * cos((double)i * arg)); sum += a->window[i]; } inv_coherent_gain = (double)a->fsize / sum; for (i = 0; i < a->fsize; i++) a->window[i] *= inv_coherent_gain; break; } } void interpM (double* res, double x, int nvals, double* xvals, double* yvals) { if (x <= xvals[0]) *res = yvals[0]; else if (x >= xvals[nvals - 1]) *res = yvals[nvals - 1]; else { int idx = 1; double xllow, xlhigh, frac; while (x > xvals[idx]) idx++; xllow = log10 (xvals[idx - 1]); xlhigh = log10 (xvals[idx]); frac = (log10 (x) - xllow) / (xlhigh - xllow); *res = yvals[idx - 1] + frac * (yvals[idx] - yvals[idx - 1]); } } int readZetaHat(const char* zeta_file, int* rows, int* cols, double* gmin, double* gmax, double* ximin, double* ximax, double* zetaHat, int* zetaValid) { char zetaBinary[256]; char bin[50] = ".bin"; sprintf (zetaBinary, "%s%s", zeta_file, bin); FILE* pzetaBinary; int e = 0; if (pzetaBinary = fopen(zetaBinary, "rb")) { int nvals = 0; // 'fread's executed only through first error if (e == 0 && fread(rows, sizeof(int), 1, pzetaBinary) != 1) e = 1; if (e == 0 && fread(cols, sizeof(int), 1, pzetaBinary) != 1) e = 1; if (e == 0 && fread(gmin, sizeof(double), 1, pzetaBinary) != 1) e = 1; if (e == 0 && fread(gmax, sizeof(double), 1, pzetaBinary) != 1) e = 1; if (e == 0 && fread(ximin, sizeof(double), 1, pzetaBinary) != 1) e = 1; if (e == 0 && fread(ximax, sizeof(double), 1, pzetaBinary) != 1) e = 1; if (e == 0) nvals = (*rows) * (*cols); if (e == 0 && fread(zetaHat, sizeof(double), nvals, pzetaBinary) != nvals) e = 1; if (e == 0 && fread(zetaValid, sizeof(int), nvals, pzetaBinary) != nvals) e = 1; fclose(pzetaBinary); } else e = 1; if (e) { *rows = CzetaRows; *cols = CzetaCols; *gmin = CzetaGmin; *gmax = CzetaGmax; *ximin = CzetaXimin; *ximax = CzetaXimax; int nvals = (*rows) * (*cols); memcpy (zetaHat, CzetaHat, nvals * sizeof (double)); memcpy (zetaValid, CzetaValid, nvals * sizeof (int)); } return 0; } void CwriteZetaHat(const char* cfile, int zetaHat_rows, int zetaHat_cols, double zetaHat_gmin, double zetaHat_gmax, double zetaHat_ximin, double zetaHat_ximax, double* zetaHat, int* zetaValid) { int n, i, j; char cfilename[256]; char dot_c[50] = ".c"; sprintf(cfilename, "%s%s", cfile, dot_c); FILE* pcfile; if (pcfile = fopen(cfilename, "w")) { fprintf(pcfile, "int CzetaRows = %d;\n", zetaHat_rows); fprintf(pcfile, "int CzetaCols = %d;\n", zetaHat_cols); fprintf(pcfile, "double CzetaGmin = %lf;\n", zetaHat_gmin); fprintf(pcfile, "double CzetaGmax = %lf;\n", zetaHat_gmax); fprintf(pcfile, "double CzetaXimin = %lf;\n", zetaHat_ximin); fprintf(pcfile, "double CzetaXimax = %lf;\n\n", zetaHat_ximax); n = zetaHat_rows * zetaHat_cols; fprintf(pcfile, "double CzetaHat [%d] =\n", n); fprintf(pcfile, "{\n"); i = 0; j = 0; while (i < n) { fprintf(pcfile, "%.17e, ", zetaHat[i++]); if (++j == 4) { fprintf(pcfile, "\n"); j = 0; } } if (j != 0) fprintf(pcfile, "\n"); fprintf(pcfile, "};\n\n"); fprintf(pcfile, "int CzetaValid [%d] =\n", n); fprintf(pcfile, "{\n"); i = 0; j = 0; while (i < n) { fprintf(pcfile, "%d, ", zetaValid[i++]); if (++j == 4) { fprintf(pcfile, "\n"); j = 0; } } if (j != 0) fprintf(pcfile, "\n"); fprintf(pcfile, "};\n"); fflush(pcfile); fclose(pcfile); } } void post2_calc_w(EMNR a); void calc_emnr(EMNR a) { int i; double Dvals[18] = { 1.0, 2.0, 5.0, 8.0, 10.0, 15.0, 20.0, 30.0, 40.0, 60.0, 80.0, 120.0, 140.0, 160.0, 180.0, 220.0, 260.0, 300.0 }; double Mvals[18] = { 0.000, 0.260, 0.480, 0.580, 0.610, 0.668, 0.705, 0.762, 0.800, 0.841, 0.865, 0.890, 0.900, 0.910, 0.920, 0.930, 0.935, 0.940 }; double Hvals[18] = { 0.000, 0.150, 0.480, 0.780, 0.980, 1.550, 2.000, 2.300, 2.520, 3.100, 3.380, 4.150, 4.350, 4.250, 3.900, 4.100, 4.700, 5.000 }; a->incr = a->fsize / a->ovrlp; a->gain = a->ogain / a->fsize / (double)a->ovrlp; if (a->fsize > a->bsize) a->iasize = a->fsize; else a->iasize = a->bsize + a->fsize - a->incr; a->iainidx = 0; a->iaoutidx = 0; if (a->fsize > a->bsize) { if (a->bsize > a->incr) a->oasize = a->bsize; else a->oasize = a->incr; a->oainidx = (a->fsize - a->bsize - a->incr) % a->oasize; } else { a->oasize = a->bsize; a->oainidx = a->fsize - a->incr; } a->init_oainidx = a->oainidx; a->oaoutidx = 0; a->msize = a->fsize / 2 + 1; a->window = (double *)malloc0(a->fsize * sizeof(double)); a->inaccum = (double *)malloc0(a->iasize * sizeof(double)); a->forfftin = (double *)malloc0(a->fsize * sizeof(double)); a->forfftout = (double *)malloc0(a->msize * sizeof(complex)); a->mask = (double *)malloc0(a->msize * sizeof(double)); a->revfftin = (double *)malloc0(a->msize * sizeof(complex)); a->revfftout = (double *)malloc0(a->fsize * sizeof(double)); a->save = (double **)malloc0(a->ovrlp * sizeof(double *)); for (i = 0; i < a->ovrlp; i++) a->save[i] = (double *)malloc0(a->fsize * sizeof(double)); a->outaccum = (double *)malloc0(a->oasize * sizeof(double)); a->nsamps = 0; a->saveidx = 0; a->Rfor = fftw_plan_dft_r2c_1d(a->fsize, a->forfftin, (fftw_complex *)a->forfftout, FFTW_ESTIMATE); a->Rrev = fftw_plan_dft_c2r_1d(a->fsize, (fftw_complex *)a->revfftin, a->revfftout, FFTW_ESTIMATE); calc_window(a); // // g a->g.msize = a->msize; a->g.mask = a->mask; a->g.y = a->forfftout; a->g.lambda_y = (double*)malloc0(a->msize * sizeof(double)); a->g.lambda_d = (double*)malloc0(a->msize * sizeof(double)); a->g.prev_gamma = (double*)malloc0(a->msize * sizeof(double)); a->g.prev_mask = (double*)malloc0(a->msize * sizeof(double)); a->g.gf1p5 = sqrt(PI) / 2.0; { double tau = -128.0 / 8000.0 / log(0.985); a->g.alpha = exp(-a->incr / a->rate / tau); } a->g.eps_floor = 1.0e-300; a->g.gamma_max = 40.0; a->g.xi_min = pow(10.0, -40.0 / 10.0); a->g.q = 0.2; for (i = 0; i < a->g.msize; i++) { a->g.prev_mask[i] = 1.0; a->g.prev_gamma[i] = 1.0; } a->g.gmax = 10000.0; // a->g.GG = (double *)malloc0(241 * 241 * sizeof(double)); a->g.GGS = (double *)malloc0(241 * 241 * sizeof(double)); if (a->g.fileb = fopen("calculus", "rb")) { fread(a->g.GG, sizeof(double), 241 * 241, a->g.fileb); fread(a->g.GGS, sizeof(double), 241 * 241, a->g.fileb); fclose(a->g.fileb); } else { memcpy (a->g.GG, GG, 241 * 241 * sizeof(double)); memcpy (a->g.GGS, GGS, 241 * 241 * sizeof(double)); } // a->g.dim_zeta = 60; a->g.zeta_hat = (double*)malloc0(a->g.dim_zeta * a->g.dim_zeta * sizeof(double)); a->g.zeta_true = (int*) malloc0(a->g.dim_zeta * a->g.dim_zeta * sizeof(int)); a->g.zeta_thresh = -2.0; int rows, cols; readZetaHat("zetaHat", &rows, &cols, &a->g.z_gamma_min, &a->g.z_gamma_max, &a->g.z_xihat_min, &a->g.z_xihat_max, a->g.zeta_hat, a->g.zeta_true); // CwriteZetaHat("zetaHat", rows, cols, a->g.z_gamma_min, a->g.z_gamma_max, a->g.z_xihat_min, a->g.z_xihat_max, a->g.zeta_hat, a->g.zeta_true); // np a->np.incr = a->incr; a->np.rate = a->rate; a->np.msize = a->msize; a->np.lambda_y = a->g.lambda_y; a->np.lambda_d = a->g.lambda_d; { double tau = -128.0 / 8000.0 / log(0.7); a->np.alphaCsmooth = exp(-a->np.incr / a->np.rate / tau); } { double tau = -128.0 / 8000.0 / log(0.96); a->np.alphaMax = exp(-a->np.incr / a->np.rate / tau); } { double tau = -128.0 / 8000.0 / log(0.7); a->np.alphaCmin = exp(-a->np.incr / a->np.rate / tau); } { double tau = -128.0 / 8000.0 / log(0.3); a->np.alphaMin_max_value = exp(-a->np.incr / a->np.rate / tau); } a->np.snrq = -a->np.incr / (0.064 * a->np.rate); { double tau = -128.0 / 8000.0 / log(0.8); a->np.betamax = exp(-a->np.incr / a->np.rate / tau); } a->np.invQeqMax = 0.5; a->np.av = 2.12; a->np.Dtime = 8.0 * 12.0 * 128.0 / 8000.0; a->np.U = 8; a->np.V = (int)(0.5 + (a->np.Dtime * a->np.rate / (a->np.U * a->np.incr))); if (a->np.V < 4) a->np.V = 4; if ((a->np.U = (int)(0.5 + (a->np.Dtime * a->np.rate / (a->np.V * a->np.incr)))) < 1) a->np.U = 1; a->np.D = a->np.U * a->np.V; interpM(&a->np.MofD, a->np.D, 18, Dvals, Mvals); interpM(&a->np.MofV, a->np.V, 18, Dvals, Mvals); a->np.invQbar_points[0] = 0.03; a->np.invQbar_points[1] = 0.05; a->np.invQbar_points[2] = 0.06; a->np.invQbar_points[3] = 1.0e300; { double db; db = 10.0 * log10(8.0) / (12.0 * 128 / 8000); a->np.nsmax[0] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate); db = 10.0 * log10(4.0) / (12.0 * 128 / 8000); a->np.nsmax[1] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate); db = 10.0 * log10(2.0) / (12.0 * 128 / 8000); a->np.nsmax[2] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate); db = 10.0 * log10(1.2) / (12.0 * 128 / 8000); a->np.nsmax[3] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate); } a->np.p = (double *)malloc0(a->np.msize * sizeof(double)); a->np.alphaOptHat = (double *)malloc0(a->np.msize * sizeof(double)); a->np.alphaHat = (double *)malloc0(a->np.msize * sizeof(double)); a->np.sigma2N = (double *)malloc0(a->np.msize * sizeof(double)); a->np.pbar = (double *)malloc0(a->np.msize * sizeof(double)); a->np.p2bar = (double *)malloc0(a->np.msize * sizeof(double)); a->np.Qeq = (double *)malloc0(a->np.msize * sizeof(double)); a->np.bmin = (double *)malloc0(a->np.msize * sizeof(double)); a->np.bmin_sub = (double *)malloc0(a->np.msize * sizeof(double)); a->np.k_mod = (int *)malloc0(a->np.msize * sizeof(int)); a->np.actmin = (double *)malloc0(a->np.msize * sizeof(double)); a->np.actmin_sub = (double *)malloc0(a->np.msize * sizeof(double)); a->np.lmin_flag = (int *)malloc0(a->np.msize * sizeof(int)); a->np.pmin_u = (double *)malloc0(a->np.msize * sizeof(double)); a->np.actminbuff = (double**)malloc0(a->np.U * sizeof(double*)); for (i = 0; i < a->np.U; i++) a->np.actminbuff[i] = (double *)malloc0(a->np.msize * sizeof(double)); { int k, ku; a->np.alphaC = 1.0; a->np.subwc = a->np.V; a->np.amb_idx = 0; for (k = 0; k < a->np.msize; k++) a->np.lambda_y[k] = 0.5; memcpy(a->np.p, a->np.lambda_y, a->np.msize * sizeof(double)); memcpy(a->np.sigma2N, a->np.lambda_y, a->np.msize * sizeof(double)); memcpy(a->np.pbar, a->np.lambda_y, a->np.msize * sizeof(double)); memcpy(a->np.pmin_u, a->np.lambda_y, a->np.msize * sizeof(double)); for (k = 0; k < a->np.msize; k++) { a->np.p2bar[k] = a->np.lambda_y[k] * a->np.lambda_y[k]; a->np.actmin[k] = 1.0e300; a->np.actmin_sub[k] = 1.0e300; for (ku = 0; ku < a->np.U; ku++) a->np.actminbuff[ku][k] = 1.0e300; } memset(a->np.lmin_flag, 0, a->np.msize * sizeof(int)); } // // nps a->nps.incr = a->incr; a->nps.rate = a->rate; a->nps.msize = a->msize; a->nps.lambda_y = a->g.lambda_y; a->nps.lambda_d = a->g.lambda_d; { double tau = -128.0 / 8000.0 / log(0.8); a->nps.alpha_pow = exp(-a->nps.incr / a->nps.rate / tau); } { double tau = -128.0 / 8000.0 / log(0.9); a->nps.alpha_Pbar = exp(-a->nps.incr / a->nps.rate / tau); } a->nps.epsH1 = pow(10.0, 15.0 / 10.0); a->nps.epsH1r = a->nps.epsH1 / (1.0 + a->nps.epsH1); a->nps.sigma2N = (double *)malloc0(a->nps.msize * sizeof(double)); a->nps.PH1y = (double *)malloc0(a->nps.msize * sizeof(double)); a->nps.Pbar = (double *)malloc0(a->nps.msize * sizeof(double)); a->nps.EN2y = (double *)malloc0(a->nps.msize * sizeof(double)); for (i = 0; i < a->nps.msize; i++) { a->nps.sigma2N[i] = 0.5; a->nps.Pbar[i] = 0.5; } // // npl a->npl.rate = a->rate; a->npl.msize = a->msize; a->npl.incr = a->incr; a->npl.Ysq = a->g.lambda_y; a->npl.P = (double*)malloc0 (a->npl.msize * sizeof(double)); a->npl.Pmin = (double*)malloc0 (a->npl.msize * sizeof(double)); a->npl.p = (double*)malloc0 (a->npl.msize * sizeof(double)); a->npl.D = (double*)malloc0 (a->npl.msize * sizeof(double)); a->npl.lambda_d = a->g.lambda_d; { double tau = -256.0 / (20100.0 * log(0.7)); a->npl.eta = exp(-a->npl.incr / (a->npl.rate * tau)); } { double tau = -256.0 / (20100.0 * log(0.998)); a->npl.gamma = exp(-a->npl.incr / (a->npl.rate * tau)); } { double tau = -256.0 / (20100.0 * log(0.8)); a->npl.beta = exp(-a->npl.incr / (a->npl.rate * tau)); } { double tau = -256.0 / (20100.0 * log(0.85)); a->npl.alpha_d = exp(-a->npl.incr / (a->npl.rate * tau)); } { double tau = -256.0 / (20100.0 * log(0.2)); a->npl.alpha_p = exp(-a->npl.incr / (a->npl.rate * tau)); } a->npl.delta_LF = 1000.0 / (a->npl.rate / 2) * a->npl.msize; a->npl.delta_MF = 3000.0 / (a->npl.rate / 2) * a->npl.msize; a->npl.delta_0 = 2.0; a->npl.delta_1 = 2.0; a->npl.delta_2 = 5.0; // // ae a->ae.msize = a->msize; a->ae.lambda_y = a->g.lambda_y; a->ae.zetaThresh = 0.75; a->ae.psi = 20.0; a->ae.t2 = 0.20; a->ae.nmask = (double *)malloc0(a->ae.msize * sizeof(double)); // // post2 a->post2.run = 0; a->post2.factor = 0.15; a->post2.nlevel = 0.15; a->post2.tc_decay = 5.0; a->post2.rate_decay = exp(-a->fsize / (a->post2.tc_decay * a->rate * a->ovrlp)); a->post2.taper = 0.12; a->post2.w = (double*)malloc0(a->msize * sizeof(double)); a->post2.noise_frames = FDnoise_frames; a->post2.noise_frame_index = 0; a->post2.noise_frame = (double*)malloc0(2 * a->msize * sizeof(double)); a->post2.olddmag = 0.0; post2_calc_w(a); } void decalc_emnr(EMNR a) { int i; // post2 _aligned_free(a->post2.noise_frame); _aligned_free(a->post2.w); // ae _aligned_free(a->ae.nmask); // npl _aligned_free(a->npl.D); _aligned_free(a->npl.p); _aligned_free(a->npl.Pmin); _aligned_free(a->npl.P); // nps _aligned_free(a->nps.EN2y); _aligned_free(a->nps.Pbar); _aligned_free(a->nps.PH1y); _aligned_free(a->nps.sigma2N); // np for (i = 0; i < a->np.U; i++) _aligned_free(a->np.actminbuff[i]); _aligned_free(a->np.actminbuff); _aligned_free(a->np.pmin_u); _aligned_free(a->np.lmin_flag); _aligned_free(a->np.actmin_sub); _aligned_free(a->np.actmin); _aligned_free(a->np.k_mod); _aligned_free(a->np.bmin_sub); _aligned_free(a->np.bmin); _aligned_free(a->np.Qeq); _aligned_free(a->np.p2bar); _aligned_free(a->np.pbar); _aligned_free(a->np.sigma2N); _aligned_free(a->np.alphaHat); _aligned_free(a->np.alphaOptHat); _aligned_free(a->np.p); // g _aligned_free(a->g.zeta_true); _aligned_free(a->g.zeta_hat); _aligned_free(a->g.GGS); _aligned_free(a->g.GG); _aligned_free(a->g.prev_mask); _aligned_free(a->g.prev_gamma); _aligned_free(a->g.lambda_d); _aligned_free(a->g.lambda_y); // fftw_destroy_plan(a->Rrev); fftw_destroy_plan(a->Rfor); _aligned_free(a->outaccum); for (i = 0; i < a->ovrlp; i++) _aligned_free(a->save[i]); _aligned_free(a->save); _aligned_free(a->revfftout); _aligned_free(a->revfftin); _aligned_free(a->mask); _aligned_free(a->forfftout); _aligned_free(a->forfftin); _aligned_free(a->inaccum); _aligned_free(a->window); } EMNR create_emnr (int run, int position, int size, double* in, double* out, int fsize, int ovrlp, int rate, int wintype, double gain, int gain_method, int npe_method, int ae_run) { EMNR a = (EMNR) malloc0 (sizeof (emnr)); a->run = run; a->position = position; a->bsize = size; a->in = in; a->out = out; a->fsize = fsize; a->ovrlp = ovrlp; a->rate = rate; a->wintype = wintype; a->ogain = gain; a->g.gain_method = gain_method; a->g.npe_method = npe_method; a->g.ae_run = ae_run; calc_emnr (a); return a; } void flush_emnr (EMNR a) { int i; memset (a->inaccum, 0, a->iasize * sizeof (double)); for (i = 0; i < a->ovrlp; i++) memset (a->save[i], 0, a->fsize * sizeof (double)); memset (a->outaccum, 0, a->oasize * sizeof (double)); a->nsamps = 0; a->iainidx = 0; a->iaoutidx = 0; a->oainidx = a->init_oainidx; a->oaoutidx = 0; a->saveidx = 0; } void destroy_emnr (EMNR a) { decalc_emnr (a); _aligned_free (a); } void LambdaD(EMNR a) { int k; double f0, f1, f2, f3; double sum_prev_p; double sum_lambda_y; double alphaCtilda; double sum_prev_sigma2N; double alphaMin, SNR; double beta, varHat, invQeq; double invQbar; double bc; double QeqTilda, QeqTildaSub; double noise_slope_max; sum_prev_p = 0.0; sum_lambda_y = 0.0; sum_prev_sigma2N = 0.0; for (k = 0; k < a->np.msize; k++) { sum_prev_p += a->np.p[k]; sum_lambda_y += a->np.lambda_y[k]; sum_prev_sigma2N += a->np.sigma2N[k]; } for (k = 0; k < a->np.msize; k++) { f0 = a->np.p[k] / a->np.sigma2N[k] - 1.0; a->np.alphaOptHat[k] = 1.0 / (1.0 + f0 * f0); } SNR = sum_prev_p / sum_prev_sigma2N; alphaMin = min (a->np.alphaMin_max_value, pow (SNR, a->np.snrq)); for (k = 0; k < a->np.msize; k++) if (a->np.alphaOptHat[k] < alphaMin) a->np.alphaOptHat[k] = alphaMin; f1 = sum_prev_p / sum_lambda_y - 1.0; alphaCtilda = 1.0 / (1.0 + f1 * f1); a->np.alphaC = a->np.alphaCsmooth * a->np.alphaC + (1.0 - a->np.alphaCsmooth) * max (alphaCtilda, a->np.alphaCmin); f2 = a->np.alphaMax * a->np.alphaC; for (k = 0; k < a->np.msize; k++) a->np.alphaHat[k] = f2 * a->np.alphaOptHat[k]; for (k = 0; k < a->np.msize; k++) a->np.p[k] = a->np.alphaHat[k] * a->np.p[k] + (1.0 - a->np.alphaHat[k]) * a->np.lambda_y[k]; invQbar = 0.0; for (k = 0; k < a->np.msize; k++) { beta = min (a->np.betamax, a->np.alphaHat[k] * a->np.alphaHat[k]); a->np.pbar[k] = beta * a->np.pbar[k] + (1.0 - beta) * a->np.p[k]; a->np.p2bar[k] = beta * a->np.p2bar[k] + (1.0 - beta) * a->np.p[k] * a->np.p[k]; varHat = a->np.p2bar[k] - a->np.pbar[k] * a->np.pbar[k]; invQeq = varHat / (2.0 * a->np.sigma2N[k] * a->np.sigma2N[k]); if (invQeq > a->np.invQeqMax) invQeq = a->np.invQeqMax; a->np.Qeq[k] = 1.0 / invQeq; invQbar += invQeq; } invQbar /= (double)a->np.msize; bc = 1.0 + a->np.av * sqrt (invQbar); for (k = 0; k < a->np.msize; k++) { QeqTilda = (a->np.Qeq[k] - 2.0 * a->np.MofD) / (1.0 - a->np.MofD); QeqTildaSub = (a->np.Qeq[k] - 2.0 * a->np.MofV) / (1.0 - a->np.MofV); a->np.bmin[k] = 1.0 + 2.0 * (a->np.D - 1.0) / QeqTilda; a->np.bmin_sub[k] = 1.0 + 2.0 * (a->np.V - 1.0) / QeqTildaSub; } memset (a->np.k_mod, 0, a->np.msize * sizeof (int)); for (k = 0; k < a->np.msize; k++) { f3 = a->np.p[k] * a->np.bmin[k] * bc; if (f3 < a->np.actmin[k]) { a->np.actmin[k] = f3; a->np.actmin_sub[k] = a->np.p[k] * a->np.bmin_sub[k] * bc; a->np.k_mod[k] = 1; } } if (a->np.subwc == a->np.V) { if (invQbar < a->np.invQbar_points[0]) noise_slope_max = a->np.nsmax[0]; else if (invQbar < a->np.invQbar_points[1]) noise_slope_max = a->np.nsmax[1]; else if (invQbar < a->np.invQbar_points[2]) noise_slope_max = a->np.nsmax[2]; else noise_slope_max = a->np.nsmax[3]; for (k = 0; k < a->np.msize; k++) { int ku; double min; if (a->np.k_mod[k]) a->np.lmin_flag[k] = 0; a->np.actminbuff[a->np.amb_idx][k] = a->np.actmin[k]; min = 1.0e300; for (ku = 0; ku < a->np.U; ku++) if (a->np.actminbuff[ku][k] < min) min = a->np.actminbuff[ku][k]; a->np.pmin_u[k] = min; if ((a->np.lmin_flag[k] == 1) && (a->np.actmin_sub[k] < noise_slope_max * a->np.pmin_u[k]) && (a->np.actmin_sub[k] > a->np.pmin_u[k])) { a->np.pmin_u[k] = a->np.actmin_sub[k]; for (ku = 0; ku < a->np.U; ku++) a->np.actminbuff[ku][k] = a->np.actmin_sub[k]; } a->np.lmin_flag[k] = 0; a->np.actmin[k] = 1.0e300; a->np.actmin_sub[k] = 1.0e300; } if (++a->np.amb_idx == a->np.U) a->np.amb_idx = 0; a->np.subwc = 1; } else { if (a->np.subwc > 1) { for (k = 0; k < a->np.msize; k++) { if (a->np.k_mod[k]) { a->np.lmin_flag[k] = 1; a->np.sigma2N[k] = min (a->np.actmin_sub[k], a->np.pmin_u[k]); a->np.pmin_u[k] = a->np.sigma2N[k]; } } } ++a->np.subwc; } memcpy (a->np.lambda_d, a->np.sigma2N, a->np.msize * sizeof (double)); } void LambdaDs (EMNR a) { int k; for (k = 0; k < a->nps.msize; k++) { a->nps.PH1y[k] = 1.0 / (1.0 + (1.0 + a->nps.epsH1) * exp (- a->nps.epsH1r * a->nps.lambda_y[k] / a->nps.sigma2N[k])); a->nps.Pbar[k] = a->nps.alpha_Pbar * a->nps.Pbar[k] + (1.0 - a->nps.alpha_Pbar) * a->nps.PH1y[k]; if (a->nps.Pbar[k] > 0.99) a->nps.PH1y[k] = min (a->nps.PH1y[k], 0.99); a->nps.EN2y[k] = (1.0 - a->nps.PH1y[k]) * a->nps.lambda_y[k] + a->nps.PH1y[k] * a->nps.sigma2N[k]; a->nps.sigma2N[k] = a->nps.alpha_pow * a->nps.sigma2N[k] + (1.0 - a->nps.alpha_pow) * a->nps.EN2y[k]; } memcpy (a->nps.lambda_d, a->nps.sigma2N, a->nps.msize * sizeof (double)); } void LambdaDl (EMNR a) { double P_old, c, Sr, delta, I, alpha_s; c = (1.0 - a->npl.gamma) / (1.0 - a->npl.beta); for (int k = 0; k < a->npl.msize; k++) { P_old = a->npl.P[k]; a->npl.P[k] = a->npl.eta * P_old + (1.0 - a->npl.eta) * a->npl.Ysq[k]; if (a->npl.Pmin[k] < a->npl.P[k]) a->npl.Pmin[k] = a->npl.gamma * a->npl.Pmin[k] + c * (a->npl.P[k] - a->npl.beta * P_old); else a->npl.Pmin[k] = a->npl.P[k]; Sr = a->npl.P[k] / a->npl.Pmin[k]; if (k <= a->npl.delta_LF) delta = a->npl.delta_0; else if (k <= a->npl.delta_MF) delta = a->npl.delta_1; else delta = a->npl.delta_2; if (Sr > delta) I = 1.0; else I = 0.0; a->npl.p[k] = a->npl.alpha_p * a->npl.p[k] + (1.0 - a->npl.alpha_p) * I; alpha_s = a->npl.alpha_d + (1.0 - a->npl.alpha_d) * a->npl.p[k]; a->npl.D[k] = alpha_s * a->npl.D[k] + (1.0 - alpha_s) * a->npl.Ysq[k]; } memcpy (a->npl.lambda_d, a->npl.D, a->npl.msize * sizeof(double)); } /******************************************************************************************************** * Begin Post-Processing Functions * ********************************************************************************************************/ void aepf(EMNR a) { int k, m; int N, n; double sumPre, sumPost, zeta, zetaT; sumPre = 0.0; sumPost = 0.0; for (k = 0; k < a->ae.msize; k++) { sumPre += a->ae.lambda_y[k]; sumPost += a->mask[k] * a->mask[k] * a->ae.lambda_y[k]; } zeta = sumPost / sumPre; if (zeta >= a->ae.zetaThresh) zetaT = 1.0; else zetaT = zeta; if (zetaT == 1.0) N = 1; else N = 1 + 2 * (int)(0.5 + a->ae.psi * (1.0 - zetaT / a->ae.zetaThresh)); n = N / 2; for (k = 0; k < n; k++) { a->ae.nmask[k] = 0.0; for (m = 0; m <= 2 * k; m++) a->ae.nmask[k] += a->mask[m]; a->ae.nmask[k] /= (double)(2 * k + 1); } for (k = n; k < (a->ae.msize - n); k++) { a->ae.nmask[k] = 0.0; for (m = k - n; m <= (k + n); m++) a->ae.nmask[k] += a->mask[m]; a->ae.nmask[k] /= (double)N; } for (k = a->ae.msize - n; k < a->ae.msize; k++) { a->ae.nmask[k] = 0.0; for (m = (a->ae.msize - 1); m >= (-a->ae.msize + 2 * k + 1); m--) a->ae.nmask[k] += a->mask[m]; a->ae.nmask[k] /= (double)(2 * (a->ae.msize - k) - 1); } memcpy (a->mask, a->ae.nmask, a->ae.msize * sizeof (double)); if (a->g.gain_method == 3 && zetaT < a->ae.t2) for (k = 0; k < a->ae.msize; k++) a->mask[k] *= 0.05; } void post2_calc_w(EMNR a) { int i; int ilim = (int)(a->post2.taper * a->msize); memset(a->post2.w, a->msize, sizeof(double)); for (i = 0; i < ilim; i++) { a->post2.w[i] = 0.75 - 0.25 * cos(PI * (ilim - 1 - i) / (ilim - 1)); } } void post2(EMNR a) { if (a->post2.run) { int i; double Iwhite, Qwhite, Irem, Qrem, Inoise, Qnoise; double factor = a->post2.factor; double nlevel = a->post2.nlevel; double rate_decay = a->post2.rate_decay; double* w = a->post2.w; int ilim = (int)(a->post2.taper * a->msize); double tdmag = 0.0, dmag = 0.0, dmult = 0.0; for (i = 1; i < ilim; i++) { tdmag = a->gain * sqrt(a->forfftout[2 * i + 0] * a->forfftout[2 * i + 0] + a->forfftout[2 * i + 1] * a->forfftout[2 * i + 1]); if (tdmag > dmag) dmag = tdmag; } if (dmag > a->post2.olddmag) a->post2.olddmag = dmag; else a->post2.olddmag *= rate_decay; dmag = fmax(dmag, a->post2.olddmag); dmult = dmag * 4.0 * a->gain; memcpy(a->post2.noise_frame, FDnoise + 2 * a->msize * a->post2.noise_frame_index, 2 * ilim * sizeof(double)); a->post2.noise_frame_index = (a->post2.noise_frame_index + 1) % a->post2.noise_frames; for (i = 1; i < ilim; i++) { Irem = a->gain * a->forfftout[2 * i + 0] - a->revfftin[2 * i + 0]; Qrem = a->gain * a->forfftout[2 * i + 1] - a->revfftin[2 * i + 1]; Iwhite = dmult * a->post2.noise_frame[2 * i + 0]; Qwhite = dmult * a->post2.noise_frame[2 * i + 1]; Inoise = (1.0 - factor) * Irem + factor * Iwhite; Qnoise = (1.0 - factor) * Qrem + factor * Qwhite; a->revfftin[2 * i + 0] = w[i] * (a->revfftin[2 * i + 0] + nlevel * Inoise); a->revfftin[2 * i + 1] = w[i] * (a->revfftin[2 * i + 1] + nlevel * Qnoise); } a->revfftin[0] = 0.0; a->revfftin[1] = 0.0; memset(a->revfftin + 2 * ilim, 0, 2 * (a->msize - ilim) * sizeof(double)); } } PORT void SetRXAEMNRpost2Run(int channel, int run) { EnterCriticalSection(&ch[channel].csDSP); rxa[channel].emnr.p->post2.run = run; LeaveCriticalSection(&ch[channel].csDSP); } PORT void SetRXAEMNRpost2Factor(int channel, double factor) { EnterCriticalSection(&ch[channel].csDSP); rxa[channel].emnr.p->post2.factor = factor / 100.0; LeaveCriticalSection(&ch[channel].csDSP); } PORT void SetRXAEMNRpost2Nlevel(int channel, double nlevel) { EnterCriticalSection(&ch[channel].csDSP); rxa[channel].emnr.p->post2.nlevel = nlevel / 100.0; LeaveCriticalSection(&ch[channel].csDSP); } PORT void SetRXAEMNRpost2Taper(int channel, int taper) { EMNR a = rxa[channel].emnr.p; EnterCriticalSection(&ch[channel].csDSP); a->post2.taper = (double)taper / 100.0; post2_calc_w(a); LeaveCriticalSection(&ch[channel].csDSP); } PORT void SetRXAEMNRpost2Rate(int channel, double tc) { EMNR a = rxa[channel].emnr.p; EnterCriticalSection(&ch[channel].csDSP); if (tc < 0.2) tc = 0.2; a->post2.tc_decay = tc; a->post2.rate_decay = exp(-a->fsize / (a->post2.tc_decay * a->rate * a->ovrlp)); a->post2.olddmag = 0.0; LeaveCriticalSection(&ch[channel].csDSP); } /******************************************************************************************************** * End Post-Processing Functions * ********************************************************************************************************/ double getKey(double* type, double gamma, double xi) { int ngamma1, ngamma2, nxi1, nxi2; double tg, tx, dg, dx; const double dmin = 0.001; const double dmax = 1000.0; if (gamma <= dmin) { ngamma1 = ngamma2 = 0; tg = 0.0; } else if (gamma >= dmax) { ngamma1 = ngamma2 = 240; tg = 60.0; } else { tg = 10.0 * log10(gamma / dmin); ngamma1 = (int)(4.0 * tg); ngamma2 = ngamma1 + 1; } if (xi <= dmin) { nxi1 = nxi2 = 0; tx = 0.0; } else if (xi >= dmax) { nxi1 = nxi2 = 240; tx = 60.0; } else { tx = 10.0 * log10(xi / dmin); nxi1 = (int)(4.0 * tx); nxi2 = nxi1 + 1; } dg = (tg - 0.25 * ngamma1) / 0.25; dx = (tx - 0.25 * nxi1) / 0.25; return (1.0 - dg) * (1.0 - dx) * type[241 * nxi1 + ngamma1] + (1.0 - dg) * dx * type[241 * nxi2 + ngamma1] + dg * (1.0 - dx) * type[241 * nxi1 + ngamma2] + dg * dx * type[241 * nxi2 + ngamma2]; } int getZeta( EMNR a, double gamma, double eps, double* zeta) { int index, i_gamma, i_xi; double gamma_dB, xi_dB, gamma_per_cell, xi_per_cell; gamma_dB = 10.0 * mlog10(gamma); xi_dB = 10.0 * mlog10(eps); gamma_per_cell = (a->g.z_gamma_max - a->g.z_gamma_min) / a->g.dim_zeta; xi_per_cell = (a->g.z_xihat_max - a->g.z_xihat_min) / a->g.dim_zeta; i_gamma = (int)floor((gamma_dB - a->g.z_gamma_min) / gamma_per_cell); i_xi = (int)floor((xi_dB - a->g.z_xihat_min) / xi_per_cell); if (i_gamma < 0 || i_gamma >= a->g.dim_zeta || i_xi < 0 || xi_dB >= a->g.dim_zeta) return -1; index = i_gamma * a->g.dim_zeta + i_xi; int ztvalue = a->g.zeta_true[index]; if (ztvalue <= 0) return -2; else *zeta = a->g.zeta_hat[index]; return 0; } void calc_gain (EMNR a) { int k; for (k = 0; k < a->g.msize; k++) { a->g.lambda_y[k] = a->g.y[2 * k + 0] * a->g.y[2 * k + 0] + a->g.y[2 * k + 1] * a->g.y[2 * k + 1]; } switch (a->g.npe_method) { case 0: LambdaD(a); break; case 1: LambdaDs(a); break; case 2: LambdaDl(a); break; } switch (a->g.gain_method) { case 0: { double gamma, eps_hat, v; for (k = 0; k < a->g.msize; k++) { gamma = min (a->g.lambda_y[k] / a->g.lambda_d[k], a->g.gamma_max); eps_hat = a->g.alpha * a->g.prev_mask[k] * a->g.prev_mask[k] * a->g.prev_gamma[k] + (1.0 - a->g.alpha) * max (gamma - 1.0, a->g.eps_floor); eps_hat = max(eps_hat, a->g.xi_min); v = (eps_hat / (1.0 + eps_hat)) * gamma; a->g.mask[k] = a->g.gf1p5 * sqrt (v) / gamma * exp (- 0.5 * v) * ((1.0 + v) * bessI0 (0.5 * v) + v * bessI1 (0.5 * v)); { double v2 = min (v, 700.0); double eta = a->g.mask[k] * a->g.mask[k] * a->g.lambda_y[k] / a->g.lambda_d[k]; double eps = eta / (1.0 - a->g.q); double witchHat = (1.0 - a->g.q) / a->g.q * exp (v2) / (1.0 + eps); a->g.mask[k] *= witchHat / (1.0 + witchHat); } if (a->g.mask[k] > a->g.gmax) a->g.mask[k] = a->g.gmax; if (a->g.mask[k] != a->g.mask[k]) a->g.mask[k] = 0.01; a->g.prev_gamma[k] = gamma; a->g.prev_mask[k] = a->g.mask[k]; } break; } case 1: { double gamma, eps_hat, v, ehr; for (k = 0; k < a->g.msize; k++) { gamma = min (a->g.lambda_y[k] / a->g.lambda_d[k], a->g.gamma_max); eps_hat = a->g.alpha * a->g.prev_mask[k] * a->g.prev_mask[k] * a->g.prev_gamma[k] + (1.0 - a->g.alpha) * max (gamma - 1.0, a->g.eps_floor); ehr = eps_hat / (1.0 + eps_hat); v = ehr * gamma; if((a->g.mask[k] = ehr * exp (min (700.0, 0.5 * e1xb(v)))) > a->g.gmax) a->g.mask[k] = a->g.gmax; if (a->g.mask[k] != a->g.mask[k])a->g.mask[k] = 0.01; a->g.prev_gamma[k] = gamma; a->g.prev_mask[k] = a->g.mask[k]; } break; } case 2: { double gamma, eps_hat, eps_p; for (k = 0; k < a->g.msize; k++) { gamma = min(a->g.lambda_y[k] / a->g.lambda_d[k], a->g.gamma_max); eps_hat = a->g.alpha * a->g.prev_mask[k] * a->g.prev_mask[k] * a->g.prev_gamma[k] + (1.0 - a->g.alpha) * max(gamma - 1.0, a->g.eps_floor); eps_p = eps_hat / (1.0 - a->g.q); a->g.mask[k] = getKey(a->g.GG, gamma, eps_hat) * getKey(a->g.GGS, gamma, eps_p); a->g.prev_gamma[k] = gamma; a->g.prev_mask[k] = a->g.mask[k]; } break; } case 3: { double gamma, xi_hat, v, zeta_hat; for (k = 0; k < a->g.msize; k++) { gamma = min(a->g.lambda_y[k] / a->g.lambda_d[k], a->g.gamma_max); xi_hat = a->g.alpha * a->g.prev_mask[k] * a->g.prev_mask[k] * a->g.prev_gamma[k] + (1.0 - a->g.alpha) * max(gamma - 1.0, a->g.eps_floor); xi_hat = max(xi_hat, a->g.xi_min); v = (xi_hat / (1.0 + xi_hat)) * gamma; a->g.mask[k] = a->g.gf1p5 * sqrt(v) / gamma * exp(-0.5 * v) * ((1.0 + v) * bessI0(0.5 * v) + v * bessI1(0.5 * v)); { double v2 = min(v, 700.0); double eta = a->g.mask[k] * a->g.mask[k] * a->g.lambda_y[k] / a->g.lambda_d[k]; double eps = eta / (1.0 - a->g.q); double witchHat = (1.0 - a->g.q) / a->g.q * exp(v2) / (1.0 + eps); a->g.mask[k] *= witchHat / (1.0 + witchHat); } if (a->g.mask[k] > a->g.gmax) a->g.mask[k] = a->g.gmax; if (a->g.mask[k] != a->g.mask[k]) a->g.mask[k] = 0.01; a->g.prev_mask[k] = a->g.mask[k]; a->g.prev_gamma[k] = gamma; { double xi_ts = a->g.mask[k] * a->g.mask[k] * gamma; xi_ts = max(xi_ts, a->g.xi_min); double v_ts = (xi_ts / (1.0 + xi_ts)) * gamma; a->g.mask[k] = a->g.gf1p5 * sqrt(v_ts) / gamma * exp(-0.5 * v_ts) * ((1.0 + v_ts) * bessI0(0.5 * v_ts) + v_ts * bessI1(0.5 * v_ts)); double v2 = min(v_ts, 700.0); double eta = a->g.mask[k] * a->g.mask[k] * a->g.lambda_y[k] / a->g.lambda_d[k]; double eps = eta / (1.0 - a->g.q); double witchHat = (1.0 - a->g.q) / a->g.q * exp(v2) / (1.0 + eps); a->g.mask[k] *= witchHat / (1.0 + witchHat); xi_hat = xi_ts; } if (a->g.mask[k] > a->g.gmax) a->g.mask[k] = a->g.gmax; if (a->g.mask[k] != a->g.mask[k]) a->g.mask[k] = 0.01; if (getZeta(a, gamma, xi_hat, &zeta_hat) >= 0) { if (zeta_hat > a->g.zeta_thresh) a->g.mask[k] = 1.0; else a->g.mask[k] = 0.0; } } break; } } if (a->g.ae_run) aepf(a); } void xemnr (EMNR a, int pos) { if (a->run && pos == a->position) { int i, j, k, sbuff, sbegin; double g1; for (i = 0; i < 2 * a->bsize; i += 2) { a->inaccum[a->iainidx] = a->in[i]; a->iainidx = (a->iainidx + 1) % a->iasize; } a->nsamps += a->bsize; while (a->nsamps >= a->fsize) { for (i = 0, j = a->iaoutidx; i < a->fsize; i++, j = (j + 1) % a->iasize) a->forfftin[i] = a->window[i] * a->inaccum[j]; a->iaoutidx = (a->iaoutidx + a->incr) % a->iasize; a->nsamps -= a->incr; fftw_execute (a->Rfor); calc_gain(a); for (i = 0; i < a->msize; i++) { g1 = a->gain * a->mask[i]; a->revfftin[2 * i + 0] = g1 * a->forfftout[2 * i + 0]; a->revfftin[2 * i + 1] = g1 * a->forfftout[2 * i + 1]; } post2(a); fftw_execute (a->Rrev); for (i = 0; i < a->fsize; i++) a->save[a->saveidx][i] = a->window[i] * a->revfftout[i]; for (i = a->ovrlp; i > 0; i--) { sbuff = (a->saveidx + i) % a->ovrlp; sbegin = a->incr * (a->ovrlp - i); for (j = sbegin, k = a->oainidx; j < a->incr + sbegin; j++, k = (k + 1) % a->oasize) { if ( i == a->ovrlp) a->outaccum[k] = a->save[sbuff][j]; else a->outaccum[k] += a->save[sbuff][j]; } } a->saveidx = (a->saveidx + 1) % a->ovrlp; a->oainidx = (a->oainidx + a->incr) % a->oasize; } for (i = 0; i < a->bsize; i++) { a->out[2 * i + 0] = a->outaccum[a->oaoutidx]; a->out[2 * i + 1] = 0.0; a->oaoutidx = (a->oaoutidx + 1) % a->oasize; } } else if (a->out != a->in) memcpy (a->out, a->in, a->bsize * sizeof (complex)); } void setBuffers_emnr (EMNR a, double* in, double* out) { a->in = in; a->out = out; } void setSamplerate_emnr (EMNR a, int rate) { decalc_emnr (a); a->rate = rate; calc_emnr (a); } void setSize_emnr (EMNR a, int size) { decalc_emnr (a); a->bsize = size; calc_emnr (a); } /******************************************************************************************************** * * * RXA Properties * * * ********************************************************************************************************/ PORT void SetRXAEMNRRun (int channel, int run) { EMNR a = rxa[channel].emnr.p; if (a->run != run) { RXAbp1Check (channel, rxa[channel].amd.p->run, rxa[channel].snba.p->run, run, rxa[channel].anf.p->run, rxa[channel].anr.p->run, rxa[channel].rnnr.p->run, rxa[channel].sbnr.p->run); // NR3 + NR4 support EnterCriticalSection (&ch[channel].csDSP); a->run = run; RXAbp1Set (channel); LeaveCriticalSection (&ch[channel].csDSP); } } PORT void SetRXAEMNRgainMethod (int channel, int method) { EnterCriticalSection (&ch[channel].csDSP); rxa[channel].emnr.p->g.gain_method = method; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRnpeMethod (int channel, int method) { EnterCriticalSection (&ch[channel].csDSP); rxa[channel].emnr.p->g.npe_method = method; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRaeRun (int channel, int run) { EnterCriticalSection (&ch[channel].csDSP); rxa[channel].emnr.p->g.ae_run = run; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRPosition (int channel, int position) { EMNR a = rxa[channel].emnr.p; EnterCriticalSection (&ch[channel].csDSP); a->position = position; rxa[channel].bp1.p->position = position; flush_emnr(a); a->post2.olddmag = 0.0; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRaeZetaThresh (int channel, double zetathresh) { EnterCriticalSection (&ch[channel].csDSP); rxa[channel].emnr.p->ae.zetaThresh = zetathresh; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRaePsi (int channel, double psi) { EnterCriticalSection (&ch[channel].csDSP); rxa[channel].emnr.p->ae.psi = psi; LeaveCriticalSection (&ch[channel].csDSP); } PORT void SetRXAEMNRtrainZetaThresh(int channel, double thresh) { EnterCriticalSection(&ch[channel].csDSP); rxa[channel].emnr.p->g.zeta_thresh = thresh; LeaveCriticalSection(&ch[channel].csDSP); } PORT void SetRXAEMNRtrainT2(int channel, double t2) { EnterCriticalSection(&ch[channel].csDSP); rxa[channel].emnr.p->ae.t2 = t2; LeaveCriticalSection(&ch[channel].csDSP); }