From 48761b77a9515d9b4bdaa9765fbb3a9becf122f4 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 22 Oct 2025 14:03:51 +0200 Subject: [PATCH] EndDeviceLoraPhy: Simulate channel bandwidth mismatch - `LoraPhy`: - Change API of `StartReceive()` to also take the channel bandwidth of the incoming packet as parameter - `LoraChannel`: - Keep info of the bandwidth of a transmission and pass it on to PHYs via the new bandwidth parameter of the `StartReceive()` function - `EndDeviceLoraPhy`: - Add getter and setter for channel bandwidth to `EndDeviceLoraPhy` and initialize `EndDeviceLoraPhy` with a default bandwidth of 125 kHz. - Add `"LostPacketBecauseWrongBandwidth"` trace source to `EndDeviceLoraPhy` - `SimpleEndDeviceLoraPhy`: - Simulate loss of packet when it was received on the same frequency but on a different channel bandwidth than tuned in and call the new trace source on loss - Reduce code duplication by factoring out the retrieval of the node ID from the trac handlers. --- model/end-device-lora-phy.cc | 25 +++++++++++++++ model/end-device-lora-phy.h | 39 +++++++++++++++++++++- model/gateway-lora-phy.h | 3 +- model/lora-channel.cc | 4 ++- model/lora-channel.h | 1 + model/lora-phy.h | 4 ++- model/simple-end-device-lora-phy.cc | 45 +++++++++++--------------- model/simple-end-device-lora-phy.h | 3 +- model/simple-gateway-lora-phy.cc | 3 +- model/simple-gateway-lora-phy.h | 3 +- test/lorawan-test-suite.cc | 50 +++++++++++++++++++++++++++++ 11 files changed, 146 insertions(+), 34 deletions(-) diff --git a/model/end-device-lora-phy.cc b/model/end-device-lora-phy.cc index 32b95a4138..2ddebe7b86 100644 --- a/model/end-device-lora-phy.cc +++ b/model/end-device-lora-phy.cc @@ -45,6 +45,12 @@ EndDeviceLoraPhy::GetTypeId() "the end device was listening on a different frequency", MakeTraceSourceAccessor(&EndDeviceLoraPhy::m_wrongFrequency), "ns3::Packet::TracedCallback") + .AddTraceSource("LostPacketBecauseWrongBandwidth", + "Trace source indicating a packet could not " + "be correctly decoded because the end device was " + "listening on a different frequency", + MakeTraceSourceAccessor(&EndDeviceLoraPhy::m_wrongBandwidth), + "ns3::Packet::TracedCallback") .AddTraceSource("LostPacketBecauseWrongSpreadingFactor", "Trace source indicating a packet " "could not be correctly decoded because" @@ -63,6 +69,7 @@ EndDeviceLoraPhy::GetTypeId() EndDeviceLoraPhy::EndDeviceLoraPhy() : m_state(State::SLEEP), m_frequencyHz(868100000), + m_bandwidthHz(125000), m_sf(7) { } @@ -100,12 +107,30 @@ EndDeviceLoraPhy::IsOnFrequency(uint32_t frequencyHz) return m_frequencyHz == frequencyHz; } +bool +EndDeviceLoraPhy::IsOnBandwidth(uint32_t bandwidthHz) const +{ + return m_bandwidthHz == bandwidthHz; +} + void EndDeviceLoraPhy::SetFrequency(uint32_t frequencyHz) { m_frequencyHz = frequencyHz; } +void +EndDeviceLoraPhy::SetBandwidth(uint32_t bandwidthHz) +{ + m_bandwidthHz = bandwidthHz; +} + +uint32_t +EndDeviceLoraPhy::GetBandwidth() const +{ + return m_bandwidthHz; +} + void EndDeviceLoraPhy::TxFinished(Ptr packet) { diff --git a/model/end-device-lora-phy.h b/model/end-device-lora-phy.h index 9f24c680ad..b08b76f700 100644 --- a/model/end-device-lora-phy.h +++ b/model/end-device-lora-phy.h @@ -147,7 +147,8 @@ class EndDeviceLoraPhy : public LoraPhy double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) override = 0; + uint32_t frequencyHz, + uint32_t bandwidthHz) override = 0; // Implementation of LoraPhy's pure virtual functions void EndReceive(Ptr packet, Ptr event) override = 0; @@ -161,6 +162,15 @@ class EndDeviceLoraPhy : public LoraPhy // Implementation of LoraPhy's pure virtual functions bool IsOnFrequency(uint32_t frequencyHz) override; + /** + * Checks whether the PHY is tuned in the given bandwidth> + * + * @param bandwidthHz The bandwidth to check + * @retval true If this PHY is able to lock on the given bandwidth + * @retval false If the PHY is **NOT** able to lock on the given bandwidth + */ + bool IsOnBandwidth(uint32_t bandwidthHz) const; + // Implementation of LoraPhy's pure virtual functions bool IsTransmitting() override; @@ -174,6 +184,24 @@ class EndDeviceLoraPhy : public LoraPhy */ void SetFrequency(uint32_t frequencyHz); + /** + * Set the channel bandwidth this end device will listen on. + * + * Should a packet be transmitted using a different bandwidth than this + * EndDeviceLoraPhy is listening on, the packet will be discarded even if + * the frequency matches. + * + * @param bandwidthHz The bandwidth [Hz] to listen to. + */ + void SetBandwidth(uint32_t bandwidthHz); + + /** + * Get the channel bandwidth this end device will listen on. + * + * @return The bandwidth [Hz] the PHY is listening to. + */ + uint32_t GetBandwidth() const; + /** * Set the Spreading Factor this end device will listen for. * @@ -259,6 +287,13 @@ class EndDeviceLoraPhy : public LoraPhy */ TracedCallback, uint32_t> m_wrongFrequency; + /** + * Trace source for when a packet is lost because it was transmitted on the + * same frequency different from the one this EndDeviceLoraPhy was configured to + * listen on. + */ + TracedCallback, uint32_t> m_wrongBandwidth; + TracedValue m_state; //!< The state this PHY is currently in. // static const double sensitivity[6]; //!< The sensitivity vector of this device to different @@ -266,6 +301,8 @@ class EndDeviceLoraPhy : public LoraPhy uint32_t m_frequencyHz; //!< The frequency [Hz] this device is listening on + uint32_t m_bandwidthHz; //!< The channel bandwidth [Hz] this device is listening on + uint8_t m_sf; //!< The Spreading Factor this device is listening for /** diff --git a/model/gateway-lora-phy.h b/model/gateway-lora-phy.h index e6c5c66535..76bdc6e667 100644 --- a/model/gateway-lora-phy.h +++ b/model/gateway-lora-phy.h @@ -55,7 +55,8 @@ class GatewayLoraPhy : public LoraPhy double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) override = 0; + uint32_t frequencyHz, + uint32_t bandwidthHz) override = 0; void EndReceive(Ptr packet, Ptr event) override = 0; diff --git a/model/lora-channel.cc b/model/lora-channel.cc index 6ee7af802e..83d66a6a31 100644 --- a/model/lora-channel.cc +++ b/model/lora-channel.cc @@ -160,6 +160,7 @@ LoraChannel::Send(Ptr sender, parameters.sf = txParams.sf; parameters.duration = duration; parameters.frequencyHz = frequencyHz; + parameters.bandwidthHz = txParams.bandwidthHz; // Schedule the receive event NS_LOG_INFO("Scheduling reception of the packet"); @@ -187,7 +188,8 @@ LoraChannel::Receive(uint32_t i, Ptr packet, LoraChannelParameters param parameters.rxPowerDbm, parameters.sf, parameters.duration, - parameters.frequencyHz); + parameters.frequencyHz, + parameters.bandwidthHz); } double diff --git a/model/lora-channel.h b/model/lora-channel.h index 60f242afda..e45135edfe 100644 --- a/model/lora-channel.h +++ b/model/lora-channel.h @@ -49,6 +49,7 @@ struct LoraChannelParameters uint8_t sf; //!< The Spreading Factor of this transmission. Time duration; //!< The duration of the transmission. uint32_t frequencyHz; //!< The frequency [Hz] of this transmission. + uint32_t bandwidthHz; //!< The bandwidth [Hz] of this transmission. }; /** diff --git a/model/lora-phy.h b/model/lora-phy.h index 33204f5a51..367236dd95 100644 --- a/model/lora-phy.h +++ b/model/lora-phy.h @@ -108,12 +108,14 @@ class LoraPhy : public Object * @param sf The Spreading Factor of the arriving packet. * @param duration The on air time of this packet. * @param frequencyHz The frequency this packet is being transmitted on. + * @param bandwidthHz The bandwidth this packet is being transmitted on. */ virtual void StartReceive(Ptr packet, double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) = 0; + uint32_t frequencyHz, + uint32_t bandwidthHz) = 0; /** * Finish reception of a packet. diff --git a/model/simple-end-device-lora-phy.cc b/model/simple-end-device-lora-phy.cc index 61d3b3c75f..53a302ee64 100644 --- a/model/simple-end-device-lora-phy.cc +++ b/model/simple-end-device-lora-phy.cc @@ -97,7 +97,8 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) + uint32_t frequencyHz, + uint32_t bandwidthHz) { NS_LOG_FUNCTION(this << packet << rxPowerDbm << unsigned(sf) << duration << frequencyHz); @@ -145,6 +146,8 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, // Save needed sensitivity double sensitivity = EndDeviceLoraPhy::sensitivity[unsigned(sf) - 7]; + uint32_t node_id = m_device ? m_device->GetNode()->GetId() : 0; + // Check frequency ////////////////// if (!IsOnFrequency(frequencyHz)) @@ -153,15 +156,19 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, << frequencyHz << " Hz and we are listening at " << m_frequencyHz << " Hz"); // Fire the trace source for this event. - if (m_device) - { - m_wrongFrequency(packet, m_device->GetNode()->GetId()); - } - else - { - m_wrongFrequency(packet, 0); - } + m_wrongFrequency(packet, node_id); + canLockOnPacket = false; + } + // Check bandwidth + ////////////////// + if (!IsOnBandwidth(bandwidthHz)) + { + NS_LOG_INFO("Packet lost because it's send using bandwidth " + << bandwidthHz << " Hz and we are listening at " << m_bandwidthHz << " Hz"); + + // Fire the trace source for this event. + m_wrongBandwidth(packet, node_id); canLockOnPacket = false; } @@ -173,15 +180,7 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, << unsigned(sf) << ", while we are listening for SF" << unsigned(m_sf)); // Fire the trace source for this event. - if (m_device) - { - m_wrongSf(packet, m_device->GetNode()->GetId()); - } - else - { - m_wrongSf(packet, 0); - } - + m_wrongSf(packet, node_id); canLockOnPacket = false; } @@ -194,15 +193,7 @@ SimpleEndDeviceLoraPhy::StartReceive(Ptr packet, << " dBm"); // Fire the trace source for this event. - if (m_device) - { - m_underSensitivity(packet, m_device->GetNode()->GetId()); - } - else - { - m_underSensitivity(packet, 0); - } - + m_underSensitivity(packet, node_id); canLockOnPacket = false; } diff --git a/model/simple-end-device-lora-phy.h b/model/simple-end-device-lora-phy.h index 8cbfe4007d..0d0c9ed85b 100644 --- a/model/simple-end-device-lora-phy.h +++ b/model/simple-end-device-lora-phy.h @@ -48,7 +48,8 @@ class SimpleEndDeviceLoraPhy : public EndDeviceLoraPhy double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) override; + uint32_t frequencyHz, + uint32_t bandwidthHz) override; // Implementation of LoraPhy's pure virtual functions void EndReceive(Ptr packet, Ptr event) override; diff --git a/model/simple-gateway-lora-phy.cc b/model/simple-gateway-lora-phy.cc index 53b1d23c63..ce7b137b97 100644 --- a/model/simple-gateway-lora-phy.cc +++ b/model/simple-gateway-lora-phy.cc @@ -112,7 +112,8 @@ SimpleGatewayLoraPhy::StartReceive(Ptr packet, double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) + uint32_t frequencyHz, + uint32_t bandwidthHz) { NS_LOG_FUNCTION(this << packet << rxPowerDbm << duration << frequencyHz); diff --git a/model/simple-gateway-lora-phy.h b/model/simple-gateway-lora-phy.h index c063e1626b..8afcbe656f 100644 --- a/model/simple-gateway-lora-phy.h +++ b/model/simple-gateway-lora-phy.h @@ -48,7 +48,8 @@ class SimpleGatewayLoraPhy : public GatewayLoraPhy double rxPowerDbm, uint8_t sf, Time duration, - uint32_t frequencyHz) override; + uint32_t frequencyHz, + uint32_t bandwidthHz) override; void EndReceive(Ptr packet, Ptr event) override; diff --git a/test/lorawan-test-suite.cc b/test/lorawan-test-suite.cc index d69b8456ef..41b1feccd2 100644 --- a/test/lorawan-test-suite.cc +++ b/test/lorawan-test-suite.cc @@ -1133,6 +1133,14 @@ class PhyConnectivityTest : public TestCase */ void WrongFrequency(Ptr packet, uint32_t node); + /** + * Callback for tracing LostPacketBecauseWrongBandwidth. + * + * @param packet The packet lost. + * @param node The receiver node id if any, 0 otherwise. + */ + void WrongBandwidth(Ptr packet, uint32_t node); + /** * Callback for tracing LostPacketBecauseWrongSpreadingFactor. * @@ -1165,6 +1173,7 @@ class PhyConnectivityTest : public TestCase int m_interferenceCalls = 0; //!< Counter for LostPacketBecauseInterference calls int m_wrongSfCalls = 0; //!< Counter for LostPacketBecauseWrongSpreadingFactor calls int m_wrongFrequencyCalls = 0; //!< Counter for LostPacketBecauseWrongFrequency calls + int m_wrongBandwidthCalls = 0; //!< Counter for LostPacketBecauseWrongBandwidth calls }; // Add some help text to this case to describe what it is intended to test @@ -1220,6 +1229,14 @@ PhyConnectivityTest::WrongFrequency(Ptr packet, uint32_t node) m_wrongFrequencyCalls++; } +void +PhyConnectivityTest::WrongBandwidth(Ptr packet, uint32_t node) +{ + NS_LOG_FUNCTION(packet << node); + + m_wrongBandwidthCalls++; +} + bool PhyConnectivityTest::IsSamePacket(Ptr packet1, Ptr packet2) { @@ -1315,6 +1332,13 @@ PhyConnectivityTest::Reset() edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency", MakeCallback(&PhyConnectivityTest::WrongFrequency, this)); + edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongBandwidth", + MakeCallback(&PhyConnectivityTest::WrongBandwidth, this)); + edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongBandwidth", + MakeCallback(&PhyConnectivityTest::WrongBandwidth, this)); + edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongBandwidth", + MakeCallback(&PhyConnectivityTest::WrongBandwidth, this)); + edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor", MakeCallback(&PhyConnectivityTest::WrongSf, this)); edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor", @@ -1554,6 +1578,32 @@ PhyConnectivityTest::DoRun() NS_TEST_EXPECT_MSG_EQ(edPhy2->GetState(), SimpleEndDeviceLoraPhy::State::STANDBY, "State didn't switch to STANDBY as expected"); + + Reset(); + txParams.sf = 12; + txParams.bandwidthHz = 250000; + + edPhy2->SetBandwidth(250000); + Simulator::Schedule(Seconds(2), + &SimpleEndDeviceLoraPhy::Send, + edPhy1, + packet, + txParams, + 868100000, + 14); + + Simulator::Stop(Hours(2)); + Simulator::Run(); + Simulator::Destroy(); + + NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, + 1, + "Exactly one transceiver should have received the packet"); + + NS_TEST_EXPECT_MSG_EQ(m_wrongBandwidthCalls, + 1, + "Exactly one transceiver should have lost the packet due to bandwidth " + "mismatch"); } /**