* receiver.cpp - receiver transformation class implementation
*
* Copyright (C) 2009 Dirk Schaefer <schad@5pm.de>
* Copyright (C) 2009 Stefan Jahn <stefan@lkcc.org>
*
* This 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, or (at your option)
* any later version.
*
* This software 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 package; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* $Id$
*
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmath>
#include <cstdint>
#include "consts.h"
#include "object.h"
#include "complex.h"
#include "vector.h"
#include "spline.h"
#include "interpolator.h"
#include "fourier.h"
#include "receiver.h"
namespace qucs {
than the given value. The maximum returned value is 2^30. */
int32_t emi::nearestbin32 (int x) {
int32_t boundary = 1 << 30;
int32_t current = 1;
if (x >= boundary) return boundary;
while (current < x) current <<= 1;
return current;
}
the frequency for which the filter is evaluated. */
nr_double_t emi::f_ideal (nr_double_t fc, nr_double_t bw, nr_double_t f) {
nr_double_t lo = fc - bw / 2;
nr_double_t hi = fc + bw / 2;
if (f >= lo && f < hi)
return 1.0;
return 0.0;
}
frequency, bandwidth and the frequency for which the filter is
evaluated. */
nr_double_t emi::f_2ndorder (nr_double_t fc, nr_double_t bw, nr_double_t f) {
nr_double_t q = fc / bw;
nr_complex_t p = nr_complex_t (0, f / fc);
nr_complex_t w = p / q / (1.0 + p / q + p * p);
return norm (w);
}
bandwidth and the frequency for which the filter is evaluated. */
nr_double_t emi::f_gauss (nr_double_t fc, nr_double_t bw, nr_double_t f) {
nr_double_t a = log (0.5) / bw / bw;
nr_double_t s = f - fc;
return exp (a * s * s);
}
waveform in the time domain. The number of points in the waveform
is required to be a power of two. Also the samples are supposed
to be equidistant. */
vector * emi::receiver (nr_double_t * ida, nr_double_t duration, int ilength) {
int i, n, points;
nr_double_t fres;
vector * ed = new vector ();
points = ilength;
fourier::_fft_1d (ida, ilength, 1);
additionally only half of the FFT result required */
for (i = 2; i < points; i++) {
ida[i] /= points / 2;
}
fres = 1.0 / duration;
nr_double_t * d = ida;
for (n = 0, i = 0; i < points / 2; i++, n += 2){
d[i] = xhypot (ida[n], ida[n + 1]);
}
points /= 2;
struct settings settings[] = {
{ 200, 150e3, 200, 200 },
{ 150e3, 30e6, 9e3, 9e3 },
{ 30e6, 1e9, 120e3, 120e3 },
{ 0, 0, 0, 0}
};
nr_double_t noise = std::pow (10.0, (-100.0 / 40.0)) * 1e-6;
nr_double_t fcur, dcur;
int ei = 0;
for (i = 0; settings[i].bandwidth != 0; i++ ) {
nr_double_t bw = settings[i].bandwidth;
nr_double_t fstart = settings[i].start;
nr_double_t fstop = settings[i].stop;
nr_double_t fstep = settings[i].stepsize;
for (fcur = fstart; fcur <= fstop; fcur += fstep) {
nr_double_t lo = fcur - bw / 2;
nr_double_t hi = fcur + bw / 2;
if (hi < fres) continue;
int il = std::floor (lo / fres);
int ir = std::floor (hi / fres);
at least part of data is within bandwidth indices */
if (ir >= 0 && il < points - 1) {
if (il < 0) il = 0;
if (ir > points - 1) ir = points - 1;
dcur = 0;
for (int j = 0; j < ir - il; j++){
nr_double_t f = fres * (il + j);
dcur += f_2ndorder (fcur, bw, f) * d[il + j];
}
dcur += noise * sqrt (bw);
ed->add (nr_complex_t (dcur, fcur));
ei++;
}
}
}
return ed;
}
takes an arbitrary waveform in the time domain and interpolates it
such, that its length results in a power of two elements. */
vector * emi::receiver (vector * da, vector * dt, int len) {
int i, nlen, olen = da->getSize ();
if (len < da->getSize ()) len = da->getSize ();
nlen = emi::nearestbin32 (len);
nr_double_t tstart = real (dt->get (0));
nr_double_t tstop = real (dt->get (olen - 1));
nr_double_t duration = tstop - tstart;
equidistant samples */
interpolator * inter = new interpolator ();
inter->rvectors (da, dt);
inter->prepare (INTERPOL_CUBIC, REPEAT_NO, DATA_RECTANGULAR);
nr_double_t * ida = new nr_double_t[2 * nlen];
nr_double_t tstep = duration / (nlen - 1);
for (i = 0; i < nlen; i++) {
nr_double_t t = i * tstep + tstart;
ida[2 * i + 0] = inter->rinterpolate (t);
ida[2 * i + 1] = 0;
}
delete inter;
vector * res = receiver (ida, duration, nlen);
delete[] ida;
return res;
}
}