My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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: receiver.cpp 1825 2011-03-11 20:42:14Z ela $
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 <math.h>
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 /* The function returns a power-of-two value which is equal or larger
45  than the given value. The maximum returned value is 2^30. */
46 nr_int32_t emi::nearestbin32 (int x) {
47  nr_int32_t boundary = 1 << 30;
48  nr_int32_t current = 1;
49  if (x >= boundary) return boundary;
50  while (current < x) current <<= 1;
51  return current;
52 }
53 
54 /* Ideal filter construction for given center frequency, bandwidth and
55  the frequency for which the filter is evaluated. */
56 nr_double_t emi::f_ideal (nr_double_t fc, nr_double_t bw, nr_double_t f) {
57  nr_double_t lo = fc - bw / 2;
58  nr_double_t hi = fc + bw / 2;
59  if (f >= lo && f < hi)
60  return 1.0;
61  return 0.0;
62 }
63 
64 /* Construction of a bandpass filter of 2nd order for given center
65  frequency, bandwidth and the frequency for which the filter is
66  evaluated. */
67 nr_double_t emi::f_2ndorder (nr_double_t fc, nr_double_t bw, nr_double_t f) {
68  nr_double_t q = fc / bw;
69  nr_complex_t p = rect (0, f / fc);
70  nr_complex_t w = p / q / (1.0 + p / q + p * p);
71  return norm (w);
72 }
73 
74 /* Construction of a gaussian filter for given center frequency,
75  bandwidth and the frequency for which the filter is evaluated. */
76 nr_double_t emi::f_gauss (nr_double_t fc, nr_double_t bw, nr_double_t f) {
77  nr_double_t a = log (0.5) / bw / bw;
78  nr_double_t s = f - fc;
79  return exp (a * s * s);
80 }
81 
82 /* The function computes a EMI receiver spectrum based on the given
83  waveform in the time domain. The number of points in the waveform
84  is required to be a power of two. Also the samples are supposed
85  to be equidistant. */
86 vector * emi::receiver (nr_double_t * ida, nr_double_t duration, int ilength) {
87 
88  int i, n, points;
89  nr_double_t fres;
90  vector * ed = new vector ();
91 
92  points = ilength;
93 
94  /* ilength must be a power of 2 - write wrapper later on */
95  fourier::_fft_1d (ida, ilength, 1); /* 1 = forward fft */
96 
97  /* start at first AC point (0 as DC point remains untouched)
98  additionally only half of the FFT result required */
99  for (i = 2; i < points; i++) {
100  ida[i] /= points / 2;
101  }
102 
103  /* calculate frequency step */
104  fres = 1.0 / duration;
105 
106  /* generate data vector; inplace calculation of magnitudes */
107  nr_double_t * d = ida;
108  for (n = 0, i = 0; i < points / 2; i++, n += 2){
109  /* abs value of complex number */
110  d[i] = xhypot (ida[n], ida[n + 1]);
111  /* vector contains complex values; thus every second value */
112  }
113 
114  points /= 2;
115 
116  /* define EMI settings */
117  struct settings settings[] = {
118  { 200, 150e3, 200, 200 },
119  { 150e3, 30e6, 9e3, 9e3 },
120  { 30e6, 1e9, 120e3, 120e3 },
121  { 0, 0, 0, 0}
122  };
123 
124  /* define EMI noise floor */
125  nr_double_t noise = pow (10.0, (-100.0 / 40.0)) * 1e-6;
126 
127  /* generate resulting data & frequency vector */
128  nr_double_t fcur, dcur;
129  int ei = 0;
130 
131  /* go through each EMI setting */
132  for (i = 0; settings[i].bandwidth != 0; i++ ) {
133 
134  nr_double_t bw = settings[i].bandwidth;
135  nr_double_t fstart = settings[i].start;
136  nr_double_t fstop = settings[i].stop;
137  nr_double_t fstep = settings[i].stepsize;
138 
139  /* go through frequencies */
140  for (fcur = fstart; fcur <= fstop; fcur += fstep) {
141 
142  /* calculate upper and lower frequency bounds */
143  nr_double_t lo = fcur - bw / 2;
144  nr_double_t hi = fcur + bw / 2;
145  if (hi < fres) continue;
146 
147  /* calculate indices covering current bandwidth */
148  int il = floor (lo / fres);
149  int ir = floor (hi / fres);
150 
151  /* right index (ri) greater 0 and left index less than points ->
152  at least part of data is within bandwidth indices */
153  if (ir >= 0 && il < points - 1) {
154  /* adjust indices to reside in the data array */
155  if (il < 0) il = 0;
156  if (ir > points - 1) ir = points - 1;
157 
158  /* sum-up the values within the bandwidth */
159  dcur = 0;
160  for (int j = 0; j < ir - il; j++){
161  nr_double_t f = fres * (il + j);
162  dcur += f_2ndorder (fcur, bw, f) * d[il + j];
163  }
164 
165  /* add noise to the result */
166  dcur += noise * sqrt (bw);
167 
168  /* save result */
169  ed->add (rect (dcur, fcur));
170  ei++;
171  }
172  }
173  }
174 
175  /* returning values of function */
176  return ed;
177 }
178 
179 /* This is a wrapper for the basic EMI rceiver functionality. It
180  takes an arbitraty waveform in the time domain and interpolates it
181  such, that its length results in a power of two elements. */
182 vector * emi::receiver (vector * da, vector * dt, int len) {
183 
184  int i, nlen, olen = da->getSize ();
185 
186  // don't allow less points than the actual length
187  if (len < da->getSize ()) len = da->getSize ();
188 
189  // find a power-of-two length
190  nlen = emi::nearestbin32 (len);
191 
192  nr_double_t tstart = real (dt->get (0));
193  nr_double_t tstop = real (dt->get (olen - 1));
194  nr_double_t duration = tstop - tstart;
195 
196  /* please note: interpolation is always performed in order to ensure
197  equidistant samples */
198 
199  // create interpolator (use cubic splines)
200  interpolator * inter = new interpolator ();
201  inter->rvectors (da, dt);
203 
204  // adjust the time domain vector using interpolation
205  nr_double_t * ida = new nr_double_t[2 * nlen];
206  nr_double_t tstep = duration / (nlen - 1);
207  for (i = 0; i < nlen; i++) {
208  nr_double_t t = i * tstep + tstart;
209  ida[2 * i + 0] = inter->rinterpolate (t);
210  ida[2 * i + 1] = 0;
211  }
212 
213  // destroy interpolator
214  delete inter;
215 
216  // run actual EMI receiver computations
217  vector * res = receiver (ida, duration, nlen);
218 
219  // delete intermediate data
220  delete[] ida;
221 
222  return res;
223 }