diff --git a/src/lr-wpan/model/lr-wpan-interference-helper.cc b/src/lr-wpan/model/lr-wpan-interference-helper.cc new file mode 100644 index 000000000..67cb6da00 --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-interference-helper.cc @@ -0,0 +1,96 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Fraunhofer FKIE + * + * 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: + * Sascha Alexander Jopen + */ +#include "lr-wpan-interference-helper.h" +#include +#include + +namespace ns3 { + +LrWpanInterferenceHelper::LrWpanInterferenceHelper (Ptr spectrumModel) : + m_spectrumModel (spectrumModel), m_dirty(true) +{ +} + +LrWpanInterferenceHelper::~LrWpanInterferenceHelper () +{ + m_spectrumModel = 0; + m_signal = 0; + m_signals.clear (); +} + +bool +LrWpanInterferenceHelper::AddSignal (Ptr signal) +{ + bool result = false; + + if (signal->GetSpectrumModel () == m_spectrumModel) + { + result = m_signals.insert (signal).second; + if (result && !m_dirty) + { + *m_signal += *signal; + } + } + return result; +} + +bool +LrWpanInterferenceHelper::RemoveSignal (Ptr signal) +{ + bool result = false; + + if (signal->GetSpectrumModel () == m_spectrumModel) + { + result = (m_signals.erase (signal) == 1); + if (result) + { + m_dirty = true; + } + } + return result; +} + +void +LrWpanInterferenceHelper::ClearSignals () +{ + m_signals.clear (); + m_dirty = true; +} + +Ptr +LrWpanInterferenceHelper::GetSignalPsd () const +{ + if (m_dirty) + { + // Sum up the current interference PSD. + std::set >::const_iterator it; + m_signal = Create (m_spectrumModel); + for (it = m_signals.begin (); it != m_signals.end (); ++it) + { + *m_signal += *(*it); + } + m_dirty = false; + } + + return m_signal->Copy (); +} + +} diff --git a/src/lr-wpan/model/lr-wpan-interference-helper.h b/src/lr-wpan/model/lr-wpan-interference-helper.h new file mode 100644 index 000000000..3ceff33a4 --- /dev/null +++ b/src/lr-wpan/model/lr-wpan-interference-helper.h @@ -0,0 +1,53 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Fraunhofer FKIE + * + * 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: + * Sascha Alexander Jopen + */ +#ifndef LR_WPAN_LR_WPAN_INTERFERENCE_HELPER_H +#define LR_WPAN_LR_WPAN_INTERFERENCE_HELPER_H + +#include +#include +#include + +namespace ns3 { + +class SpectrumValue; +class SpectrumModel; + +class LrWpanInterferenceHelper : public SimpleRefCount +{ +public: + LrWpanInterferenceHelper (Ptr spectrumModel); + ~LrWpanInterferenceHelper (); + + bool AddSignal (Ptr signal); + bool RemoveSignal (Ptr signal); + void ClearSignals (); + Ptr GetSignalPsd () const; + Ptr GetSpectrumModel () const; +private: + Ptr m_spectrumModel; + std::set > m_signals; + mutable Ptr m_signal; + mutable bool m_dirty; +}; + +} + +#endif /* LR_WPAN_LR_WPAN_INTERFERENCE_HELPER_H */ diff --git a/src/lr-wpan/model/lr-wpan-phy.cc b/src/lr-wpan/model/lr-wpan-phy.cc index a3ce8e279..8601d3fdc 100644 --- a/src/lr-wpan/model/lr-wpan-phy.cc +++ b/src/lr-wpan/model/lr-wpan-phy.cc @@ -126,10 +126,12 @@ LrWpanPhy::LrWpanPhy () m_txPsd = psdHelper.CreateTxPowerSpectralDensity (m_phyPIBAttributes.phyTransmitPower, m_phyPIBAttributes.phyCurrentChannel); m_noise = psdHelper.CreateNoisePowerSpectralDensity (m_phyPIBAttributes.phyCurrentChannel); - m_rxPsd = 0; - Ptr none = 0; - m_currentRxPacket = std::make_pair (none, true); - m_currentTxPacket = std::make_pair (none, true); + m_signal = Create (m_noise->GetSpectrumModel ()); + m_rxLastUpdate = Seconds (0); + Ptr none_packet = 0; + Ptr none_params = 0; + m_currentRxPacket = std::make_pair (none_params, true); + m_currentTxPacket = std::make_pair (none_packet, true); m_errorModel = 0; ChangeTrxState (IEEE_802_15_4_PHY_TRX_OFF); @@ -153,8 +155,8 @@ LrWpanPhy::DoDispose () m_device = 0; m_channel = 0; m_txPsd = 0; - m_rxPsd = 0; m_noise = 0; + m_signal = 0; m_errorModel = 0; m_pdDataIndicationCallback = MakeNullCallback< void, uint32_t, Ptr, uint8_t > (); m_pdDataConfirmCallback = MakeNullCallback< void, LrWpanPhyEnumeration > (); @@ -243,8 +245,6 @@ LrWpanPhy::SetAntenna (Ptr a) m_antenna = a; } - - void LrWpanPhy::StartRx (Ptr spectrumRxParams) { @@ -253,118 +253,147 @@ LrWpanPhy::StartRx (Ptr spectrumRxParams) Ptr lrWpanRxParams = DynamicCast (spectrumRxParams); + NS_ASSERT (lrWpanRxParams != 0); + Ptr p = (lrWpanRxParams->packetBurst->GetPackets ()).front (); + NS_ASSERT (p != 0); + + // Add any incoming packet to the current interference. + m_signal->AddSignal (lrWpanRxParams->psd); // Prevent PHY from receiving another packet while switching the transceiver state. if (m_trxState == IEEE_802_15_4_PHY_RX_ON && !m_setTRXState.IsRunning ()) { - if (lrWpanRxParams != 0) + // The specification doesn't seem to refer to BUSY_RX, but vendor + // data sheets suggest that this is a substate of the RX_ON state + // that is entered after preamble detection when the digital receiver + // is enabled. Here, for now, we use BUSY_RX to mark the period between + // StartRx() and EndRx() states. + + // We are going to BUSY_RX state when receiving the first bit of an SHR, + // as opposed to real receivers, which should go to this state only after + // successfully receiving the SHR. + + // TODO: Check that the SINR is high enough for synchronizing to the packet. + // If synchronizing to the packet is possible, change to BUSY_RX state, + // otherwise drop the packet and stay in RX state. The actual synchronization + // is not modeled. + Ptr interferenceAndNoise = m_signal->GetSignalPsd (); + *interferenceAndNoise -= *lrWpanRxParams->psd; + *interferenceAndNoise += *m_noise; + double sinr = LrWpanSpectrumValueHelper::TotalAvgPower (lrWpanRxParams->psd) / LrWpanSpectrumValueHelper::TotalAvgPower (interferenceAndNoise); + if (sinr > 1) { - // The specification doesn't seem to refer to BUSY_RX, but vendor - // data sheets suggest that this is a substate of the RX_ON state - // that is entered after preamble detection when the digital receiver - // is enabled. Here, for now, we use BUSY_RX to mark the period between - // StartRx() and EndRx() states. - Ptr p = (lrWpanRxParams->packetBurst->GetPackets ()).front (); - NS_ASSERT(p != 0); - m_rxPsd = lrWpanRxParams->psd; - m_rxTotalPower = psdHelper.TotalAvgPower (m_rxPsd); + ChangeTrxState (IEEE_802_15_4_PHY_BUSY_RX); + m_currentRxPacket = std::make_pair (lrWpanRxParams, false); + m_phyRxBeginTrace (p); - if (m_rxTotalPower >= m_rxSensitivity) - { - ChangeTrxState (IEEE_802_15_4_PHY_BUSY_RX); - Time duration = lrWpanRxParams->duration; - m_currentRxPacket = std::make_pair (p, false); - - Simulator::Schedule (duration, &LrWpanPhy::EndRx, this); - m_phyRxBeginTrace (p); - } - else - { - // We are below our receiver sensitivity, the packet cannot be received. - // TODO: Add the power somehow to the interference. - m_phyRxDropTrace (p); - } + m_rxLastUpdate = Simulator::Now (); + } + else + { + m_phyRxDropTrace (p); } - NS_LOG_LOGIC (this << " state: " << m_trxState << " m_rxTotalPower: " << m_rxTotalPower); } else if (m_trxState == IEEE_802_15_4_PHY_BUSY_RX) { - // TODO: Drop the second packet and add the signal power to the interference of - // the currently received packet. Consider the received signal power - // during CCA/ED, too. + // Drop the new packet. NS_LOG_DEBUG (this << " packet collision"); - Ptr p = (lrWpanRxParams->packetBurst->GetPackets ()).front (); m_phyRxDropTrace (p); } else { + // Simply drop the packet. NS_LOG_DEBUG (this << " transceiver not in RX state"); - Ptr p = (lrWpanRxParams->packetBurst->GetPackets ()).front (); m_phyRxDropTrace (p); } + + // Always call EndRx to update the interference. + // TODO: Do we need to keep track of these events to unschedule them when disposing off the PHY? + Simulator::Schedule (lrWpanRxParams->duration, &LrWpanPhy::EndRx, this, lrWpanRxParams); + ++m_rxTotalNum; } -void LrWpanPhy::EndRx () +void +LrWpanPhy::EndRx (Ptr params) { NS_LOG_FUNCTION (this); + NS_ASSERT (params != 0); + + // Calculate whether packet was lost. LrWpanSpectrumValueHelper psdHelper; - // Calculate whether packet was lost - if (m_currentRxPacket.second == true) - { - if (m_currentRxPacket.first != 0) - { - NS_LOG_DEBUG ("Reception was previously terminated; dropping packet"); - m_phyRxDropTrace (m_currentRxPacket.first); - m_currentRxPacket.first = 0; - } - else - { - // TODO: This should never happen, but it does! - NS_LOG_UNCOND (this << " Finishing receive of NULL packet!"); - } - } - else + Ptr currentRxParams = m_currentRxPacket.first; + Ptr packet = params->packetBurst->GetPackets ().front (); + + // We are currently receiving a packet. + if (m_trxState == IEEE_802_15_4_PHY_BUSY_RX) { + NS_ASSERT (currentRxParams && !m_currentRxPacket.second); + + Ptr currentPacket = currentRxParams->packetBurst->GetPackets ().front (); if (m_errorModel != 0) { - double sinr = psdHelper.TotalAvgPower (m_rxPsd) / psdHelper.TotalAvgPower (m_noise); - Ptr p = m_currentRxPacket.first; - NS_ASSERT (p != 0); - p->AddPacketTag (LrWpanLqiTag (sinr)); + // How many bits did we receive since the last calculation? + double t = (Simulator::Now () - m_rxLastUpdate).ToDouble (Time::MS); + uint32_t chunkSize = ceil (t * (GetDataOrSymbolRate (true) / 1000)); + std::cout << "current signal : " << 10 * log10 (LrWpanSpectrumValueHelper::TotalAvgPower (currentRxParams->psd)) << std::endl; + std::cout << "all signals : " << 10 * log10 (LrWpanSpectrumValueHelper::TotalAvgPower (m_signal->GetSignalPsd ())) << std::endl; + std::cout << "noise : " << 10 * log10 (LrWpanSpectrumValueHelper::TotalAvgPower (m_noise)) << std::endl; + Ptr interferenceAndNoise = m_signal->GetSignalPsd (); + *interferenceAndNoise -= *currentRxParams->psd; + *interferenceAndNoise += *m_noise; + std::cout << "interference and noise : " << 10 * log10 (LrWpanSpectrumValueHelper::TotalAvgPower (interferenceAndNoise)) << std::endl; + double sinr = LrWpanSpectrumValueHelper::TotalAvgPower (currentRxParams->psd) / LrWpanSpectrumValueHelper::TotalAvgPower (interferenceAndNoise); + std::cout << "sinr : " << sinr << std::endl; + double per = 1.0 - m_errorModel->GetChunkSuccessRate (sinr, chunkSize); + std::cout << "per : " << per << std::endl; - // Simplified calculation; the chunk is the whole packet - double per = 1.0 - m_errorModel->GetChunkSuccessRate (sinr, p->GetSize () * 8); - if (m_random.GetValue () > per) + // TODO: What is the LQI for our model. The SINR is wrong in any case! + LrWpanLqiTag tag(sinr); + currentPacket->ReplacePacketTag (tag); + + if (m_random.GetValue () < per) { - NS_LOG_DEBUG ("Reception success for packet: per " << per << " sinr " << sinr); - m_phyRxEndTrace (p, sinr); - if (!m_pdDataIndicationCallback.IsNull ()) - { - m_pdDataIndicationCallback (p->GetSize (), p, (uint8_t)sinr); - } - } - else - { - /* Failure */ - NS_LOG_DEBUG ("Reception failure for packet per" << per << " sinr " << sinr); - m_phyRxEndTrace (p, sinr); - m_phyRxDropTrace (p); + // The packet was destroyed, drop the packet after reception. + m_currentRxPacket.second = true; } } else { + LrWpanLqiTag tag; + currentPacket->ReplacePacketTag (tag); NS_LOG_WARN ("Missing ErrorModel"); - Ptr p = m_currentRxPacket.first; - p->AddPacketTag (LrWpanLqiTag ()); - m_phyRxEndTrace (p, 0); + } + } + + // Update the interference. + m_signal->RemoveSignal (params->psd); + m_rxLastUpdate = Simulator::Now (); + --m_rxTotalNum; + + // If this is the end of the currently received packet, check if reception was successfull. + if (currentRxParams == params) + { + Ptr currentPacket = currentRxParams->packetBurst->GetPackets ().front (); + NS_ASSERT (currentPacket != 0); + + LrWpanLqiTag tag; + currentPacket->PeekPacketTag (tag); + m_phyRxEndTrace (currentPacket, tag.Get ()); + + if (!m_currentRxPacket.second) + { + // The packet was successfully received, push it up the stack. if (!m_pdDataIndicationCallback.IsNull ()) { - m_pdDataIndicationCallback (p->GetSize (), p, 0); + m_pdDataIndicationCallback (currentPacket->GetSize (), currentPacket, tag.Get ()); } } - - m_rxTotalPower = 0; - Ptr none = 0; + else + { + // The packet was destroyed, drop it. + m_phyRxDropTrace (currentPacket); + } + Ptr none = 0; m_currentRxPacket = std::make_pair (none, true); // We may be waiting to apply a pending state change. @@ -385,10 +414,7 @@ void LrWpanPhy::EndRx () } else { - if (m_trxState != IEEE_802_15_4_PHY_TRX_OFF) - { - ChangeTrxState (IEEE_802_15_4_PHY_RX_ON); - } + ChangeTrxState (IEEE_802_15_4_PHY_RX_ON); } } } @@ -499,7 +525,7 @@ LrWpanPhy::PlmeEdRequest (void) NS_LOG_FUNCTION (this); if (m_trxState == IEEE_802_15_4_PHY_RX_ON) { - m_rxEdPeakPower = m_rxTotalPower; + m_rxEdPeakPower = LrWpanSpectrumValueHelper::TotalAvgPower (m_signal->GetSignalPsd()); Time edTime = Seconds (8.0 / GetDataOrSymbolRate (false)); m_edRequest = Simulator::Schedule (edTime, &LrWpanPhy::EndEd, this); } @@ -1080,11 +1106,10 @@ LrWpanPhy::CalculateTxTime (Ptr packet) { NS_LOG_FUNCTION (this << packet); - Time txTime = Seconds (0); bool isData = true; + Time txTime = GetPpduHeaderTxTime (); - txTime = Seconds (GetPpduHeaderTxTime () - + packet->GetSize () * 8.0 / GetDataOrSymbolRate (isData)); + txTime += Time::FromDouble (packet->GetSize () * 8.0 / GetDataOrSymbolRate (isData) * 1000, Time::MS); return txTime; } @@ -1110,7 +1135,7 @@ LrWpanPhy::GetDataOrSymbolRate (bool isData) return (rate * 1000.0); } -double +Time LrWpanPhy::GetPpduHeaderTxTime (void) { NS_LOG_FUNCTION (this); @@ -1124,7 +1149,7 @@ LrWpanPhy::GetPpduHeaderTxTime (void) + ppduHeaderSymbolNumbers[m_phyOption].shrSfd + ppduHeaderSymbolNumbers[m_phyOption].phr; - return totalPpduHdrSymbols / GetDataOrSymbolRate (isData); + return Time::FromDouble (totalPpduHdrSymbols / GetDataOrSymbolRate (isData) * 1000, Time::MS); } // IEEE802.15.4-2006 Table 2 in section 6.1.2 diff --git a/src/lr-wpan/model/lr-wpan-phy.h b/src/lr-wpan/model/lr-wpan-phy.h index b9fb98627..27ce3f37a 100644 --- a/src/lr-wpan/model/lr-wpan-phy.h +++ b/src/lr-wpan/model/lr-wpan-phy.h @@ -22,6 +22,8 @@ #ifndef LR_WPAN_PHY_H #define LR_WPAN_PHY_H +#include "lr-wpan-interference-helper.h" + #include #include #include @@ -378,19 +380,18 @@ private: void SetMyPhyOption (void); LrWpanPhyOption GetMyPhyOption (void); void EndTx (); - void EndRx (); + void EndRx (Ptr params); void EndEd (); void EndCca (); void EndSetTRXState (); Time CalculateTxTime (Ptr packet); - double GetPpduHeaderTxTime (void); + Time GetPpduHeaderTxTime (void); bool ChannelSupported (uint8_t); Ptr m_mobility; Ptr m_device; Ptr m_channel; Ptr m_antenna; Ptr m_txPsd; - Ptr m_rxPsd; Ptr m_noise; Ptr m_errorModel; LrWpanPhyPibAttributes m_phyPIBAttributes; @@ -461,7 +462,9 @@ private: double m_rxTotalPower; uint32_t m_rxTotalNum; double m_rxSensitivity; - PacketAndStatus m_currentRxPacket; + Ptr m_signal; + Time m_rxLastUpdate; + std::pair, bool> m_currentRxPacket; PacketAndStatus m_currentTxPacket; EventId m_ccaRequest; diff --git a/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc b/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc index 7428935f1..dea753c20 100644 --- a/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc +++ b/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc @@ -121,7 +121,7 @@ LrWpanSpectrumValueHelper::CreateNoisePowerSpectralDensity (uint32_t channel) double LrWpanSpectrumValueHelper::TotalAvgPower (Ptr psd) { - NS_LOG_FUNCTION (this << psd); + NS_LOG_FUNCTION (psd); double totalAvgPower = 0.0; // numerically integrate to get area under psd using diff --git a/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h b/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h index dc7b5c607..647439e87 100644 --- a/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h +++ b/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h @@ -57,7 +57,7 @@ public: * \param power spectral density * \return total power (using composite trap. rule to numerally integrate */ - double TotalAvgPower (Ptr psd); + static double TotalAvgPower (Ptr psd); private: double m_noiseFactor; diff --git a/src/lr-wpan/test/lr-wpan-error-model-test.cc b/src/lr-wpan/test/lr-wpan-error-model-test.cc index 16e440b73..120dc9cdc 100644 --- a/src/lr-wpan/test/lr-wpan-error-model-test.cc +++ b/src/lr-wpan/test/lr-wpan-error-model-test.cc @@ -125,9 +125,9 @@ LrWpanErrorDistanceTestCase::DoRun (void) Simulator::Run (); - // Test that we received 978 packets out of 1000, at distance of 100 m + // Test that we received 173 packets out of 1000, at distance of 100 m // with default power of 0 - NS_TEST_ASSERT_MSG_EQ (GetReceived (), 978, "Model fails"); + NS_TEST_ASSERT_MSG_EQ (GetReceived (), 173, "Model fails"); Simulator::Destroy (); } diff --git a/src/lr-wpan/wscript b/src/lr-wpan/wscript index 7311f67e6..6345c6ab8 100644 --- a/src/lr-wpan/wscript +++ b/src/lr-wpan/wscript @@ -4,6 +4,7 @@ def build(bld): obj = bld.create_ns3_module('lr-wpan', ['core', 'network', 'mobility', 'spectrum', 'propagation']) obj.source = [ 'model/lr-wpan-error-model.cc', + 'model/lr-wpan-interference-helper.cc', 'model/lr-wpan-phy.cc', 'model/lr-wpan-mac.cc', 'model/lr-wpan-mac-header.cc', @@ -28,6 +29,7 @@ def build(bld): headers.module = 'lr-wpan' headers.source = [ 'model/lr-wpan-error-model.h', + 'model/lr-wpan-interference-helper.h', 'model/lr-wpan-phy.h', 'model/lr-wpan-mac.h', 'model/lr-wpan-mac-header.h',