diff --git a/CHANGES.html b/CHANGES.html
index f6b7147d3..322646dbf 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -54,6 +54,8 @@ us a note on ns-developers mailing list.
Changes from ns-3.32 to ns-3.33
New API:
+- New channel models based on 3GPP TR 37.885 have been added to support vehicular simulations.
+Time::RoundTo (unit) allows time to be rounded to the nearest integer multiple of unit
- Time::RoundTo (unit) allows time to be rounded to the nearest integer multiple of unit
- UdpClient now can report both transmitted and received bytes.
diff --git a/examples/channel-models/examples-to-run.py b/examples/channel-models/examples-to-run.py
new file mode 100644
index 000000000..430364089
--- /dev/null
+++ b/examples/channel-models/examples-to-run.py
@@ -0,0 +1,20 @@
+#! /usr/bin/env python3
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+# A list of C++ examples to run in order to ensure that they remain
+# buildable and runnable over time. Each tuple in the list contains
+#
+# (example_name, do_run, do_valgrind_run).
+#
+# See test.py for more information.
+cpp_examples = [
+ ("three-gpp-v2v-channel-example", "True", "True"),
+]
+
+# A list of Python examples to run in order to ensure that they remain
+# runnable over time. Each tuple in the list contains
+#
+# (example_name, do_run).
+#
+# See test.py for more information.
+python_examples = []
diff --git a/examples/channel-models/three-gpp-v2v-channel-example.cc b/examples/channel-models/three-gpp-v2v-channel-example.cc
new file mode 100644
index 000000000..c0956a086
--- /dev/null
+++ b/examples/channel-models/three-gpp-v2v-channel-example.cc
@@ -0,0 +1,373 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020, University of Padova, Dep. of Information Engineering, SIGNET lab
+ *
+ * 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
+ *
+ */
+
+/**
+* This is an example on how to configure the channel model classes to simulate
+* a vehicular environment.
+* The channel condition is determined using the model specified in [1], Table 6.2-1.
+* The pathloss is determined using the model specified in [1], Table 6.2.1-1.
+* The model for the fast fading is the one described in 3GPP TR 38.901 v15.0.0,
+* the model parameters are those specified in [1], Table 6.2.3-1.
+*
+* This example generates the output file 'example-output.txt'. Each row of the
+* file is organized as follows:
+* Time[s] TxPosX[m] TxPosY[m] RxPosX[m] RxPosY[m] ChannelState SNR[dB] Pathloss[dB]
+* We also provide a bash script which reads the output file and generates two
+* figures:
+* (i) map.gif, a GIF representing the simulation scenario and vehicle mobility;
+* (ii) snr.png, which represents the behavior of the SNR.
+*
+* [1] 3GPP TR 37.885, v15.3.0
+*/
+
+#include "ns3/buildings-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include
+#include "ns3/three-gpp-antenna-array-model.h"
+#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
+#include "ns3/three-gpp-v2v-propagation-loss-model.h"
+#include "ns3/three-gpp-channel-model.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("ThreeGppV2vChannelExample");
+
+static Ptr m_propagationLossModel; //!< the PropagationLossModel object
+static Ptr m_spectrumLossModel; //!< the SpectrumPropagationLossModel object
+static Ptr m_condModel; //!< the ChannelConditionModel object
+
+/**
+ * Perform the beamforming using the DFT beamforming method
+ * \param thisDevice the device performing the beamforming
+ * \param thisAntenna the antenna object associated to thisDevice
+ * \param otherDevice the device towards which point the beam
+ */
+static void
+DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice)
+{
+ ThreeGppAntennaArrayModel::ComplexVector antennaWeights;
+
+ // retrieve the position of the two devices
+ Vector aPos = thisDevice->GetNode ()->GetObject ()->GetPosition ();
+ Vector bPos = otherDevice->GetNode ()->GetObject ()->GetPosition ();
+
+ // compute the azimuth and the elevation angles
+ Angles completeAngle (bPos,aPos);
+
+ double hAngleRadian = fmod (completeAngle.phi, 2.0 * M_PI); // the azimuth angle
+ if (hAngleRadian < 0)
+ {
+ hAngleRadian += 2.0 * M_PI;
+ }
+ double vAngleRadian = completeAngle.theta; // the elevation angle
+
+ // retrieve the number of antenna elements
+ int totNoArrayElements = thisAntenna->GetNumberOfElements ();
+
+ // the total power is divided equally among the antenna elements
+ double power = 1 / sqrt (totNoArrayElements);
+
+ // compute the antenna weights
+ for (int ind = 0; ind < totNoArrayElements; ind++)
+ {
+ Vector loc = thisAntenna->GetElementLocation (ind);
+ double phase = -2 * M_PI * (sin (vAngleRadian) * cos (hAngleRadian) * loc.x
+ + sin (vAngleRadian) * sin (hAngleRadian) * loc.y
+ + cos (vAngleRadian) * loc.z);
+ antennaWeights.push_back (exp (std::complex (0, phase)) * power);
+ }
+
+ // store the antenna weights
+ thisAntenna->SetBeamformingVector (antennaWeights);
+}
+
+/**
+ * Compute the average SNR
+ * \param txMob the tx mobility model
+ * \param rxMob the rx mobility model
+ * \param txPsd the PSD of the transmitting signal
+ * \param noiseFigure the noise figure in dB
+ */
+static void
+ComputeSnr (Ptr txMob, Ptr rxMob, Ptr txPsd, double noiseFigure)
+{
+ Ptr rxPsd = txPsd->Copy ();
+
+ // check the channel condition
+ Ptr cond = m_condModel->GetChannelCondition (txMob, rxMob);
+
+ // apply the pathloss
+ double propagationGainDb = m_propagationLossModel->CalcRxPower (0, txMob, rxMob);
+ NS_LOG_DEBUG ("Pathloss " << -propagationGainDb << " dB");
+ double propagationGainLinear = std::pow (10.0, (propagationGainDb) / 10.0);
+ *(rxPsd) *= propagationGainLinear;
+
+ // apply the fast fading and the beamforming gain
+ rxPsd = m_spectrumLossModel->CalcRxPowerSpectralDensity (rxPsd, txMob, rxMob);
+ NS_LOG_DEBUG ("Average rx power " << 10 * log10 (Sum (*rxPsd) * 180e3) << " dB");
+
+ // create the noise psd
+ // taken from lte-spectrum-value-helper
+ const double kT_dBm_Hz = -174.0; // dBm/Hz
+ double kT_W_Hz = std::pow (10.0, (kT_dBm_Hz - 30) / 10.0);
+ double noiseFigureLinear = std::pow (10.0, noiseFigure / 10.0);
+ double noisePowerSpectralDensity = kT_W_Hz * noiseFigureLinear;
+ Ptr noisePsd = Create (txPsd->GetSpectrumModel ());
+ (*noisePsd) = noisePowerSpectralDensity;
+
+ // compute the SNR
+ NS_LOG_DEBUG ("Average SNR " << 10 * log10 (Sum (*rxPsd) / Sum (*noisePsd)) << " dB");
+
+ // print the SNR and pathloss values in the snr-trace.txt file
+ std::ofstream f;
+ f.open ("example-output.txt", std::ios::out | std::ios::app);
+ f << Simulator::Now ().GetSeconds () << " " // time [s]
+ << txMob->GetPosition ().x << " "
+ << txMob->GetPosition ().y << " "
+ << rxMob->GetPosition ().x << " "
+ << rxMob->GetPosition ().y << " "
+ << cond->GetLosCondition () << " " // channel state
+ << 10 * log10 (Sum (*rxPsd) / Sum (*noisePsd)) << " " // SNR [dB]
+ << -propagationGainDb << std::endl; // pathloss [dB]
+ f.close ();
+}
+
+/**
+ * Generates a GNU-plottable file representig the buildings deployed in the
+ * scenario
+ * \param filename the name of the output file
+ */
+void
+PrintGnuplottableBuildingListToFile (std::string filename)
+{
+ std::ofstream outFile;
+ outFile.open (filename.c_str (), std::ios_base::out | std::ios_base::trunc);
+ if (!outFile.is_open ())
+ {
+ NS_LOG_ERROR ("Can't open file " << filename);
+ return;
+ }
+ uint32_t index = 0;
+ for (BuildingList::Iterator it = BuildingList::Begin (); it != BuildingList::End (); ++it)
+ {
+ ++index;
+ Box box = (*it)->GetBoundaries ();
+ outFile << "set object " << index
+ << " rect from " << box.xMin << "," << box.yMin
+ << " to " << box.xMax << "," << box.yMax
+ << std::endl;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ double frequency = 28.0e9; // operating frequency in Hz
+ double txPow_dbm = 30.0; // tx power in dBm
+ double noiseFigure = 9.0; // noise figure in dB
+ Time simTime = Seconds (40); // simulation time
+ Time timeRes = MilliSeconds (10); // time resolution
+ std::string scenario = "V2V-Urban"; // 3GPP propagation scenario, V2V-Urban or V2V-Highway
+ double vScatt = 0; // maximum speed of the vehicles in the scenario [m/s]
+ double subCarrierSpacing = 60e3; // subcarrier spacing in kHz
+ uint32_t numRb = 275; // number of resource blocks
+
+ CommandLine cmd (__FILE__);
+ cmd.AddValue ("frequency", "operating frequency in Hz", frequency);
+ cmd.AddValue ("txPow", "tx power in dBm", txPow_dbm);
+ cmd.AddValue ("noiseFigure", "noise figure in dB", noiseFigure);
+ cmd.AddValue ("scenario", "3GPP propagation scenario, V2V-Urban or V2V-Highway", scenario);
+ cmd.Parse (argc, argv);
+
+ // create the nodes
+ NodeContainer nodes;
+ nodes.Create (2);
+
+ // create the tx and rx devices
+ Ptr txDev = CreateObject ();
+ Ptr rxDev = CreateObject ();
+
+ // associate the nodes and the devices
+ nodes.Get (0)->AddDevice (txDev);
+ txDev->SetNode (nodes.Get (0));
+ nodes.Get (1)->AddDevice (rxDev);
+ rxDev->SetNode (nodes.Get (1));
+
+ // create the antenna objects and set their dimensions
+ Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (-M_PI / 2));
+ Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2), "BearingAngle", DoubleValue (M_PI / 2));
+
+ Ptr txMob;
+ Ptr rxMob;
+ if (scenario == "V2V-Urban")
+ {
+ // 3GPP defines that the maximum speed in urban scenario is 60 km/h
+ vScatt = 60 / 3.6;
+
+ // create a grid of buildings
+ double buildingSizeX = 250 - 3.5 * 2 - 3; // m
+ double buildingSizeY = 433 - 3.5 * 2 - 3; // m
+ double streetWidth = 20; // m
+ double buildingHeight = 10; // m
+ uint32_t numBuildingsX = 2;
+ uint32_t numBuildingsY = 2;
+ double maxAxisX = (buildingSizeX + streetWidth) * numBuildingsX;
+ double maxAxisY = (buildingSizeY + streetWidth) * numBuildingsY;
+
+ std::vector > buildingVector;
+ for (uint32_t buildingIdX = 0; buildingIdX < numBuildingsX; ++buildingIdX)
+ {
+ for (uint32_t buildingIdY = 0; buildingIdY < numBuildingsY; ++buildingIdY)
+ {
+ Ptr < Building > building;
+ building = CreateObject ();
+
+ building->SetBoundaries (Box (buildingIdX * (buildingSizeX + streetWidth),
+ buildingIdX * (buildingSizeX + streetWidth) + buildingSizeX,
+ buildingIdY * (buildingSizeY + streetWidth),
+ buildingIdY * (buildingSizeY + streetWidth) + buildingSizeY,
+ 0.0, buildingHeight));
+ building->SetNRoomsX (1);
+ building->SetNRoomsY (1);
+ building->SetNFloors (1);
+ buildingVector.push_back (building);
+ }
+ }
+
+ // set the mobility model
+ double vTx = vScatt;
+ double vRx = vScatt / 2;
+ txMob = CreateObject ();
+ rxMob = CreateObject ();
+ Time nextWaypoint = Seconds (0.0);
+ txMob->GetObject ()->AddWaypoint (Waypoint (nextWaypoint, Vector (maxAxisX / 2 - streetWidth / 2, 1.0, 1.5)));
+ nextWaypoint += Seconds ((maxAxisY - streetWidth) / 2 / vTx);
+ txMob->GetObject ()->AddWaypoint (Waypoint (nextWaypoint, Vector (maxAxisX / 2 - streetWidth / 2, maxAxisY / 2 - streetWidth / 2, 1.5)));
+ nextWaypoint += Seconds ((maxAxisX - streetWidth) / 2 / vTx);
+ txMob->GetObject ()->AddWaypoint (Waypoint (nextWaypoint, Vector (0.0, maxAxisY / 2 - streetWidth / 2, 1.5)));
+ nextWaypoint = Seconds (0.0);
+ rxMob->GetObject ()->AddWaypoint (Waypoint (nextWaypoint, Vector (maxAxisX / 2 - streetWidth / 2, 0.0, 1.5)));
+ nextWaypoint += Seconds (maxAxisY / vRx);
+ rxMob->GetObject ()->AddWaypoint (Waypoint (nextWaypoint, Vector (maxAxisX / 2 - streetWidth / 2, maxAxisY, 1.5)));
+
+ nodes.Get (0)->AggregateObject (txMob);
+ nodes.Get (1)->AggregateObject (rxMob);
+
+ // create the channel condition model
+ m_condModel = CreateObject ();
+
+ // create the propagation loss model
+ m_propagationLossModel = CreateObject ();
+ }
+ else if (scenario == "V2V-Highway")
+ {
+ // Two vehicles are travelling one behid the other with constant velocity
+ // along the y axis. The distance between the two vehicles is 20 meters.
+
+ // 3GPP defines that the maximum speed in urban scenario is 140 km/h
+ vScatt = 140 / 3.6;
+ double vTx = vScatt;
+ double vRx = vScatt / 2;
+
+ txMob = CreateObject ();
+ rxMob = CreateObject ();
+ txMob->GetObject ()->SetPosition (Vector (300.0, 20.0, 1.5));
+ txMob->GetObject ()->SetVelocity (Vector (0.0, vTx, 0.0));
+ rxMob->GetObject ()->SetPosition (Vector (300.0, 0.0, 1.5));
+ rxMob->GetObject ()->SetVelocity (Vector (0.0, vRx, 0.0));
+
+ nodes.Get (0)->AggregateObject (txMob);
+ nodes.Get (1)->AggregateObject (rxMob);
+
+ // create the channel condition model
+ m_condModel = CreateObject ();
+
+ // create the propagation loss model
+ m_propagationLossModel = CreateObject ();
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Unknown scenario");
+ }
+
+ m_condModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (100)));
+
+ m_propagationLossModel->SetAttribute ("Frequency", DoubleValue (frequency));
+ m_propagationLossModel->SetAttribute ("ShadowingEnabled", BooleanValue (false));
+ m_propagationLossModel->SetAttribute ("ChannelConditionModel", PointerValue (m_condModel));
+
+ // create the channel model
+ Ptr channelModel = CreateObject ();
+ channelModel->SetAttribute ("Scenario", StringValue (scenario));
+ channelModel->SetAttribute ("Frequency", DoubleValue (frequency));
+ channelModel->SetAttribute ("ChannelConditionModel", PointerValue (m_condModel));
+
+ // create the spectrum propagation loss model
+ m_spectrumLossModel = CreateObjectWithAttributes ("ChannelModel", PointerValue (channelModel));
+ m_spectrumLossModel->SetAttribute ("vScatt", DoubleValue (vScatt));
+
+ // initialize the devices in the ThreeGppSpectrumPropagationLossModel
+ m_spectrumLossModel->AddDevice (txDev, txAntenna);
+ m_spectrumLossModel->AddDevice (rxDev, rxAntenna);
+
+ BuildingsHelper::Install (nodes);
+
+ // set the beamforming vectors
+ DoBeamforming (txDev, txAntenna, rxDev);
+ DoBeamforming (rxDev, rxAntenna, txDev);
+
+ // create the tx power spectral density
+ Bands rbs;
+ double freqSubBand = frequency;
+ for (uint16_t n = 0; n < numRb; ++n)
+ {
+ BandInfo rb;
+ rb.fl = freqSubBand;
+ freqSubBand += subCarrierSpacing / 2;
+ rb.fc = freqSubBand;
+ freqSubBand += subCarrierSpacing / 2;
+ rb.fh = freqSubBand;
+ rbs.push_back (rb);
+ }
+ Ptr spectrumModel = Create (rbs);
+ Ptr txPsd = Create (spectrumModel);
+ double txPow_w = std::pow (10., (txPow_dbm - 30) / 10);
+ double txPowDens = (txPow_w / (numRb * subCarrierSpacing));
+ (*txPsd) = txPowDens;
+
+ for (int i = 0; i < simTime / timeRes; i++)
+ {
+ Simulator::Schedule (timeRes * i, &ComputeSnr, txMob, rxMob, txPsd, noiseFigure);
+ }
+
+ // initialize the output file
+ std::ofstream f;
+ f.open ("example-output.txt", std::ios::out);
+ f << "Time[s] TxPosX[m] TxPosY[m] RxPosX[m] RxPosY[m] ChannelState SNR[dB] Pathloss[dB]" << std::endl;
+ f.close ();
+
+ // print the list of buildings to file
+ PrintGnuplottableBuildingListToFile ("buildings.txt");
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+ return 0;
+}
diff --git a/examples/channel-models/three-gpp-v2v-channel-example.sh b/examples/channel-models/three-gpp-v2v-channel-example.sh
new file mode 100644
index 000000000..f3a3e8ce3
--- /dev/null
+++ b/examples/channel-models/three-gpp-v2v-channel-example.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# Copyright (c) 2020, University of Padova, Dep. of Information Engineering, SIGNET lab
+#
+# 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
+
+#
+# Plot the traces generated by three-gpp-vehicular-channel-condition-model-example
+#
+
+cat >aa <`)
+
The models have been designed with LTE in mind, though their implementation is in fact independent from any LTE-specific code, and can be used with other ns-3 wireless technologies as well (e.g., wifi, wimax).
The ``HybridBuildingsPropagationLossModel`` pathloss model included is obtained through a combination of several well known pathloss models in order to mimic different environmental scenarios such as urban, suburban and open areas. Moreover, the model considers both outdoor and indoor indoor and outdoor communication has to be included since HeNB might be installed either within building and either outside. In case of indoor communication, the model has to consider also the type of building in outdoor <-> indoor communication according to some general criteria such as the wall penetration losses of the common materials; moreover it includes some general configuration for the internal walls in indoor communications.
@@ -267,4 +269,3 @@ The following pseudo-code illustrates how the different pathloss model elements
L = OH + EWL
We note that OhBuildingsPropagationLossModel is a significant simplification with respect to HybridBuildingsPropagationLossModel, due to the fact that OH is used always. While this gives a less accurate model in some scenarios (especially below rooftop and indoor), it effectively avoids the issue of pathloss discontinuities that affects HybridBuildingsPropagationLossModel.
-
diff --git a/src/buildings/doc/source/buildings-user.rst b/src/buildings/doc/source/buildings-user.rst
index 6aa6a4598..df654f1a9 100644
--- a/src/buildings/doc/source/buildings-user.rst
+++ b/src/buildings/doc/source/buildings-user.rst
@@ -168,13 +168,18 @@ for the wireless module that you are considering (lte, wifi, wimax,
etc.), so please refer to the documentation of that model for specific
instructions.
-Building-aware channel condition model
-**************************************
+Building-aware channel condition models
+***************************************
The class BuildingsChannelConditionModel implements a `channel condition model `_
which determines the LOS/NLOS channel state based on the buildings deployed in
the scenario.
+The classes ``ThreeGppV2vUrbanChannelConditionModel`` and
+``ThreeGppV2vHighwayChannelConditionModel`` implement hybrid channel condition
+models, specifically designed to model vehicular environments.
+More information can be found in the :ref:`documentation
+of the propagation module `.
Main configurable attributes
============================
diff --git a/src/buildings/examples/outdoor-random-walk-example.sh b/src/buildings/examples/outdoor-random-walk-example.sh
index 09b5bfdf2..f0b885f82 100755
--- a/src/buildings/examples/outdoor-random-walk-example.sh
+++ b/src/buildings/examples/outdoor-random-walk-example.sh
@@ -38,4 +38,4 @@ plot "pos.txt" with circles lc rgb "blue"
EOL
gnuplot buildings.txt aa
rm aa
-rm pos.txt
\ No newline at end of file
+rm pos.txt
diff --git a/src/buildings/model/buildings-channel-condition-model.cc b/src/buildings/model/buildings-channel-condition-model.cc
index 79bb83437..a4d90fb02 100644
--- a/src/buildings/model/buildings-channel-condition-model.cc
+++ b/src/buildings/model/buildings-channel-condition-model.cc
@@ -55,6 +55,7 @@ Ptr
BuildingsChannelConditionModel::GetChannelCondition (Ptr a,
Ptr b) const
{
+ NS_LOG_FUNCTION (this);
Ptr a1 = a->GetObject ();
Ptr b1 = b->GetObject ();
NS_ASSERT_MSG ((a1 != nullptr) && (b1 != nullptr),
@@ -68,35 +69,45 @@ BuildingsChannelConditionModel::GetChannelCondition (Ptr a,
if (!isAIndoor && !isBIndoor) // a and b are outdoor
{
+ cond->SetO2iCondition (ChannelCondition::O2iConditionValue::O2O);
+
// The outdoor case, determine LOS/NLOS
// The channel condition should be LOS if the line of sight is not blocked,
// otherwise NLOS
bool blocked = IsLineOfSightBlocked (a->GetPosition (), b->GetPosition ());
+ NS_LOG_DEBUG ("a and b are outdoor, blocked " << blocked);
if (!blocked)
{
+ NS_LOG_DEBUG ("Set LOS");
cond->SetLosCondition (ChannelCondition::LosConditionValue::LOS);
}
else
{
cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOS);
}
-
}
else if (isAIndoor && isBIndoor) // a and b are indoor
{
+ cond->SetO2iCondition (ChannelCondition::O2iConditionValue::I2I);
+
// Indoor case, determine is the two nodes are inside the same building
// or not
if (a1->GetBuilding () == b1->GetBuilding ())
{
+ NS_LOG_DEBUG ("a and b are indoor in the same building");
cond->SetLosCondition (ChannelCondition::LosConditionValue::LOS);
}
else
{
+ NS_LOG_DEBUG ("a and b are indoor in different buildings");
cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOS);
}
}
else //outdoor to indoor case
{
+ cond->SetO2iCondition (ChannelCondition::O2iConditionValue::O2I);
+
+ NS_LOG_DEBUG ("a is indoor and b outdoor or viceversa");
cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOS);
}
diff --git a/src/buildings/model/three-gpp-v2v-channel-condition-model.cc b/src/buildings/model/three-gpp-v2v-channel-condition-model.cc
new file mode 100644
index 000000000..fd6ff370d
--- /dev/null
+++ b/src/buildings/model/three-gpp-v2v-channel-condition-model.cc
@@ -0,0 +1,207 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ * Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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
+ */
+
+#include "three-gpp-v2v-channel-condition-model.h"
+#include "ns3/mobility-model.h"
+#include "ns3/log.h"
+#include
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("ThreeGppV2vChannelConditionModel");
+
+NS_OBJECT_ENSURE_REGISTERED (ThreeGppV2vUrbanChannelConditionModel);
+
+TypeId
+ThreeGppV2vUrbanChannelConditionModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ThreeGppV2vUrbanChannelConditionModel")
+ .SetParent ()
+ .SetGroupName ("Buildings")
+ .AddConstructor ()
+ ;
+ return tid;
+}
+
+ThreeGppV2vUrbanChannelConditionModel::ThreeGppV2vUrbanChannelConditionModel ()
+ : ThreeGppChannelConditionModel ()
+{
+ m_buildingsCcm = CreateObject ();
+}
+
+ThreeGppV2vUrbanChannelConditionModel::~ThreeGppV2vUrbanChannelConditionModel ()
+{}
+
+double
+ThreeGppV2vUrbanChannelConditionModel::ComputePlos (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // determine if there is a building in between the tx and rx
+ Ptr cond = m_buildingsCcm->GetChannelCondition (a, b);
+ NS_ASSERT_MSG (cond->IsO2o (), "The nodes should be outdoor");
+
+ double pLos = 0.0;
+ if (cond->IsLos ())
+ {
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ // compute the LOS probability (see 3GPP TR 37.885, Table 6.2-1)
+ pLos = std::min (1.0, 1.05 * exp (-0.0114 * distance2D));
+ }
+
+ return pLos;
+}
+
+double
+ThreeGppV2vUrbanChannelConditionModel::ComputePnlos (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // determine the NLOS due to buildings
+ Ptr cond = m_buildingsCcm->GetChannelCondition (a, b);
+ NS_ASSERT_MSG (cond->IsO2o (), "The nodes should be outdoor");
+
+ double pNlos = 0.0;
+ if (cond->IsNlos ())
+ {
+ pNlos = 1.0;
+ }
+
+ return pNlos;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED (ThreeGppV2vHighwayChannelConditionModel);
+
+TypeId
+ThreeGppV2vHighwayChannelConditionModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ThreeGppV2vHighwayChannelConditionModel")
+ .SetParent ()
+ .SetGroupName ("Buildings")
+ .AddConstructor ()
+ ;
+ return tid;
+}
+
+ThreeGppV2vHighwayChannelConditionModel::ThreeGppV2vHighwayChannelConditionModel ()
+ : ThreeGppChannelConditionModel ()
+{
+ m_buildingsCcm = CreateObject ();
+ ComputeChCond = std::bind (&ThreeGppV2vHighwayChannelConditionModel::GetChCondAndFixCallback, this,
+ std::placeholders::_1, std::placeholders::_2);
+}
+
+ThreeGppV2vHighwayChannelConditionModel::~ThreeGppV2vHighwayChannelConditionModel ()
+{}
+
+double
+ThreeGppV2vHighwayChannelConditionModel::ComputePlos (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // determine if there is a building in between the tx and rx
+ Ptr cond = ComputeChCond (a, b);
+ NS_ASSERT_MSG (cond->IsO2o (), "The nodes should be outdoor");
+
+ double pLos = 0.0;
+ if (cond->IsLos ())
+ {
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ // compute the LOS probability (see 3GPP TR 37.885, Table 6.2-1)
+ if (distance2D <= 475.0)
+ {
+ pLos = std::min (1.0, 2.1013e-6 * distance2D * distance2D - 0.002 * distance2D + 1.0193);
+ }
+ else
+ {
+ pLos = std::max (0.0, 0.54 - 0.001 * (distance2D - 475.0));
+ }
+ }
+
+ return pLos;
+}
+
+double
+ThreeGppV2vHighwayChannelConditionModel::ComputePnlos (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // determine the NLOS due to buildings
+ Ptr cond = ComputeChCond (a, b);
+ NS_ASSERT_MSG (cond->IsO2o (), "The nodes should be outdoor");
+
+ double pNlos = 0;
+ if (cond->IsNlos ())
+ {
+ pNlos = 1.0;
+ }
+
+ return pNlos;
+}
+
+Ptr
+ThreeGppV2vHighwayChannelConditionModel::GetChCondAndFixCallback (Ptr a,
+ Ptr b)
+{
+ Ptr cond;
+ if (BuildingList::Begin () != BuildingList::End ())
+ {
+ ComputeChCond = std::bind (&ThreeGppV2vHighwayChannelConditionModel::GetChCondWithBuildings, this,
+ std::placeholders::_1, std::placeholders::_2);
+ cond = GetChCondWithBuildings (a, b);
+ }
+ else
+ {
+ ComputeChCond = std::bind (&ThreeGppV2vHighwayChannelConditionModel::GetChCondWithNoBuildings, this,
+ std::placeholders::_1, std::placeholders::_2);
+ cond = GetChCondWithNoBuildings (a, b);
+ }
+ return cond;
+}
+
+Ptr
+ThreeGppV2vHighwayChannelConditionModel::GetChCondWithBuildings (Ptr a,
+ Ptr b) const
+{
+ Ptr cond = m_buildingsCcm->GetChannelCondition (a, b);
+ return cond;
+}
+
+Ptr
+ThreeGppV2vHighwayChannelConditionModel::GetChCondWithNoBuildings (Ptr a,
+ Ptr b) const
+{
+ Ptr cond = CreateObject ();
+ cond->SetO2iCondition (ChannelCondition::O2iConditionValue::O2O);
+ cond->SetLosCondition (ChannelCondition::LosConditionValue::LOS);
+ return cond;
+}
+
+} // end namespace ns3
diff --git a/src/buildings/model/three-gpp-v2v-channel-condition-model.h b/src/buildings/model/three-gpp-v2v-channel-condition-model.h
new file mode 100644
index 000000000..f5c1fc6b9
--- /dev/null
+++ b/src/buildings/model/three-gpp-v2v-channel-condition-model.h
@@ -0,0 +1,208 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ * Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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
+ */
+
+#ifndef THREE_GPP_V2V_CHANNEL_CONDITION_MODEL
+#define THREE_GPP_V2V_CHANNEL_CONDITION_MODEL
+
+#include "ns3/channel-condition-model.h"
+#include "buildings-channel-condition-model.h"
+#include
+
+namespace ns3 {
+
+class MobilityModel;
+
+/**
+ * \ingroup buildings
+ *
+ * \brief Computes the channel condition for the V2V Urban scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * V2V Urban scenario reported in Table 6.2-1 of 3GPP TR 37.885.
+ *
+ * 3GPP TR 37.885 defines 3 different channel states for vehicular environments:
+ * LOS, NLOS and NLOSv, the latter representing the case in which the LOS path is
+ * blocked by other vehicles in the scenario. The document defines a probabilistic
+ * model to determine if the channel state is LOS or NLOSv, while the NLOS state
+ * is determined in a deterministic way based on the buildings deployed in the
+ * scenario. For this reason, this class makes use of an instance of
+ * BuildingsChannelConditionModel to determine if the LOS is obstructed by
+ * buildings or not.
+ */
+class ThreeGppV2vUrbanChannelConditionModel : public ThreeGppChannelConditionModel
+{
+public:
+ /**
+ * Get the type ID.
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor for the ThreeGppV2vUrbanChannelConditionModel class
+ */
+ ThreeGppV2vUrbanChannelConditionModel ();
+
+ /**
+ * Destructor for the ThreeGppV2vUrbanChannelConditionModel class
+ */
+ virtual ~ThreeGppV2vUrbanChannelConditionModel () override;
+
+private:
+ /**
+ * Compute the LOS probability as specified in Table Table 6.2-1 of 3GPP TR 37.885
+ * for the V2V Urban scenario.
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the LOS probability
+ */
+ virtual double ComputePlos (Ptr a, Ptr b) const override;
+
+ /**
+ * Compute the NLOS probability. It determines the presence of obstructions
+ * between the tx and the rx based on the buildings deployed in the scenario.
+ * It returns 1 if the LOS path is obstructed, 0 otherwise.
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the NLOS probability
+ */
+ virtual double ComputePnlos (Ptr a, Ptr b) const override;
+
+ Ptr m_buildingsCcm; //!< used to determine the obstructions due to buildings
+};
+
+/**
+ * \ingroup buildings
+ *
+ * \brief Computes the channel condition for the V2V Highway scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * V2V Highway scenario reported in Table 6.2-1 of 3GPP TR 37.885.
+ *
+ * 3GPP TR 37.885 defines 3 different channel states for vehicular environments:
+ * LOS, NLOS and NLOSv, the latter representing the case in which the LOS path is
+ * blocked by other vehicles in the scenario. The document defines a probabilistic
+ * model to determine if the channel state is LOS or NLOSv, while the NLOS state
+ * is determined in a deterministic way based on the buildings deployed in the
+ * scenario. For this reason, this class makes use of an instance of
+ * BuildingsChannelConditionModel to determine if the LOS is obstructed by
+ * buildings or not.
+ */
+class ThreeGppV2vHighwayChannelConditionModel : public ThreeGppChannelConditionModel
+{
+public:
+ /**
+ * Get the type ID.
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor for the ThreeGppV2vHighwayChannelConditionModel class
+ */
+ ThreeGppV2vHighwayChannelConditionModel ();
+
+ /**
+ * Destructor for the ThreeGppV2vHighwayChannelConditionModel class
+ */
+ virtual ~ThreeGppV2vHighwayChannelConditionModel () override;
+
+private:
+ /**
+ * Compute the LOS probability as specified in Table Table 6.2-1 of 3GPP TR 37.885
+ * for the V2V Highway scenario.
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the LOS probability
+ */
+ virtual double ComputePlos (Ptr a, Ptr b) const override;
+
+ /**
+ * Compute the NLOS probability. It determines the presence of obstructions
+ * between the tx and the rx based on the buildings deployed in the scenario.
+ * It returns 1 if the LOS path is obstructed, 0 otherwise.
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the NLOS probability
+ */
+ virtual double ComputePnlos (Ptr a, Ptr b) const override;
+
+ /**
+ * \brief The callback which is hooked to a method to compute channel condition.
+ *
+ * This callback is implemented to make this model robust against the
+ * presence and absence of buildings in a highway scenario. If there are
+ * buildings in a scenario, this model will use
+ * \link BuildingsChannelConditionModel \endlink, which requires
+ * \link MobilityBuildingInfo \endlink aggregated to the nodes to compute
+ * LOS and NLOS. Otherwise, the callback is hooked to a local method
+ * \link GetChaCondWithNoBuildings \endlink
+ * , which construct the ChannelCondtion object and set the condition to
+ * outdoor to outdoor with LOS.
+ */
+ std::function (Ptr, Ptr) > ComputeChCond;
+
+ /**
+ * \brief Get the channel condition and redirect the callback
+ * \link ComputeChCond \endlink to \link GetChaCondWithBuildings \endlink
+ * or to \link GetChaCondWithNoBuildings \endlink depending on if there are
+ * buildings in the scenario or not.
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the the condition of the channel between \p a and \p b
+ */
+ Ptr GetChCondAndFixCallback (Ptr a, Ptr b);
+
+ /**
+ * \brief Get the channel condition between \p a and \p b
+ * using BuildingsChannelConditionModel.
+ *
+ * This method will be called for the scenarios with buildings
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the condition of the channel between \p a and \p b
+ */
+ Ptr GetChCondWithBuildings (Ptr a, Ptr b) const;
+
+ /**
+ * \brief Get the channel condition between \p a and \p b
+ *
+ * This method will be called for the scenarios without buildings
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the condition of the channel between \p a and \p b
+ */
+ Ptr GetChCondWithNoBuildings (Ptr a, Ptr b) const;
+
+ Ptr m_buildingsCcm; //!< used to determine the obstructions due to buildings
+};
+
+} // end ns3 namespace
+
+#endif /* THREE_GPP_V2V_CHANNEL_CONDITION_MODEL */
diff --git a/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc b/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc
new file mode 100644
index 000000000..9d1f726ba
--- /dev/null
+++ b/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc
@@ -0,0 +1,509 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ * Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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
+ */
+
+#include "ns3/abort.h"
+#include "ns3/test.h"
+#include "ns3/config.h"
+#include "ns3/buildings-channel-condition-model.h"
+#include "ns3/channel-condition-model.h"
+#include "ns3/three-gpp-v2v-channel-condition-model.h"
+#include "ns3/three-gpp-v2v-propagation-loss-model.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/buildings-module.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/uinteger.h"
+#include "ns3/boolean.h"
+#include "ns3/core-module.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("ThreeGppV2vChannelConditionModelsTest");
+
+/**
+ * Test case for the classes ThreeGppV2vUrbanChannelConditionModel,
+ * and ThreeGppV2vHighwayChannelConditionModel to test their code to
+ * deterministically determine NLOS state. The test checks if the
+ * channel condition is correctly determined when a building is deployed in the
+ * scenario. Methodology from buildings-channel-condition-model-test.cc is used.
+ */
+class ThreeGppV2vBuildingsChCondModelTestCase : public TestCase
+{
+public:
+ /**
+ * Constructor
+ */
+ ThreeGppV2vBuildingsChCondModelTestCase ();
+
+ /**
+ * Destructor
+ */
+ virtual ~ThreeGppV2vBuildingsChCondModelTestCase ();
+
+private:
+ /**
+ * Builds the simulation scenario and perform the tests
+ */
+ virtual void DoRun (void);
+
+ /**
+ * Struct containing the parameters for each test
+ */
+ typedef struct
+ {
+ Vector m_positionA; //!< the position of the first node
+ Vector m_positionB; //!< the position of the second node
+ ChannelCondition::LosConditionValue m_losCond; //!< the correct channel condition
+ TypeId m_typeId; //!< the type ID of the channel condition model to be used
+ } TestVector;
+
+ TestVectors m_testVectors; //!< array containg all the test vectors
+};
+
+ThreeGppV2vBuildingsChCondModelTestCase::ThreeGppV2vBuildingsChCondModelTestCase ()
+ : TestCase ("Test case for the ThreeGppV2vUrban and ThreeGppV2vHighway ChannelConditionModel with building"), m_testVectors ()
+{}
+
+ThreeGppV2vBuildingsChCondModelTestCase::~ThreeGppV2vBuildingsChCondModelTestCase ()
+{}
+
+void
+ThreeGppV2vBuildingsChCondModelTestCase::DoRun (void)
+{
+ RngSeedManager::SetSeed (1);
+ RngSeedManager::SetRun (1);
+
+ TestVector testVector;
+ //Add vectors for ThreeGppV2vUrbanChannelConditionModel
+ testVector.m_positionA = Vector (-5.0, 5.0, 1.5);
+ testVector.m_positionB = Vector (20.0, 5.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::NLOS;
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0.0, 11.0, 1.5);
+ testVector.m_positionB = Vector (4.0, 11.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::LOS;
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0.0, 11.0, 1.5);
+ testVector.m_positionB = Vector (1000.0, 11.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::NLOSv;
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ //Now add same vectors for ThreeGppV2vHighwayChannelConditionModel
+ testVector.m_positionA = Vector (-5.0, 5.0, 1.5);
+ testVector.m_positionB = Vector (20.0, 5.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::NLOS;
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0.0, 11.0, 1.5);
+ testVector.m_positionB = Vector (4.0, 11.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::LOS;
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0.0, 11.0, 1.5);
+ testVector.m_positionB = Vector (1000.0, 11.0, 1.5);
+ testVector.m_losCond = ChannelCondition::LosConditionValue::NLOSv;
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ // create the factory for the channel condition models
+ ObjectFactory condModelFactory;
+
+ // Deploy nodes and building and get the channel condition
+ NodeContainer nodes;
+ nodes.Create (2);
+
+ Ptr a = CreateObject ();
+ nodes.Get (0)->AggregateObject (a);
+
+ Ptr b = CreateObject ();
+ nodes.Get (1)->AggregateObject (b);
+
+ Ptr building = Create ();
+ building->SetNRoomsX (1);
+ building->SetNRoomsY (1);
+ building->SetNFloors (1);
+ building->SetBoundaries (Box (0.0, 10.0, 0.0, 10.0, 0.0, 5.0));
+
+ BuildingsHelper::Install (nodes);
+
+ for (uint32_t i = 0; i < m_testVectors.GetN (); ++i)
+ {
+ testVector = m_testVectors.Get (i);
+ condModelFactory.SetTypeId (testVector.m_typeId);
+ Ptr condModel = DynamicCast (condModelFactory.Create ());
+ condModel->AssignStreams (1);
+
+ a->SetPosition (testVector.m_positionA);
+ b->SetPosition (testVector.m_positionB);
+ Ptr buildingInfoA = a->GetObject ();
+ buildingInfoA->MakeConsistent (a);
+ Ptr buildingInfoB = b->GetObject ();
+ buildingInfoB->MakeConsistent (b);
+ Ptr cond;
+ cond = condModel->GetChannelCondition (a, b);
+
+ NS_LOG_DEBUG ("Got " << cond->GetLosCondition () << " expected condition " << testVector.m_losCond);
+ NS_TEST_ASSERT_MSG_EQ (cond->GetLosCondition (), testVector.m_losCond, "Got unexpected channel condition");
+ }
+
+ Simulator::Destroy ();
+}
+
+/**
+ * Test case for the 3GPP V2V Urban channel condition models (probabilistic
+ * model for LOS/NLOSv states). It determines the channel condition multiple times,
+ * estimates the LOS probability and compares it with the value given by the
+ * formulas in 3GPP TR 37.885, Table 6.2-1. Methodology from channel-condition-model-
+ * test-suite.cc is used.
+ */
+class ThreeGppV2vUrbanLosNlosvChCondModelTestCase : public TestCase
+{
+public:
+ /**
+ * Constructor
+ */
+ ThreeGppV2vUrbanLosNlosvChCondModelTestCase ();
+
+ /**
+ * Destructor
+ */
+ virtual ~ThreeGppV2vUrbanLosNlosvChCondModelTestCase ();
+
+private:
+ /**
+ * Builds the simulation scenario and perform the tests
+ */
+ virtual void DoRun (void);
+
+ /**
+ * Evaluates the channel condition between two nodes by calling the method
+ * GetChannelCondition on m_condModel. If the channel condition is LOS it
+ * increments m_numLos
+ * \param a the mobility model of the first node
+ * \param b the mobility model of the second node
+ */
+ void EvaluateChannelCondition (Ptr a, Ptr b);
+
+ /**
+ * Struct containing the parameters for each test
+ */
+ typedef struct
+ {
+ Vector m_positionA; //!< the position of the first node
+ Vector m_positionB; //!< the position of the second node
+ double m_pLos; //!< LOS probability
+ TypeId m_typeId; //!< the type ID of the channel condition model to be used
+ } TestVector;
+
+ TestVectors m_testVectors; //!< array containing all the test vectors
+ Ptr m_condModel; //!< the channel condition model
+ uint64_t m_numLos {0}; //!< the number of LOS occurrences
+ double m_tolerance; //!< tolerance
+};
+
+ThreeGppV2vUrbanLosNlosvChCondModelTestCase::ThreeGppV2vUrbanLosNlosvChCondModelTestCase ()
+ : TestCase ("Test case for the class ThreeGppV2vUrbanChannelConditionModel"),
+ m_testVectors (),
+ m_tolerance (2e-3)
+{}
+
+ThreeGppV2vUrbanLosNlosvChCondModelTestCase::~ThreeGppV2vUrbanLosNlosvChCondModelTestCase ()
+{}
+
+void
+ThreeGppV2vUrbanLosNlosvChCondModelTestCase::EvaluateChannelCondition (Ptr a, Ptr b)
+{
+ Ptr cond = m_condModel->GetChannelCondition (a, b);
+ if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::LOS)
+ {
+ m_numLos++;
+ }
+}
+
+void
+ThreeGppV2vUrbanLosNlosvChCondModelTestCase::DoRun (void)
+{
+ RngSeedManager::SetSeed (1);
+ RngSeedManager::SetRun (1);
+
+ // create the test vector
+ TestVector testVector;
+
+ // tests for the V2v Urban scenario
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (10, 0, 1.6);
+ testVector.m_pLos = std::min (1.0, 1.05 * exp (-0.0114 * 10.0));
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (100, 0, 1.6);
+ testVector.m_pLos = std::min (1.0, 1.05 * exp (-0.0114 * 100.0));
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (1000, 0, 1.6);
+ testVector.m_pLos = std::min (1.0, 1.05 * exp (-0.0114 * 1000.0));
+ testVector.m_typeId = ThreeGppV2vUrbanChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ // create the factory for the channel condition models
+ ObjectFactory condModelFactory;
+
+ // create the two nodes
+ NodeContainer nodes;
+ nodes.Create (2);
+
+ // create the mobility models
+ Ptr a = CreateObject ();
+ Ptr b = CreateObject ();
+
+ // aggregate the nodes and the mobility models
+ nodes.Get (0)->AggregateObject (a);
+ nodes.Get (1)->AggregateObject (b);
+
+ BuildingsHelper::Install (nodes);
+
+ // Get the channel condition multiple times and compute the LOS probability
+ uint32_t numberOfReps = 500000;
+ for (uint32_t i = 0; i < m_testVectors.GetN (); ++i)
+ {
+ testVector = m_testVectors.Get (i);
+
+ // set the distance between the two nodes
+ a->SetPosition (testVector.m_positionA);
+ b->SetPosition (testVector.m_positionB);
+ Ptr buildingInfoA = a->GetObject ();
+ buildingInfoA->MakeConsistent (a);
+ Ptr buildingInfoB = b->GetObject ();
+ buildingInfoB->MakeConsistent (b);
+
+ // create the channel condition model
+ condModelFactory.SetTypeId (testVector.m_typeId);
+ m_condModel = condModelFactory.Create ();
+ m_condModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (9)));
+ m_condModel->AssignStreams (1);
+
+ m_numLos = 0;
+ for (uint32_t j = 0; j < numberOfReps; j++)
+ {
+ Simulator::Schedule (MilliSeconds (10 * j), &ThreeGppV2vUrbanLosNlosvChCondModelTestCase::EvaluateChannelCondition, this, a, b);
+ }
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ double resultPlos = double (m_numLos) / double (numberOfReps);
+ NS_LOG_DEBUG (testVector.m_typeId << " a pos " << testVector.m_positionA << " b pos " << testVector.m_positionB << " numLos " << m_numLos << " numberOfReps " << numberOfReps << " resultPlos " << resultPlos << " ref " << testVector.m_pLos);
+ NS_TEST_EXPECT_MSG_EQ_TOL (resultPlos, testVector.m_pLos, m_tolerance, "Got unexpected LOS probability");
+ }
+}
+
+/**
+ * Test case for the 3GPP V2V Highway channel condition models (probabilistic
+ * model for LOS/NLOSv states). It determines the channel condition multiple times,
+ * estimates the LOS probability and compares it with the value given by the
+ * formulas in 3GPP TR 37.885, Table 6.2-1. Methodology from channel-condition-model-
+ * test-suite.cc is used.
+ */
+class ThreeGppV2vHighwayLosNlosvChCondModelTestCase : public TestCase
+{
+public:
+ /**
+ * Constructor
+ */
+ ThreeGppV2vHighwayLosNlosvChCondModelTestCase ();
+
+ /**
+ * Destructor
+ */
+ virtual ~ThreeGppV2vHighwayLosNlosvChCondModelTestCase ();
+
+private:
+ /**
+ * Builds the simulation scenario and perform the tests
+ */
+ virtual void DoRun (void);
+
+ /**
+ * Evaluates the channel condition between two nodes by calling the method
+ * GetChannelCondition on m_condModel. If the channel condition is LOS it
+ * increments m_numLos
+ * \param a the mobility model of the first node
+ * \param b the mobility model of the second node
+ */
+ void EvaluateChannelCondition (Ptr a, Ptr b);
+
+ /**
+ * Struct containing the parameters for each test
+ */
+ typedef struct
+ {
+ Vector m_positionA; //!< the position of the first node
+ Vector m_positionB; //!< the position of the second node
+ double m_pLos; //!< LOS probability
+ TypeId m_typeId; //!< the type ID of the channel condition model to be used
+ } TestVector;
+
+ TestVectors m_testVectors; //!< array containing all the test vectors
+ Ptr m_condModel; //!< the channel condition model
+ uint64_t m_numLos {0}; //!< the number of LOS occurrences
+ double m_tolerance; //!< tolerance
+};
+
+ThreeGppV2vHighwayLosNlosvChCondModelTestCase::ThreeGppV2vHighwayLosNlosvChCondModelTestCase ()
+ : TestCase ("Test case for the class ThreeGppV2vHighwayChannelConditionModel"),
+ m_testVectors (),
+ m_tolerance (2e-3)
+{}
+
+ThreeGppV2vHighwayLosNlosvChCondModelTestCase::~ThreeGppV2vHighwayLosNlosvChCondModelTestCase ()
+{}
+
+void
+ThreeGppV2vHighwayLosNlosvChCondModelTestCase::EvaluateChannelCondition (Ptr a, Ptr b)
+{
+ Ptr cond = m_condModel->GetChannelCondition (a, b);
+ if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::LOS)
+ {
+ m_numLos++;
+ }
+}
+
+void
+ThreeGppV2vHighwayLosNlosvChCondModelTestCase::DoRun (void)
+{
+ RngSeedManager::SetSeed (1);
+ RngSeedManager::SetRun (1);
+
+ // create the test vector
+ TestVector testVector;
+
+ // tests for the V2v Highway scenario
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (10, 0, 1.6);
+ testVector.m_pLos = std::min (1.0, 0.0000021013 * 10.0 * 10.0 - 0.002 * 10.0 + 1.0193);
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (100, 0, 1.6);
+ testVector.m_pLos = std::min (1.0, 0.0000021013 * 100.0 * 100.0 - 0.002 * 100.0 + 1.0193);
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ testVector.m_positionA = Vector (0, 0, 1.6);
+ testVector.m_positionB = Vector (1000, 0, 1.6);
+ testVector.m_pLos = std::max (0.0, 0.54 - 0.001 * (1000.0 - 475));
+ testVector.m_typeId = ThreeGppV2vHighwayChannelConditionModel::GetTypeId ();
+ m_testVectors.Add (testVector);
+
+ // create the factory for the channel condition models
+ ObjectFactory condModelFactory;
+
+ // create the two nodes
+ NodeContainer nodes;
+ nodes.Create (2);
+
+ // create the mobility models
+ Ptr a = CreateObject ();
+ Ptr b = CreateObject ();
+
+ // aggregate the nodes and the mobility models
+ nodes.Get (0)->AggregateObject (a);
+ nodes.Get (1)->AggregateObject (b);
+
+ BuildingsHelper::Install (nodes);
+
+ // Get the channel condition multiple times and compute the LOS probability
+ uint32_t numberOfReps = 500000;
+ for (uint32_t i = 0; i < m_testVectors.GetN (); ++i)
+ {
+ testVector = m_testVectors.Get (i);
+
+ // set the distance between the two nodes
+ a->SetPosition (testVector.m_positionA);
+ b->SetPosition (testVector.m_positionB);
+
+ // create the channel condition model
+ condModelFactory.SetTypeId (testVector.m_typeId);
+ m_condModel = condModelFactory.Create ();
+ m_condModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (9)));
+ m_condModel->AssignStreams (1);
+
+ m_numLos = 0;
+ for (uint32_t j = 0; j < numberOfReps; j++)
+ {
+ Simulator::Schedule (MilliSeconds (10 * j), &ThreeGppV2vHighwayLosNlosvChCondModelTestCase::EvaluateChannelCondition, this, a, b);
+ }
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ double resultPlos = static_cast (m_numLos) / static_cast (numberOfReps);
+ NS_LOG_DEBUG (testVector.m_typeId << " a pos " << testVector.m_positionA << " b pos " << testVector.m_positionB << " numLos " << m_numLos << " numberOfReps " << numberOfReps << " resultPlos " << resultPlos << " ref " << testVector.m_pLos);
+ NS_TEST_EXPECT_MSG_EQ_TOL (resultPlos, testVector.m_pLos, m_tolerance, "Got unexpected LOS probability");
+ }
+}
+
+
+/**
+ * Test suite for the 3GPP V2V channel condition model
+ *
+ * Note that, in 3GPP V2V scenarios, the channel condition model is
+ * determined based on a two step procedure: 1st) NLOS state is determined
+ * based on a deterministic model (using buildings), and 2nd) the LOS or NLOSv
+ * state is determined based on a probabilistic model (using 3GPP formulas), in
+ * case that the vehicles are not in NLOS condition.
+ *
+ * The test ThreeGppV2vBuildingsChCondModelTestCase checks the
+ * 1st step of the procedure, the deterministic one, using buildings for
+ * both \link ThreeGppV2vUrbanChannelConditionModel \endlink and
+ * \link ThreeGppV2vHighwayChannelConditionModel \endlink .
+ *
+ * The tests ThreeGppV2vUrbanLosNlosvChCondModelTestCase and
+ * ThreeGppV2vHighwayLosNlosvChCondModelTestCase check the
+ * 2nd step of the procedure, the probabilistic one, without buildings, for
+ * the V2V Urban and V2V Highway scenarios, respectively.
+ *
+ */
+class ThreeGppV2vChCondModelsTestSuite : public TestSuite
+{
+public:
+ ThreeGppV2vChCondModelsTestSuite ();
+};
+
+ThreeGppV2vChCondModelsTestSuite::ThreeGppV2vChCondModelsTestSuite ()
+ : TestSuite ("three-gpp-v2v-channel-condition-model", SYSTEM)
+{
+ AddTestCase (new ThreeGppV2vBuildingsChCondModelTestCase, TestCase::QUICK); // test for the deterministic procedure (NLOS vs LOS/NLOSv), based on buildings
+ AddTestCase (new ThreeGppV2vUrbanLosNlosvChCondModelTestCase, TestCase::QUICK); // test for the probabilistic procedure (LOS vs NLOSv), in V2V urban scenario
+ AddTestCase (new ThreeGppV2vHighwayLosNlosvChCondModelTestCase, TestCase::QUICK); // test for the probabilistic procedure (LOS vs NLOSv), in V2V highway scenario
+}
+
+static ThreeGppV2vChCondModelsTestSuite ThreeGppV2vChCondModelsTestSuite;
diff --git a/src/buildings/wscript b/src/buildings/wscript
index 7309429e8..5e63112a7 100644
--- a/src/buildings/wscript
+++ b/src/buildings/wscript
@@ -12,6 +12,7 @@ def build(bld):
'model/hybrid-buildings-propagation-loss-model.cc',
'model/oh-buildings-propagation-loss-model.cc',
'model/buildings-channel-condition-model.cc',
+ 'model/three-gpp-v2v-channel-condition-model.cc',
'helper/building-container.cc',
'helper/building-position-allocator.cc',
'helper/building-allocator.cc',
@@ -27,6 +28,7 @@ def build(bld):
'test/buildings-shadowing-test.cc',
'test/buildings-channel-condition-model-test.cc',
'test/outdoor-random-walk-test.cc',
+ 'test/three-gpp-v2v-channel-condition-model-test.cc',
]
# Tests encapsulating example programs should be listed here
@@ -46,6 +48,7 @@ def build(bld):
'model/hybrid-buildings-propagation-loss-model.h',
'model/oh-buildings-propagation-loss-model.h',
'model/buildings-channel-condition-model.h',
+ 'model/three-gpp-v2v-channel-condition-model.h',
'helper/building-container.h',
'helper/building-allocator.h',
'helper/building-position-allocator.h',
diff --git a/src/propagation/doc/propagation.rst b/src/propagation/doc/propagation.rst
index 3342ac76d..ac6195a2a 100644
--- a/src/propagation/doc/propagation.rst
+++ b/src/propagation/doc/propagation.rst
@@ -6,8 +6,8 @@
Propagation
-----------
-The |ns3| propagation module defines two generic interfaces, namely :cpp:class:`PropagationLossModel`
-and :cpp:class:`PropagationDelayModel`, for the modeling of respectively propagation loss and propagation delay.
+The |ns3| ``propagation`` module defines two generic interfaces, namely :cpp:class:`PropagationLossModel`
+and :cpp:class:`PropagationDelayModel`, to model respectively the propagation loss and the propagation delay.
PropagationLossModel
********************
@@ -613,8 +613,8 @@ channel condition model related to the same scenario is set (e.g., by default,
:cpp:class:`ThreeGppRmaPropagationLossModel` is paired with
:cpp:class:`ThreeGppRmaChannelConditionModel`), but it can be configured using
the method SetChannelConditionModel. The channel condition models are stored inside the
-propagation module, for a limitation of the current spectrum API and to avoid
-a circular dependency between the spectrum and the propagation modules. Please
+``propagation`` module, for a limitation of the current spectrum API and to avoid
+a circular dependency between the spectrum and the ``propagation`` modules. Please
note that it is necessary to install at least one :cpp:class:`ChannelConditionModel` when
using any :cpp:class:`ThreeGppPropagationLossModel` subclass. Please look below for more
information about the Channel Condition models.
@@ -802,6 +802,174 @@ The propagation delay is totally random, and it changes each time the model is c
All the packets (even those between two fixed nodes) experience a random delay.
As a consequence, the packets order is not preserved.
+Models for vehicular environments
+*********************************
+
+The 3GPP TR 37.885 [37885]_ specifications extends the channel modeling framework
+described in TR 38.901 [38901]_ to simulate wireless channels in vehicular environments.
+The extended framework supports frequencies between 0.5 to 100 GHz and provides
+the possibility to simulate urban and highway propagation environments.
+To do so, new propagation loss and channel condition models, as well as new
+parameters for the fast fading model, are provided.
+
+.. _sec-3gpp-v2v-ch-cond:
+
+Vehicular channel condition models
+==================================
+
+To properly capture channel dynamics in vehicular environments, three different
+channel conditions have been identified:
+ * LOS (Line Of Sight): represents the case in which the direct path between
+ the transmitter and the receiver is not blocked
+ * NLOSv (Non Line Of Sight vehicle): when the direct path
+ between the transmitter and the receiver is blocked by a vehicle
+ * NLOS (Non Line Of Sight): when the direct path is blocked by a building
+
+TR 37.885 includes two models that can be used to determine the condition of
+the wireless channel between a pair of nodes, the first for urban and the second
+for highway environments.
+Each model includes both a deterministic and a stochastic part, and works as
+follows.
+ 1. The model determines the presence of buildings obstructing the direct path
+ between the communicating nodes. This is done in a deterministic way, looking at
+ the possible interceptions between the direct path and the buildings.
+ If the path is obstructed, the channel condition is set to NLOS.
+ 2. If not, the model determines the presence of vehicles obstructing the
+ direct path. This is done using a probabilistic model, which is specific
+ for the scenario of interest. If the path is obstructed, the channel
+ condition is set to NLOSv, otherwise is set to LOS.
+
+These models have been implemented by extending the interface
+:cpp:class:`ChannelConditionModel` with the following classes. They have been included in
+the ``building`` module, because they make use of :cpp:class:`Buildings` objects to determine
+the presence of obstructions caused by buildings.
+ * :cpp:class:`ThreeGppV2vUrbanChannelConditionModel`: implements the model
+ described in Table 6.2-1 of TR 37.885 for the urban scenario.
+ * :cpp:class:`ThreeGppV2vHighwayChannelConditionModel`: implements the model
+ described in Table 6.2-1 of TR 37.885 for the highway scenario.
+These models rely on :cpp:class:`Buildings` objects to determine the presence
+of obstructing buildings. When considering large scenarios with a large number of
+buildings, this process may become computationally demanding and dramatically
+increase the simulation time.
+To solve this problem, we implemented two fully-probabilistic models
+that can be used as an alternative to the ones included in TR 37.885.
+These models are based on the work carried out by M. Boban et al. [Boban2016Modeling]_,
+which derived a statistical representation of the three channel conditions,
+With the fully-probabilistic models there is no need to determine the presence of blocking
+buildings in a deterministic way, and therefore the computational effort is
+reduced.
+To determine the channel condition, these models account for the propagation
+environment, i.e., urban or highway, as well as for the density of vehicles in the
+scenario, which can be high, medium, or low.
+
+The classes implementing the fully-probabilistic models are:
+ * :cpp:class:`ProbabilisticV2vUrbanChannelConditionModel`: implements the model
+ described in [Boban2016Modeling]_ for the urban scenario.
+ * :cpp:class:`ProbabilisticV2vHighwayChannelConditionModel`: implements the model
+ described in [Boban2016Modeling]_ for the highway scenario.
+Both the classes own the attribute "Density", which can be used to select the
+proper value depending on the scenario that have to be simulated.
+Differently from the hybrid models described above, these classes have been
+included in the ``propagation`` module, since they do not have any dependency on the
+``building`` module.
+
+**NOTE:** Both the hybrid and the fully-probabilistic models supports the
+modeling of outdoor scenarios, no support is provided for the modeling of
+indoor scenarios.
+
+Vehicular propagation loss models
+=================================
+
+The propagation models described in TR 37.885 determines the attenuation caused
+by path loss and shadowing by considering the propagation environment and the
+channel condition.
+
+These models have been implemented by extending the interface
+:cpp:class:`ThreeGppPropagationLossModel` with the following classes, which
+are part of the ``propagation`` module:
+ * :cpp:class:`ThreeGppV2vUrbanPropagationLossModel`: implements the models
+ defined in Table 6.2.1-1 of TR 37.885 for the urban scenario.
+ * :cpp:class:`ThreeGppV2vHighwayPropagationLossModel`: implements the models
+ defined in Table 6.2.1-1 of TR 37.885 for the highway scenario.
+As for all the classes extending the interface :cpp:class:`ThreeGppPropagationLossModel`,
+they have to be paired with an instance of the class :cpp:class:`ChannelConditionModel`
+which is used to determine the channel condition.
+This is done by setting the attribute :cpp:class:`ChannelConditionModel`.
+To build the channel modeling framework described in TR 37.885,
+:cpp:class:`ThreeGppV2vUrbanChannelConditionModel` or
+:cpp:class:`ThreeGppV2vHighwayChannelConditionModel` should be used, but users
+are allowed to test any other combination.
+
+.. _sec-3gpp-v2v-ff:
+
+Vehicular fast fading model
+===========================
+
+The fast fading model described in Sec. 6.2.3 of TR 37.885 is based on the one
+specified in TR 38.901, whose implementation is provided in the ``spectrum`` module
+(see the :ref:`spectrum module documentation `).
+This model is general and includes different parameters which can
+be tuned to simulate multiple propagation environments.
+To better model the channel dynamics in vehicular environments, TR 37.885
+provides new sets of values for these parameters, specific for
+vehicle-to-vehicle transmissions in urban and highway scenarios.
+To select the parameters for vehicular scenarios, it is necessary to set
+the attribute "Scenario" of the class :cpp:class:`ThreeGppChannelModel` using the value
+"V2V-Urban" or "V2V-Highway".
+
+Additionally, TR 37.885 specifies a new equation to compute the Doppler component,
+which accounts for the mobility of both nodes, as well as scattering
+from the environment.
+In particular, the scattering effect is considered by deviating the Doppler
+frequency by a random value, whose distribution depends on the parameter :math:`v_{scatt}`.
+TR 37.885 specifies that :math:`v_{scatt}` should be set to the maximum speed of the
+vehicles in the layout and, if :math:`v_{scatt} = 0`, the scattering effect is not considered.
+The Doppler equation is implemented in the class :cpp:class:`ThreeGppSpectrumPropagationLossModel`.
+By means of the attribute "vScatt", it is possible to adjust the value of
+:math:`v_{scatt} = 0` (by default, the value is set to 0).
+
+Example
+=======
+
+We implemented the example ``three-gpp-v2v-channel-example.cc`` which shows how to
+configure the different classes to simulate wireless propagation in vehicular
+scenarios, it can be found in the folder ``examples/channel-models``.
+
+We considered two communicating vehicles moving within the scenario, and
+computed the SNR experienced during the entire simulation, with a time
+resolution of 10 ms.
+The vehicles are equipped with 2x2 antenna arrays modeled using the
+:ref:`3GPP antenna model `.
+The bearing and the downtilt angles are properly configured and the
+optimal beamforming vectors are computed at the beginning of the simulation.
+
+The simulation script accepts the following command line parameters:
+ * *frequency*: the operating frequency in Hz
+ * *txPow*: the transmission power in dBm
+ * *noiseFigure*: the noise figure in dB
+ * *scenario*: the simulation scenario, "V2V-Urban" or "V2V-Highway"
+
+The "V2V-Urban" scenario simulates urban environment with a rectangular grid of
+buildings. The vehicles moves with a waypoint mobility model. They start from
+the same position and travel in the same direction, along the main street.
+The first vehicle moves at 60 km/h and the second at 30 km/h.
+At a certain point, the first vehicle turns left while the second continues on
+the main street.
+
+The "V2V-Highway" scenario simulates an highway environment in which the
+two vehicles travel on the same lane, in the same direction, and keep a safety
+distance of 20 m. They maintain a constant speed of 140 km/h.
+
+The example generates the output file ``example-output.txt``. Each row of the
+file is organized as follows:
+
+``Time[s] TxPosX[m] TxPosY[m] RxPosX[m] RxPosY[m] ChannelState SNR[dB] Pathloss[dB]``
+
+We also provide the bash script ``three-gpp-v2v-channel-example.sh`` which reads the
+output file and generates two figures:
+ 1. map.gif, a GIF representing the simulation scenario and vehicle mobility;
+ 2. snr.png, which represents the behavior of the SNR.
+
References
**********
@@ -820,3 +988,9 @@ References
in Proc. of the 8th International Symposium on Antennas, Propagation and EM Theory (ISAPE), Kunming, China, Nov 2008.
.. [38901] 3GPP. 2018. TR 38.901, Study on channel model for frequencies from 0.5 to 100 GHz, V15.0.0. (2018-06).
+
+.. [37885] 3GPP. 2019. TR 37.885, Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR, V15.3.0. (2019-06).
+
+.. [Boban2016Modeling] M. Boban, X. Gong, and W. Xu, “Modeling the evolution
+ of line-of-sight blockage for V2V channels,” in IEEE 84th Vehicular Technology
+ Conference (VTC-Fall), 2016.
diff --git a/src/propagation/model/channel-condition-model.cc b/src/propagation/model/channel-condition-model.cc
index 676263bf8..efc311815 100644
--- a/src/propagation/model/channel-condition-model.cc
+++ b/src/propagation/model/channel-condition-model.cc
@@ -24,6 +24,7 @@
#include
#include "ns3/node.h"
#include "ns3/simulator.h"
+#include "ns3/string.h"
namespace ns3 {
@@ -42,12 +43,18 @@ ChannelCondition::GetTypeId (void)
}
ChannelCondition::ChannelCondition ()
+ : m_losCondition (LosConditionValue::LC_ND),
+ m_o2iCondition (O2iConditionValue::O2I_ND)
+{}
+
+ChannelCondition::ChannelCondition (ChannelCondition::LosConditionValue losCondition, ChannelCondition::O2iConditionValue o2iCondition)
{
+ m_losCondition = losCondition;
+ m_o2iCondition = o2iCondition;
}
ChannelCondition::~ChannelCondition ()
-{
-}
+{}
ChannelCondition::LosConditionValue
ChannelCondition::GetLosCondition () const
@@ -61,6 +68,78 @@ ChannelCondition::SetLosCondition (LosConditionValue cond)
m_losCondition = cond;
}
+ChannelCondition::O2iConditionValue
+ChannelCondition::GetO2iCondition () const
+{
+ return m_o2iCondition;
+}
+
+void
+ChannelCondition::SetO2iCondition (O2iConditionValue o2iCondition)
+{
+ m_o2iCondition = o2iCondition;
+}
+
+bool
+ChannelCondition::IsLos () const
+{
+ return (m_losCondition == ChannelCondition::LOS);
+}
+
+bool
+ChannelCondition::IsNlos () const
+{
+ return (m_losCondition == ChannelCondition::NLOS);
+}
+
+bool
+ChannelCondition::IsNlosv () const
+{
+ return (m_losCondition == ChannelCondition::NLOSv);
+}
+
+bool
+ChannelCondition::IsO2i () const
+{
+ return (m_o2iCondition == ChannelCondition::O2I);
+}
+
+bool
+ChannelCondition::IsO2o () const
+{
+ return (m_o2iCondition == ChannelCondition::O2O);
+}
+
+bool
+ChannelCondition::IsI2i () const
+{
+ return (m_o2iCondition == ChannelCondition::I2I);
+}
+
+bool
+ChannelCondition::IsEqual (Ptr otherCondition) const
+{
+ return (m_o2iCondition == otherCondition->GetO2iCondition ()
+ && m_losCondition == otherCondition->GetLosCondition ());
+}
+
+std::ostream& operator<< (std::ostream& os, ChannelCondition::LosConditionValue cond)
+{
+ if (cond == ChannelCondition::LosConditionValue::LOS)
+ {
+ os << "LOS";
+ }
+ else if (cond == ChannelCondition::LosConditionValue::NLOS)
+ {
+ os << "NLOS";
+ }
+ else if (cond == ChannelCondition::LosConditionValue::NLOSv)
+ {
+ os << "NLOSv";
+ }
+
+ return os;
+}
// ------------------------------------------------------------------------- //
NS_OBJECT_ENSURE_REGISTERED (ChannelConditionModel);
@@ -76,12 +155,10 @@ ChannelConditionModel::GetTypeId (void)
}
ChannelConditionModel::ChannelConditionModel ()
-{
-}
+{}
ChannelConditionModel::~ChannelConditionModel ()
-{
-}
+{}
// ------------------------------------------------------------------------- //
@@ -99,12 +176,10 @@ AlwaysLosChannelConditionModel::GetTypeId (void)
}
AlwaysLosChannelConditionModel::AlwaysLosChannelConditionModel ()
-{
-}
+{}
AlwaysLosChannelConditionModel::~AlwaysLosChannelConditionModel ()
-{
-}
+{}
Ptr
AlwaysLosChannelConditionModel::GetChannelCondition (Ptr a,
@@ -113,8 +188,7 @@ AlwaysLosChannelConditionModel::GetChannelCondition (Ptr a,
NS_UNUSED (a);
NS_UNUSED (b);
- Ptr c = CreateObject ();
- c->SetLosCondition (ChannelCondition::LOS);
+ Ptr c = CreateObject (ChannelCondition::LOS);
return c;
}
@@ -141,12 +215,10 @@ NeverLosChannelConditionModel::GetTypeId (void)
}
NeverLosChannelConditionModel::NeverLosChannelConditionModel ()
-{
-}
+{}
NeverLosChannelConditionModel::~NeverLosChannelConditionModel ()
-{
-}
+{}
Ptr
NeverLosChannelConditionModel::GetChannelCondition (Ptr a,
@@ -155,8 +227,7 @@ NeverLosChannelConditionModel::GetChannelCondition (Ptr a,
NS_UNUSED (a);
NS_UNUSED (b);
- Ptr c = CreateObject ();
- c->SetLosCondition (ChannelCondition::NLOS);
+ Ptr c = CreateObject (ChannelCondition::NLOS);
return c;
}
@@ -169,6 +240,43 @@ NeverLosChannelConditionModel::AssignStreams (int64_t stream)
// ------------------------------------------------------------------------- //
+NS_OBJECT_ENSURE_REGISTERED (NeverLosVehicleChannelConditionModel);
+
+TypeId
+NeverLosVehicleChannelConditionModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::NeverLosVehicleChannelConditionModel")
+ .SetParent ()
+ .SetGroupName ("Propagation")
+ .AddConstructor ()
+ ;
+ return tid;
+}
+
+NeverLosVehicleChannelConditionModel::NeverLosVehicleChannelConditionModel ()
+{}
+
+NeverLosVehicleChannelConditionModel::~NeverLosVehicleChannelConditionModel ()
+{}
+
+Ptr
+NeverLosVehicleChannelConditionModel::GetChannelCondition (Ptr /* a */,
+ Ptr /* b */) const
+{
+
+ Ptr c = CreateObject (ChannelCondition::NLOSv);
+
+ return c;
+}
+
+int64_t
+NeverLosVehicleChannelConditionModel::AssignStreams (int64_t /* stream */)
+{
+ return 0;
+}
+
+// ------------------------------------------------------------------------- //
+
NS_OBJECT_ENSURE_REGISTERED (ThreeGppChannelConditionModel);
TypeId
@@ -194,8 +302,7 @@ ThreeGppChannelConditionModel::ThreeGppChannelConditionModel ()
}
ThreeGppChannelConditionModel::~ThreeGppChannelConditionModel ()
-{
-}
+{}
void ThreeGppChannelConditionModel::DoDispose ()
{
@@ -239,38 +346,63 @@ ThreeGppChannelConditionModel::GetChannelCondition (Ptr a,
// generate a new channel condition
if (notFound || update)
{
- // compute the LOS probability (see 3GPP TR 38.901, Sec. 7.4.2)
- double pLos = ComputePlos (a, b);
-
- // draw a random value
- double pRef = m_uniformVar->GetValue ();
-
- // get the channel condition
- cond = CreateObject ();
- if (pRef <= pLos)
- {
- // LOS
- cond->SetLosCondition (ChannelCondition::LosConditionValue::LOS);
- }
- else
- {
- // NLOS
- cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOS);
- }
-
- {
- // store the channel condition in m_channelConditionMap, used as cache.
- // For this reason you see a const_cast.
- Item mapItem;
- mapItem.m_condition = cond;
- mapItem.m_generatedTime = Simulator::Now ();
- const_cast (this)->m_channelConditionMap [key] = mapItem;
- }
+ cond = ComputeChannelCondition (a, b);
+ // store the channel condition in m_channelConditionMap, used as cache.
+ // For this reason you see a const_cast.
+ Item mapItem;
+ mapItem.m_condition = cond;
+ mapItem.m_generatedTime = Simulator::Now ();
+ const_cast (this)->m_channelConditionMap [key] = mapItem;
}
return cond;
}
+Ptr
+ThreeGppChannelConditionModel::ComputeChannelCondition (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this << a << b);
+ Ptr cond = CreateObject ();
+
+ // compute the LOS probability
+ double pLos = ComputePlos (a, b);
+ double pNlos = ComputePnlos (a, b);
+
+ // draw a random value
+ double pRef = m_uniformVar->GetValue ();
+
+ NS_LOG_DEBUG ("pRef " << pRef << " pLos " << pLos << " pNlos " << pNlos);
+
+ // get the channel condition
+ if (pRef <= pLos)
+ {
+ // LOS
+ cond->SetLosCondition (ChannelCondition::LosConditionValue::LOS);
+ }
+ else if (pRef <= pLos + pNlos)
+ {
+ // NLOS
+ cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOS);
+ }
+ else
+ {
+ // NLOSv (added to support vehicular scenarios)
+ cond->SetLosCondition (ChannelCondition::LosConditionValue::NLOSv);
+ }
+
+ return cond;
+}
+
+double
+ThreeGppChannelConditionModel::ComputePnlos (Ptr a,
+ Ptr b) const
+{
+ NS_LOG_FUNCTION (this << a << b);
+ // by default returns 1 - PLOS
+ return (1 - ComputePlos (a, b));
+}
+
int64_t
ThreeGppChannelConditionModel::AssignStreams (int64_t stream)
{
@@ -319,12 +451,10 @@ ThreeGppRmaChannelConditionModel::GetTypeId (void)
ThreeGppRmaChannelConditionModel::ThreeGppRmaChannelConditionModel ()
: ThreeGppChannelConditionModel ()
-{
-}
+{}
ThreeGppRmaChannelConditionModel::~ThreeGppRmaChannelConditionModel ()
-{
-}
+{}
double
ThreeGppRmaChannelConditionModel::ComputePlos (Ptr a,
@@ -367,12 +497,10 @@ ThreeGppUmaChannelConditionModel::GetTypeId (void)
ThreeGppUmaChannelConditionModel::ThreeGppUmaChannelConditionModel ()
: ThreeGppChannelConditionModel ()
-{
-}
+{}
ThreeGppUmaChannelConditionModel::~ThreeGppUmaChannelConditionModel ()
-{
-}
+{}
double
ThreeGppUmaChannelConditionModel::ComputePlos (Ptr a,
@@ -437,12 +565,10 @@ ThreeGppUmiStreetCanyonChannelConditionModel::GetTypeId (void)
ThreeGppUmiStreetCanyonChannelConditionModel::ThreeGppUmiStreetCanyonChannelConditionModel ()
: ThreeGppChannelConditionModel ()
-{
-}
+{}
ThreeGppUmiStreetCanyonChannelConditionModel::~ThreeGppUmiStreetCanyonChannelConditionModel ()
-{
-}
+{}
double
ThreeGppUmiStreetCanyonChannelConditionModel::ComputePlos (Ptr a,
@@ -492,12 +618,10 @@ ThreeGppIndoorMixedOfficeChannelConditionModel::GetTypeId (void)
ThreeGppIndoorMixedOfficeChannelConditionModel::ThreeGppIndoorMixedOfficeChannelConditionModel ()
: ThreeGppChannelConditionModel ()
-{
-}
+{}
ThreeGppIndoorMixedOfficeChannelConditionModel::~ThreeGppIndoorMixedOfficeChannelConditionModel ()
-{
-}
+{}
double
ThreeGppIndoorMixedOfficeChannelConditionModel::ComputePlos (Ptr a,
@@ -551,12 +675,10 @@ ThreeGppIndoorOpenOfficeChannelConditionModel::GetTypeId (void)
ThreeGppIndoorOpenOfficeChannelConditionModel::ThreeGppIndoorOpenOfficeChannelConditionModel ()
: ThreeGppChannelConditionModel ()
-{
-}
+{}
ThreeGppIndoorOpenOfficeChannelConditionModel::~ThreeGppIndoorOpenOfficeChannelConditionModel ()
-{
-}
+{}
double
ThreeGppIndoorOpenOfficeChannelConditionModel::ComputePlos (Ptr a,
diff --git a/src/propagation/model/channel-condition-model.h b/src/propagation/model/channel-condition-model.h
index 88a735638..fade2fb95 100644
--- a/src/propagation/model/channel-condition-model.h
+++ b/src/propagation/model/channel-condition-model.h
@@ -48,7 +48,20 @@ public:
enum LosConditionValue
{
LOS, //!< Line of Sight
- NLOS //!< Non Line of Sight
+ NLOS, //!< Non Line of Sight
+ NLOSv, //!< Non Line of Sight due to a vehicle
+ LC_ND //!< Los condition not defined
+ };
+
+ /**
+ * Possible values for Outdoor to Indoor condition.
+ */
+ enum O2iConditionValue
+ {
+ O2O, //!< Outdoor to Outdoor
+ O2I, //!< Outdoor to Indoor
+ I2I, //!< Indoor to Indoor
+ O2I_ND //!< Outdoor to Indoor condition not defined
};
/**
@@ -62,6 +75,13 @@ public:
* Constructor for the ChannelCondition class
*/
ChannelCondition ();
+
+ /**
+ * Constructor for the ChannelCondition class
+ * \param losCondition the LOS condition value
+ * \param o2iCondition the O2I condition value (by default is set to O2O)
+ */
+ ChannelCondition (LosConditionValue losCondition, O2iConditionValue o2iCondition = O2O);
/**
* Destructor for the ChannelCondition class
@@ -83,9 +103,89 @@ public:
* \param the LosConditionValue
*/
void SetLosCondition (LosConditionValue losCondition);
+
+ /**
+ * Get the O2iConditionValue contaning the information about the O2I
+ * state of the channel
+ *
+ * \return the O2iConditionValue
+ */
+ O2iConditionValue GetO2iCondition () const;
+
+ /**
+ * Set the O2iConditionValue contaning the information about the O2I
+ * state of the channel
+ *
+ * \param o2iCondition the O2iConditionValue
+ */
+ void SetO2iCondition (O2iConditionValue o2iCondition);
+
+ /**
+ * Return true if the channel condition is LOS
+ *
+ * \return true if the channel condition is LOS
+ */
+ bool IsLos () const;
+
+ /**
+ * Return true if the channel condition is NLOS
+ *
+ * It does not consider the case in which the LOS path is obstructed by a
+ * vehicle. This case is represented as a separate channel condition (NLOSv),
+ * use the method IsNlosv instead.
+ *
+ * \return true if the channel condition is NLOS
+ */
+ bool IsNlos () const;
+
+ /**
+ * Return true if the channel condition is NLOSv
+ *
+ * \return true if the channel condition is NLOSv
+ */
+ bool IsNlosv () const;
+
+ /**
+ * Return true if the channel is outdoor-to-indoor
+ *
+ * \return true if the channel is outdoor-to-indoor
+ */
+ bool IsO2i () const;
+
+ /**
+ * Return true if the channel is outdoor-to-outdoor
+ *
+ * \return true if the channel is outdoor-to-outdoor
+ */
+ bool IsO2o () const;
+
+ /**
+ * Return true if the channel is indoor-to-indoor
+ *
+ * \return true if the channel is indoor-to-indoor
+ */
+ bool IsI2i () const;
+
+ /**
+ * Return true if this instance is equivalent to the one passed as argument
+ *
+ * \param otherCondition the other instance to compare with this instance
+ * \return true if this instance is equivalent to the one passed as argument
+ */
+ bool IsEqual (Ptr otherCondition) const;
private:
- LosConditionValue m_losCondition; //!< contains the information about the LOS/NLOS state of the channel
+ LosConditionValue m_losCondition; //!< contains the information about the LOS state of the channel
+ O2iConditionValue m_o2iCondition; //!< contains the information about the O2I state of the channel
+
+ /**
+ * Prints a LosConditionValue to output
+ * \param os the output stream
+ * \param cond the LosConditionValue
+ *
+ * \return a reference to the output stream
+ */
+ friend std::ostream& operator<< (std::ostream& os, LosConditionValue cond);
};
@@ -133,7 +233,7 @@ public:
* 'stream'. Return the number of streams (possibly zero) that
* have been assigned.
*
- * \param stream
+ * \param stream the offset used to set the stream numbers
* \return the number of stream indices assigned by this model
*/
virtual int64_t AssignStreams (int64_t stream) = 0;
@@ -170,12 +270,12 @@ public:
static TypeId GetTypeId (void);
/**
- * Constructor for the ChannelConditionModel class
+ * Constructor
*/
AlwaysLosChannelConditionModel ();
/**
- * Destructor for the ChannelConditionModel class
+ * Destructor
*/
virtual ~AlwaysLosChannelConditionModel ();
@@ -199,7 +299,7 @@ public:
* \brief Copy constructor
*
* Defined and unimplemented to avoid misuse
- * \returns
+ * \returns a copy of the object
*/
AlwaysLosChannelConditionModel &operator = (const AlwaysLosChannelConditionModel &) = delete;
@@ -209,7 +309,7 @@ public:
* 'stream'. Return the number of streams (possibly zero) that
* have been assigned.
*
- * \param stream
+ * \param stream the offset used to set the stream numbers
* \return the number of stream indices assigned by this model
*/
virtual int64_t AssignStreams (int64_t stream) override;
@@ -231,12 +331,12 @@ public:
static TypeId GetTypeId (void);
/**
- * Constructor for the ChannelConditionModel class
+ * Constructor
*/
NeverLosChannelConditionModel ();
/**
- * Destructor for the ChannelConditionModel class
+ * Destructor
*/
virtual ~NeverLosChannelConditionModel ();
@@ -260,7 +360,7 @@ public:
* \brief Copy constructor
*
* Defined and unimplemented to avoid misuse
- * \returns
+ * \returns a copy of the object
*/
NeverLosChannelConditionModel &operator = (const NeverLosChannelConditionModel &) = delete;
@@ -270,7 +370,68 @@ public:
* 'stream'. Return the number of streams (possibly zero) that
* have been assigned.
*
- * \param stream
+ * \param stream the offset used to set the stream numbers
+ * \return the number of stream indices assigned by this model
+ */
+ virtual int64_t AssignStreams (int64_t stream) override;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Models a never in-LoS condition model caused by a blocking vehicle
+ */
+class NeverLosVehicleChannelConditionModel : public ChannelConditionModel
+{
+public:
+ /**
+ * Get the type ID.
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor
+ */
+ NeverLosVehicleChannelConditionModel ();
+
+ /**
+ * Destructor
+ */
+ virtual ~NeverLosVehicleChannelConditionModel ();
+
+ /**
+ * Computes the condition of the channel between a and b, that will be always NLOSv
+ *
+ * \param a mobility model
+ * \param b mobility model
+ * \return the condition of the channel between a and b, that will be always NLOSv
+ */
+ virtual Ptr GetChannelCondition (Ptr a, Ptr b) const override;
+
+ /**
+ * \brief Copy constructor
+ *
+ * Defined and unimplemented to avoid misuse
+ */
+ NeverLosVehicleChannelConditionModel (const NeverLosVehicleChannelConditionModel&) = delete;
+
+ /**
+ * \brief Copy constructor
+ *
+ * Defined and unimplemented to avoid misuse
+ * \returns a copy of the object
+ */
+ NeverLosVehicleChannelConditionModel &operator = (const NeverLosVehicleChannelConditionModel &) = delete;
+
+ /**
+ * If this model uses objects of type RandomVariableStream,
+ * set the stream numbers to the integers starting with the offset
+ * 'stream'. Return the number of streams (possibly zero) that
+ * have been assigned.
+ *
+ * \param stream the offset used to set the stream numbers
* \return the number of stream indices assigned by this model
*/
virtual int64_t AssignStreams (int64_t stream) override;
@@ -305,9 +466,9 @@ public:
/**
* \brief Retrieve the condition of the channel between a and b.
*
- * If the channel condition does not exists, the method creates it and
- * store it in a local cache, that will be updated following the "UpdatePeriod"
- * parameter.
+ * If the channel condition does not exists, the method computes it by calling
+ * ComputeChannelCondition and stores it in a local cache, that will be updated
+ * following the "UpdatePeriod" parameter.
*
* \param a mobility model
* \param b mobility model
@@ -321,7 +482,7 @@ public:
* 'stream'. Return the number of streams (possibly zero) that
* have been assigned.
*
- * \param stream
+ * \param stream the offset used to set the stream numbers
* \return the number of stream indices assigned by this model
*/
virtual int64_t AssignStreams (int64_t stream) override;
@@ -329,6 +490,17 @@ public:
protected:
virtual void DoDispose () override;
+ /**
+ * Determine the density of vehicles in a V2V scenario.
+ */
+ enum VehicleDensity
+ {
+ LOW,
+ MEDIUM,
+ HIGH,
+ INVALID
+ };
+
/**
* \brief Computes the 2D distance between two 3D vectors
* \param a the first 3D vector
@@ -336,16 +508,37 @@ protected:
* \return the 2D distance between a and b
*/
static double Calculate2dDistance (const Vector &a, const Vector &b);
+
+ Ptr m_uniformVar; //!< uniform random variable
private:
/**
- * Compute the LOS probability as specified in Table 7.4.2-1 of 3GPP TR 38.901.
+ * This method computes the channel condition based on a probabilistic model
+ * that is specific for the scenario of interest
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the channel condition
+ */
+ Ptr ComputeChannelCondition (Ptr a, Ptr b) const;
+
+ /**
+ * Compute the LOS probability.
*
* \param a tx mobility model
* \param b rx mobility model
* \return the LOS probability
*/
virtual double ComputePlos (Ptr a, Ptr b) const = 0;
+
+ /**
+ * Compute the NLOS probability. By default returns 1 - PLOS
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the LOS probability
+ */
+ virtual double ComputePnlos (Ptr a, Ptr b) const;
/**
* \brief Returns a unique and reciprocal key for the channel between a and b.
@@ -366,7 +559,6 @@ private:
std::unordered_map m_channelConditionMap; //!< map to store the channel conditions
Time m_updatePeriod; //!< the update period for the channel condition
- Ptr m_uniformVar; //!< uniform random variable
};
/**
diff --git a/src/propagation/model/probabilistic-v2v-channel-condition-model.cc b/src/propagation/model/probabilistic-v2v-channel-condition-model.cc
new file mode 100644
index 000000000..b93f89d6d
--- /dev/null
+++ b/src/propagation/model/probabilistic-v2v-channel-condition-model.cc
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * 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
+ */
+
+#include "probabilistic-v2v-channel-condition-model.h"
+#include "ns3/log.h"
+#include "ns3/string.h"
+#include "ns3/mobility-model.h"
+#include "ns3/enum.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("ProbabilisticV2vChannelConditionModel");
+
+NS_OBJECT_ENSURE_REGISTERED (ProbabilisticV2vUrbanChannelConditionModel);
+
+TypeId
+ProbabilisticV2vUrbanChannelConditionModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ProbabilisticV2vUrbanChannelConditionModel")
+ .SetParent ()
+ .SetGroupName ("Propagation")
+ .AddConstructor ()
+ .AddAttribute ("Density", "Specifies the density of the vehicles in the scenario."
+ "It can be set to Low, Medium or High.",
+ EnumValue (VehicleDensity::LOW),
+ MakeEnumAccessor (&ProbabilisticV2vUrbanChannelConditionModel::m_densityUrban),
+ MakeEnumChecker (VehicleDensity::LOW, "Low",
+ VehicleDensity::MEDIUM, "Medium",
+ VehicleDensity::HIGH, "High"))
+ ;
+ return tid;
+}
+
+ProbabilisticV2vUrbanChannelConditionModel::ProbabilisticV2vUrbanChannelConditionModel ()
+ : ThreeGppChannelConditionModel ()
+{}
+
+ProbabilisticV2vUrbanChannelConditionModel::~ProbabilisticV2vUrbanChannelConditionModel ()
+{}
+
+double
+ProbabilisticV2vUrbanChannelConditionModel::ComputePlos (Ptr a,
+ Ptr b) const
+{
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ double pLos = 0.0;
+ switch (m_densityUrban)
+ {
+ case VehicleDensity::LOW:
+ pLos = std::min (1.0, std::max (0.0, 0.8548 * exp (-0.0064 * distance2D)));
+ break;
+ case VehicleDensity::MEDIUM:
+ pLos = std::min (1.0, std::max (0.0, 0.8372 * exp (-0.0114 * distance2D)));
+ break;
+ case VehicleDensity::HIGH:
+ pLos = std::min (1.0, std::max (0.0, 0.8962 * exp (-0.017 * distance2D)));
+ break;
+ default:
+ NS_FATAL_ERROR ("Undefined density, choose between Low, Medium and High");
+ }
+
+ return pLos;
+}
+
+double
+ProbabilisticV2vUrbanChannelConditionModel::ComputePnlos (Ptr a,
+ Ptr b) const
+{
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ // compute the NLOSv probability
+ double pNlosv = 0.0;
+ switch (m_densityUrban)
+ {
+ case VehicleDensity::LOW:
+ pNlosv = std::min (1.0, std::max (0.0, 1 / (0.0396 * distance2D) * exp (-(log (distance2D) - 5.2718) * (log (distance2D) - 5.2718) / 3.4827)));
+ break;
+ case VehicleDensity::MEDIUM:
+ pNlosv = std::min (1.0, std::max (0.0, 1 / (0.0312 * distance2D) * exp (-(log (distance2D) - 5.0063) * (log (distance2D) - 5.0063) / 2.4544)));
+ break;
+ case VehicleDensity::HIGH:
+ pNlosv = std::min (1.0, std::max (0.0, 1 / (0.0242 * distance2D) * exp (-(log (distance2D) - 5.0115) * (log (distance2D) - 5.0115) / 2.2092)));
+ break;
+ default:
+ NS_FATAL_ERROR ("Undefined density, choose between Low, Medium and High");
+ }
+
+ // derive the NLOS probability
+ double pNlos = 1 - ComputePlos (a, b) - pNlosv;
+ return pNlos;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED (ProbabilisticV2vHighwayChannelConditionModel);
+
+TypeId
+ProbabilisticV2vHighwayChannelConditionModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ProbabilisticV2vHighwayChannelConditionModel")
+ .SetParent ()
+ .SetGroupName ("Propagation")
+ .AddConstructor ()
+ .AddAttribute ("Density", "Specifies the density of the vehicles in the scenario."
+ "It can be set to Low, Medium or High.",
+ EnumValue (VehicleDensity::LOW),
+ MakeEnumAccessor (&ProbabilisticV2vHighwayChannelConditionModel::m_densityHighway),
+ MakeEnumChecker (VehicleDensity::LOW, "Low",
+ VehicleDensity::MEDIUM, "Medium",
+ VehicleDensity::HIGH, "High"))
+ ;
+ return tid;
+}
+
+ProbabilisticV2vHighwayChannelConditionModel::ProbabilisticV2vHighwayChannelConditionModel ()
+ : ThreeGppChannelConditionModel ()
+{}
+
+ProbabilisticV2vHighwayChannelConditionModel::~ProbabilisticV2vHighwayChannelConditionModel ()
+{}
+
+double
+ProbabilisticV2vHighwayChannelConditionModel::ComputePlos (Ptr a,
+ Ptr b) const
+{
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ double aLos = 0.0;
+ double bLos = 0.0;
+ double cLos = 0.0;
+ switch (m_densityHighway)
+ {
+ case VehicleDensity::LOW:
+ aLos = 1.5e-6;
+ bLos = -0.0015;
+ cLos = 1.0;
+ break;
+ case VehicleDensity::MEDIUM:
+ aLos = 2.7e-6;
+ bLos = -0.0025;
+ cLos = 1.0;
+ break;
+ case VehicleDensity::HIGH:
+ aLos = 3.2e-6;
+ bLos = -0.003;
+ cLos = 1.0;
+ break;
+ default:
+ NS_FATAL_ERROR ("Undefined density, choose between Low, Medium and High");
+ }
+
+ double pLos = std::min (1.0, std::max (0.0, aLos * distance2D * distance2D + bLos * distance2D + cLos));
+
+ return pLos;
+}
+
+double
+ProbabilisticV2vHighwayChannelConditionModel::ComputePnlos (Ptr a,
+ Ptr b) const
+{
+ // compute the 2D distance between a and b
+ double distance2D = Calculate2dDistance (a->GetPosition (), b->GetPosition ());
+
+ double aNlos = 0.0;
+ double bNlos = 0.0;
+ double cNlos = 0.0;
+ switch (m_densityHighway)
+ {
+ case VehicleDensity::LOW:
+ aNlos = -2.9e-7;
+ bNlos = 0.00059;
+ cNlos = 0.0017;
+ break;
+ case VehicleDensity::MEDIUM:
+ aNlos = -3.7e-7;
+ bNlos = 0.00061;
+ cNlos = 0.015;
+ break;
+ case VehicleDensity::HIGH:
+ aNlos = -4.1e-7;
+ bNlos = 0.00067;
+ cNlos = 0.0;
+ break;
+ default:
+ NS_FATAL_ERROR ("Undefined density, choose between Low, Medium and High");
+ }
+
+ double pNlos = std::min (1.0, std::max (0.0, aNlos * pow (distance2D, 2) + bNlos * distance2D + cNlos));
+
+ return pNlos;
+}
+
+} // end namespace ns3
diff --git a/src/propagation/model/probabilistic-v2v-channel-condition-model.h b/src/propagation/model/probabilistic-v2v-channel-condition-model.h
new file mode 100644
index 000000000..570a13c3c
--- /dev/null
+++ b/src/propagation/model/probabilistic-v2v-channel-condition-model.h
@@ -0,0 +1,135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * 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
+ */
+
+#ifndef PROBABILISTIC_V2V_CHANNEL_CONDITION_MODEL_H
+#define PROBABILISTIC_V2V_CHANNEL_CONDITION_MODEL_H
+
+#include "ns3/channel-condition-model.h"
+
+namespace ns3 {
+
+class MobilityModel;
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the V2V Urban scenario
+ *
+ * Computes the channel condition following the probabilistic model described in
+ * M. Boban, X.Gong, and W. Xu, “Modeling the evolution of line-of-sight
+ * blockage for V2V channels,” in IEEE 84th Vehicular Technology
+ * Conference (VTC-Fall), 2016.
+ */
+class ProbabilisticV2vUrbanChannelConditionModel : public ThreeGppChannelConditionModel
+{
+public:
+ /**
+ * Get the type ID.
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor for the ProbabilisticV2vUrbanChannelConditionModel class
+ */
+ ProbabilisticV2vUrbanChannelConditionModel ();
+
+ /**
+ * Destructor for the ProbabilisticV2vUrbanChannelConditionModel class
+ */
+ virtual ~ProbabilisticV2vUrbanChannelConditionModel () override;
+
+private:
+ /**
+ * Compute the LOS probability
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the LOS probability
+ */
+ virtual double ComputePlos (Ptr a, Ptr b) const override;
+
+ /**
+ * Compute the NLOS probability
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the NLOS probability
+ */
+ virtual double ComputePnlos (Ptr a, Ptr b) const override;
+
+ enum VehicleDensity m_densityUrban {VehicleDensity::INVALID}; //!< vehicle density
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the V2V Highway scenario
+ *
+ * Computes the channel condition following the probabilistic model described in
+ * M. Boban, X.Gong, and W. Xu, “Modeling the evolution of line-of-sight
+ * blockage for V2V channels,” in IEEE 84th Vehicular Technology
+ * Conference (VTC-Fall), 2016.
+ */
+class ProbabilisticV2vHighwayChannelConditionModel : public ThreeGppChannelConditionModel
+{
+public:
+ /**
+ * Get the type ID.
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor for the ProbabilisticV2vHighwayChannelConditionModel class
+ */
+ ProbabilisticV2vHighwayChannelConditionModel ();
+
+ /**
+ * Destructor for the ProbabilisticV2vHighwayChannelConditionModel class
+ */
+ virtual ~ProbabilisticV2vHighwayChannelConditionModel () override;
+
+private:
+ /**
+ * Compute the LOS probability
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the LOS probability
+ */
+ virtual double ComputePlos (Ptr a, Ptr b) const override;
+
+ /**
+ * Compute the NLOS probability
+ *
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \return the NLOS probability
+ */
+ virtual double ComputePnlos (Ptr a, Ptr b) const override;
+
+ enum VehicleDensity m_densityHighway {VehicleDensity::INVALID}; //!< vehicle density
+};
+
+} // end ns3 namespace
+
+#endif /* PROBABILISTIC_V2V_CHANNEL_CONDITION_MODEL_H */
diff --git a/src/propagation/model/three-gpp-propagation-loss-model.cc b/src/propagation/model/three-gpp-propagation-loss-model.cc
index 01db191f0..267567f8a 100644
--- a/src/propagation/model/three-gpp-propagation-loss-model.cc
+++ b/src/propagation/model/three-gpp-propagation-loss-model.cc
@@ -139,21 +139,8 @@ ThreeGppPropagationLossModel::DoCalcRxPower (double txPowerDbm,
std::pair heights = GetUtAndBsHeights (a->GetPosition ().z, b->GetPosition ().z);
double rxPow = txPowerDbm;
- if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::LOS)
- {
- rxPow -= GetLossLos (distance2d, distance3d, heights.first, heights.second);
- NS_LOG_DEBUG ("Channel codition is LOS, rxPower = " << rxPow);
- }
- else if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::NLOS)
- {
- rxPow -= GetLossNlos (distance2d, distance3d, heights.first, heights.second);
- NS_LOG_DEBUG ("Channel codition is NLOS, rxPower = " << rxPow);
- }
- else
- {
- NS_FATAL_ERROR ("Unknown channel condition");
- }
-
+ rxPow -= GetLoss (cond, distance2d, distance3d, heights.first, heights.second);
+
if (m_shadowingEnabled)
{
rxPow -= GetShadowing (a, b, cond->GetLosCondition ());
@@ -162,6 +149,39 @@ ThreeGppPropagationLossModel::DoCalcRxPower (double txPowerDbm,
return rxPow;
}
+double
+ThreeGppPropagationLossModel::GetLoss (Ptr cond, double distance2d, double distance3d, double hUt, double hBs) const
+{
+ NS_LOG_FUNCTION (this);
+
+ double loss = 0;
+ if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::LOS)
+ {
+ loss = GetLossLos (distance2d, distance3d, hUt, hBs);
+ }
+ else if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::NLOSv)
+ {
+ loss = GetLossNlosv (distance2d, distance3d, hUt, hBs);
+ }
+ else if (cond->GetLosCondition () == ChannelCondition::LosConditionValue::NLOS)
+ {
+ loss = GetLossNlos (distance2d, distance3d, hUt, hBs);
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Unknown channel condition");
+ }
+ return loss;
+}
+
+double
+ThreeGppPropagationLossModel::GetLossNlosv (double distance2D, double distance3D, double hUt, double hBs) const
+{
+ NS_LOG_FUNCTION (this);
+ NS_FATAL_ERROR ("Unsupported channel condition (NLOSv)");
+ return 0;
+}
+
double
ThreeGppPropagationLossModel::GetShadowing (Ptr a, Ptr b, ChannelCondition::LosConditionValue cond) const
{
diff --git a/src/propagation/model/three-gpp-propagation-loss-model.h b/src/propagation/model/three-gpp-propagation-loss-model.h
index 100eb7274..6aefc42f0 100644
--- a/src/propagation/model/three-gpp-propagation-loss-model.h
+++ b/src/propagation/model/three-gpp-propagation-loss-model.h
@@ -111,6 +111,17 @@ private:
* \return the number of stream indices assigned by this model
*/
virtual int64_t DoAssignStreams (int64_t stream) override;
+
+ /**
+ * \brief Computes the pathloss between a and b
+ * \param cond the channel condition
+ * \param distance2D the 2D distance between tx and rx in meters
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ double GetLoss (Ptr cond, double distance2D, double distance3D, double hUt, double hBs) const;
/**
* \brief Computes the pathloss between a and b considering that the line of
@@ -133,6 +144,18 @@ private:
* \return pathloss value in dB
*/
virtual double GetLossNlos (double distance2D, double distance3D, double hUt, double hBs) const = 0;
+
+ /**
+ * \brief Computes the pathloss between a and b considering that the line of
+ * sight is obstructed by a vehicle. By default it raises an error to
+ * avoid misuse.
+ * \param distance2D the 2D distance between tx and rx in meters
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ virtual double GetLossNlosv (double distance2D, double distance3D, double hUt, double hBs) const;
/**
* \brief Determines hUT and hBS. The default implementation assumes that
diff --git a/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc b/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc
new file mode 100644
index 000000000..d2967afc3
--- /dev/null
+++ b/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc
@@ -0,0 +1,235 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * 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
+ */
+
+#include "three-gpp-v2v-propagation-loss-model.h"
+#include "ns3/double.h"
+#include "ns3/log.h"
+#include "ns3/string.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("ThreeGppV2vPropagationLossModel");
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED (ThreeGppV2vUrbanPropagationLossModel);
+
+TypeId
+ThreeGppV2vUrbanPropagationLossModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ThreeGppV2vUrbanPropagationLossModel")
+ .SetParent ()
+ .SetGroupName ("Propagation")
+ .AddConstructor ()
+ .AddAttribute ("PercType3Vehicles",
+ "The percentage of vehicles of type 3 (i.e., trucks) in the scenario",
+ DoubleValue (0.0),
+ MakeDoubleAccessor (&ThreeGppV2vUrbanPropagationLossModel::m_percType3Vehicles),
+ MakeDoubleChecker (0.0, 100.0))
+ ;
+ return tid;
+}
+
+ThreeGppV2vUrbanPropagationLossModel::ThreeGppV2vUrbanPropagationLossModel ()
+ : ThreeGppPropagationLossModel ()
+{
+ NS_LOG_FUNCTION (this);
+ m_uniformVar = CreateObject ();
+ m_logNorVar = CreateObject ();
+
+ // set a default channel condition model
+ // TODO the default ccm needs buildings, how to do this?
+ // m_channelConditionModel = CreateObject ();
+}
+
+ThreeGppV2vUrbanPropagationLossModel::~ThreeGppV2vUrbanPropagationLossModel ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetLossLos (double /* distance2D */, double distance3D, double /* hUt */, double /* hBs */) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
+ double loss = 38.77 + 16.7 * log10 (distance3D) + 18.2 * log10 (m_frequency / 1e9);
+
+ return loss;
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetLossNlosv (double distance2D, double distance3D, double hUt, double hBs) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
+ double loss = GetLossLos (distance2D, distance3D, hUt, hBs) + GetAdditionalNlosvLoss (distance3D, hUt, hBs);
+
+ return loss;
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss (double distance3D, double hUt, double hBs) const
+{
+ NS_LOG_FUNCTION (this);
+ // From TR 37.885 v15.2.0
+ // When a V2V link is in NLOSv, additional vehicle blockage loss is
+ // added as follows:
+ // 1. The blocker height is the vehicle height which is randomly selected
+ // out of the three vehicle types according to the portion of the vehicle
+ // types in the simulated scenario.
+ double additionalLoss = 0;
+ double blockerHeight = 0;
+ double mu_a = 0;
+ double sigma_a = 0;
+ double randomValue = m_uniformVar->GetValue () * 3.0;
+ if (randomValue < m_percType3Vehicles)
+ {
+ // vehicles of type 3 have height 3 meters
+ blockerHeight = 3.0;
+ }
+ else
+ {
+ // vehicles of type 1 and 2 have height 1.6 meters
+ blockerHeight = 1.6;
+ }
+
+ // The additional blockage loss is max {0 dB, a log-normal random variable}
+ if (std::min (hUt, hBs) > blockerHeight)
+ {
+ // Case 1: Minimum antenna height value of TX and RX > Blocker height
+ additionalLoss = 0;
+ }
+ else if (std::max (hUt, hBs) < blockerHeight)
+ {
+ // Case 2: Maximum antenna height value of TX and RX < Blocker height
+ mu_a = 9.0 + std::max (0.0, 15 * log10 (distance3D) - 41.0);
+ sigma_a = 4.5;
+ m_logNorVar->SetAttribute ("Mu", DoubleValue (log10 (pow (mu_a, 2) / sqrt (pow (sigma_a, 2) + pow (mu_a, 2)))));
+ m_logNorVar->SetAttribute ("Sigma", DoubleValue (sqrt (log10 (pow (sigma_a, 2) / pow (mu_a, 2) + 1))));
+ additionalLoss = std::max (0.0, m_logNorVar->GetValue ());
+ }
+ else
+ {
+ // Case 3: Otherwise
+ mu_a = 5.0 + std::max (0.0, 15 * log10 (distance3D) - 41.0);
+ sigma_a = 4.0;
+
+ m_logNorVar->SetAttribute ("Mu", DoubleValue (log10 (pow (mu_a,2) / sqrt (pow (sigma_a, 2) + pow (mu_a, 2)))));
+ m_logNorVar->SetAttribute ("Sigma", DoubleValue (sqrt (log10 (pow (sigma_a,2) / pow (mu_a, 2) + 1))));
+ additionalLoss = std::max (0.0, m_logNorVar->GetValue ());
+ }
+
+ return additionalLoss;
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetLossNlos (double /* distance2D */, double distance3D, double /* hUt */, double /* hBs */) const
+{
+ NS_LOG_FUNCTION (this);
+
+ double loss = 36.85 + 30 * log10 (distance3D) + 18.9 * log10 (m_frequency / 1e9);
+
+ return loss;
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetShadowingStd (Ptr /* a */, Ptr /* b */, ChannelCondition::LosConditionValue cond) const
+{
+ NS_LOG_FUNCTION (this);
+ double shadowingStd;
+
+ if (cond == ChannelCondition::LosConditionValue::LOS || cond == ChannelCondition::LosConditionValue::NLOSv)
+ {
+ shadowingStd = 3.0;
+ }
+ else if (cond == ChannelCondition::LosConditionValue::NLOS)
+ {
+ shadowingStd = 4.0;
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Unknown channel condition");
+ }
+
+ return shadowingStd;
+}
+
+double
+ThreeGppV2vUrbanPropagationLossModel::GetShadowingCorrelationDistance (ChannelCondition::LosConditionValue cond) const
+{
+ NS_LOG_FUNCTION (this);
+ double correlationDistance;
+
+ // See 3GPP TR 37.885, Table 6.2.3-1
+ if (cond == ChannelCondition::LosConditionValue::LOS)
+ {
+ correlationDistance = 10;
+ }
+ else if (cond == ChannelCondition::LosConditionValue::NLOSv || cond == ChannelCondition::LosConditionValue::NLOS)
+ {
+ correlationDistance = 13;
+ }
+ else
+ {
+ NS_FATAL_ERROR ("Unknown channel condition");
+ }
+
+ return correlationDistance;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED (ThreeGppV2vHighwayPropagationLossModel);
+
+TypeId
+ThreeGppV2vHighwayPropagationLossModel::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::ThreeGppV2vHighwayPropagationLossModel")
+ .SetParent ()
+ .SetGroupName ("Propagation")
+ .AddConstructor ()
+ ;
+ return tid;
+}
+
+ThreeGppV2vHighwayPropagationLossModel::ThreeGppV2vHighwayPropagationLossModel ()
+ : ThreeGppV2vUrbanPropagationLossModel ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+ThreeGppV2vHighwayPropagationLossModel::~ThreeGppV2vHighwayPropagationLossModel ()
+{
+ NS_LOG_FUNCTION (this);
+}
+
+double
+ThreeGppV2vHighwayPropagationLossModel::GetLossLos (double /* distance2D */, double distance3D, double /* hUt */, double /* hBs */) const
+{
+ NS_LOG_FUNCTION (this);
+
+ // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
+ double loss = 32.4 + 20 * log10 (distance3D) + 20 * log10 (m_frequency / 1e9);
+
+ return loss;
+}
+
+} // namespace ns3
diff --git a/src/propagation/model/three-gpp-v2v-propagation-loss-model.h b/src/propagation/model/three-gpp-v2v-propagation-loss-model.h
new file mode 100644
index 000000000..8a30f33ad
--- /dev/null
+++ b/src/propagation/model/three-gpp-v2v-propagation-loss-model.h
@@ -0,0 +1,171 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2020 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * 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
+ */
+
+#ifndef THREE_GPP_V2V_PROPAGATION_LOSS_MODEL_H
+#define THREE_GPP_V2V_PROPAGATION_LOSS_MODEL_H
+
+#include "three-gpp-propagation-loss-model.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Implements the pathloss model defined in 3GPP TR 37.885, Table 6.2.1-1
+ * for the Urban scenario.
+ */
+class ThreeGppV2vUrbanPropagationLossModel : public ThreeGppPropagationLossModel
+{
+public:
+ /**
+ * \brief Get the type ID.
+ * \return the object TypeId
+ */
+ static TypeId GetTypeId (void);
+
+ /**
+ * Constructor
+ */
+ ThreeGppV2vUrbanPropagationLossModel ();
+
+ /**
+ * Destructor
+ */
+ virtual ~ThreeGppV2vUrbanPropagationLossModel () override;
+
+ /**
+ * \brief Copy constructor
+ *
+ * Defined and unimplemented to avoid misuse
+ */
+ ThreeGppV2vUrbanPropagationLossModel (const ThreeGppV2vUrbanPropagationLossModel &) = delete;
+
+ /**
+ * \brief Copy constructor
+ *
+ * Defined and unimplemented to avoid misuse
+ * \returns the ThreeGppRmaPropagationLossModel instance
+ */
+ ThreeGppV2vUrbanPropagationLossModel & operator = (const ThreeGppV2vUrbanPropagationLossModel &) = delete;
+
+private:
+ /**
+ * \brief Computes the pathloss between a and b considering that the line of
+ * sight is not obstructed
+ * \param distance2D the 2D distance between tx and rx in meters
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ virtual double GetLossLos (double distance2D, double distance3D, double hUt, double hBs) const override;
+
+ /**
+ * \brief Computes the pathloss between a and b considering that the line of
+ * sight is obstructed by a vehicle
+ * \param distance2D the 2D distance between tx and rx in meters
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ virtual double GetLossNlosv (double distance2D, double distance3D, double hUt, double hBs) const override;
+
+ /**
+ * \brief Computes the pathloss between a and b considering that the line of
+ * sight is obstructed by a building
+ * \param distance2D the 2D distance between tx and rx in meters
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ virtual double GetLossNlos (double distance2D, double distance3D, double hUt, double hBs) const override;
+
+ /**
+ * \brief Computes the additional loss due to an obstruction caused by a vehicle
+ * \param distance3D the 3D distance between tx and rx in meters
+ * \param hUt the height of the UT in meters
+ * \param hBs the height of the BS in meters
+ * \return pathloss value in dB
+ */
+ double GetAdditionalNlosvLoss (double distance3D, double hUt, double hBs) const;
+
+ /**
+ * \brief Returns the shadow fading standard deviation
+ * \param a tx mobility model
+ * \param b rx mobility model
+ * \param cond the LOS/NLOS channel condition
+ * \return shadowing std in dB
+ */
+ virtual double GetShadowingStd (Ptr