spectrum API change
authorNicola Baldo <nicola@baldo.biz>
Sun, 13 Nov 2011 16:08:44 +0100
changeset 7581 6ac3fa410583
parent 7580 3ae0a64434f0
child 7582 b87e5f12a8f2
spectrum API change
CHANGES.html
src/lte/model/lte-phy.h
src/lte/model/lte-spectrum-phy.cc
src/lte/model/lte-spectrum-phy.h
src/lte/wscript
src/spectrum/model/half-duplex-ideal-phy.cc
src/spectrum/model/half-duplex-ideal-phy.h
src/spectrum/model/multi-model-spectrum-channel.cc
src/spectrum/model/multi-model-spectrum-channel.h
src/spectrum/model/single-model-spectrum-channel.cc
src/spectrum/model/single-model-spectrum-channel.h
src/spectrum/model/spectrum-analyzer.cc
src/spectrum/model/spectrum-analyzer.h
src/spectrum/model/spectrum-channel.h
src/spectrum/model/spectrum-interference.cc
src/spectrum/model/spectrum-phy.h
src/spectrum/model/spectrum-value.cc
src/spectrum/model/spectrum-value.h
src/spectrum/model/waveform-generator.cc
src/spectrum/model/waveform-generator.h
src/spectrum/wscript
--- a/CHANGES.html	Sat Nov 12 12:33:47 2011 +0100
+++ b/CHANGES.html	Sun Nov 13 16:08:44 2011 +0100
@@ -80,6 +80,9 @@
 
 <h2>Changes to existing API:</h2>
 <ul>
+<li> In the spectrum module, the parameters to SpectrumChannel::StartTx () and SpectrumPhy::StartRx () methods are now passed using the new struct SpectrumSignalParameters. This new struct supports inheritance, hence it allows technology-specific PHY implementations to provide technology-specific parameters in SpectrumChannel::StartTx() and SpectrumPhy::StartRx(), while at the same time keeping a set of technology-independent parameters common across all spectrum-enabled PHY implementations (i.e., the duration and the power spectral density which are needed for interference calculation). Additionally, the SpectrumType class has been removed, since now the type of a spectrum signal can be inferred by doing a dynamic cast on SpectrumSignalParameters. See the <A href="http://mailman.isi.edu/pipermail/ns-developers/2011-October/009495.html" >Spectrum API change discussion on ns-developers</A> for the motivation behind this API change.
+</li>
+
 <li> The WifiPhyStandard enumerators for specifying half- and quarter-channel 
 width standards has had a change in capitalization:
 <ul>
--- a/src/lte/model/lte-phy.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/lte/model/lte-phy.h	Sun Nov 13 16:08:44 2011 +0100
@@ -28,10 +28,10 @@
 #include <ns3/nstime.h>
 #include <ns3/spectrum-phy.h>
 #include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-type.h>
+#include <ns3/spectrum-signal-parameters.h>
 #include <ns3/spectrum-interference.h>
 #include <ns3/generic-phy.h>
-#include "lte-spectrum-phy.h"
+#include <ns3/lte-spectrum-phy.h>
 
 namespace ns3 {
 
@@ -54,12 +54,12 @@
 
   static TypeId GetTypeId (void);
 
-  /** 
+  /**
    * \brief Set the device where the phy layer is attached
    * \param d the device
    */
   void SetDevice (Ptr<LteNetDevice> d);
-  /** 
+  /**
    * \brief Get the device where the phy layer is attached
    * \return the pointer to the device
    */
@@ -123,8 +123,8 @@
   /**
    * \brief set a list of sub channel to use in the downlink.
    * A sub channel is composed by a couple of resource bloks (180KHz x 1 ms)
-   * \param mask a vector of intefer values. Each elements of this vector carries information about 
-   * the corresponding DL sub channel. If the i-th value of mask is equal to 1 (0) it means that the corresponding sub channel is used (not used) for the downlink. 
+   * \param mask a vector of intefer values. Each elements of this vector carries information about
+   * the corresponding DL sub channel. If the i-th value of mask is equal to 1 (0) it means that the corresponding sub channel is used (not used) for the downlink.
    */
   void SetDownlinkSubChannels (std::vector<int> mask );
   /**
@@ -135,8 +135,8 @@
   /**
    * \brief set a list of sub channel to use in the uplink.
    * A sub channel is composed by a couple of resource bloks (180KHz x 1 ms)
-   * \param mask a vector of intefer values. Each elements of this vector carries information about 
-   * the corresponding UL sub channel. If the i-th value of mask is equal to 1 (0) it means that the corresponding sub channel is used (not used) for the uplink. 
+   * \param mask a vector of intefer values. Each elements of this vector carries information about
+   * the corresponding UL sub channel. If the i-th value of mask is equal to 1 (0) it means that the corresponding sub channel is used (not used) for the uplink.
    */
   void SetUplinkSubChannels (std::vector<int> mask);
   /**
@@ -157,7 +157,7 @@
 
 
   /**
-   * \brief Compute the TX Power Spectral Density 
+   * \brief Compute the TX Power Spectral Density
    * \return a Ptr to a created SpectrumValue
    */
   virtual Ptr<SpectrumValue> CreateTxPowerSpectralDensity () = 0;
--- a/src/lte/model/lte-spectrum-phy.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/lte/model/lte-spectrum-phy.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -28,6 +28,7 @@
 #include <ns3/trace-source-accessor.h>
 #include "ns3/spectrum-error-model.h"
 #include "lte-spectrum-phy.h"
+#include "lte-spectrum-signal-parameters.h"
 #include "lte-net-device.h"
 
 NS_LOG_COMPONENT_DEFINE ("LteSpectrumPhy");
@@ -165,15 +166,6 @@
 }
 
 
-SpectrumType
-LteSpectrumPhy::GetSpectrumType ()
-{
-  NS_LOG_FUNCTION (this);
-  static SpectrumType st = SpectrumTypeFactory::Create ("IdealOfdm");
-  return st;
-}
-
-
 void
 LteSpectrumPhy::SetTxPowerSpectralDensity (Ptr<SpectrumValue> txPsd)
 {
@@ -193,9 +185,9 @@
   m_noise = noisePsd;
 }
 
-Ptr<const SpectrumValue> 
+Ptr<const SpectrumValue>
 LteSpectrumPhy::GetNoisePowerSpectralDensity (void)
-{ 
+{
   NS_LOG_FUNCTION (this);
   return m_noise;
 }
@@ -286,7 +278,12 @@
       ChangeState (TX);
       NS_ASSERT (m_channel);
       double tti = 0.001;
-      m_channel->StartTx (pb, m_txPsd, GetSpectrumType (), Seconds (tti), GetObject<SpectrumPhy> ());
+      Ptr<LteSpectrumSignalParameters> txParams = Create<LteSpectrumSignalParameters> ();
+      txParams->duration = Seconds (tti);
+      txParams->txPhy = GetObject<SpectrumPhy> ();
+      txParams->psd = m_txPsd;
+      txParams->packetBurst = pb;
+      m_channel->StartTx (txParams);
       Simulator::Schedule (Seconds (tti), &LteSpectrumPhy::EndTx, this);
       return false;
     }
@@ -329,18 +326,19 @@
 
 
 void
-LteSpectrumPhy::StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration)
+LteSpectrumPhy::StartRx (Ptr<SpectrumSignalParameters> spectrumRxParams)
 {
-  NS_LOG_FUNCTION (this << pb << rxPsd << st << duration);
+  NS_LOG_FUNCTION (this << spectrumRxParams);
   NS_LOG_LOGIC (this << "state: " << m_state);
 
 
   // interference will happen regardless of the state of the receiver
   // m_interference->AddSignal (rxPsd, duration);
 
+  Ptr<LteSpectrumSignalParameters> lteRxParams = DynamicCast<LteSpectrumSignalParameters> (spectrumRxParams);
   // the device might start RX only if the signal is of a type understood by this device
   // this corresponds in real device to preamble detection
-  if (st == GetSpectrumType ())
+  if (lteRxParams != 0)
     {
       switch (m_state)
         {
@@ -360,16 +358,17 @@
           // preamble detection and synchronization is supposed to be always successful.
           NS_LOG_LOGIC (this << " receiving new packet");
 
-          for (std::list<Ptr<Packet> >::const_iterator iter = pb->Begin (); iter
-               != pb->End (); ++iter)
+          for (std::list<Ptr<Packet> >::const_iterator iter = lteRxParams->packetBurst->Begin (); iter
+               != lteRxParams->packetBurst->End (); ++iter)
             {
               Ptr<Packet> packet = (*iter)->Copy ();
               m_phyRxStartTrace (packet);
             }
 
 
-          m_rxPacket = pb;
-          m_rxPsd = rxPsd;
+          m_rxPacket = lteRxParams->packetBurst;
+          m_rxPsd = lteRxParams->psd;
+          Time duration = lteRxParams->duration;
 
           ChangeState (RX);
 
@@ -385,7 +384,7 @@
 
           // XXX: modify SpectrumInterference in order to compute
           // the correct/erroneus reception of PacketBurst!!!
-          /* 
+          /*
           for (std::list<Ptr<Packet> >::const_iterator iter = pb->Begin (); iter
                != pb->End (); ++iter)
             {
--- a/src/lte/model/lte-spectrum-phy.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/lte/model/lte-spectrum-phy.h	Sun Nov 13 16:08:44 2011 +0100
@@ -30,7 +30,6 @@
 #include <ns3/net-device.h>
 #include <ns3/spectrum-phy.h>
 #include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-type.h>
 #include <ns3/spectrum-interference.h>
 #include <ns3/data-rate.h>
 #include <ns3/generic-phy.h>
@@ -70,6 +69,7 @@
   Ptr<MobilityModel> GetMobility ();
   Ptr<NetDevice> GetDevice ();
   Ptr<const SpectrumModel> GetRxSpectrumModel () const;
+  void StartRx (Ptr<SpectrumSignalParameters> params);
 
   /**
    * \brief Get the channel where the physical layer is attached
@@ -77,15 +77,6 @@
    */
   Ptr<SpectrumChannel> GetChannel (void);
 
-
-  /**
-   * Get the SpectrumType used by this PHY
-   *
-   * @return
-   */
-  SpectrumType GetSpectrumType ();
-
-
   /**
    * set the Power Spectral Density of outgoing signals in W/Hz.
    *
@@ -117,15 +108,6 @@
    */
   bool StartTx (Ptr<PacketBurst> pb);
 
-  /**
-   * \brief Notify the SpectrumPhy instance of an incoming waveform
-   * \param pb the burst of packet associated with the incoming waveform
-   * \param rxPsd the Power Spectral Density of the incoming waveform. 
-   * The units of the SPD are the same specified for SpectrumChannel::StartTx().
-   * \param st the spectrum type
-   * \param duration the duration of the incoming waveform
-   */
-  void StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration);
 
   /**
    * set the callback for the end of a TX, as part of the
@@ -170,7 +152,7 @@
 
   /**
    * \brief Set the state of the phy layer
-   * \param newState the state 
+   * \param newState the state
    */
   void SetState (State newState);
 
--- a/src/lte/wscript	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/lte/wscript	Sun Nov 13 16:08:44 2011 +0100
@@ -5,6 +5,7 @@
     module = bld.create_ns3_module('lte', ['internet', 'spectrum', 'wimax'])
     module.source = [
         'model/lte-spectrum-phy.cc',
+        'model/lte-spectrum-signal-parameters.cc',
         'model/enb-lte-spectrum-phy.cc',
         'model/ue-lte-spectrum-phy.cc',
         'model/lte-phy.cc',
@@ -51,6 +52,7 @@
     headers.module = 'lte'
     headers.source = [
         'model/lte-spectrum-phy.h',
+        'model/lte-spectrum-signal-parameters.h',
         'model/enb-lte-spectrum-phy.h',
         'model/ue-lte-spectrum-phy.h',
         'model/lte-phy.h',
--- a/src/spectrum/model/half-duplex-ideal-phy.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/half-duplex-ideal-phy.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -27,13 +27,14 @@
 #include <ns3/packet-burst.h>
 #include <ns3/callback.h>
 #include "half-duplex-ideal-phy.h"
+#include "half-duplex-ideal-phy-signal-parameters.h"
 #include "spectrum-error-model.h"
 
+
 NS_LOG_COMPONENT_DEFINE ("HalfDuplexIdealPhy");
 
 namespace ns3 {
 
-
 NS_OBJECT_ENSURE_REGISTERED (HalfDuplexIdealPhy);
 
 HalfDuplexIdealPhy::HalfDuplexIdealPhy ()
@@ -178,15 +179,6 @@
     }
 }
 
-
-SpectrumType
-HalfDuplexIdealPhy::GetSpectrumType ()
-{
-  NS_LOG_FUNCTION (this);
-  static SpectrumType st = SpectrumTypeFactory::Create ("IdealOfdm");
-  return st;
-}
-
 void
 HalfDuplexIdealPhy::SetTxPowerSpectralDensity (Ptr<SpectrumValue> txPsd)
 {
@@ -274,10 +266,15 @@
       {
         m_txPacket = p;
         ChangeState (TX);
+        Ptr<HalfDuplexIdealPhySignalParameters> txParams = Create<HalfDuplexIdealPhySignalParameters> ();
         double txTimeSeconds = m_rate.CalculateTxTime (p->GetSize ());
-        Ptr<PacketBurst> pb = Create<PacketBurst> ();
-        pb->AddPacket (p);
-        m_channel->StartTx (pb, m_txPsd, GetSpectrumType (), Seconds (txTimeSeconds), GetObject<SpectrumPhy> ());
+        txParams->duration = Seconds (txTimeSeconds);
+        txParams->txPhy = GetObject<SpectrumPhy> ();
+        txParams->psd = m_txPsd;
+        txParams->data = m_txPacket;
+
+        NS_LOG_LOGIC (this << " tx power: " << 10 * log10 (Integral (*(txParams->psd))) + 30 << " dBm");
+        m_channel->StartTx (txParams);
         Simulator::Schedule (Seconds (txTimeSeconds), &HalfDuplexIdealPhy::EndTx, this);
       }
       break;
@@ -295,7 +292,7 @@
 HalfDuplexIdealPhy::EndTx ()
 {
   NS_LOG_FUNCTION (this);
-  NS_LOG_LOGIC (this << "state: " << m_state);
+  NS_LOG_LOGIC (this << " state: " << m_state);
 
   NS_ASSERT (m_state == TX);
 
@@ -312,18 +309,21 @@
 
 
 void
-HalfDuplexIdealPhy::StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration)
+HalfDuplexIdealPhy::StartRx (Ptr<SpectrumSignalParameters> spectrumParams)
 {
-  NS_LOG_FUNCTION (this << pb << rxPsd << st << duration);
-  NS_LOG_LOGIC (this << "state: " << m_state);
+  NS_LOG_FUNCTION (this << spectrumParams);
+  NS_LOG_LOGIC (this << " state: " << m_state);
+  NS_LOG_LOGIC (this << " rx power: " << 10 * log10 (Integral (*(spectrumParams->psd))) + 30 << " dBm");
 
   // interference will happen regardless of the state of the receiver
-  m_interference.AddSignal (rxPsd, duration);
+  m_interference.AddSignal (spectrumParams->psd, spectrumParams->duration);
 
   // the device might start RX only if the signal is of a type understood by this device
-  // this corresponds in real device to preamble detection
-  if (st == GetSpectrumType ())
+  // this corresponds in real devices to preamble detection
+  Ptr<HalfDuplexIdealPhySignalParameters> rxParams = DynamicCast<HalfDuplexIdealPhySignalParameters> (spectrumParams);
+  if (rxParams != 0)
     {
+      // signal is of known type
       switch (m_state)
         {
         case TX:
@@ -341,12 +341,11 @@
 
         case IDLE:
           // preamble detection and synchronization is supposed to be always successful.
-          NS_LOG_LOGIC (this << " receiving " << pb->GetNPackets () << "  packet(s)" );
-          NS_ASSERT (pb->GetNPackets () == 1); // this PHY only supports a single packet per waveform
-          Ptr<Packet> p = pb->GetPackets ().front ();
+
+          Ptr<Packet> p = rxParams->data;
           m_phyRxStartTrace (p);
           m_rxPacket = p;
-          m_rxPsd = rxPsd;
+          m_rxPsd = rxParams->psd;
           ChangeState (RX);
           if (!m_phyMacRxStartCallback.IsNull ())
             {
@@ -357,16 +356,20 @@
             {
               NS_LOG_LOGIC (this << " m_phyMacRxStartCallback is NULL");
             }
-          m_interference.StartRx (p, rxPsd);
-          NS_LOG_LOGIC (this << " scheduling EndRx with delay " << duration);
-          m_endRxEventId = Simulator::Schedule (duration, &HalfDuplexIdealPhy::EndRx, this);
+          m_interference.StartRx (p, rxParams->psd);
+          NS_LOG_LOGIC (this << " scheduling EndRx with delay " << rxParams->duration);
+          m_endRxEventId = Simulator::Schedule (rxParams->duration, &HalfDuplexIdealPhy::EndRx, this);
 
           break;
 
         }
     }
+  else // rxParams == 0
+    {
+      NS_LOG_LOGIC (this << " signal of unknown type");
+    }
 
-  NS_LOG_LOGIC (this << "state: " << m_state);
+  NS_LOG_LOGIC (this << " state: " << m_state);
 }
 
 
@@ -388,7 +391,7 @@
 HalfDuplexIdealPhy::EndRx ()
 {
   NS_LOG_FUNCTION (this);
-  NS_LOG_LOGIC (this << "state: " << m_state);
+  NS_LOG_LOGIC (this << " state: " << m_state);
 
   NS_ASSERT (m_state == RX);
 
--- a/src/spectrum/model/half-duplex-ideal-phy.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/half-duplex-ideal-phy.h	Sun Nov 13 16:08:44 2011 +0100
@@ -29,16 +29,14 @@
 #include <ns3/net-device.h>
 #include <ns3/spectrum-phy.h>
 #include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-type.h>
 #include <ns3/spectrum-interference.h>
 #include <ns3/data-rate.h>
 #include <ns3/generic-phy.h>
 #include <ns3/event-id.h>
+#include <ns3/spectrum-signal-parameters.h>
 
 namespace ns3 {
 
-
-
 /**
  * \ingroup spectrum
  *
@@ -99,16 +97,7 @@
   Ptr<MobilityModel> GetMobility ();
   Ptr<NetDevice> GetDevice ();
   Ptr<const SpectrumModel> GetRxSpectrumModel () const;
-  void StartRx (Ptr<PacketBurst> p, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration);
-
-
-
-  /**
-   * Get the SpectrumType used by this PHY
-   *
-   * @return
-   */
-  SpectrumType GetSpectrumType ();
+  void StartRx (Ptr<SpectrumSignalParameters> params);
 
 
   /**
--- a/src/spectrum/model/multi-model-spectrum-channel.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/multi-model-spectrum-channel.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -99,7 +99,7 @@
   static TypeId tid = TypeId ("ns3::MultiModelSpectrumChannel")
     .SetParent<SpectrumChannel> ()
     .AddConstructor<MultiModelSpectrumChannel> ()
-    .AddAttribute ("MaxLossDb", 
+    .AddAttribute ("MaxLossDb",
                    "If a single-frequency PropagationLossModel is used, this value "
                    "represents the maximum loss in dB for which transmissions will be "
                    "passed to the receiving PHY. Signals for which the PropagationLossModel "
@@ -223,20 +223,20 @@
 
 
 void
-MultiModelSpectrumChannel::StartTx (Ptr<PacketBurst> p, Ptr <SpectrumValue> originalTxPowerSpectrum, SpectrumType st, Time duration, Ptr<SpectrumPhy> txPhy)
+MultiModelSpectrumChannel::StartTx (Ptr<SpectrumSignalParameters> txParams)
 {
-  NS_LOG_FUNCTION (this << p << *originalTxPowerSpectrum << duration << txPhy);
+  NS_LOG_FUNCTION (this << txParams);
 
-  NS_ASSERT (txPhy);
-  NS_ASSERT (originalTxPowerSpectrum);
+  NS_ASSERT (txParams->txPhy);
+  NS_ASSERT (txParams->psd);
 
 
-  Ptr<MobilityModel> txMobility = txPhy->GetMobility ();
-  SpectrumModelUid_t txSpectrumModelUid = originalTxPowerSpectrum->GetSpectrumModelUid ();
+  Ptr<MobilityModel> txMobility = txParams->txPhy->GetMobility ();
+  SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid ();
   NS_LOG_LOGIC (" txSpectrumModelUid " << txSpectrumModelUid);
 
   //
-  TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator = FindAndEventuallyAddTxSpectrumModel (originalTxPowerSpectrum->GetSpectrumModel ());
+  TxSpectrumModelInfoMap_t::const_iterator txInfoIteratorerator = FindAndEventuallyAddTxSpectrumModel (txParams->psd->GetSpectrumModel ());
   NS_ASSERT (txInfoIteratorerator != m_txSpectrumModelInfoMap.end ());
 
   NS_LOG_LOGIC ("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
@@ -251,20 +251,20 @@
       NS_LOG_LOGIC (" rxSpectrumModelUids " << rxSpectrumModelUid);
 
       Ptr <SpectrumValue> convertedTxPowerSpectrum;
-
       if (txSpectrumModelUid == rxSpectrumModelUid)
         {
-          NS_LOG_LOGIC ("no conversion needed");
-          convertedTxPowerSpectrum = originalTxPowerSpectrum;
+          NS_LOG_LOGIC ("no spectrum conversion needed");
+          convertedTxPowerSpectrum = txParams->psd;
         }
       else
         {
           NS_LOG_LOGIC (" converting txPowerSpectrum SpectrumModelUids" << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
           SpectrumConverterMap_t::const_iterator rxConverterIterator = txInfoIteratorerator->second.m_spectrumConverterMap.find (rxSpectrumModelUid);
           NS_ASSERT (rxConverterIterator != txInfoIteratorerator->second.m_spectrumConverterMap.end ());
-          convertedTxPowerSpectrum = rxConverterIterator->second.Convert (originalTxPowerSpectrum);
+          convertedTxPowerSpectrum = rxConverterIterator->second.Convert (txParams->psd);
         }
 
+
       for (std::list<Ptr<SpectrumPhy> >::const_iterator rxPhyIterator = rxInfoIterator->second.m_rxPhyList.begin ();
            rxPhyIterator != rxInfoIterator->second.m_rxPhyList.end ();
            ++rxPhyIterator)
@@ -272,10 +272,14 @@
           NS_ASSERT_MSG ((*rxPhyIterator)->GetRxSpectrumModel ()->GetUid () == rxSpectrumModelUid,
                          "MultiModelSpectrumChannel only supports devices that use a single RxSpectrumModel that does not change for the whole simulation");
 
-          if ((*rxPhyIterator) != txPhy)
+
+
+          if ((*rxPhyIterator) != txParams->txPhy)
             {
-              Ptr <SpectrumValue> rxPowerSpectrum = convertedTxPowerSpectrum->Copy ();
-              Time delay = MicroSeconds (0); 
+              NS_LOG_LOGIC (" copying signal parameters " << txParams);
+              Ptr<SpectrumSignalParameters> rxParams = txParams->Copy ();
+              rxParams->psd = Copy<SpectrumValue> (convertedTxPowerSpectrum);
+              Time delay = MicroSeconds (0);
 
               Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ();
 
@@ -284,19 +288,19 @@
                   if (m_propagationLoss)
                     {
                       double gainDb = m_propagationLoss->CalcRxPower (0, txMobility, receiverMobility);
-                      m_propagationLossTrace (txPhy, *rxPhyIterator, -gainDb);
+                      m_propagationLossTrace (txParams->txPhy, *rxPhyIterator, -gainDb);
                       if ( (-gainDb) > m_maxLossDb)
                         {
                           // beyond range
                           continue;
                         }
-                      double gainLinear = pow (10.0, gainDb/10.0);
-                      *rxPowerSpectrum = (*rxPowerSpectrum) * gainLinear;
+                      double gainLinear = pow (10.0, gainDb / 10.0);
+                      *(rxParams->psd) *= gainLinear;
                     }
 
                   if (m_spectrumPropagationLoss)
                     {
-                      rxPowerSpectrum = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity (rxPowerSpectrum, txMobility, receiverMobility);
+                      rxParams->psd = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity (rxParams->psd, txMobility, receiverMobility);
                     }
 
                   if (m_propagationDelay)
@@ -305,20 +309,19 @@
                     }
                 }
 
-              Ptr<PacketBurst> pktBurstCopy = p->Copy ();
               Ptr<NetDevice> netDev = (*rxPhyIterator)->GetDevice ();
               if (netDev)
                 {
                   // the receiver has a NetDevice, so we expect that it is attached to a Node
                   uint32_t dstNode =  netDev->GetNode ()->GetId ();
                   Simulator::ScheduleWithContext (dstNode, delay, &MultiModelSpectrumChannel::StartRx, this,
-                                                  pktBurstCopy, rxPowerSpectrum, st, duration, *rxPhyIterator);
+                                                  rxParams, *rxPhyIterator);
                 }
               else
                 {
                   // the receiver is not attached to a NetDevice, so we cannot assume that it is attached to a node
                   Simulator::Schedule (delay, &MultiModelSpectrumChannel::StartRx, this,
-                                       pktBurstCopy, rxPowerSpectrum, st, duration, *rxPhyIterator);
+                                       rxParams, *rxPhyIterator);
                 }
             }
         }
@@ -328,10 +331,10 @@
 }
 
 void
-MultiModelSpectrumChannel::StartRx (Ptr<PacketBurst> pb, Ptr <SpectrumValue> rxPsd, SpectrumType st, Time duration, Ptr<SpectrumPhy> receiver)
+MultiModelSpectrumChannel::StartRx (Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver)
 {
   NS_LOG_FUNCTION (this);
-  receiver->StartRx (pb, rxPsd, st, duration);
+  receiver->StartRx (params);
 }
 
 
--- a/src/spectrum/model/multi-model-spectrum-channel.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/multi-model-spectrum-channel.h	Sun Nov 13 16:08:44 2011 +0100
@@ -92,7 +92,7 @@
   virtual void AddSpectrumPropagationLossModel (Ptr<SpectrumPropagationLossModel> loss);
   virtual void SetPropagationDelayModel (Ptr<PropagationDelayModel> delay);
   virtual void AddRx (Ptr<SpectrumPhy> phy);
-  virtual void StartTx (Ptr<PacketBurst> p, Ptr <SpectrumValue> txPsd, SpectrumType st, Time duration, Ptr<SpectrumPhy> sender);
+  virtual void StartTx (Ptr<SpectrumSignalParameters> params);
 
 
   // inherited from Channel
@@ -135,12 +135,10 @@
   /**
    * used internally to reschedule transmission after the propagation delay
    *
-   * @param p
-   * @param rxPowerSpectrum
-   * @param duration
+   * @param params
    * @param receiver
    */
-  virtual void StartRx (Ptr<PacketBurst> p, Ptr <SpectrumValue> rxPowerSpectrum, SpectrumType st, Time duration, Ptr<SpectrumPhy> receiver);
+  virtual void StartRx (Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver);
 
 
 
--- a/src/spectrum/model/single-model-spectrum-channel.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/single-model-spectrum-channel.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -68,7 +68,7 @@
   static TypeId tid = TypeId ("ns3::SingleModelSpectrumChannel")
     .SetParent<SpectrumChannel> ()
     .AddConstructor<SingleModelSpectrumChannel> ()
-    .AddAttribute ("MaxLossDb", 
+    .AddAttribute ("MaxLossDb",
                    "If a single-frequency PropagationLossModel is used, this value "
                    "represents the maximum loss in dB for which transmissions will be "
                    "passed to the receiving PHY. Signals for which the PropagationLossModel "
@@ -103,59 +103,59 @@
 
 
 void
-SingleModelSpectrumChannel::StartTx (Ptr<PacketBurst> p, Ptr <SpectrumValue> txPsd, SpectrumType st, Time duration, Ptr<SpectrumPhy> txPhy)
+SingleModelSpectrumChannel::StartTx (Ptr<SpectrumSignalParameters> txParams)
 {
-  NS_LOG_FUNCTION (this << p << *txPsd << st << duration << txPhy);
-  NS_ASSERT_MSG (p, "NULL PacketBurst");
-  NS_ASSERT_MSG (txPsd, "NULL txPsd");
-  NS_ASSERT_MSG (txPhy, "NULL txPhy");
+  NS_LOG_FUNCTION (this << txParams->psd << txParams->duration << txParams->txPhy);
+  NS_ASSERT_MSG (txParams->psd, "NULL txPsd");
+  NS_ASSERT_MSG (txParams->txPhy, "NULL txPhy");
 
   // just a sanity check routine. We might want to remove it to save some computational load -- one "if" statement  ;-)
   if (m_spectrumModel == 0)
     {
       // first pak, record SpectrumModel
-      m_spectrumModel = txPsd->GetSpectrumModel ();
+      m_spectrumModel = txParams->psd->GetSpectrumModel ();
     }
   else
     {
       // all attached SpectrumPhy instances must use the same SpectrumModel
-      NS_ASSERT (*(txPsd->GetSpectrumModel ()) == *m_spectrumModel);
+      NS_ASSERT (*(txParams->psd->GetSpectrumModel ()) == *m_spectrumModel);
     }
 
 
 
 
-  Ptr<MobilityModel> senderMobility = txPhy->GetMobility ();
+  Ptr<MobilityModel> senderMobility = txParams->txPhy->GetMobility ();
 
   for (PhyList::const_iterator rxPhyIterator = m_phyList.begin ();
        rxPhyIterator != m_phyList.end ();
        ++rxPhyIterator)
     {
-      if ((*rxPhyIterator) != txPhy)
+      if ((*rxPhyIterator) != txParams->txPhy)
         {
-          Ptr <SpectrumValue> rxPsd = Copy<SpectrumValue> (txPsd);
           Time delay  = MicroSeconds (0);
 
           Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility ();
+          NS_LOG_LOGIC ("copying signal parameters " << txParams);
+          Ptr<SpectrumSignalParameters> rxParams = txParams->Copy ();
 
           if (senderMobility && receiverMobility)
             {
               if (m_propagationLoss)
                 {
                   double gainDb = m_propagationLoss->CalcRxPower (0, senderMobility, receiverMobility);
-                  m_propagationLossTrace (txPhy, *rxPhyIterator, -gainDb);
+                  m_propagationLossTrace (txParams->txPhy, *rxPhyIterator, -gainDb);
                   if ( (-gainDb) > m_maxLossDb)
                     {
                       // beyond range
                       continue;
                     }
-                  double gainLinear = pow (10.0, gainDb/10.0);
-                  *rxPsd = (*rxPsd) * gainLinear;
+                  double gainLinear = pow (10.0, gainDb / 10.0);
+                  *(rxParams->psd) *= gainLinear;
                 }
 
               if (m_spectrumPropagationLoss)
                 {
-                  rxPsd = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity (rxPsd, senderMobility, receiverMobility);
+                  rxParams->psd = m_spectrumPropagationLoss->CalcRxPowerSpectralDensity (rxParams->psd, senderMobility, receiverMobility);
                 }
 
               if (m_propagationDelay)
@@ -164,20 +164,19 @@
                 }
             }
 
-          Ptr<PacketBurst> pktBurstCopy = p->Copy ();
+
           Ptr<NetDevice> netDev = (*rxPhyIterator)->GetDevice ();
           if (netDev)
             {
               // the receiver has a NetDevice, so we expect that it is attached to a Node
               uint32_t dstNode =  netDev->GetNode ()->GetId ();
-              Simulator::ScheduleWithContext (dstNode, delay, &SingleModelSpectrumChannel::StartRx, this,
-                                              pktBurstCopy, rxPsd, st, duration, *rxPhyIterator);
+              Simulator::ScheduleWithContext (dstNode, delay, &SingleModelSpectrumChannel::StartRx, this, rxParams, *rxPhyIterator);
             }
           else
             {
               // the receiver is not attached to a NetDevice, so we cannot assume that it is attached to a node
               Simulator::Schedule (delay, &SingleModelSpectrumChannel::StartRx, this,
-                                   pktBurstCopy, rxPsd, st, duration, *rxPhyIterator);
+                                   rxParams, *rxPhyIterator);
             }
         }
     }
@@ -185,10 +184,10 @@
 }
 
 void
-SingleModelSpectrumChannel::StartRx (Ptr<PacketBurst> p, Ptr <SpectrumValue> rxPsd, SpectrumType st, Time duration, Ptr<SpectrumPhy> receiver)
+SingleModelSpectrumChannel::StartRx (Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver)
 {
-  NS_LOG_FUNCTION (this << p << *rxPsd << st << duration << receiver);
-  receiver->StartRx (p, rxPsd, st, duration);
+  NS_LOG_FUNCTION (this << params);
+  receiver->StartRx (params);
 }
 
 
--- a/src/spectrum/model/single-model-spectrum-channel.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/single-model-spectrum-channel.h	Sun Nov 13 16:08:44 2011 +0100
@@ -51,11 +51,7 @@
   virtual void AddSpectrumPropagationLossModel (Ptr<SpectrumPropagationLossModel> loss);
   virtual void SetPropagationDelayModel (Ptr<PropagationDelayModel> delay);
   virtual void AddRx (Ptr<SpectrumPhy> phy);
-  virtual void StartTx (Ptr<PacketBurst> p,
-                        Ptr <SpectrumValue> txPsd,
-                        SpectrumType st,
-                        Time duration,
-                        Ptr<SpectrumPhy> sender);
+  virtual void StartTx (Ptr<SpectrumSignalParameters> params);
 
 
   // inherited from Channel
@@ -73,13 +69,10 @@
   /**
    * used internally to reschedule transmission after the propagation delay
    *
-   * @param p
-   * @param rxPowerSpectrum
-   * @param st
-   * @param duration
+   * @param params
    * @param receiver
    */
-  virtual void StartRx (Ptr<PacketBurst> p, Ptr <SpectrumValue> rxPowerSpectrum, SpectrumType st, Time duration, Ptr<SpectrumPhy> receiver);
+  void StartRx (Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver);
 
   /**
    * list of SpectrumPhy instances attached to
--- a/src/spectrum/model/spectrum-analyzer.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-analyzer.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -136,14 +136,11 @@
 
 
 void
-SpectrumAnalyzer::StartRx (Ptr<PacketBurst> pb,
-                           Ptr <const SpectrumValue> rxPowerSpectralDensity,
-                           SpectrumType st,
-                           Time duration)
+SpectrumAnalyzer::StartRx (Ptr<SpectrumSignalParameters> params)
 {
-  NS_LOG_FUNCTION ( this << st << duration << *rxPowerSpectralDensity);
-  AddSignal (rxPowerSpectralDensity);
-  Simulator::Schedule (duration, &SpectrumAnalyzer::SubtractSignal, this, rxPowerSpectralDensity);
+  NS_LOG_FUNCTION ( this << params);
+  AddSignal (params->psd);
+  Simulator::Schedule (params->duration, &SpectrumAnalyzer::SubtractSignal, this, params->psd);
 }
 
 
--- a/src/spectrum/model/spectrum-analyzer.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-analyzer.h	Sun Nov 13 16:08:44 2011 +0100
@@ -58,7 +58,7 @@
   Ptr<MobilityModel> GetMobility ();
   Ptr<NetDevice> GetDevice ();
   Ptr<const SpectrumModel> GetRxSpectrumModel () const;
-  void StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPowerSpectralDensity, SpectrumType st, Time duration);
+  void StartRx (Ptr<SpectrumSignalParameters> params);
 
 
   /**
--- a/src/spectrum/model/spectrum-channel.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-channel.h	Sun Nov 13 16:08:44 2011 +0100
@@ -25,7 +25,7 @@
 #include <ns3/object.h>
 #include <ns3/nstime.h>
 #include <ns3/channel.h>
-#include <ns3/spectrum-type.h>
+#include <ns3/spectrum-signal-parameters.h>
 
 namespace ns3 {
 
@@ -53,7 +53,7 @@
   /**
    * set the single-frequency propagation loss model to be used
    * \warning only models that do not depend on the TX power should be used.
-   * 
+   *
    * \param loss a pointer to the propagation loss model to be used.
    */
   virtual void AddPropagationLossModel (Ptr<PropagationLossModel> loss) = 0;
@@ -72,21 +72,11 @@
 
 
   /**
-   * Used by attached PHY instances to transmit waveforms on the channel
+   * Used by attached PHY instances to transmit signals on the channel
    *
-   * @param p the PacketBurst associated with the waveform being transmitted
-   * @param txPsd the Power Spectral Density of the
-   * waveform, in linear units. The exact unit will depend on the
-   * type of transmission medium involved: W for radio communications, Pa for
-   * underwater acoustic communications. Other transmission media to be defined.
-   * @param st spectrum type
-   * @param duration duration of the packet transmission. It is
-   * assumed that the Power Spectral Density remains constant for the
-   * whole duration of the transmission. In other words, all waveform
-   * have a rect shape with respect to time.
-   * @param sender the SpectrumPhy instance making this function call
+   * @param params the parameters of the signals being transmitted
    */
-  virtual void StartTx (Ptr<PacketBurst> p, Ptr <SpectrumValue> txPsd, SpectrumType st, Time duration, Ptr<SpectrumPhy> sender) = 0;
+  virtual void StartTx (Ptr<SpectrumSignalParameters> params) = 0;
 
   /**
    * @brief add a SpectrumPhy to a channel, so it can receive packets
--- a/src/spectrum/model/spectrum-interference.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-interference.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -110,10 +110,15 @@
 SpectrumInterference::ConditionallyEvaluateChunk ()
 {
   NS_LOG_FUNCTION (this);
-  if (m_receiving && (Now () > m_lastChangeTime))
+  NS_LOG_LOGIC ("m_receiving: " << m_receiving );
+  NS_LOG_LOGIC ("m_lastChangeTime: " << m_lastChangeTime << " Now: " << Now ());
+  bool condition  = m_receiving && (Now () > m_lastChangeTime);
+  NS_LOG_LOGIC ("if condition: " << condition);
+  if (condition)
     {
       SpectrumValue sinr = (*m_rxSignal) / ((*m_allSignals) - (*m_rxSignal) + (*m_noise));
       Time duration = Now () - m_lastChangeTime;
+      NS_LOG_LOGIC ("calling m_errorModel->EvaluateChunk (sinr, duration)");
       m_errorModel->EvaluateChunk (sinr, duration);
     }
 }
--- a/src/spectrum/model/spectrum-phy.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-phy.h	Sun Nov 13 16:08:44 2011 +0100
@@ -24,7 +24,6 @@
 
 #include <ns3/object.h>
 #include <ns3/nstime.h>
-#include <ns3/spectrum-type.h>
 
 namespace ns3 {
 
@@ -34,6 +33,7 @@
 class SpectrumValue;
 class SpectrumModel;
 class NetDevice;
+struct SpectrumSignalParameters;
 
 /**
  * \ingroup spectrum
@@ -94,15 +94,11 @@
   virtual Ptr<const SpectrumModel> GetRxSpectrumModel () const = 0;
 
   /**
-   * Notify the SpectrumPhy instance of an incoming waveform
+   * Notify the SpectrumPhy instance of an incoming signal
    *
-   * @param p the PacketBurst associated with the incoming waveform
-   * @param rxPsd the Power Spectral Density of the incoming
-   * waveform. The units of the PSD are the same specified for SpectrumChannel::StartTx().
-   * @param st spectrum type
-   * @param duration the duration of the incoming waveform
+   * @param params the parameters of the signals being received
    */
-  virtual void StartRx (Ptr<PacketBurst> p, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration) = 0;
+  virtual void StartRx (Ptr<SpectrumSignalParameters> params) = 0;
 
 
 };
--- a/src/spectrum/model/spectrum-value.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-value.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -24,7 +24,7 @@
 #include <ns3/log.h>
 
 #ifdef __FreeBSD__
-#define log2(x) (log(x)/M_LN2)
+#define log2(x) (log (x) / M_LN2)
 #endif
 
 
@@ -387,6 +387,24 @@
   return s;
 }
 
+double
+Integral (const SpectrumValue& x)
+{
+  double i = 0;
+  Values::const_iterator vit = x.ConstValuesBegin ();
+  Bands::const_iterator bit = x.ConstBandsBegin ();
+  while (vit != x.ConstValuesEnd ())
+    {
+      NS_ASSERT (bit != x.ConstBandsEnd ());
+      i += (*vit) * (bit->fh - bit->fl);
+      ++vit;
+      ++bit;
+    }
+  NS_ASSERT (bit == x.ConstBandsEnd ());
+  return i;
+}
+
+
 
 Ptr<SpectrumValue>
 SpectrumValue::Copy () const
--- a/src/spectrum/model/spectrum-value.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/spectrum-value.h	Sun Nov 13 16:08:44 2011 +0100
@@ -482,6 +482,15 @@
 
   /**
    *
+   *
+   * @param arg the argument
+   *
+   * @return the value of the integral \f$\int_F g(f) df  \f$
+   */
+  friend double Integral (const SpectrumValue&  arg);
+
+  /**
+   *
    * @return a Ptr to a copy of this instance
    */
   Ptr<SpectrumValue> Copy () const;
--- a/src/spectrum/model/waveform-generator.cc	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/waveform-generator.cc	Sun Nov 13 16:08:44 2011 +0100
@@ -134,17 +134,9 @@
 
 
 void
-WaveformGenerator::StartRx (Ptr<PacketBurst> pb, Ptr <const SpectrumValue> rxPowerSpectrum, SpectrumType st, Time duration)
+WaveformGenerator::StartRx (Ptr<SpectrumSignalParameters> params)
 {
-  NS_LOG_FUNCTION (pb << rxPowerSpectrum << duration);
-}
-
-
-SpectrumType
-WaveformGenerator::GetSpectrumType ()
-{
-  static SpectrumType st = SpectrumTypeFactory::Create ("GenericWaveform");
-  return st;
+  NS_LOG_FUNCTION (this << params);
 }
 
 void
@@ -188,12 +180,14 @@
 {
   NS_LOG_FUNCTION (this);
 
-  Ptr<PacketBurst> pb = Create<PacketBurst> ();
-  Time duration = Time (m_period * m_dutyCycle);
+  Ptr<SpectrumSignalParameters> txParams = Create<SpectrumSignalParameters> ();
+  txParams->duration = Time (m_period * m_dutyCycle);
+  txParams->psd = m_txPowerSpectralDensity;
+  txParams->txPhy = GetObject<SpectrumPhy> ();
 
   NS_LOG_LOGIC ("generating waveform : " << *m_txPowerSpectralDensity);
   m_phyTxStartTrace (0);
-  m_channel->StartTx (pb, m_txPowerSpectralDensity, GetSpectrumType (), duration, GetObject<SpectrumPhy> ());
+  m_channel->StartTx (txParams);
 
   if (m_active)
     {
--- a/src/spectrum/model/waveform-generator.h	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/model/waveform-generator.h	Sun Nov 13 16:08:44 2011 +0100
@@ -29,7 +29,6 @@
 #include <ns3/net-device.h>
 #include <ns3/spectrum-phy.h>
 #include <ns3/spectrum-channel.h>
-#include <ns3/spectrum-type.h>
 #include <ns3/trace-source-accessor.h>
 
 namespace ns3 {
@@ -61,7 +60,7 @@
   Ptr<MobilityModel> GetMobility ();
   Ptr<NetDevice> GetDevice ();
   Ptr<const SpectrumModel> GetRxSpectrumModel () const;
-  void StartRx (Ptr<PacketBurst> p, Ptr <const SpectrumValue> rxPsd, SpectrumType st, Time duration);
+  void StartRx (Ptr<SpectrumSignalParameters> params);
 
 
   /**
@@ -71,16 +70,6 @@
    */
   void SetTxPowerSpectralDensity (Ptr<SpectrumValue> txs);
 
-
-  /**
-   * Get the SpectrumType used by this PHY
-   *
-   * @return
-   */
-  SpectrumType GetSpectrumType ();
-
-
-
   /**
    * Set the period according to which the WaveformGenerator switches
    * on and off
--- a/src/spectrum/wscript	Sat Nov 12 12:33:47 2011 +0100
+++ b/src/spectrum/wscript	Sun Nov 13 16:08:44 2011 +0100
@@ -7,7 +7,7 @@
         'model/spectrum-model.cc',
         'model/spectrum-value.cc',
         'model/spectrum-converter.cc',
-        'model/spectrum-type.cc',
+        'model/spectrum-signal-parameters.cc',
         'model/spectrum-propagation-loss-model.cc',
         'model/friis-spectrum-propagation-loss.cc',
         'model/spectrum-phy.cc',
@@ -24,6 +24,7 @@
         'model/aloha-noack-mac-header.cc',
         'model/aloha-noack-net-device.cc',
         'model/half-duplex-ideal-phy.cc',
+        'model/half-duplex-ideal-phy-signal-parameters.cc',
         'model/non-communicating-net-device.cc',
         'model/microwave-oven-spectrum-value-helper.cc',
         'helper/spectrum-helper.cc',
@@ -45,7 +46,7 @@
         'model/spectrum-model.h',
         'model/spectrum-value.h',
         'model/spectrum-converter.h',
-        'model/spectrum-type.h',
+        'model/spectrum-signal-parameters.h',
         'model/spectrum-propagation-loss-model.h',
         'model/friis-spectrum-propagation-loss.h',
         'model/spectrum-phy.h',
@@ -62,6 +63,7 @@
         'model/aloha-noack-mac-header.h',
         'model/aloha-noack-net-device.h',
         'model/half-duplex-ideal-phy.h',
+        'model/half-duplex-ideal-phy-signal-parameters.h',
         'model/non-communicating-net-device.h',
         'model/microwave-oven-spectrum-value-helper.h',
         'helper/spectrum-helper.h',