OLD | NEW |
(Empty) | |
| 1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
| 2 /* |
| 3 * Copyright (c) 2010 Stylianos Papanastasiou, Jens Mittag |
| 4 * |
| 5 * This program is free software; you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 2 as |
| 7 * published by the Free Software Foundation; |
| 8 * |
| 9 * This program is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 14 * You should have received a copy of the GNU General Public License |
| 15 * along with this program; if not, write to the Free Software |
| 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 * |
| 18 * Stylianos Papanastasiou <stylianos@gmail.com> |
| 19 * Jens Mittag <jens.mittag@kit.edu> |
| 20 * |
| 21 */ |
| 22 |
| 23 #include "physim-vehicular-TDL-channel.h" |
| 24 #include "ns3/log.h" |
| 25 #include "ns3/uinteger.h" |
| 26 #include "ns3/enum.h" |
| 27 #include <itpp/base/math/misc.h> |
| 28 #include <itpp/stat/misc_stat.h> |
| 29 |
| 30 NS_LOG_COMPONENT_DEFINE ("Vehicular_TDL_Channel"); |
| 31 |
| 32 namespace ns3 { |
| 33 IFFTFadingGenerator::IFFTFadingGenerator (double norm_doppler, |
| 34 VEHICULAR_DOPPLER_SPECTRUM spectrum, d
ouble fShift) |
| 35 : Correlated_Fading_Generator (norm_doppler), |
| 36 shape (spectrum), |
| 37 freqShift ( |
| 38 fShift) |
| 39 { |
| 40 time_offset = 0; |
| 41 } |
| 42 |
| 43 IFFTFadingGenerator::~IFFTFadingGenerator () |
| 44 { |
| 45 } |
| 46 |
| 47 void |
| 48 IFFTFadingGenerator::generate (int no_samples, itpp::cvec &output) |
| 49 { |
| 50 if (init_flag == false) |
| 51 { |
| 52 init (); |
| 53 } |
| 54 |
| 55 generate_Spectrum (no_samples, output, shape, freqShift); |
| 56 |
| 57 if (los_power > 0.0) |
| 58 { // LOS component exist |
| 59 for (int i = 0; i < no_samples; i++) |
| 60 { |
| 61 add_LOS (i, output (i)); |
| 62 } |
| 63 } |
| 64 |
| 65 time_offset += no_samples; |
| 66 } |
| 67 itpp::cvec |
| 68 IFFTFadingGenerator::generate (int no_samples) |
| 69 { |
| 70 itpp::cvec output; |
| 71 generate (no_samples, output); |
| 72 return output; |
| 73 } |
| 74 |
| 75 void |
| 76 IFFTFadingGenerator::reset_time_offset () |
| 77 { |
| 78 time_offset = 0; |
| 79 } |
| 80 |
| 81 void |
| 82 IFFTFadingGenerator::add_LOS (int idx, std::complex<double>& sample) |
| 83 { |
| 84 double tmp_arg = itpp::m_2pi * los_dopp * (idx + time_offset); |
| 85 sample *= los_diffuse; |
| 86 sample += los_direct * std::complex<double> (std::cos (tmp_arg), std::sin ( |
| 87 tmp_arg)); |
| 88 } |
| 89 |
| 90 void |
| 91 IFFTFadingGenerator::generate_Spectrum (int no_samples, itpp::cvec &output, |
| 92 VEHICULAR_DOPPLER_SPECTRUM shape, double
freqShift) |
| 93 { |
| 94 int Nfft = itpp::pow2i (itpp::levels2bits (no_samples)); |
| 95 double df = 1.0 / Nfft; |
| 96 int noisesamp = itpp::ceil_i (n_dopp / df); |
| 97 int no_upsample = 1; |
| 98 |
| 99 while (noisesamp <= 10) |
| 100 { // if too few samples, increase the FFT size |
| 101 Nfft *= 2; |
| 102 no_upsample *= 2; |
| 103 df = 1.0 / Nfft; |
| 104 noisesamp = itpp::ceil_i (n_dopp / df); |
| 105 } |
| 106 |
| 107 itpp::vec Fpos = itpp::linspace (0, 0.5, Nfft / 2 + 1); |
| 108 itpp::vec F = itpp::concat (Fpos, reverse (-Fpos (1, Nfft / 2 - 1))); |
| 109 itpp::vec S = itpp::zeros (Nfft); |
| 110 switch (shape) |
| 111 { |
| 112 case Classic6dB: |
| 113 for (int i = 0; i < F.size (); i++) |
| 114 { |
| 115 NS_ASSERT (F (i) <= n_dopp); |
| 116 if (std::fabs (F (i)) < n_dopp) |
| 117 { |
| 118 double calc = 1 - std::pow ((F (i) + freqShift) / n_dopp, 2); |
| 119 if (calc > 0) |
| 120 { |
| 121 S (i) = std::sqrt (1.5 / (itpp::pi * n_dopp * std::sqrt (calc)
)); |
| 122 } |
| 123 else |
| 124 { |
| 125 S (i) = 0; |
| 126 } |
| 127 } |
| 128 else if (std::fabs (F (i)) == n_dopp) |
| 129 { |
| 130 S (i) = 1000000; |
| 131 } |
| 132 NS_ASSERT (!isnan (S (i))); |
| 133 } |
| 134 break; |
| 135 case Classic3dB: |
| 136 for (int i = 0; i < F.size (); i++) |
| 137 { |
| 138 NS_ASSERT (F (i) <= n_dopp); // Otherwise this is undefined |
| 139 if (std::fabs (F (i)) < n_dopp) |
| 140 { |
| 141 double calc = 1 - std::pow ((F (i) + freqShift) / n_dopp, 2); |
| 142 if (calc > 0) |
| 143 { |
| 144 S (i) = std::sqrt (std::sqrt (1.5 / (itpp::pi * n_dopp * std::
sqrt (calc)))); |
| 145 } |
| 146 else |
| 147 { |
| 148 S (i) = 0; |
| 149 } |
| 150 } |
| 151 else if (std::fabs (F (i)) == n_dopp) |
| 152 { |
| 153 S (i) = 1000000; |
| 154 } |
| 155 NS_ASSERT (!isnan (S (i))); |
| 156 } |
| 157 break; |
| 158 case ROUND: |
| 159 for (int i = 0; i < F.size (); i++) |
| 160 { |
| 161 double calc = 1 - std::pow ((F (i) + freqShift) / n_dopp, 2); |
| 162 if (calc > 0) |
| 163 { |
| 164 S (i) = std::sqrt (itpp::pi * n_dopp * std::sqrt (calc)); |
| 165 } |
| 166 else |
| 167 { |
| 168 S (i) = 0; |
| 169 } |
| 170 NS_ASSERT (!isnan (S (i))); |
| 171 } |
| 172 break; |
| 173 case FLAT: |
| 174 for (int i = 0; i < F.size (); i++) |
| 175 { |
| 176 S (i) = 1; |
| 177 } |
| 178 break; |
| 179 } |
| 180 S /= itpp::norm (S, 2); |
| 181 S *= Nfft; |
| 182 |
| 183 itpp::cvec x = itpp::zeros_c (Nfft); |
| 184 |
| 185 for (int i = 0; i < noisesamp; ++i) |
| 186 { |
| 187 x (i) = S (i) * itpp::randn_c (); |
| 188 x (Nfft - 1 - i) = S (Nfft - 1 - i) * itpp::randn_c (); |
| 189 } |
| 190 |
| 191 x = ifft (x); |
| 192 output = x.mid (0, no_samples); |
| 193 } |
| 194 |
| 195 Vehicular_TDL_Channel::Vehicular_TDL_Channel () |
| 196 { |
| 197 |
| 198 } |
| 199 |
| 200 Vehicular_TDL_Channel::Vehicular_TDL_Channel ( |
| 201 const Vehicular_Channel_Specification &channel_spec, |
| 202 double sampling_time) |
| 203 : init_flag (false), |
| 204 Ts (sampling_time) |
| 205 { |
| 206 if (sampling_time != 0.1e-6) |
| 207 { |
| 208 NS_FATAL_ERROR ("Sampling time must be 100 ns!!"); |
| 209 } |
| 210 set_channel_profile (channel_spec); |
| 211 } |
| 212 |
| 213 Vehicular_TDL_Channel::~Vehicular_TDL_Channel () |
| 214 { |
| 215 } |
| 216 |
| 217 void Vehicular_TDL_Channel::set_channel_profile ( |
| 218 const Vehicular_Channel_Specification &channel_spec) |
| 219 { |
| 220 channel = channel_spec; |
| 221 N_taps = channel.get_no_taps (); |
| 222 a_prof = pow (10.0, channel.get_avg_power_dB () / 20.0); // Convert power prof
ile to amplitude profile |
| 223 d_prof = channel.get_delay_prof (); |
| 224 relSpeed = channel.get_relative_speed (); |
| 225 init_flag = false; |
| 226 } |
| 227 |
| 228 void Vehicular_TDL_Channel::get_channel_profile (itpp::vec &avg_power_dB, |
| 229 itpp::vec &delay_prof) const |
| 230 { |
| 231 avg_power_dB = channel.get_avg_power_dB (); |
| 232 delay_prof = d_prof; |
| 233 } |
| 234 |
| 235 itpp::vec Vehicular_TDL_Channel::get_avg_power_dB () const |
| 236 { |
| 237 return channel.get_avg_power_dB (); |
| 238 } |
| 239 |
| 240 void Vehicular_TDL_Channel::init () |
| 241 { |
| 242 it_assert (N_taps > 0, |
| 243 "Vehicular_TDL_Channel::init(): Channel profile not defined yet") |
| 244 ; |
| 245 if (fading_gen.size () > 0) |
| 246 { // delete all old generators |
| 247 fading_gen.clear (); |
| 248 } |
| 249 NS_ASSERT (fading_gen.size () == 0); // make sure no generators defined |
| 250 for (int i = 0; i < N_taps; ++i) |
| 251 { |
| 252 itpp::Array<VEHICULAR_DOPPLER_SPECTRUM> spectrum = channel.taps (i).get_Do
ppler_Shapes (); |
| 253 itpp::ivec fShift = channel.taps (i).get_freq_Shift (); |
| 254 itpp::vec los_power = channel.taps (i).get_rician_K (); // !< Relative pow
er for each Rice component |
| 255 itpp::ivec los_dopp = channel.taps (i).get_LOS_Doppler (); // !< Relative
LOS Doppler for each Rice component |
| 256 for (int j = 0; j < channel.taps (i).get_no_paths (); ++j) |
| 257 { |
| 258 // need to create fading generators for each path |
| 259 double vratio = relSpeed / channel.get_relative_speed (); |
| 260 double adjustedFadingDopp = static_cast<double> (channel.taps (i).get_
fading_doppler ().get (j)) * 1e-7 * vratio; |
| 261 double adjustedFreqShift = static_cast<double> (fShift (j)) * 1e-7 * v
ratio; |
| 262 IFFTFadingGenerator gen = IFFTFadingGenerator (adjustedFadingDopp,spec
trum (j), adjustedFreqShift); |
| 263 if (los_power (j) != 0) |
| 264 { |
| 265 double adjustedLosDopp = los_dopp (j) * 1e-7 * vratio; |
| 266 gen.set_LOS_power (pow (10,los_power (j) / 10)); // los_power is r
icianK so is it 10^(LB/10) |
| 267 gen.set_LOS_doppler (adjustedLosDopp); // los_dopp is as set in t
he table |
| 268 } |
| 269 gen.init (); |
| 270 fading_gen.push_back (gen); |
| 271 } |
| 272 } |
| 273 init_flag = true; |
| 274 } |
| 275 void Vehicular_TDL_Channel::reset_gens () |
| 276 { |
| 277 if (init_flag == false) |
| 278 { |
| 279 init (); |
| 280 } |
| 281 for (uint i = 0; i < fading_gen.size (); ++i) |
| 282 { |
| 283 fading_gen.at (i).reset_time_offset (); |
| 284 } |
| 285 } |
| 286 |
| 287 void Vehicular_TDL_Channel::generate (const int no_samples, itpp::Array<itpp::cv
ec> &channel_coeff) |
| 288 { |
| 289 if (init_flag == false) |
| 290 { |
| 291 init (); |
| 292 } |
| 293 itpp::Array<itpp::cvec> tap_coeff; |
| 294 tap_coeff.set_size (N_taps,false); |
| 295 channel_coeff.set_size (N_taps, false); |
| 296 itpp::cvec path_coeff (no_samples); |
| 297 double tap_power_sum; // after the path addition make taps have unit power |
| 298 for (int i = 0; i < N_taps; ++i) |
| 299 { |
| 300 path_coeff.zeros (); |
| 301 tap_power_sum = 0; |
| 302 itpp::vec rel_path_gain = channel.taps (i).get_relative_path_loss (); |
| 303 for (int j = 0; j < channel.taps (i).get_no_paths (); ++j) |
| 304 { // add the paths |
| 305 path_coeff += pow (10,rel_path_gain (j) / 20.0) * fading_gen[j].genera
te (no_samples); |
| 306 tap_power_sum += pow (10,rel_path_gain (j) / 10); |
| 307 } |
| 308 tap_coeff (i) = path_coeff / sqrt (tap_power_sum); |
| 309 NS_ASSERT (a_prof (i) == pow (10,channel.tap_power (i) / 20)); |
| 310 channel_coeff (i) = a_prof (i) * tap_coeff (i); |
| 311 } |
| 312 } |
| 313 |
| 314 void Vehicular_TDL_Channel::filter (const itpp::cvec &input, itpp::cvec &output,
itpp::Array<itpp::cvec> &channel_coeff) |
| 315 { |
| 316 generate (input.size (),channel_coeff); |
| 317 filter_known_channel (input,output,channel_coeff); |
| 318 } |
| 319 |
| 320 void Vehicular_TDL_Channel::set_relative_speed (double speed) |
| 321 { |
| 322 relSpeed = speed; |
| 323 init_flag = false; |
| 324 } |
| 325 |
| 326 void Vehicular_TDL_Channel::filter_known_channel (const itpp::cvec &input, itpp:
:cvec &output, const itpp::Array<itpp::cvec> &channel_coeff) |
| 327 { |
| 328 int maxdelay = static_cast<int> (max (d_prof * 1e7)); // delay value per tap i
n samples |
| 329 output.set_size (input.size () + maxdelay, false); |
| 330 output.zeros (); |
| 331 int delayinsamples; |
| 332 for (int i = 0; i < N_taps; i++) |
| 333 { |
| 334 delayinsamples = static_cast<int> (d_prof (i) * 1e7); |
| 335 output += itpp::concat (itpp::zeros_c (delayinsamples), itpp::elem_mult (i
nput, channel_coeff (i)), itpp::zeros_c (maxdelay - delayinsamples)); |
| 336 } |
| 337 } |
| 338 } // namespace ns3 |
OLD | NEW |