Qucs-core  0.0.18
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
receiver.cpp
Go to the documentation of this file.
1 /*
2  * receiver.cpp - receiver transformation class implementation
3  *
4  * Copyright (C) 2009 Dirk Schaefer <schad@5pm.de>
5  * Copyright (C) 2009 Stefan Jahn <stefan@lkcc.org>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this package; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * $Id$
23  *
24  */
25 
26 #if HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <cmath>
34 
35 #include "consts.h"
36 #include "object.h"
37 #include "complex.h"
38 #include "vector.h"
39 #include "spline.h"
40 #include "interpolator.h"
41 #include "fourier.h"
42 #include "receiver.h"
43 
44 namespace qucs {
45 
46 /* The function returns a power-of-two value which is equal or larger
47  than the given value. The maximum returned value is 2^30. */
48 nr_int32_t emi::nearestbin32 (int x) {
49  nr_int32_t boundary = 1 << 30;
50  nr_int32_t current = 1;
51  if (x >= boundary) return boundary;
52  while (current < x) current <<= 1;
53  return current;
54 }
55 
56 /* Ideal filter construction for given center frequency, bandwidth and
57  the frequency for which the filter is evaluated. */
58 nr_double_t emi::f_ideal (nr_double_t fc, nr_double_t bw, nr_double_t f) {
59  nr_double_t lo = fc - bw / 2;
60  nr_double_t hi = fc + bw / 2;
61  if (f >= lo && f < hi)
62  return 1.0;
63  return 0.0;
64 }
65 
66 /* Construction of a bandpass filter of 2nd order for given center
67  frequency, bandwidth and the frequency for which the filter is
68  evaluated. */
69 nr_double_t emi::f_2ndorder (nr_double_t fc, nr_double_t bw, nr_double_t f) {
70  nr_double_t q = fc / bw;
71  nr_complex_t p = nr_complex_t (0, f / fc);
72  nr_complex_t w = p / q / (1.0 + p / q + p * p);
73  return norm (w);
74 }
75 
76 /* Construction of a gaussian filter for given center frequency,
77  bandwidth and the frequency for which the filter is evaluated. */
78 nr_double_t emi::f_gauss (nr_double_t fc, nr_double_t bw, nr_double_t f) {
79  nr_double_t a = log (0.5) / bw / bw;
80  nr_double_t s = f - fc;
81  return exp (a * s * s);
82 }
83 
84 /* The function computes a EMI receiver spectrum based on the given
85  waveform in the time domain. The number of points in the waveform
86  is required to be a power of two. Also the samples are supposed
87  to be equidistant. */
88 vector * emi::receiver (nr_double_t * ida, nr_double_t duration, int ilength) {
89 
90  int i, n, points;
91  nr_double_t fres;
92  vector * ed = new vector ();
93 
94  points = ilength;
95 
96  /* ilength must be a power of 2 - write wrapper later on */
97  fourier::_fft_1d (ida, ilength, 1); /* 1 = forward fft */
98 
99  /* start at first AC point (0 as DC point remains untouched)
100  additionally only half of the FFT result required */
101  for (i = 2; i < points; i++) {
102  ida[i] /= points / 2;
103  }
104 
105  /* calculate frequency step */
106  fres = 1.0 / duration;
107 
108  /* generate data vector; inplace calculation of magnitudes */
109  nr_double_t * d = ida;
110  for (n = 0, i = 0; i < points / 2; i++, n += 2){
111  /* abs value of complex number */
112  d[i] = xhypot (ida[n], ida[n + 1]);
113  /* vector contains complex values; thus every second value */
114  }
115 
116  points /= 2;
117 
118  /* define EMI settings */
119  struct settings settings[] = {
120  { 200, 150e3, 200, 200 },
121  { 150e3, 30e6, 9e3, 9e3 },
122  { 30e6, 1e9, 120e3, 120e3 },
123  { 0, 0, 0, 0}
124  };
125 
126  /* define EMI noise floor */
127  nr_double_t noise = std::pow (10.0, (-100.0 / 40.0)) * 1e-6;
128 
129  /* generate resulting data & frequency vector */
130  nr_double_t fcur, dcur;
131  int ei = 0;
132 
133  /* go through each EMI setting */
134  for (i = 0; settings[i].bandwidth != 0; i++ ) {
135 
136  nr_double_t bw = settings[i].bandwidth;
137  nr_double_t fstart = settings[i].start;
138  nr_double_t fstop = settings[i].stop;
139  nr_double_t fstep = settings[i].stepsize;
140 
141  /* go through frequencies */
142  for (fcur = fstart; fcur <= fstop; fcur += fstep) {
143 
144  /* calculate upper and lower frequency bounds */
145  nr_double_t lo = fcur - bw / 2;
146  nr_double_t hi = fcur + bw / 2;
147  if (hi < fres) continue;
148 
149  /* calculate indices covering current bandwidth */
150  int il = std::floor (lo / fres);
151  int ir = std::floor (hi / fres);
152 
153  /* right index (ri) greater 0 and left index less than points ->
154  at least part of data is within bandwidth indices */
155  if (ir >= 0 && il < points - 1) {
156  /* adjust indices to reside in the data array */
157  if (il < 0) il = 0;
158  if (ir > points - 1) ir = points - 1;
159 
160  /* sum-up the values within the bandwidth */
161  dcur = 0;
162  for (int j = 0; j < ir - il; j++){
163  nr_double_t f = fres * (il + j);
164  dcur += f_2ndorder (fcur, bw, f) * d[il + j];
165  }
166 
167  /* add noise to the result */
168  dcur += noise * sqrt (bw);
169 
170  /* save result */
171  ed->add (nr_complex_t (dcur, fcur));
172  ei++;
173  }
174  }
175  }
176 
177  /* returning values of function */
178  return ed;
179 }
180 
181 /* This is a wrapper for the basic EMI rceiver functionality. It
182  takes an arbitraty waveform in the time domain and interpolates it
183  such, that its length results in a power of two elements. */
184 vector * emi::receiver (vector * da, vector * dt, int len) {
185 
186  int i, nlen, olen = da->getSize ();
187 
188  // don't allow less points than the actual length
189  if (len < da->getSize ()) len = da->getSize ();
190 
191  // find a power-of-two length
192  nlen = emi::nearestbin32 (len);
193 
194  nr_double_t tstart = real (dt->get (0));
195  nr_double_t tstop = real (dt->get (olen - 1));
196  nr_double_t duration = tstop - tstart;
197 
198  /* please note: interpolation is always performed in order to ensure
199  equidistant samples */
200 
201  // create interpolator (use cubic splines)
202  interpolator * inter = new interpolator ();
203  inter->rvectors (da, dt);
204  inter->prepare (INTERPOL_CUBIC, REPEAT_NO, DATA_RECTANGULAR);
205 
206  // adjust the time domain vector using interpolation
207  nr_double_t * ida = new nr_double_t[2 * nlen];
208  nr_double_t tstep = duration / (nlen - 1);
209  for (i = 0; i < nlen; i++) {
210  nr_double_t t = i * tstep + tstart;
211  ida[2 * i + 0] = inter->rinterpolate (t);
212  ida[2 * i + 1] = 0;
213  }
214 
215  // destroy interpolator
216  delete inter;
217 
218  // run actual EMI receiver computations
219  vector * res = receiver (ida, duration, nlen);
220 
221  // delete intermediate data
222  delete[] ida;
223 
224  return res;
225 }
226 
227 } // namespace qucs
std::complex< nr_double_t > nr_complex_t
Definition: complex.h:31
void _fft_1d(nr_double_t *, int, int isign=1)
Definition: fourier.cpp:50
#define REPEAT_NO
Definition: interpolator.h:33
matrix real(matrix a)
Real part matrix.
Definition: matrix.cpp:568
nr_double_t stepsize
Definition: receiver.h:37
nr_complex_t pow(const nr_complex_t z, const nr_double_t d)
Compute power function with real exponent.
Definition: complex.cpp:238
t
Definition: parse_vcd.y:290
n
Definition: parse_citi.y:147
nr_double_t start
Definition: receiver.h:35
#define DATA_RECTANGULAR
Definition: interpolator.h:36
i
Definition: parse_mdl.y:516
nr_complex_t sqrt(const nr_complex_t z)
Compute principal value of square root.
Definition: complex.cpp:271
nr_double_t xhypot(const nr_complex_t a, const nr_complex_t b)
Euclidean distance function for complex argument.
Definition: complex.cpp:465
points
Definition: parse_zvr.y:129
#define INTERPOL_CUBIC
Definition: interpolator.h:30
qucs::vector * receiver(nr_double_t *, nr_double_t, int)
Definition: receiver.cpp:88
nr_double_t f_gauss(nr_double_t, nr_double_t, nr_double_t)
Definition: receiver.cpp:78
nr_double_t stop
Definition: receiver.h:36
Global math constants header file.
x
Definition: parse_mdl.y:498
nr_complex_t floor(const nr_complex_t z)
Complex floor.
Definition: complex.cpp:623
nr_int32_t nearestbin32(int)
Definition: receiver.cpp:48
nr_double_t norm(const nr_complex_t z)
Compute euclidian norm of complex number.
Definition: complex.cpp:283
nr_complex_t exp(const nr_complex_t z)
Compute complex exponential.
Definition: complex.cpp:205
nr_double_t bandwidth
Definition: receiver.h:38
nr_double_t f_ideal(nr_double_t, nr_double_t, nr_double_t)
Definition: receiver.cpp:58
nr_complex_t log(const nr_complex_t z)
Compute principal value of natural logarithm of z.
Definition: complex.cpp:215
nr_double_t f_2ndorder(nr_double_t, nr_double_t, nr_double_t)
Definition: receiver.cpp:69