3 * Copyright 2005 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio 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)
12 * GNU Radio 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.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
32 #include <gr_complex.h>
36 #include <gr_fxpt_nco.h>
37 #include "time_series.h"
38 #include "simulation.h"
40 static const double C = 3e8; // sped of light, m/s
43 // ------------------------------------------------------------------------
46 std::vector<gr_complex> d_z;
50 delay_line(unsigned int max_delay)
51 : d_z(gr_rounduppow2(max_delay)), d_mask(d_z.size()-1), d_newest(0)
56 push_item(gr_complex x)
58 d_newest = (d_newest - 1) & d_mask;
63 ref_item(int delay) const
65 return d_z[(d_newest + delay) & d_mask];
69 // ------------------------------------------------------------------------
74 double d_last_slant_range;
77 aux_state(dyn_object *obj) : d_obj(obj) {}
80 // ------------------------------------------------------------------------
82 class my_sim : public simulation
86 unsigned long long d_pos; // position in time series
88 dyn_object *d_tx; // transmitter (not moving)
89 dyn_object *d_rx0; // receiver (not moving)
90 std::vector<aux_state*> d_target;
92 double d_baseline; // length of baseline in meters
93 double d_range_bin; // meters/range_bin
94 float d_tx_lambda; // wavelength of tx signals in meters
96 float d_gain; // linear scale factor
98 void adjust_for_start_time(double start_time);
100 bool write_output(gr_complex x)
102 return fwrite(&x, sizeof(x), 1, d_output) == 1;
106 my_sim(FILE *output, time_series &ref, double timestep, float sample_rate,
107 double start_time, double tx_freq, double gain_db);
111 bool run(long long nsteps);
115 my_sim::my_sim(FILE *output, time_series &ref, double timestep,
116 float sample_rate, double start_time,
117 double tx_freq, double gain_db)
118 : simulation(timestep),
119 d_output(output), d_ref(ref), d_pos(0), d_z(1024),
120 d_range_bin(C * timestep), d_tx_lambda(C/tx_freq),
121 d_sample_rate(sample_rate), d_gain(exp10(gain_db/10))
123 d_tx = new dyn_object(point(0,0), point(0,0), "Tx");
124 d_rx0 = new dyn_object(point(45e3,0), point(0,0), "Rx0");
128 d_baseline = dyn_object::distance(*d_tx, *d_rx0);
132 float aircraft_speed;
133 float aircraft_angle;
138 aircraft_speed = 135; // m/s
139 aircraft_angle = 240 * M_PI/180;
140 aircraft_pos = point(55e3, 20e3);
142 ac = new dyn_object(aircraft_pos,
143 point(aircraft_speed * cos(aircraft_angle),
144 aircraft_speed * sin(aircraft_angle)),
147 d_target.push_back(new aux_state(ac));
150 aircraft_speed = 350; // m/s
151 aircraft_angle = 0 * M_PI/180;
152 aircraft_pos = point(-20e3, 60e3);
154 ac = new dyn_object(aircraft_pos,
155 point(aircraft_speed * cos(aircraft_angle),
156 aircraft_speed * sin(aircraft_angle)),
159 d_target.push_back(new aux_state(ac));
162 adjust_for_start_time(start_time);
164 for (unsigned i = 0; i < d_target.size(); i++)
165 d_target[i]->d_last_slant_range =
166 (dyn_object::distance(*d_tx, *d_target[i]->d_obj)
167 + dyn_object::distance(*d_target[i]->d_obj, *d_rx0));
176 my_sim::adjust_for_start_time(double start_time)
178 for (unsigned i = 0; i < d_obj.size(); i++){
179 // Adjust initial starting positions depending on simulation
180 // start time. FIXME Assumes velocity is constant
181 point p = d_obj[i]->pos();
182 point v = d_obj[i]->vel();
183 p.set_x(p.x() + v.x() * start_time);
184 p.set_y(p.y() + v.y() * start_time);
185 d_obj[i]->set_pos(p);
192 // std::cout << *d_ac0 << std::endl;
194 // grab new item from input and insert it into delay line
195 const gr_complex *in = (const gr_complex *) d_ref.seek(d_pos++, 1);
200 gr_complex s = 0; // output sample
201 // FIXME ought to add in attenuated direct path input
204 // for each target, compute slant_range and slant_range'
206 for (unsigned i = 0; i < d_target.size(); i++){
207 aux_state *t = d_target[i];
210 (dyn_object::distance(*d_tx, *t->d_obj)
211 + dyn_object::distance(*t->d_obj, *d_rx0)); // meters
213 double delta_slant_range = slant_range - t->d_last_slant_range;
214 t->d_last_slant_range = slant_range;
215 double deriv_slant_range_wrt_time = delta_slant_range / timestep(); // m/sec
217 //fprintf(stdout, "%10.3f\t%10.3f\n", slant_range, deriv_slant_range_wrt_time);
219 // FIXME, may want to interpolate between two bins.
220 int int_delay = lrint((slant_range - d_baseline) / d_range_bin);
222 gr_complex x = d_z.ref_item(int_delay);
224 // scale amplitude (this includes everything: RCS, antenna gain, losses, etc...)
228 // compute doppler and apply it
229 float f_doppler = -deriv_slant_range_wrt_time / d_tx_lambda;
231 t->d_nco.set_freq(f_doppler / d_sample_rate);
232 gr_complex phasor(t->d_nco.cos(), t->d_nco.sin());
237 s += x; // add in this target's contribution
242 return simulation::update(); // run generic update
246 my_sim::run(long long nsteps)
248 //fprintf(stdout, "<%12.2f, %12.2f>\n", d_ac0->pos().x(), d_ac0->pos().y());
249 //std::cout << *d_ac0 << std::endl;
250 bool ok = simulation::run(nsteps);
251 //std::cout << *d_ac0 << std::endl;
252 //fprintf(stdout, "<%12.2f, %12.2f>\n", d_ac0->pos().x(), d_ac0->pos().y());
256 // ------------------------------------------------------------------------
259 usage(const char *argv0)
261 const char *progname;
262 const char *t = std::strrchr(argv0, '/');
268 fprintf(stderr, "usage: %s [options] ref_file\n", progname);
269 fprintf(stderr, " -o OUTPUT_FILENAME [default=sim.dat]\n");
270 fprintf(stderr, " -n NSAMPLES_TO_PRODUCE [default=+inf]\n");
271 fprintf(stderr, " -s NSAMPLES_TO_SKIP [default=0]\n");
272 fprintf(stderr, " -g reflection gain in dB (should be <= 0) [default=0]\n");
273 fprintf(stderr, " -f transmitter freq in Hz [default=100MHz]\n");
274 fprintf(stderr, " -r sample rate in Hz [default=250kHz]\n");
275 fprintf(stderr, " -S simulation start time in seconds [default=0]\n");
279 main(int argc, char **argv)
282 const char *output_filename = "sim.dat";
283 const char *ref_filename = 0;
284 long long int nsamples_to_skip = 0;
285 long long int nsamples_to_produce = std::numeric_limits<long long int>::max();
286 double sample_rate = 250e3;
288 double tx_freq = 100e6;
289 double start_time = 0;
291 while ((ch = getopt(argc, argv, "o:s:n:g:f:S:")) != -1){
294 output_filename = optarg;
298 nsamples_to_skip = (long long) strtof(optarg, 0);
299 if (nsamples_to_skip < 0){
301 fprintf(stderr, " nsamples_to_skip must be >= 0\n");
307 nsamples_to_produce = (long long) strtof(optarg, 0);
308 if (nsamples_to_produce < 0){
310 fprintf(stderr, " nsamples_to_produce must be >= 0\n");
316 gain_db = strtof(optarg, 0);
320 tx_freq = strtof(optarg, 0);
324 sample_rate = strtof(optarg, 0);
328 start_time = strtof(optarg, 0);
339 if (argc - optind != 1){
344 ref_filename = argv[optind++];
346 double timestep = 1.0/sample_rate;
349 FILE *output = fopen(output_filename, "wb");
351 perror(output_filename);
355 unsigned long long ref_starting_offset = 0;
356 ref_starting_offset += nsamples_to_skip;
359 time_series ref(sizeof(gr_complex), ref_filename, ref_starting_offset, 0);
361 my_sim simulator(output, ref, timestep, sample_rate, start_time,
363 simulator.run(nsamples_to_produce);
365 catch (std::string &s){
366 std::cerr << s << std::endl;