spectrum: Add hexagonal wraparound model
This commit is contained in:
@@ -10,6 +10,7 @@ set(source_files
|
||||
model/friis-spectrum-propagation-loss.cc
|
||||
model/half-duplex-ideal-phy-signal-parameters.cc
|
||||
model/half-duplex-ideal-phy.cc
|
||||
model/hexagonal-wraparound-model.cc
|
||||
model/ism-spectrum-value-helper.cc
|
||||
model/matrix-based-channel-model.cc
|
||||
model/microwave-oven-spectrum-value-helper.cc
|
||||
@@ -51,6 +52,7 @@ set(header_files
|
||||
model/friis-spectrum-propagation-loss.h
|
||||
model/half-duplex-ideal-phy-signal-parameters.h
|
||||
model/half-duplex-ideal-phy.h
|
||||
model/hexagonal-wraparound-model.h
|
||||
model/ism-spectrum-value-helper.h
|
||||
model/matrix-based-channel-model.h
|
||||
model/microwave-oven-spectrum-value-helper.h
|
||||
@@ -98,4 +100,5 @@ build_lib(
|
||||
test/tv-helper-distribution-test.cc
|
||||
test/tv-spectrum-transmitter-test.cc
|
||||
test/two-ray-splm-test-suite.cc
|
||||
test/wraparound-model-test.cc
|
||||
)
|
||||
|
||||
140
src/spectrum/model/hexagonal-wraparound-model.cc
Normal file
140
src/spectrum/model/hexagonal-wraparound-model.cc
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2025 CTTC
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hexagonal-wraparound-model.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
constexpr double M_SQRT3 = 1.732050807568877; // sqrt(3)
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
/**
|
||||
* Coefficients used to wraparound a cluster with 7 sites (1 ring)
|
||||
*/
|
||||
std::vector<Vector2D> WRAPPING_COEFF_CLUSTER7 =
|
||||
{{0.0, 0.0}, {-3.0, 2.0}, {3.0, -2.0}, {-1.5, -2.5}, {1.5, 2.5}, {-4.5, -0.5}, {4.5, 0.5}};
|
||||
|
||||
/**
|
||||
* Coefficients used to wraparound a cluster with 19 sites (3 rings)
|
||||
*/
|
||||
std::vector<Vector2D> WRAPPING_COEFF_CLUSTER19 =
|
||||
{{0.0, 0.0}, {-3.0, -4.0}, {3.0, 4.0}, {-4.5, 3.5}, {4.5, -3.5}, {-7.5, -0.5}, {7.5, 0.5}};
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("HexagonalWraparoundModel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(HexagonalWraparoundModel);
|
||||
|
||||
TypeId
|
||||
HexagonalWraparoundModel::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId("ns3::HexagonalWraparoundModel")
|
||||
.SetParent<WraparoundModel>()
|
||||
.SetGroupName("Spectrum")
|
||||
.AddConstructor<HexagonalWraparoundModel>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
HexagonalWraparoundModel::HexagonalWraparoundModel()
|
||||
: m_numSites(1)
|
||||
{
|
||||
}
|
||||
|
||||
HexagonalWraparoundModel::HexagonalWraparoundModel(double isd, size_t numSites)
|
||||
: m_numSites(numSites)
|
||||
{
|
||||
SetSiteDistance(isd);
|
||||
}
|
||||
|
||||
void
|
||||
HexagonalWraparoundModel::SetSiteDistance(double isd)
|
||||
{
|
||||
m_isd = isd;
|
||||
m_radius = isd / M_SQRT3;
|
||||
}
|
||||
|
||||
void
|
||||
HexagonalWraparoundModel::SetNumSites(uint8_t numSites)
|
||||
{
|
||||
NS_ASSERT((numSites == 1) || (numSites == 7) || (numSites == 19));
|
||||
m_numSites = numSites;
|
||||
}
|
||||
|
||||
void
|
||||
HexagonalWraparoundModel::AddSitePosition(const Vector3D& pos)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << pos);
|
||||
NS_ASSERT(m_sitePositions.size() < m_numSites);
|
||||
m_sitePositions.push_back(pos);
|
||||
}
|
||||
|
||||
void
|
||||
HexagonalWraparoundModel::SetSitePositions(const std::vector<Vector3D>& positions)
|
||||
{
|
||||
NS_ASSERT(positions.size() == m_numSites);
|
||||
m_sitePositions = positions;
|
||||
}
|
||||
|
||||
double
|
||||
HexagonalWraparoundModel::CalculateDistance(const Vector3D& a, const Vector3D& b) const
|
||||
{
|
||||
return (a - GetVirtualPosition(b, a)).GetLength();
|
||||
}
|
||||
|
||||
// Wraparound calculation is based on
|
||||
// R. S. Panwar and K. M. Sivalingam, "Implementation of wrap
|
||||
// around mechanism for system level simulation of LTE cellular
|
||||
// networks in NS3," 2017 IEEE 18th International Symposium on
|
||||
// A World of Wireless, Mobile and Multimedia Networks (WoWMoM),
|
||||
// Macau, 2017, pp. 1-9, doi: 10.1109/WoWMoM.2017.7974289.
|
||||
Vector3D
|
||||
HexagonalWraparoundModel::GetSitePosition(const Vector3D& pos) const
|
||||
{
|
||||
NS_ASSERT(m_numSites == m_sitePositions.size());
|
||||
|
||||
std::vector<double> virtDists;
|
||||
virtDists.resize(m_numSites);
|
||||
std::transform(m_sitePositions.begin(),
|
||||
m_sitePositions.end(),
|
||||
virtDists.begin(),
|
||||
[&](const Vector3D& sitePos) {
|
||||
return (this->GetVirtualPosition(pos, sitePos) - sitePos).GetLength();
|
||||
});
|
||||
auto idx = std::min_element(virtDists.begin(), virtDists.end()) - virtDists.begin();
|
||||
return m_sitePositions[idx];
|
||||
}
|
||||
|
||||
Vector3D
|
||||
HexagonalWraparoundModel::GetVirtualPosition(const Vector3D txPos, const Vector3D rxPos) const
|
||||
{
|
||||
NS_ASSERT_MSG((m_numSites == 1) || (m_numSites == 7) || (m_numSites == 19),
|
||||
"invalid numSites: " << m_numSites);
|
||||
|
||||
if (m_numSites == 1)
|
||||
{
|
||||
return txPos;
|
||||
}
|
||||
|
||||
auto& coeffs = (m_numSites == 7) ? WRAPPING_COEFF_CLUSTER7 : WRAPPING_COEFF_CLUSTER19;
|
||||
|
||||
std::vector<double> virtDists;
|
||||
virtDists.resize(coeffs.size());
|
||||
std::transform(coeffs.begin(), coeffs.end(), virtDists.begin(), [&](const Vector2D& coeff) {
|
||||
Vector3D virtPos2 = txPos;
|
||||
virtPos2.x += coeff.x * m_radius;
|
||||
virtPos2.y += coeff.y * m_isd;
|
||||
return static_cast<double>((virtPos2 - rxPos).GetLength());
|
||||
});
|
||||
|
||||
auto idx = std::min_element(virtDists.begin(), virtDists.end()) - virtDists.begin();
|
||||
Vector3D offset(m_radius * coeffs[idx].x, m_isd * coeffs[idx].y, 0.0);
|
||||
return txPos + offset;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
120
src/spectrum/model/hexagonal-wraparound-model.h
Normal file
120
src/spectrum/model/hexagonal-wraparound-model.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2025 CTTC
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HEXAGONAL_WRAPAROUND_H
|
||||
#define HEXAGONAL_WRAPAROUND_H
|
||||
|
||||
#include "wraparound-model.h"
|
||||
|
||||
#include "ns3/vector.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
/**
|
||||
* @ingroup propagation
|
||||
* @brief Hexagonal wraparound model wraps nodes around in space based on an
|
||||
* hexagonal deployment. It is used to determine a virtual position after
|
||||
* wraparound and calculate the distance between a point of reference and
|
||||
* the virtual position.
|
||||
*
|
||||
* This model is used for the hexagonal deployments typical of mobile networks.
|
||||
* It supports rings 0 (1 site), 1 (7 sites) and 3 rings (19 sites).
|
||||
* To use it, set the inter-site distance (isd) and the number of sites.
|
||||
* Then, add the position coordinates of the sites.
|
||||
* All space coordinates in this class and its subclasses are understood
|
||||
* to be meters or meters/s. i.e., they are all metric international units.
|
||||
*
|
||||
* When GetRelativeVirtualPosition (absPos1, absPos2) is called,
|
||||
* the relative position of the absPos2 is calculated respective to the
|
||||
* reference coordinate absPos1, applying the wrapping based on the model
|
||||
* described in:
|
||||
*
|
||||
* R. S. Panwar and K. M. Sivalingam, "Implementation of wrap
|
||||
* around mechanism for system level simulation of LTE cellular
|
||||
* networks in NS3," 2017 IEEE 18th International Symposium on
|
||||
* A World of Wireless, Mobile and Multimedia Networks (WoWMoM),
|
||||
* Macau, 2017, pp. 1-9, doi: 10.1109/WoWMoM.2017.7974289.
|
||||
*/
|
||||
class HexagonalWraparoundModel : public WraparoundModel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Register this type with the TypeId system.
|
||||
* @return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
HexagonalWraparoundModel();
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param isd inter-site distance
|
||||
* @param numSites number of sites
|
||||
*/
|
||||
HexagonalWraparoundModel(double isd, size_t numSites);
|
||||
|
||||
/**
|
||||
* @brief Set site distance
|
||||
* @param isd site distance
|
||||
*/
|
||||
void SetSiteDistance(double isd);
|
||||
|
||||
/**
|
||||
* @brief Set number of sites
|
||||
* @param numSites number of sites
|
||||
*/
|
||||
void SetNumSites(uint8_t numSites);
|
||||
|
||||
/**
|
||||
* @brief Add a site position
|
||||
* @param pos position of a site
|
||||
*/
|
||||
void AddSitePosition(const Vector3D& pos);
|
||||
|
||||
/**
|
||||
* @brief Set site positions
|
||||
* @param positions positions of all sites
|
||||
*/
|
||||
void SetSitePositions(const std::vector<Vector3D>& positions);
|
||||
|
||||
/**
|
||||
* @brief Calculate the site position
|
||||
* @param pos original position
|
||||
* @return closest cell center based on wraparound distance
|
||||
*/
|
||||
Vector3D GetSitePosition(const Vector3D& pos) const;
|
||||
|
||||
/**
|
||||
* @brief Calculate distance after wraparound between two points
|
||||
* @param a position of point a
|
||||
* @param b position of point b
|
||||
* @return wraparound distance between a and b
|
||||
*/
|
||||
double CalculateDistance(const Vector3D& a, const Vector3D& b) const;
|
||||
/**
|
||||
* @brief Get virtual position of txPos with respect to rxPos
|
||||
* @param txPos
|
||||
* @param rxPos
|
||||
* @return virtual position of txPos
|
||||
*/
|
||||
Vector3D GetVirtualPosition(const Vector3D txPos, const Vector3D rxPos) const override;
|
||||
|
||||
private:
|
||||
double m_isd; //!< distance between sites
|
||||
double m_radius; //!< site radius
|
||||
uint8_t m_numSites; //!< number of sites
|
||||
std::vector<Vector3D> m_sitePositions; //!< site positions
|
||||
};
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* HEXAGONAL_WRAPAROUND_H */
|
||||
257
src/spectrum/test/wraparound-model-test.cc
Normal file
257
src/spectrum/test/wraparound-model-test.cc
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2025 CTTC
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
|
||||
*/
|
||||
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/hexagonal-wraparound-model.h"
|
||||
#include "ns3/mobility-helper.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/waypoint-mobility-model.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/**
|
||||
* @ingroup propagation-test
|
||||
*
|
||||
* @brief Wraparound Model Test
|
||||
*/
|
||||
class WraparoundModelTest : public TestCase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor for test case
|
||||
* @param name description of test case
|
||||
* @param numRings number of rings used in the deployment
|
||||
* @param alternativeConfig wraparound is configured manually when false, or via constructor
|
||||
* when true.
|
||||
*/
|
||||
WraparoundModelTest(std::string name, int numRings, bool alternativeConfig)
|
||||
: TestCase(name),
|
||||
m_numRings(numRings),
|
||||
m_alternativeConfig(alternativeConfig)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
int m_numRings; ///< number of wrings to wraparound
|
||||
bool m_alternativeConfig; ///< indicate whether to configure isd and numSites via constructor or
|
||||
///< manually
|
||||
private:
|
||||
void DoRun() override;
|
||||
};
|
||||
|
||||
size_t
|
||||
GetNearestSite(std::vector<Vector3D>& sites, size_t numSites, Vector3D virtualPos)
|
||||
{
|
||||
double minDist = std::numeric_limits<double>::max();
|
||||
size_t minSite = 0;
|
||||
for (size_t siteI = 0; siteI < sites.size() && siteI < numSites; siteI++)
|
||||
{
|
||||
auto dist = CalculateDistance(sites.at(siteI), virtualPos);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
minSite = siteI;
|
||||
}
|
||||
}
|
||||
return minSite;
|
||||
}
|
||||
|
||||
void
|
||||
WraparoundModelTest::DoRun()
|
||||
{
|
||||
int numSites = 0;
|
||||
switch (m_numRings)
|
||||
{
|
||||
case 0:
|
||||
numSites = 1;
|
||||
break;
|
||||
case 1:
|
||||
numSites = 7;
|
||||
break;
|
||||
case 3:
|
||||
numSites = 19;
|
||||
break;
|
||||
default:
|
||||
NS_TEST_EXPECT_MSG_EQ(false,
|
||||
true,
|
||||
"Wraparound does not support " << m_numRings << " rings");
|
||||
break;
|
||||
}
|
||||
|
||||
NodeContainer userNodes(1);
|
||||
NodeContainer siteNodes(numSites);
|
||||
|
||||
MobilityHelper mobilityHelper;
|
||||
mobilityHelper.SetMobilityModel("ns3::ConstantPositionMobilityModel");
|
||||
|
||||
// Site positions
|
||||
// clang-format off
|
||||
std::vector<Vector3D> sitePositions = {
|
||||
Vector3D( 0, 0, 30), // Site 01
|
||||
Vector3D( 1000, 0, 30), // Site 02
|
||||
Vector3D( 500, 866, 30), // Site 03
|
||||
Vector3D( -500, 866, 30), // Site 04
|
||||
Vector3D(-1000, 0, 30), // Site 05
|
||||
Vector3D( -500, -866, 30), // Site 06
|
||||
Vector3D( 500, -866, 30), // Site 07
|
||||
Vector3D( 2000, 0, 30), // Site 08
|
||||
Vector3D( 1500, 866, 30), // Site 09
|
||||
Vector3D( 500, 1732, 30), // Site 10
|
||||
Vector3D( -500, 1732, 30), // Site 11
|
||||
Vector3D(-1500, 866, 30), // Site 12
|
||||
Vector3D(-2000, 0, 30), // Site 13
|
||||
Vector3D(-1500, -866, 30), // Site 14
|
||||
Vector3D( -500, -1732, 30), // Site 15
|
||||
Vector3D( 500, -1732, 30), // Site 16
|
||||
Vector3D( 1500, -866, 30), // Site 17
|
||||
Vector3D( 1000, 1732, 30), // Site 18
|
||||
Vector3D(-1000, 1732, 30), // Site 19
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
Ptr<HexagonalWraparoundModel> wraparoundModel =
|
||||
m_alternativeConfig ? CreateObject<HexagonalWraparoundModel>()
|
||||
: CreateObject<HexagonalWraparoundModel>(1000, numSites);
|
||||
|
||||
if (m_alternativeConfig)
|
||||
{
|
||||
wraparoundModel->SetSiteDistance(1000);
|
||||
wraparoundModel->SetNumSites(numSites);
|
||||
auto sitePositionsSlice =
|
||||
std::vector<Vector3D>(sitePositions.begin(), sitePositions.begin() + numSites);
|
||||
wraparoundModel->SetSitePositions(sitePositionsSlice);
|
||||
}
|
||||
|
||||
// Install mobility models
|
||||
mobilityHelper.Install(userNodes);
|
||||
mobilityHelper.Install(siteNodes);
|
||||
|
||||
// Add site positions and wraparound model
|
||||
for (auto i = 0; i < numSites; i++)
|
||||
{
|
||||
auto siteMm = siteNodes.Get(i)->GetObject<MobilityModel>();
|
||||
siteMm->SetPosition(sitePositions.at(i));
|
||||
if (!m_alternativeConfig)
|
||||
{
|
||||
wraparoundModel->AddSitePosition(sitePositions.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve user node mobility to move it around
|
||||
auto userMm = userNodes.Get(0)->GetObject<MobilityModel>();
|
||||
|
||||
// Test cases (target site number, expected UE virtual site, real user position, expected
|
||||
// wrapped position)
|
||||
std::vector<std::tuple<size_t, size_t, Vector3D, Vector3D>> testPoint;
|
||||
// clang-format off
|
||||
switch (m_numRings)
|
||||
{
|
||||
case 3: // Cases involving sites 8-19
|
||||
testPoint.emplace_back( 7, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back( 8, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back( 9, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(10, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(11, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(12, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(13, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(14, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(15, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(16, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(17, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(18, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back( 7, 0, Vector3D( 100, 0, 0), Vector3D( 100, 0, 0));
|
||||
testPoint.emplace_back( 8, 0, Vector3D( 500, 0, 0), Vector3D( 500, 0, 0));
|
||||
testPoint.emplace_back( 9, 1, Vector3D( 1000, 0, 0), Vector3D( 1000, 0, 0));
|
||||
testPoint.emplace_back(10, 2, Vector3D( 1000, 1000, 0), Vector3D( 1000, 1000, 0));
|
||||
testPoint.emplace_back(11, 0, Vector3D( -500, 0, 0), Vector3D( -500, 0, 0));
|
||||
testPoint.emplace_back(12, 0, Vector3D( 0, -500, 0), Vector3D( 0, -500, 0));
|
||||
testPoint.emplace_back(13, 5, Vector3D(-1000, -1000, 0), Vector3D(-1000, -1000, 0));
|
||||
testPoint.emplace_back(14, 13, Vector3D( 2000, -1000, 0), Vector3D(-2330, -1500, 0));
|
||||
testPoint.emplace_back(15, 16, Vector3D(-1000, 2000, 0), Vector3D( 1598, -1500, 0));
|
||||
testPoint.emplace_back(16, 15, Vector3D( 2000, 2000, 0), Vector3D( 267, -2000, 0));
|
||||
testPoint.emplace_back(17, 10, Vector3D(-2000, -2000, 0), Vector3D( -268, 2000, 0));
|
||||
testPoint.emplace_back(18, 11, Vector3D(-2000, 1500, 0), Vector3D(-2000, 1500, 0));
|
||||
break;
|
||||
case 1: // Cases involving sites 2-7
|
||||
testPoint.emplace_back(1, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(2, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(3, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(4, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(5, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(6, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(1, 1, Vector3D( 1000, 0, 0), Vector3D( 1000, 0, 0));
|
||||
testPoint.emplace_back(2, 3, Vector3D( 1000, -500, 0), Vector3D( -732, 1500, 0));
|
||||
testPoint.emplace_back(3, 4, Vector3D( 1000, 500, 0), Vector3D(-1598, 0, 0));
|
||||
testPoint.emplace_back(4, 4, Vector3D(-1000, 0, 0), Vector3D(-1000, 0, 0));
|
||||
testPoint.emplace_back(5, 6, Vector3D(-1000, 500, 0), Vector3D( 732, -1500, 0));
|
||||
testPoint.emplace_back(6, 1, Vector3D(-1000, -500, 0), Vector3D( 1598, 0, 0));
|
||||
break;
|
||||
case 0: // Cases involving site 1. No wraparound.
|
||||
testPoint.emplace_back(0, 0, Vector3D( 0, 0, 0), Vector3D( 0, 0, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D( 1000, 1000, 0), Vector3D( 1000, 1000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D( 1000, -1000, 0), Vector3D( 1000, -1000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D(-1000, 1000, 0), Vector3D(-1000, 1000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D(-1000, -1000, 0), Vector3D(-1000, -1000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D( 2000, 2000, 0), Vector3D( 2000, 2000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D( 2000, -2000, 0), Vector3D( 2000, -2000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D(-2000, 2000, 0), Vector3D(-2000, 2000, 0));
|
||||
testPoint.emplace_back(0, 0, Vector3D(-2000, -2000, 0), Vector3D(-2000, -2000, 0));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
for (auto [siteNumber, expectedVirtualUserSite, realUserPos, expectedVirtualPos] : testPoint)
|
||||
{
|
||||
userMm->SetPosition(realUserPos);
|
||||
auto siteMm = siteNodes.Get(siteNumber)->GetObject<MobilityModel>();
|
||||
auto virtualPos =
|
||||
wraparoundModel->GetVirtualPosition(userMm->GetPosition(), siteMm->GetPosition());
|
||||
auto nearestSiteToVirtualUser = GetNearestSite(sitePositions, numSites, virtualPos);
|
||||
NS_TEST_EXPECT_MSG_EQ(nearestSiteToVirtualUser,
|
||||
expectedVirtualUserSite,
|
||||
"Virtual position leads to from real site "
|
||||
<< GetNearestSite(sitePositions, numSites, realUserPos)
|
||||
<< " to incorrect site " << nearestSiteToVirtualUser);
|
||||
NS_TEST_EXPECT_MSG_LT_OR_EQ(CalculateDistance(virtualPos, expectedVirtualPos),
|
||||
5,
|
||||
"Expected " << expectedVirtualPos << " and obtained "
|
||||
<< virtualPos << " virtual positions differ");
|
||||
}
|
||||
// Move user node and check virtual positions correspond to the expected sites
|
||||
Simulator::Stop(MilliSeconds(1));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup propagation-test
|
||||
*
|
||||
* @brief Wraparound Model Test Suite
|
||||
*/
|
||||
static struct WraparoundModelTestSuite : public TestSuite
|
||||
{
|
||||
WraparoundModelTestSuite()
|
||||
: TestSuite("wraparound-model", Type::UNIT)
|
||||
{
|
||||
std::vector<bool> alternativeConfig{false, true};
|
||||
for (auto altConf : alternativeConfig)
|
||||
{
|
||||
// Supported ring numbers
|
||||
AddTestCase(new WraparoundModelTest("Check wraparound with 0 rings", 0, altConf),
|
||||
TestCase::Duration::QUICK);
|
||||
AddTestCase(new WraparoundModelTest("Check wraparound with 1 rings", 1, altConf),
|
||||
TestCase::Duration::QUICK);
|
||||
AddTestCase(new WraparoundModelTest("Check wraparound with 3 rings", 3, altConf),
|
||||
TestCase::Duration::QUICK);
|
||||
}
|
||||
}
|
||||
} g_WraparoundModelTestSuite; ///< the test suite
|
||||
Reference in New Issue
Block a user