Bug 1140: fixed. New Jakes model has been implemented.
authorKirill Andreev <andreev@telum.ru>
Mon, 21 May 2012 19:15:32 +0400
changeset 8786 8f366d5eee06
parent 8785 5b5cb5261865
child 8788 6b31c0c234cc
Bug 1140: fixed. New Jakes model has been implemented.
src/propagation/examples/jakes-propagation-model-example.cc
src/propagation/examples/main-propagation-loss.cc
src/propagation/examples/wscript
src/propagation/model/jakes-process.cc
src/propagation/model/jakes-process.h
src/propagation/model/jakes-propagation-loss-model.cc
src/propagation/model/jakes-propagation-loss-model.h
src/propagation/model/propagation-cache.h
src/propagation/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/propagation/examples/jakes-propagation-model-example.cc	Mon May 21 19:15:32 2012 +0400
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Telum (www.telum.ru)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Kirill Andreev <andreev@telum.ru>
+ */
+#include "ns3/core-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/jakes-propagation-loss-model.h"
+#include <vector>
+#include <math.h>
+
+using namespace ns3;
+/**
+ * \ingroup propagation
+ * \brief Constructs a JakesPropagationlossModel and print the loss value as a function of time into std::cout.
+ * Distribution and correlation statistics is compared woth a theoretical ones using R package (http://www.r-project.org/).
+ * Scripts are presented within comments.
+ */
+class JakesPropagationExample
+{
+public:
+  JakesPropagationExample ();
+  ~JakesPropagationExample ();
+private:
+  Ptr<PropagationLossModel> m_loss;
+  Ptr<MobilityModel> m_firstMobility;
+  Ptr<MobilityModel> m_secondMobility;
+  Time m_step;
+  EventId m_nextEvent;
+  void Next ();
+
+};
+
+JakesPropagationExample::JakesPropagationExample () :
+  m_step (Seconds (0.0002)) //1/5000 part of the second
+{
+  m_loss = CreateObject<JakesPropagationLossModel> ();
+  m_firstMobility = CreateObject<ConstantPositionMobilityModel> ();
+  m_secondMobility = CreateObject<ConstantPositionMobilityModel> ();
+  m_firstMobility->SetPosition (Vector (0, 0, 0));
+  m_secondMobility->SetPosition (Vector (10, 0, 0));
+  m_nextEvent = Simulator::Schedule (m_step, &JakesPropagationExample::Next, this);
+}
+
+JakesPropagationExample::~JakesPropagationExample ()
+{
+}
+
+void JakesPropagationExample::Next ()
+{
+  m_nextEvent = Simulator::Schedule (m_step, &JakesPropagationExample::Next, this);
+  std::cout << Simulator::Now ().GetMilliSeconds () << " " << m_loss->CalcRxPower (0, m_firstMobility, m_secondMobility) << std::endl;
+}
+
+int main (int argc, char *argv[])
+{
+  Config::SetDefault ("ns3::JakesProcess::NumberOfOscillators", UintegerValue (100));
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+  JakesPropagationExample example;
+  Simulator::Stop (Seconds (1000));
+  Simulator::Run ();
+  Simulator::Destroy ();
+  /*
+   * R script for plotting a distribution:
+   data<-read.table ("data")
+   rayleigh<-(rnorm(1e6)^2+rnorm(1e6)^2)/2
+   qqplot(10*log10(rayleigh), data$V2, main="QQ-plot for improved Jakes model", xlab="Reference Rayleigh distribution [power, dB]", ylab="Sum-of-sinusoids distribution [power, dB]", xlim=c(-45, 10), ylim=c(-45, 10))
+   lines (c(-50, 50), c(-50, 50))
+   abline (v=-50:50*2, h=-50:50*2, col="light grey")
+   */
+
+  /*
+   * R script to plot autocorrelation function:
+   # Read amplitude distribution:
+   data<-10^(read.table ("data")$V2/20)
+   x<-1:2000/10
+   acf (data, lag.max=200, main="Autocorrelation function of the improved Jakes model", xlab="Time x200 microseconds ", ylab="Autocorrelation")
+   # If we have a delta T = 1/5000 part of the second and doppler freq = 80 Hz
+   lines (x, besselJ(x*80*2*pi/5000, 0)^2)
+   abline (h=0:10/10, col="light grey")
+   */
+  return 0;
+}
--- a/src/propagation/examples/main-propagation-loss.cc	Mon May 21 07:25:00 2012 -0700
+++ b/src/propagation/examples/main-propagation-loss.cc	Mon May 21 19:15:32 2012 +0400
@@ -249,7 +249,7 @@
     Ptr<JakesPropagationLossModel> jakes = CreateObject<JakesPropagationLossModel> ();
 
     // doppler frequency shift for 5.15 GHz at 100 km/h
-    jakes->SetAttribute ("DopplerFreq", DoubleValue (477.9));
+    Config::SetDefault ("ns3::JakesProcess::DopplerFrequencyHz", DoubleValue (477.9));
 
     Gnuplot plot = TestDeterministicByTime (jakes, Seconds (0.001), Seconds (1.0));
     plot.SetTitle ("ns3::JakesPropagationLossModel (with 477.9 Hz shift and 1 millisec resolution)");
@@ -260,7 +260,7 @@
     Ptr<JakesPropagationLossModel> jakes = CreateObject<JakesPropagationLossModel> ();
 
     // doppler frequency shift for 5.15 GHz at 100 km/h
-    jakes->SetAttribute ("DopplerFreq", DoubleValue (477.9));
+    Config::SetDefault ("ns3::JakesProcess::DopplerFrequencyHz", DoubleValue (477.9));
 
     Gnuplot plot = TestDeterministicByTime (jakes, Seconds (0.0001), Seconds (0.1));
     plot.SetTitle ("ns3::JakesPropagationLossModel (with 477.9 Hz shift and 0.1 millisec resolution)");
--- a/src/propagation/examples/wscript	Mon May 21 07:25:00 2012 -0700
+++ b/src/propagation/examples/wscript	Mon May 21 19:15:32 2012 +0400
@@ -8,4 +8,9 @@
                                  ['core', 'mobility', 'config-store', 'tools', 'propagation'])
     obj.source = 'main-propagation-loss.cc'
 
+    obj = bld.create_ns3_program('jakes-propagation-model-example',
+                                 ['core', 'propagation'])
+    obj.source = 'jakes-propagation-model-example.cc'
 
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/propagation/model/jakes-process.cc	Mon May 21 19:15:32 2012 +0400
@@ -0,0 +1,134 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Telum (www.telum.ru)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Kirill Andreev <andreev@telum.ru>, Alexander Sofronov <sofronov@telum.ru>
+ */
+
+#include "jakes-process.h"
+#include "ns3/random-variable.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+
+namespace ns3 {
+const double JakesProcess::PI = 3.14159265358979323846;
+
+/// Represents a single oscillator
+JakesProcess::Oscillator::Oscillator (std::complex<double> amplitude, double initialPhase, double omega) :
+  m_amplitude (amplitude),
+  m_phase (initialPhase),
+  m_omega (omega)
+{}
+
+std::complex<double>
+JakesProcess::Oscillator::GetValueAt (Time at) const
+{
+  return (m_amplitude * cos (at.GetSeconds () * m_omega + m_phase));
+}
+
+NS_OBJECT_ENSURE_REGISTERED (JakesProcess);
+
+TypeId
+JakesProcess::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::JakesProcess")
+    .SetParent<Object> ()
+    .AddConstructor<JakesProcess> ()
+    .AddAttribute ("DopplerFrequencyHz", "Corresponding doppler frequency[Hz]",
+                   DoubleValue (80),
+                   MakeDoubleAccessor (&JakesProcess::SetDopplerFrequencyHz),
+                   MakeDoubleChecker<double> (0.0, 1e4))
+    .AddAttribute ("NumberOfOscillators", "The number of oscillators",
+                   UintegerValue (20),
+                   MakeUintegerAccessor (&JakesProcess::SetNOscillators),
+                   MakeUintegerChecker<unsigned int> (4, 1000))
+  ;
+  return tid;
+}
+
+void
+JakesProcess::SetNOscillators (unsigned int nOscillators)
+{
+  m_nOscillators = nOscillators;
+  if (m_omegaDopplerMax != 0)
+    {
+      ConstructOscillators ();
+    }
+}
+
+void
+JakesProcess::SetDopplerFrequencyHz (double dopplerFrequencyHz)
+{
+  m_omegaDopplerMax = 2 * dopplerFrequencyHz * PI;
+  if (m_nOscillators != 0)
+    {
+      ConstructOscillators ();
+    }
+}
+
+void
+JakesProcess::ConstructOscillators ()
+{
+  // Initial phase is common for all oscillators:
+  double phi = UniformVariable (-PI, PI).GetValue ();
+  // Theta is common for all oscillatoer:
+  double theta = UniformVariable (-PI, PI).GetValue ();
+  for (unsigned int i = 0; i < m_nOscillators; i++)
+    {
+      unsigned int n = i + 1;
+      /// 1. Rotation speed
+      /// 1a. Initiate \f[ \alpha_n = \frac{2\pi n - \pi + \theta}{4M},  n=1,2, \ldots,M\f], n is oscillatorNumber, M is m_nOscillators
+      double alpha = (2.0 * PI * n - PI + theta) / (4.0 * m_nOscillators);
+      /// 1b. Initiate rotation speed:
+      double omega = m_omegaDopplerMax * cos (alpha);
+      /// 2. Initiate complex amplitude:
+      double psi = UniformVariable (-PI, PI).GetValue ();
+      std::complex<double> amplitude = std::complex<double> (cos (psi), sin (psi)) * 2.0 / sqrt (m_nOscillators);
+      /// 3. Construct oscillator:
+      m_oscillators.push_back (Oscillator (amplitude, phi, omega)); 
+    }
+}
+
+JakesProcess::JakesProcess () :
+  m_omegaDopplerMax (0),
+  m_nOscillators (0)
+{}
+
+JakesProcess::~JakesProcess()
+{
+  m_oscillators.clear ();
+}
+
+std::complex<double>
+JakesProcess::GetComplexGain () const
+{
+  std::complex<double> sumAplitude = std::complex<double> (0, 0);
+  for (unsigned int i = 0; i < m_oscillators.size (); i++)
+    {
+      sumAplitude += m_oscillators[i].GetValueAt (Now ());
+    }
+  return sumAplitude;
+}
+
+double
+JakesProcess::GetChannelGainDb () const
+{
+  std::complex<double> complexGain = GetComplexGain ();
+  return (10 * log10 ((pow (complexGain.real (), 2) + pow (complexGain.imag (), 2)) / 2));
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/propagation/model/jakes-process.h	Mon May 21 19:15:32 2012 +0400
@@ -0,0 +1,92 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Telum (www.telum.ru)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Kirill Andreev <andreev@telum.ru>, Alexander Sofronov <sofronov@telum.ru>
+ */
+#ifndef DOPPLER_PROCESS_H
+#define DOPPLER_PROCESS_H
+
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include <complex>
+
+namespace ns3
+{
+/**
+ * \ingroup fading
+ *
+ * \brief Implementation for a single path Stationary Jakes propagation loss model.
+ *
+ * The Jakes propagation loss model implemented here is
+ * described in [1].
+ *
+ * We consider one transmitter - receiver pair and calculate
+ * the complex coefficients for this case as follow:
+ * \f[ X(t)=X_c(t) + j X_s(t)\f]
+ * \f[ X_c(t) = \frac{2}{\sqrt{M}}\sum_{n=1}^{M}\cos(\psi_n)\cos(\omega_d t\cos(\alpha_n)+\phi_n)\f]
+ * \f[ X_s(t) = \frac{2}{\sqrt{M}}\sum_{n=1}^{M}\sin(\psi_n)\cos(\omega_d t\cos(\alpha_n)+\phi_n)\f]
+ * with
+ * \f[ \alpha_n = \frac{2\pi n - \pi + \theta}{4M},  n=1,2, \ldots,M\f]
+ * where
+ *\f$\theta\f$, \f$\phi\f$, and \f$\psi_n\f$ are statically independent and uniformly distributed over \f$[-\pi, \pi)\f$ for all \f$n\f$.
+ *
+ *
+ * [1] Y. R. Zheng and C. Xiao, "Simulation Models With Correct
+ * Statistical Properties for Rayleigh Fading Channel", IEEE
+ * Trans. on Communications, Vol. 51, pp 920-928, June 2003
+ */
+class JakesProcess : public Object
+{
+public:
+  static TypeId GetTypeId (void);
+  JakesProcess ();
+  virtual ~JakesProcess();
+  std::complex<double> GetComplexGain () const;
+  /// Get Channel gain [dB]
+  double GetChannelGainDb () const;
+private:
+  /// Represents a single oscillator
+  struct Oscillator
+  {
+    /// Initiate oscillator with complex amplitude, initial phase and rotation speed
+    Oscillator (std::complex<double> amplitude, double initialPhase, double omega);
+    // Get the complex amplitude at moment \param t
+    std::complex<double> GetValueAt (Time t) const;
+    /// Complex number \f[Re=\cos(\psi_n), Im = i\sin(\psi_n)]
+    std::complex<double> m_amplitude;
+    /// Phase \f[\phi_n] of the oscillator
+    double m_phase;
+    /// Rotation speed of the oscillator \f[\omega_d \cos(\alpha_n)]
+    double m_omega;
+  };
+  /// PI Constant
+  static const double PI;
+private:
+  void SetNOscillators (unsigned int nOscillators);
+  void SetDopplerFrequencyHz (double dopplerFrequencyHz);
+  void ConstructOscillators ();
+private:
+  /// Vector of oscillators:
+  std::vector<Oscillator> m_oscillators;
+  ///\name Attributes:
+  ///\{
+  double m_omegaDopplerMax;
+  unsigned int m_nOscillators;
+  ///\}
+};
+} // namespace ns3
+#endif // DOPPLER_PROCESS_H
--- a/src/propagation/model/jakes-propagation-loss-model.cc	Mon May 21 07:25:00 2012 -0700
+++ b/src/propagation/model/jakes-propagation-loss-model.cc	Mon May 21 19:15:32 2012 +0400
@@ -1,9 +1,9 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2005,2006,2007 INRIA
+ * Copyright (c) 2012 Telum (www.telum.ru)
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as 
+ * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation;
  *
  * This program is distributed in the hope that it will be useful,
@@ -15,246 +15,37 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Author: Federico Maguolo <maguolof@dei.unipd.it>
+ * Author: Kirill Andreev <andreev@telum.ru>
  */
 
-#include "ns3/simulator.h"
-#include "ns3/uinteger.h"
-#include "ns3/double.h"
-#include "ns3/random-variable.h"
-#include "ns3/mobility-model.h"
-#include "ns3/log.h"
 #include "jakes-propagation-loss-model.h"
-#include <math.h>
 
-NS_LOG_COMPONENT_DEFINE ("Jakes");
-
-namespace ns3 {
-
+namespace ns3
+{
 NS_OBJECT_ENSURE_REGISTERED (JakesPropagationLossModel);
 
-class JakesPropagationLossModel::PathCoefficients 
-{
-public:
-  PathCoefficients (Ptr<const JakesPropagationLossModel> jakes,
-                    Ptr<MobilityModel> receiver, 
-                    uint8_t nRays, 
-                    uint8_t nOscillators);
-  ~PathCoefficients ();
-  double GetLoss (Ptr<const JakesPropagationLossModel> jakes);
-  Ptr<MobilityModel> GetReceiver (void);
-private:
-  void DoConstruct (Ptr<const JakesPropagationLossModel> jakes);
-  Ptr<MobilityModel> m_receiver;
-  uint8_t m_nOscillators;
-  uint8_t m_nRays;
-  double **m_phases;
-  Time m_lastUpdate;
-};
-
-
-JakesPropagationLossModel::PathCoefficients::PathCoefficients (Ptr<const JakesPropagationLossModel> jakes, 
-                                                               Ptr<MobilityModel> receiver,
-                                                               uint8_t nRays,
-                                                               uint8_t nOscillators)
-  : m_receiver (receiver),
-    m_nOscillators (nOscillators),
-    m_nRays (nRays)
-{
-  DoConstruct (jakes);
-}
-
-JakesPropagationLossModel::PathCoefficients::~PathCoefficients ()
-{
-  for (uint8_t i = 0; i < m_nRays; i++) 
-    {
-      delete [] m_phases[i];
-    }
-  delete [] m_phases;
-}
+JakesPropagationLossModel::JakesPropagationLossModel()
+{}
 
-void
-JakesPropagationLossModel::PathCoefficients::DoConstruct (Ptr<const JakesPropagationLossModel> jakes)
-{
-  m_phases = new double*[m_nRays];
-  for (uint8_t i = 0; i < m_nRays; i++) 
-    {
-      m_phases[i] = new double[m_nOscillators + 1];
-      for (uint8_t j = 0; j <= m_nOscillators; j++) 
-        {
-          m_phases[i][j] = 2.0 * JakesPropagationLossModel::PI * jakes->m_variable.GetValue ();
-        }
-    }
-  m_lastUpdate = Simulator::Now ();
-}
-
-Ptr<MobilityModel>
-JakesPropagationLossModel::PathCoefficients::GetReceiver ()
-{
-  return m_receiver;
-}
-
-double
-JakesPropagationLossModel::PathCoefficients::GetLoss (Ptr<const JakesPropagationLossModel> jakes)
-{
-  uint16_t N = 4 * m_nOscillators + 2;
-  Time interval = Simulator::Now () - m_lastUpdate;
-  ComplexNumber coef= { 0.0, 0.0};
-  ComplexNumber fading;
-  double norm = 0.0;
-  for (uint8_t i = 0; i < m_nRays; i++) 
-    {
-      fading.real = 0.0;
-      fading.imag = 0.0;
-      for (uint8_t j = 0; j <= m_nOscillators; j++) 
-        {
-          m_phases[i][j] += 2.0 * JakesPropagationLossModel::PI * 
-            cos (2.0 * JakesPropagationLossModel::PI * j / N) * jakes->m_fd * interval.GetSeconds ();
-          m_phases[i][j] -= 2.0 * JakesPropagationLossModel::PI * 
-            floor (m_phases[i][j] / 2.0 / JakesPropagationLossModel::PI);
-          fading.real += jakes->m_amp[j].real * cos (m_phases[i][j]);
-          fading.imag += jakes->m_amp[j].imag * cos (m_phases[i][j]);
-          norm += sqrt (pow (jakes->m_amp[j].real, 2) + pow (jakes->m_amp[j].imag, 2));
-        }
-      coef.real += fading.real;
-      coef.imag += fading.imag;
-    }
-  m_lastUpdate = Simulator::Now ();
-  double k = sqrt (pow (coef.real, 2) + pow (coef.imag, 2)) / norm;
-  NS_LOG_DEBUG ("Jakes coef "<< k << " (" << 10 * log10 (k) << "dB)");
-  return 10 * log10 (k);
-}
-
-const double JakesPropagationLossModel::PI = 3.14159265358979323846;
+JakesPropagationLossModel::~JakesPropagationLossModel()
+{}
 
 TypeId
-JakesPropagationLossModel::GetTypeId (void)
+JakesPropagationLossModel::GetTypeId ()
 {
   static TypeId tid = TypeId ("ns3::JakesPropagationLossModel")
     .SetParent<PropagationLossModel> ()
     .AddConstructor<JakesPropagationLossModel> ()
-    .AddAttribute ("NumberOfRaysPerPath",
-                   "The number of rays to use by default for compute the fading coeficent for a given path (default is 1)",
-                   UintegerValue (1),
-                   MakeUintegerAccessor (&JakesPropagationLossModel::SetNRays,
-                                         &JakesPropagationLossModel::GetNRays),
-                   MakeUintegerChecker<uint8_t> ())
-    .AddAttribute ("NumberOfOscillatorsPerRay",
-                   "The number of oscillators to use by default for compute the coeficent for a given ray of a given "
-                   "path (default is 4)",
-                   UintegerValue (4),
-                   MakeUintegerAccessor (&JakesPropagationLossModel::SetNOscillators,
-                                         &JakesPropagationLossModel::GetNOscillators),
-                   MakeUintegerChecker<uint8_t> ())
-    .AddAttribute ("DopplerFreq",
-                   "The doppler frequency in Hz (f_d = v / lambda = v * f / c), the default is 0)",
-                   DoubleValue (0.0),
-                   MakeDoubleAccessor (&JakesPropagationLossModel::m_fd),
-                   MakeDoubleChecker<double> ())
-    .AddAttribute ("Distribution",
-                   "The distribution to choose the initial phases.",
-                   RandomVariableValue (ConstantVariable (1.0)),
-                   MakeRandomVariableAccessor (&JakesPropagationLossModel::m_variable),
-                   MakeRandomVariableChecker ())
   ;
   return tid;
 }
 
-JakesPropagationLossModel::JakesPropagationLossModel ()
-  : m_amp (0),
-    m_nRays (0),
-    m_nOscillators (0)
-{
-}
-
-JakesPropagationLossModel::~JakesPropagationLossModel ()
-{
-  delete [] m_amp;
-  for (PathsList::reverse_iterator i = m_paths.rbegin (); i != m_paths.rend (); i++)
-    {
-      PathsSet *ps = *i;
-      for (DestinationList::iterator r = ps->receivers.begin (); r != ps->receivers.end (); r++)
-        {
-          PathCoefficients *pc = *r;
-          delete pc;
-        }
-      ps->sender = 0;
-      ps->receivers.clear ();
-      delete ps;
-    }
-  m_paths.clear ();
-}
-
-void
-JakesPropagationLossModel::SetNRays (uint8_t nRays)
-{
-  m_nRays = nRays;
-}
-
-void
-JakesPropagationLossModel::SetNOscillators (uint8_t nOscillators)
-{
-  m_nOscillators = nOscillators;
-  delete [] m_amp;
-  uint16_t N = 4 * m_nOscillators + 2;
-  m_amp = new ComplexNumber[m_nOscillators + 1];
-  m_amp[0].real = 2.0 * sqrt (2.0 / N) * cos (PI / 4.0);
-  m_amp[0].imag = 2.0 * sqrt (2.0 / N) * sin (PI / 4.0);
-  for (uint8_t i = 1; i <= m_nOscillators; i++) 
-    {
-      double beta = PI * (double)i / m_nOscillators;
-      m_amp[i].real = 4.0 * cos (beta) / sqrt (N);
-      m_amp[i].imag = 4.0 * sin (beta) / sqrt (N);
-    }
-}
-
-uint8_t 
-JakesPropagationLossModel::GetNRays (void) const
-{
-  return m_nRays;
-}
-uint8_t 
-JakesPropagationLossModel::GetNOscillators (void) const
-{
-  return m_nOscillators;
-}
-
-
-double 
+double
 JakesPropagationLossModel::DoCalcRxPower (double txPowerDbm,
                                           Ptr<MobilityModel> a,
                                           Ptr<MobilityModel> b) const
 {
-  PathsList::iterator i = m_paths.end ();
-  while (i != m_paths.begin ()) 
-    {
-      i--;
-      PathsSet *ps = *i;
-      if (ps->sender == a) 
-        {
-          m_paths.erase (i);
-          m_paths.push_back (ps);
-          for (DestinationList::iterator r = ps->receivers.begin (); r != ps->receivers.end (); r++) 
-            {
-              PathCoefficients *pc = *r;
-              if (pc->GetReceiver () == b) 
-                {
-                  ps->receivers.erase (r);
-                  ps->receivers.push_back (pc);
-                  return txPowerDbm + pc->GetLoss (this);
-                }
-            }
-          PathCoefficients *pc = new PathCoefficients (this, b, m_nRays, m_nOscillators);
-          ps->receivers.push_back (pc);
-          return txPowerDbm + pc->GetLoss (this);
-        }
-    }
-  PathsSet *ps = new PathsSet;
-  ps->sender = a;
-  PathCoefficients *pc = new PathCoefficients (this, b, m_nRays, m_nOscillators);
-  ps->receivers.push_back (pc);
-  m_paths.push_back (ps);
-  return txPowerDbm + pc->GetLoss (this);
+  return txPowerDbm + m_propagationCache.GetPathData (a, b, 0 /**Spectrum model uid is not used in PropagationLossModel*/)->GetChannelGainDb ();
 }
 
 } // namespace ns3
--- a/src/propagation/model/jakes-propagation-loss-model.h	Mon May 21 07:25:00 2012 -0700
+++ b/src/propagation/model/jakes-propagation-loss-model.h	Mon May 21 19:15:32 2012 +0400
@@ -1,9 +1,9 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2005,2006,2007 INRIA
+ * Copyright (c) 2012 Telum (www.telum.ru)
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as 
+ * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation;
  *
  * This program is distributed in the hope that it will be useful,
@@ -15,125 +15,41 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Author: Federico Maguolo <maguolof@dei.unipd.it>
+ * Author: Kirill Andreev <andreev@telum.ru>
  */
-#ifndef PROPAGATION_JAKES_MODEL_H
-#define PROPAGATION_JAKES_MODEL_H
+#ifndef JAKES_STATIONARY_LOSS_MODEL_H
+#define JAKES_STATIONARY_LOSS_MODEL_H
 
-#include "ns3/nstime.h"
-#include "propagation-loss-model.h"
+#include "ns3/propagation-loss-model.h"
+#include "ns3/propagation-cache.h"
+#include "ns3/jakes-process.h"
 
-namespace ns3 {
-
-
+namespace ns3
+{
 /**
  * \ingroup propagation
  *
- * \brief a Jakes propagation loss model
- *
- * The Jakes propagation loss model implemented here is 
- * described in [1].
- * 
- *
- * We call path the set of rays that depart from a given 
- * transmitter and arrive to a given receiver. For each ray
- * The complex coefficient is compute as follow:
- * \f[ u(t)=u_c(t) + j u_s(t)\f]
- * \f[ u_c(t) = \frac{2}{\sqrt{N}}\sum_{n=0}^{M}a_n\cos(\omega_n t+\phi_n)\f]
- * \f[ u_s(t) = \frac{2}{\sqrt{N}}\sum_{n=0}^{M}b_n\cos(\omega_n t+\phi_n)\f]
- * where
- * \f[ a_n=\left \{ \begin{array}{ll}
- * \sqrt{2}\cos\beta_0 & n=0 \\
- * 2\cos\beta_n & n=1,2,\ldots,M
- * \end{array}
- * \right .\f]
- * \f[ b_n=\left \{ \begin{array}{ll}
- * \sqrt{2}\sin\beta_0 & n=0 \\
- * 2\sin\beta_n & n=1,2,\ldots,M
- * \end{array}
- * \right .\f]
- * \f[ \beta_n=\left \{ \begin{array}{ll}
- * \frac{\pi}{4} & n=0 \\
- * \frac{\pi n}{M} & n=1,2,\ldots,M
- * \end{array}
- * \right .\f]
- * \f[ \omega_n=\left \{ \begin{array}{ll}
- * 2\pi f_d & n=0 \\
- * 2\pi f_d \cos\frac{2\pi n}{N} & n=1,2,\ldots,M
- * \end{array}
- * \right .\f]
- *
- * The parameter \f$f_d\f$ is the doppler frequency and \f$N=4M+2\f$ where
- * \f$M\f$ is the number of oscillators per ray.
- *
- * The attenuation coefficent of the path is the magnitude of the sum of 
- * all the ray coefficients. This attenuation coefficient could be greater than
- * \f$1\f$, hence it is divide by \f$ \frac{2N_r}{\sqrt{N}} \sum_{n+0}^{M}\sqrt{a_n^2 +b_n^2}\f$
- * where \f$N_r\f$ is the number of rays.
- *
- * The initail phases \f$\phi_i\f$ are random and they are choosen according 
- * to a given distribution.
- * 
- * [1] Y. R. Zheng and C. Xiao, "Simulation Models With Correct 
- * Statistical Properties for Rayleigh Fading Channel", IEEE
- * Trans. on Communications, Vol. 51, pp 920-928, June 2003
+ * \brief a  jakes narrowband propagation model.
+ * Symmetrical cache for JakesProcess
  */
+
 class JakesPropagationLossModel : public PropagationLossModel
 {
 public:
-  static TypeId GetTypeId (void);
+  static TypeId GetTypeId ();
   JakesPropagationLossModel ();
   virtual ~JakesPropagationLossModel ();
 
-  /**
-   * \param nRays Number of rays per path
-   *
-   * Set the number of rays for each path
-   */
-  void SetNRays (uint8_t nRays);
-  /**
-   * \param nOscillators Number of oscillators
-   *
-   * Set the number of oscillators to use to compute the ray coefficient
-   */
-  void SetNOscillators (uint8_t nOscillators);
-
-  uint8_t GetNRays (void) const;
-  uint8_t GetNOscillators (void) const;
+private:
+  double DoCalcRxPower (double txPowerDbm,
+                        Ptr<MobilityModel> a,
+                        Ptr<MobilityModel> b) const;
 
 private:
-  JakesPropagationLossModel (const JakesPropagationLossModel &o);
-  JakesPropagationLossModel & operator = (const JakesPropagationLossModel &o);
-  void DoConstruct (void);
-  virtual double DoCalcRxPower (double txPowerDbm,
-                                Ptr<MobilityModel> a,
-                                Ptr<MobilityModel> b) const;
-
-  class PathCoefficients;
-  struct ComplexNumber {
-    double real;
-    double imag;
-  };
-  friend class PathCoefficents;
-  typedef std::vector<PathCoefficients *> DestinationList;
-  struct PathsSet {
-    Ptr<MobilityModel> sender;
-    DestinationList receivers;
-  };
-  typedef std::vector<PathsSet *> PathsList;
-
-
-  static const double PI;
-  ComplexNumber* m_amp;
-  RandomVariable m_variable;
-  double m_fd;
-  mutable PathsList m_paths;
-  uint8_t m_nRays;
-  uint8_t m_nOscillators;
+  mutable PropagationCache<JakesProcess> m_propagationCache;
 };
 
 } // namespace ns3
 
-#endif /* PROPAGATION_JAKES_MODEL_H */
+#endif /* JAKES_STATIONARY_LOSS_MODEL_H */
 
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/propagation/model/propagation-cache.h	Mon May 21 19:15:32 2012 +0400
@@ -0,0 +1,86 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Telum (www.telum.ru)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Kirill Andreev <andreev@telum.ru>
+ */
+#ifndef PROPAGATION_CACHE_H_
+#define PROPAGATION_CACHE_H_
+
+#include "ns3/mobility-model.h"
+#include <map>
+
+namespace ns3
+{
+/**
+ * \ingroup propagation
+ * \brief Constructs a cache of objects, where each obect is responsible for a single propagation path loss calculations.
+ * Propagation path a-->b and b-->a is the same thing. Propagation path is identified by
+ * a couple of MobilityModels and a spectrum model UID
+ */
+template<class T>
+class PropagationCache
+{
+public:
+  PropagationCache () {};
+  ~PropagationCache () {};
+  Ptr<T> GetPathData (Ptr<const MobilityModel> a, Ptr<const MobilityModel> b, uint32_t modelUid)
+  {
+    PropagationPathIdentifier key = PropagationPathIdentifier (a, b, modelUid);
+    typename PathCache::iterator it = m_pathCache.find (key);
+    if (it == m_pathCache.end ())
+      {
+        Ptr<T> newPath = CreateObject<T> ();
+        m_pathCache.insert (std::make_pair (key, newPath));
+        return newPath;
+      }
+    return it->second;
+  };
+private:
+  /// Each path is identified by
+  struct PropagationPathIdentifier
+  {
+    PropagationPathIdentifier (Ptr<const MobilityModel> a, Ptr<const MobilityModel> b, uint32_t modelUid) :
+      m_srcMobility (a), m_dstMobility (b), m_spectrumModelUid (modelUid)
+    {};
+    Ptr<const MobilityModel> m_srcMobility;
+    Ptr<const MobilityModel> m_dstMobility;
+    uint32_t m_spectrumModelUid;
+    bool operator < (const PropagationPathIdentifier & other) const
+    {
+      if (m_spectrumModelUid != other.m_spectrumModelUid)
+        {
+          return m_spectrumModelUid < other.m_spectrumModelUid;
+        }
+      /// Links are supposed to be symmetrical!
+      if (std::min (m_dstMobility, m_srcMobility) != std::min (other.m_dstMobility, other.m_srcMobility))
+        {
+          return std::min (m_dstMobility, m_srcMobility) < std::min (other.m_dstMobility, other.m_srcMobility);
+        }
+      if (std::max (m_dstMobility, m_srcMobility) != std::max (other.m_dstMobility, other.m_srcMobility))
+        {
+          return std::max (m_dstMobility, m_srcMobility) < std::max (other.m_dstMobility, other.m_srcMobility);
+        }
+      return false;
+    }
+  };
+  typedef std::map<PropagationPathIdentifier, Ptr<T> > PathCache;
+private:
+  PathCache m_pathCache;
+};
+} // namespace ns3
+
+#endif // PROPAGATION_CACHE_H_
--- a/src/propagation/wscript	Mon May 21 07:25:00 2012 -0700
+++ b/src/propagation/wscript	Mon May 21 19:15:32 2012 +0400
@@ -7,6 +7,7 @@
         'model/propagation-delay-model.cc',
         'model/propagation-loss-model.cc',
         'model/jakes-propagation-loss-model.cc',
+        'model/jakes-process.cc',
         'model/cost231-propagation-loss-model.cc',
         'model/okumura-hata-propagation-loss-model.cc',
         'model/itu-r-1411-los-propagation-loss-model.cc',
@@ -29,6 +30,8 @@
         'model/propagation-delay-model.h',
         'model/propagation-loss-model.h',
         'model/jakes-propagation-loss-model.h',
+        'model/jakes-process.h',
+        'model/propagation-cache.h',
         'model/cost231-propagation-loss-model.h',
         'model/propagation-environment.h',
         'model/okumura-hata-propagation-loss-model.h',