diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 581ad7882..807f264dd 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,9 +1,9 @@ ns-3 RELEASE NOTES -This file contains ns-3 release notes (most recent releases first). +This file contains ns-3 release notes (most recent releases first). -All of the ns-3 documentation is accessible from the ns-3 website: +All of the ns-3 documentation is accessible from the ns-3 website: http://www.nsnam.org including tutorials: http://www.nsnam.org/tutorials.html Consult the file CHANGES.html for more detailed information about changed @@ -22,10 +22,12 @@ To be determined. New user-visible features ------------------------- -- (internet) An option to enable IPv4 hash-based multicast duplicate packet +- (internet) An option to enable IPv4 hash-based multicast duplicate packet detection (DPD) based on RFC 6621 has been added. - (stats) A new interface to SQLite has been added. - (propagation) 3GPP TR 38.901 pathloss and channel condition models added +- (spectrum) Addition three-gpp-channel-model (part of Integration of the 3GPP TR 38.901 fast fading model) +- (antenna) Addition of three-gpp-antenna-array-model (part of Integration of the 3GPP TR 38.901 fast fading model) Bugs fixed ---------- @@ -74,7 +76,7 @@ Features are identical to release 3.30. Bugs fixed ---------- -- Issue #62 - ICMP does not handle ICMPv4 TIME_EXCEEDED responses +- Issue #62 - ICMP does not handle ICMPv4 TIME_EXCEEDED responses - Issue #77 - Wi-Fi VHT capabilities MaxMpduLength had invalid restriction - Issue #79 - Wi-Fi connection drop or low throughput due to Block Ack transmit window - Example program tap-wifi-virtual-machine.py had a syntax error @@ -218,10 +220,10 @@ Supported platforms This release is intended to work on systems with the following minimal requirements (Note: not all features available on all platforms): - g++-4.9 or later -- Apple LLVM version 7.0.2 or later +- Apple LLVM version 7.0.2 or later - clang-3.3 or later -In addition, Python 2.7 (Python 2 series) or Python 3.4-3.7 (Python 3 series) +In addition, Python 2.7 (Python 2 series) or Python 3.4-3.7 (Python 3 series) This release has been tested on the following platforms: - Ubuntu 18.04 (64 bit) with g++-7.3.0 and Python 2.7.15 @@ -275,7 +277,7 @@ Bugs fixed - Bug 2931 - traffic-control: QueueDisc drops the CE marked packets - Bug 2936 - Disable -Wparentheses with GTK+ and gcc-8 - Bug 2938 - build: add --disable-werror flag to Waf -- Bug 2940 - traffic-control: QueueDisc SojournTime should be TracedCallback +- Bug 2940 - traffic-control: QueueDisc SojournTime should be TracedCallback - Bug 2941 - wifi: Order bit of Frame control field of WifiMacHeader not correctly set for some frames - Bug 2948 - network: SetPriority does not support value 7 - Bug 2949 - test: Exit test.py if incorrect fullness option used @@ -300,9 +302,9 @@ Supported platforms This release is intended to work on systems with the following minimal compiler requirements (other compilers supporting C++11 may also work): - g++-4.9 or later -- Apple LLVM version 7.0.2 or later +- Apple LLVM version 7.0.2 or later - clang-3.3 or later -In addition, a Python 2.7 (Python 2 series) or Python 3.4 (Python 3 series) +In addition, a Python 2.7 (Python 2 series) or Python 3.4 (Python 3 series) or later is required. This release has been tested on the following platforms: @@ -311,10 +313,10 @@ This release has been tested on the following platforms: - Fedora Core 27 (64 bit) with g++-7.3.1 and Python 2.7.14 - Fedora Core 26 (64 bit) with g++-7.3.1 and g++-7.1.1, and Python 2.7.14 - CentOS/RHEL 7.4 (64-bit) with g++-6.3.1 and Python 3.5.1 - - Note: the default g++ version (4.8) must be upgraded + - Note: the default g++ version (4.8) must be upgraded - CentOS/RHEL 6.8 (64-bit) with g++-4.9.2 and Python 2.7.13 - - Note: the default g++ version (4.4) must be upgraded - - Note: the default Python version (2.6) must be upgraded + - Note: the default g++ version (4.4) must be upgraded + - Note: the default Python version (2.6) must be upgraded - OS X Sierra 10.12.6 with Xcode 9.2, Apple LLVM version 9.0.0, Python 2.7.13 - OS X Yosemite 10.10.5 with Xcode 7.2.1, Apple LLVM vers. 7.0.2, Python 2.7.10 @@ -339,7 +341,7 @@ Bugs fixed - Bug 2107 - lte: Enable PCAP for S1 and X2 point-to-point links - Bug 2152 - lte: Fix uplink HARQ retx. out of synch at the MAC layer - Bug 2151 - lte: Generate correct redundancy version in uplink HARQ -- Bug 2277 - lte: EpcTftClassifier::Classify blindly assumes that a packet has a L4 header +- Bug 2277 - lte: EpcTftClassifier::Classify blindly assumes that a packet has a L4 header - Bug 2505 - network: Avoid asserts in Header/Trailer deserialization - Bug 2653 - tcp: Avoid saving smaller TS in case of packet reordering - Bug 2656 - wifi: Minstrel and MinstrelHt provide different results for 802.11a/b/g @@ -368,7 +370,7 @@ Bugs fixed - Bug 2849 - lte: Received RLC and PDCP PDUs are missing in the stats files - Bug 2854 - wifi: Fix 802.11ax channel width capabilities - Bug 2856 - wifi: Correct bugs and improve logging in MinstrelHt -- Bug 2859 - tcp: calculation of BytesInFlight during partial recovery is fixed +- Bug 2859 - tcp: calculation of BytesInFlight during partial recovery is fixed - Bug 2866 - tcp: Removed VS warnings on TcpSocketBase - Bug 2872 - csma: Packet copy in CsmaChannel breaks netanim tracing - Bug 2873 - tcp: Potential SIGFPE in TcpYeah @@ -400,7 +402,7 @@ Supported platforms This release is intended to work on systems with the following minimal requirements (Note: not all features available on all platforms): - g++-4.9 or later (Note: this is an upgraded requirement from ns-3.26) -- Apple LLVM version 7.0.2 or later +- Apple LLVM version 7.0.2 or later - clang-3.3 or later - Python 2.7 (Python 2 series) or Python 3.4 (Python 3 series) or later @@ -408,14 +410,14 @@ This release has been tested on the following platforms: - Ubuntu 17.04 (64 bit) with g++-6.3.0 - Ubuntu 16.04 (64 bit) with g++-5.4.0 - Ubuntu 14.04.5 (64 bit) with g++-4.9.4 - - Note: the default g++ version (4.8) must be upgraded + - Note: the default g++ version (4.8) must be upgraded - Fedora Core 26 (64 bit) with g++-7.1.1 - Fedora Core 22 (64 bit) with g++-5.3.1 - CentOS/RHEL 7.4 (64-bit) with g++-6.3.1 - - Note: the default g++ version (4.8) must be upgraded + - Note: the default g++ version (4.8) must be upgraded - CentOS/RHEL 6.8 (64-bit) with g++-4.9.2 - - Note: the default g++ version (4.4) must be upgraded - - Note: the default Python version (2.6) must be upgraded + - Note: the default g++ version (4.4) must be upgraded + - Note: the default Python version (2.6) must be upgraded - OS X Sierra 10.12.6 with Xcode 9.0 and Apple LLVM version 9.0.0 - OS X El Capitan 10.11.6 with Xcode 8.2.1 and Apple LLVM version 8.0.0 - OS X Yosemite 10.10.5 with Xcode 7.2.1 and Apple LLVM version 7.0.2 @@ -455,7 +457,7 @@ Bugs fixed - Bug 2456 - lte: MemberCschedSapProvider and Member CschedSapProvider templates - Bug 2464 - spectrum: Store spectrum conversion matrix in CSR format - Bug 2467 - spectrum: Do not schedule StartRx for receivers on other models -- Bug 2471 - wifi: unable to disable Block Ack agreement for 802.11n +- Bug 2471 - wifi: unable to disable Block Ack agreement for 802.11n - Bug 2477 - wifi: DCF manager assert - Bug 2485 - traffic-control: Check queue full before checking RED thresholds - Bug 2491 - wifi: replace DcfManager::MY_DEBUG @@ -595,8 +597,8 @@ This release has been tested on the following platforms: New user-visible features ------------------------- -- (aodv) The node search radius is increased progressively (as per standard). -- (build system) New --check-config option to waf to reprint the summary +- (aodv) The node search radius is increased progressively (as per standard). +- (build system) New --check-config option to waf to reprint the summary of optional features which are configured. - (build system) C++11 features are now supported in the codebase - (core) DES Metrics support; see the API docs for class DesMetrics. @@ -607,7 +609,7 @@ New user-visible features Users can use RecvFrom (for UDP) or GetPeerName (for TCP) instead. - (traffic control) Added the FQ-CoDel and PIE queue disc models - (traffic control) Introduce Byte Queue Limits (BQL) -- (wifi) A new SpectrumWifiPhy physical layer model, making use of the +- (wifi) A new SpectrumWifiPhy physical layer model, making use of the ns-3 spectrum framework, has been introduced. The current version of this model matches the API and behavior of YansWifiPhy closely, but over time is expected to support a different PHY abstraction and error @@ -693,7 +695,7 @@ Bugs fixed - Bug 2500 - Ipv[4,6]RawSocket ignores IpTtl tag - Bug 2507 - ConfigStore RawTextConfigLoad doesn't reset stream error state - Bug 2508 - Duplicate of bug 2507 -- Bug 2514 - The maximum transmission time for VHT A-MPDUs is not correct +- Bug 2514 - The maximum transmission time for VHT A-MPDUs is not correct - No BugId - Arp logging: label with request or reply properly Known issues @@ -726,26 +728,26 @@ This release has been tested on the following platforms: New user-visible features ------------------------- -- (internet) The native TCP implementation has been refactored, for the - following improvements: - 1) congestion control has been aligned with the Linux architecture, +- (internet) The native TCP implementation has been refactored, for the + following improvements: + 1) congestion control has been aligned with the Linux architecture, to facilitate easier coding of new congestion control algorithms - or porting implementations from the Linux kernel, - 2) Fast Retransmit and Fast Recovery algorithms, compliant to RFCs, are - shared by all TCP variants, unlike previous releases. + or porting implementations from the Linux kernel, + 2) Fast Retransmit and Fast Recovery algorithms, compliant to RFCs, are + shared by all TCP variants, unlike previous releases. 3) TCP Hybla and TCP HighSpeed variants have been added. - (routing) The PrintRoutingTable* functions now print the following information - each time they are called: - 1) the node ID, - 2) the global time, - 3) the local time (allowing for future introduction of per-node clocks), + each time they are called: + 1) the node ID, + 2) the global time, + 3) the local time (allowing for future introduction of per-node clocks), 4) the routing protocol type - (traffic control) A traffic control sublayer has been added with the aim of - introducing an equivalent of the Linux Traffic +Control infrastructure into - ns-3. This layer sits in between the NetDevices (L2) and the network - protocol (e.g. IP). It is in charge of processing packets and performing + introducing an equivalent of the Linux Traffic +Control infrastructure into + ns-3. This layer sits in between the NetDevices (L2) and the network + protocol (e.g. IP). It is in charge of processing packets and performing actions on them: scheduling, dropping, marking, policing, etc. Initial support for flow control has been added to the PointToPointNetDevice; backward-compatible support for other device types is provided. @@ -758,7 +760,7 @@ New user-visible features - (wifi) A number of changes related to improving support for 802.11n/ac models have been introduced. 1) Two rate controls compatible with High Throughput (HT) Wi-Fi modes - (e.g. 802.11n/ac), Ideal and MinstrelHT, have been added + (e.g. 802.11n/ac), Ideal and MinstrelHT, have been added 2) Support for multiple spatial streams (MIMO) using existing SISO error models 3) The WiFi helper API for the WifiMac sublayer, and the configuration @@ -767,33 +769,33 @@ New user-visible features - (wifi) 802.11g was made backward compatible with 802.11b networks -- (internet) L4 protocols (e.g., TCP, UDP, ICMP, etc.) can be demultiplexed - by IP according to the incoming interface. In other words, it is now +- (internet) L4 protocols (e.g., TCP, UDP, ICMP, etc.) can be demultiplexed + by IP according to the incoming interface. In other words, it is now possible to use specialized L4 protocols according to the interface. -- (internet) Ipv6Address::IsAllHostsMulticast() is now deprecated. +- (internet) Ipv6Address::IsAllHostsMulticast() is now deprecated. FF02::3 is not in the official reserved IPv6 multicast address list. -- (internet) Ipv6Address::IsAll[Nodes,Routers]Multicast() now checks the - address scope beyond the simple link-local. Nodes are checked for - Interface-Local, Link-Local and Realm-Local, Routers for the above plus +- (internet) Ipv6Address::IsAll[Nodes,Routers]Multicast() now checks the + address scope beyond the simple link-local. Nodes are checked for + Interface-Local, Link-Local and Realm-Local, Routers for the above plus Site-Local. -- (internet) Ipv6 routing protocols must now *not* forward packets to upper - layers unless for extremey specific cases. The Ipv6L3protocol handles +- (internet) Ipv6 routing protocols must now *not* forward packets to upper + layers unless for extremey specific cases. The Ipv6L3protocol handles almost all the packets directed to the host. -- (internet) Ipv6 can now reject packets directed to an address not configured +- (internet) Ipv6 can now reject packets directed to an address not configured on the interface they are received from (Strong End System Model, RFC 1222). - (internet) UDP and Ipv6 RAW sockets can now join Ipv6 multicast groups. - Incoming packets will be filtered according to if there's a socket listening + Incoming packets will be filtered according to if there's a socket listening to that group. Source filtering is left to the application. -- (network) ns-3 is now capable of serializing cooked (SLL) headers. This is +- (network) ns-3 is now capable of serializing cooked (SLL) headers. This is used in DCE to allow the generation of pcap directly readable by wireshark. -- (internet) It is now possible to set custom values for RipNg Link Down +- (internet) It is now possible to set custom values for RipNg Link Down (standard is 16). - (internet) permanent (static) NDISC entries can be created for IPv6 @@ -829,7 +831,7 @@ Bugs fixed - Bug 2206 - Split internet-apps from applications - Bug 2207 - Print node ID and time when printing routing tables - Bug 2208 - Interface index based L4 protocols -- Bug 2210 - set Order field to 0 for HT/VHT +- Bug 2210 - set Order field to 0 for HT/VHT - Bug 2211 - Ipv{4,6}EndPoint can cause memory corruption - Bug 2213 - Inconsistencies may exist between the selected WifiMacHelper and the chosen 802.11 version - Bug 2219 - SixLowPanNetDevice hangs trying to decode a IPv6 Fragment extension header @@ -953,7 +955,7 @@ This release has been tested on the following platforms: New user-visible features ------------------------- - (build system) Python 3 is now supported by waf and test runner programs -- (wifi) 802.11ac Very High Throughput (VHT) physical layer modes are now +- (wifi) 802.11ac Very High Throughput (VHT) physical layer modes are now supported. - (internet) permanent (static) ARP entries can be created for IPv4 - (network) SimpleChannel allows per-NetDevice blacklists, in order to do hidden terminal testcases. @@ -1033,11 +1035,11 @@ New user-visible features CalculateBytesTxTime and CalculateBitsTxTime are to be used instead. The return value is a Time, instead of a double. - (mobility) Classes added for converting geographic to cartesian coordinates. -- (spectrum) TvSpectrumTransmitter models added to create television - transmitter(s) that transmit PSD spectrums customized by attributes such +- (spectrum) TvSpectrumTransmitter models added to create television + transmitter(s) that transmit PSD spectrums customized by attributes such as modulation type, power, antenna type, channel frequency, etc. -- (wifi) Several model improvements have been made. Access points now - establish BSSBasicRateSet for control frame transmissions. PLCP header +- (wifi) Several model improvements have been made. Access points now + establish BSSBasicRateSet for control frame transmissions. PLCP header and payload reception have been decoupled for improved PHY modeling accuracy. RTS/CTS with A-MPDU is now fully supported, and 802.11n stations now support two-level aggregation. @@ -1050,7 +1052,7 @@ Bugs fixed - Bug 2004 - Wrong timeout calculation for 802.11n in WifiMac - Bug 2008 - (lr-wpan) Crash if ending rx while status change is in progress - Bug 2025 - (lr-wpan) Changing the channel doesn't affect the Tx params -- Bug 2034 - (lr-wpan) CSMA-CA BackoffPeriod is too short +- Bug 2034 - (lr-wpan) CSMA-CA BackoffPeriod is too short - Bug 2054 - TCP window update can shrink the Left Edge of the window - Bug 2066 - A-MPDU reception should check for successful preamble - Bug 2067 - TCP performance when advertised window exceeds sender buffer size @@ -1095,12 +1097,12 @@ This release has been tested on the following platforms: New user-visible features ------------------------- -- (wifi) Support for MPDU aggregation has been added to the wifi model, +- (wifi) Support for MPDU aggregation has been added to the wifi model, as well as a number of related example programs. - (wifi) Added two combined power and rate control mechanisms to the wifi module. The new mechanisms, PARF and APARF, are the first in the - wifi module to jointly control transmission power and data rate. Two use - case examples (PowerAdaptationDistance and PowerAdaptationInterference) + wifi module to jointly control transmission power and data rate. Two use + case examples (PowerAdaptationDistance and PowerAdaptationInterference) and a test case have also been added. - (lte) In previous releases of the LTE module, the bearer release functionality was only partially supported. As an enhancement, a @@ -1109,18 +1111,18 @@ New user-visible features LteHelper::DeActivateDedicatedEpsBearer(). The related output can be seen through the stats collected at different layers like PDCP, RLC, MAC, PHY. To support this implementation, an example and test suite is - added within the LTE module examples and tests folder. -- (wave) Additional support has been added for WiFi-based vehicular networks, - including the channel-access coordination features of IEEE 1609.4 and a - comprehensive VANET routing example that includes a Basic Safety - Message (BSM) packet generator application and associated statistics - counters. Together, these allow users to evaluate the performance effects - in a VANET of varying transmission and channel properties (e.g., packet - rate, message size, transmit power, propagation loss model, impact of + added within the LTE module examples and tests folder. +- (wave) Additional support has been added for WiFi-based vehicular networks, + including the channel-access coordination features of IEEE 1609.4 and a + comprehensive VANET routing example that includes a Basic Safety + Message (BSM) packet generator application and associated statistics + counters. Together, these allow users to evaluate the performance effects + in a VANET of varying transmission and channel properties (e.g., packet + rate, message size, transmit power, propagation loss model, impact of routing protocol traffic, etc.). -- (internet) It is now possible to print the Neighbor Cache (ARP and NDISC) +- (internet) It is now possible to print the Neighbor Cache (ARP and NDISC) by using the RoutingProtocolHelper -- (stats) A new TimeProbe class has been added to hook the data collection +- (stats) A new TimeProbe class has been added to hook the data collection framework to traced values emitting Time objects - (documentation) the callback function signatures for all TraceSources is documented in Doxygen @@ -1166,7 +1168,7 @@ Bugs fixed - Bug 2037 - HT capabilities may print bogus chars - Bug 2038 - Stop method does not stop next wave in WaveformGenerator - Bug 2042 - LTE a3-rsrp-handover-algorithm.cc: error: overflow in implicit constant conversion -- Bug 2043 - print-introspected-doxygen crashes when some modules are disabled +- Bug 2043 - print-introspected-doxygen crashes when some modules are disabled - Bug 2044 - Buffer::Iterator::ReadNtohU16() and ReadNtohU32() not implemented correctly - Bug 2045 - Missing NS_OBJECT_ENSURE_REGISTERED in TcpTxBuffer and TcpRxBuffer - Bug 2046 - set Block Ack timeout when SetStandard is called @@ -1207,40 +1209,40 @@ New user-visible features interfaces over emulated links via the new helper class EmuEpcHelper. - CommandLine can now provide a shorthand argument name for any Attribute. -- Implemented support for Frequency Reuse algorithms in LTE module, as the - outcome of GSoC 2014 project. +- Implemented support for Frequency Reuse algorithms in LTE module, as the + outcome of GSoC 2014 project. The project also includes several sub-features, such as: - implementation of Downlink Power Control - implementation of Uplink Power Control - - new DL-CQI generation approach, which increases throughput if FR algorithms + - new DL-CQI generation approach, which increases throughput if FR algorithms are used - - seven options of Frequency Reuse algorithms: LteFrNoOpAlgorithm, - LteFrHardAlgorithm, LteFrStrictAlgorithm, LteFrSoftAlgorithm, + - seven options of Frequency Reuse algorithms: LteFrNoOpAlgorithm, + LteFrHardAlgorithm, LteFrStrictAlgorithm, LteFrSoftAlgorithm, LteFfrSoftAlgorithm, LteFfrEnhancedAlgorithm, LteFfrDistributedAlgorithm - - updated RadioEnvironmentMapHelper. Now RadioEnvironmentMap can be generated - for Data or Control channel and for specified RbId, what is helpful when + - updated RadioEnvironmentMapHelper. Now RadioEnvironmentMap can be generated + for Data or Control channel and for specified RbId, what is helpful when using FR algorithms - Added a CoDel queue model. CoDel queues measure and control the queue - traversal delay. The ns-3 implementation is a port of the Linux + traversal delay. The ns-3 implementation is a port of the Linux implementation. - Added support for TCP timestamp and window scale options, and added ability to trace the TCP slow start threshold value. - SimpleNetDevice and SimpleChannel (used for adding basic link effects - for testing of higher-layer protocols) have been extended to support + for testing of higher-layer protocols) have been extended to support the option of broadcast or PointToPoint link semantics. The bandwidth and link delay can be constrained, and it uses an output queue. -- SimpleNetDevice and SimpleChannel can be installed in a node through +- SimpleNetDevice and SimpleChannel can be installed in a node through a new helper: SimpleNetDeviceHelper. - Implemented new PacketSocketServer and PacketSocketClient applications. - The primary use is in tests, to avoid using the ones from the + The primary use is in tests, to avoid using the ones from the application module that also bring in a dependency on the internet module. - + Bugs fixed ---------- - Bug 1673 - Config::Set/Connect does not search for attributes in parent class - Bug 1762 - UE stuck in IDLE_CONNECTING because RRC CONN REQ is not transmitted -- Bug 1811 - basic traffic generator for network module +- Bug 1811 - basic traffic generator for network module - Bug 1824 - L4 protocol sockets should support BindToNetDevice over IPv6 - Bug 1831 - TcpSocket SlowStartThreshold is not a TraceSource - Bug 1851 - WifiRadioEnergyModel energy consumption values are taken from a 802.15.4 chip @@ -1294,17 +1296,17 @@ New user-visible features - A new LrWpan model, providing initial support for IEEE 802.15.4 networks - A new IPv6 routing protocol has been added: RIPng. This protocol is an Interior Gateway Protocol and it is available in the Internet module. -- A new LTE MAC downlink scheduling algorithm named Channel and QoS Aware (CQA) +- A new LTE MAC downlink scheduling algorithm named Channel and QoS Aware (CQA) Scheduler is provided by the new ``ns3::CqaFfMacScheduler`` object. - The Internet FlowMonitor can now track IPv6 packets. - FlowMonitor no longer tracks multicast/broadcast packets, reflecting its original design. -- FlowMonitor "SerializeToXml" functions are now directly available +- FlowMonitor "SerializeToXml" functions are now directly available from the helper. - The SixLowPan model can now use uncompressed IPv6 headers. An option to - define the minimum compressed packet size has been added. + define the minimum compressed packet size has been added. - Simplify output of Times in a specific unit; see Time::As () -- Ipv6Extension::m_dropTrace has been removed. Ipv6L3Protocol::m_dropTrace +- Ipv6Extension::m_dropTrace has been removed. Ipv6L3Protocol::m_dropTrace is now fired when appropriate. - IPv4 identification field value is now dependent on the protocol field. - Fixes to support Python >= 3.3 in ns3 Python bindings @@ -1413,7 +1415,7 @@ New user-visible features - A new FixedRoomPositionAllocator has been added to the buildings module. It allows one to generate a random position uniformly - distributed in the volume of a chosen room inside a chosen building. + distributed in the volume of a chosen room inside a chosen building. - A new attribute ns3::LteRlcAm::TxOpportunityForRetxAlwaysBigEnough allows to overcome the lack for re-segmentation in the RLC AM @@ -1424,22 +1426,22 @@ New user-visible features for speed, resulting in a significantly lower execution time of the LTE model when used with the error model enabled. -- A new WiFi extension for vehicular simulation support is available in - the src/wave directory. The current code represents an interim capability - to realize an IEEE 802.11p-compliant device, but without the WAVE - extensions (which are planned for a later patch). The WaveNetDevice +- A new WiFi extension for vehicular simulation support is available in + the src/wave directory. The current code represents an interim capability + to realize an IEEE 802.11p-compliant device, but without the WAVE + extensions (which are planned for a later patch). The WaveNetDevice modelled herein enforces that a WAVE-compliant physical layer (at 5.9 GHz) - is selected, and does not require any association between devices (similar - to an adhoc WiFi MAC), but is otherwise similar (at this time) to a - WifiNetDevice. WAVE capabililties of switching between control and + is selected, and does not require any association between devices (similar + to an adhoc WiFi MAC), but is otherwise similar (at this time) to a + WifiNetDevice. WAVE capabililties of switching between control and service channels, or using multiple radios, are not yet modelled. - A new IPv6 over Low power Wireless Personal Area Networks (6LoWPAN) model is available. Using ns-3's naming convention, the acronym is expanded - to SixLowPanNetDevice. The SixLowPanNetDevice is able to act as a - shim between IPv6 and a NetDevice, compressing IPv6 headers according - to RFCs 4944 and 6262. The SixLowPanNetDevice is meant to be used over - IEEE 802.15.4 NetDevices, but it can be used on other NetDevices as + to SixLowPanNetDevice. The SixLowPanNetDevice is able to act as a + shim between IPv6 and a NetDevice, compressing IPv6 headers according + to RFCs 4944 and 6262. The SixLowPanNetDevice is meant to be used over + IEEE 802.15.4 NetDevices, but it can be used on other NetDevices as well (see the manual for full details). This model precedes the general availability of an 802.15.4 model, so must be run in conjunction with a wired NetDevice model for now, or with experimental versions of @@ -1448,23 +1450,23 @@ New user-visible features - It is now possible to use Ipv6PacketInfoTag from UDP applications in the same way as with Ipv4PacketInfoTag. See Doxygen for current limitations in using Ipv[4,6]PacketInfoTag to set IP properties. - + - Ipv[4,6]Interfaces not respecting the minimum MTU requirements (68 octects for IPv4 and 1280 octects for IPv6) will be automatically set as Down. - + - IPv6 addresses and routing tables are printed in a more conventional way, closely matching the Linux "route -A inet6" command. - Additional time units (Year, Day, Hour, Minute) were added to the time - value class that represents simulation time; the largest unit prior to + value class that represents simulation time; the largest unit prior to this addition was Second. -- A new parallel scheduling algorithm based on null messages, a common - parallel DES scheduling algorithm, has been added. The null message +- A new parallel scheduling algorithm based on null messages, a common + parallel DES scheduling algorithm, has been added. The null message scheduler has better scaling properties when running on some scenarios - with large numbers of nodes since it does not require a global + with large numbers of nodes since it does not require a global communication. - + Bugs fixed ---------- - Bug 1496 - Option to print log level in NS_LOG messages, and documentation. @@ -1519,8 +1521,8 @@ These platforms have been tested; others may work also: New user-visible features ------------------------- -- It is now possible to randomize the time of the first beacon from an - access point. Use an attribute "EnableBeaconJitter" to enable/disable +- It is now possible to randomize the time of the first beacon from an + access point. Use an attribute "EnableBeaconJitter" to enable/disable this feature. - A new FixedRoomPositionAllocator helper class is available; it allows one to generate a random position uniformly distributed in the @@ -1551,7 +1553,7 @@ Release 3.18 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.18.tar.bz2 Supported platforms @@ -1575,19 +1577,19 @@ New user-visible features - New generic hash function interface. Two hash functions are provided: murmur3 (default), and the venerable FNV1a. See the Hash Functions section in the Manual. -- New Mac16Address has been added, Mac64Address is now in-line with - Mac48Address and all the three can be used in IPv6 autoconfigure. +- New Mac16Address has been added, Mac64Address is now in-line with + Mac48Address and all the three can be used in IPv6 autoconfigure. - Previously, the use of Building models was limited to the use of the companion BuildingsMobilityModel. Now, any MobilityModel can be - used with Building models. + used with Building models. - The latest LTE module code by the LENA project has been merged, - including the following new features: + including the following new features: - PHY support for UE measurements (RSRP and RSRQ) - RRC support for UE measurements (configuration, execution, reporting) - Automatic Handover trigger based on RRC UE measurement reports -- IPv6 can now detect and use Path-MTU. See +- IPv6 can now detect and use Path-MTU. See examples/ipv6/fragmentation-ipv6-two-MTU.cc for an example. -- Radvd application have a new Helper. See the updated +- Radvd application have a new Helper. See the updated examples/ipv6/radvd.cc for an example. - 11n- It is now possible to create a high throughput (HT) node that used the new 11n data rates and preambles. - It is now possible to request printing command line arguments to the @@ -1644,7 +1646,7 @@ Release 3.17 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.17.tar.bz2 Supported platforms @@ -1664,18 +1666,18 @@ New user-visible features - new TCP Westwood and Westwood+ models - new FdNetDevice model and associated helpers. The FdNetDevice is able to read and write from a file descriptor. Various helpers are provided - to associate this descriptor with underlying devices or sockets on the + to associate this descriptor with underlying devices or sockets on the host operating system, including a packet socket for emulation, and tap devices including a version specialized for use on PlanetLab. - ns-3-click: it's now possible to (i) have Click pull random numbers from - ns-3 and (ii) have ns-3 set "defines" in Click via the simulation file + ns-3 and (ii) have ns-3 set "defines" in Click via the simulation file (see src/click/examples/nsclick-defines.cc). - Waf shipped with ns-3 has been upgraded to version 1.7.10 and custom pkg-config generator has been replaced by Waf's builtin tool. - create-module.py script has been updated to work with waf 1.7 and support for creating modules with names containing dashes has been added. - the M5 release of the LTE module by the LENA project has been - merged; please see src/lte/RELEASE_NOTES for more detailed info + merged; please see src/lte/RELEASE_NOTES for more detailed info Bugs fixed ---------- @@ -1744,7 +1746,7 @@ Release 3.16 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.16.tar.bz2 Supported platforms @@ -1760,20 +1762,20 @@ Supported platforms New user-visible features ------------------------- -- Support several new LTE MAC schedulers developed in GSoC 2012 project. +- Support several new LTE MAC schedulers developed in GSoC 2012 project. Those schedulers include FD-MT, TD-MT, TTA, FD-BET, TD-BET, FD-TBFQ, - TD-TBFQ, PSS. Here, FD and TD mean frequency domain and time domain + TD-TBFQ, PSS. Here, FD and TD mean frequency domain and time domain respectively. - It's now possible to use distcc when building ns-3 by using $ CXX='distcc g++' ./waf configure $ ./waf build -- Support topology generation with the (external) BRITE topology generation +- Support topology generation with the (external) BRITE topology generation tool Bugs fixed ---------- - bug 555 - DCF immediate access -- bug 976 - wifi-wired-bridging regression test fails because of +- bug 976 - wifi-wired-bridging regression test fails because of rounding errors in mobility model - bug 1055: Wrong UAN's Thorp absorption loss model formula - bug 1284 - ./test.py performance tests do not exist @@ -1789,17 +1791,17 @@ Bugs fixed - bug 1485 - Setting global properties in config file (raw text) does not have any effect - bug 1493 - test.py --list should show the test type default tip -- bug 1493 - test.py --list should show the test type +- bug 1493 - test.py --list should show the test type - bug 1494 - test.py --constrain doesn't work - bug 1495 - test.py claims test passed when no test was run - bug 1506: TCP data segment piggybacking acknowledgment - bug 1509 - RttEstimator returns invalid value in presence of errors - bug 1516 - GtkConfigStore does not show read-only attributes - bug 1520 - Config paths not fully documented (partial fix) -- bug 1524 - Fragmentation Threshold equals to Packet Size at MAC Layer +- bug 1524 - Fragmentation Threshold equals to Packet Size at MAC Layer (Data + IP + UDP) crash the reception - bug 1525 - Linker error with mpi on Mac 10.8 -- bug 1526: Wrong calculation of pathloss within +- bug 1526: Wrong calculation of pathloss within UanPropModelThorp::GetPathLossDb - bug 1527 - Ipv4RawSocket's BindToNetDevice not working - bug 1528 - BindToNetDevice not working for IPv6 sockets @@ -1816,7 +1818,7 @@ Release 3.15 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.15.tar.bz2 Supported platforms @@ -1826,16 +1828,16 @@ Supported platforms - Ubuntu 12.04 (32/64 bit) with g++-4.6.3 - Ubuntu 10.04.4 LTS (64 bit) with g++-4.4.3 - OS X Mountain Lion 10.7.4 with g++-4.2.1 -- OS X Snow Leopard 10.6.8 with g++-4.2.1 +- OS X Snow Leopard 10.6.8 with g++-4.2.1 - FreeBSD 8.2 (32 bit) with g++-4.2.1 - Cygwin 1.7.9-1 with g++-4.5.3 New user-visible features ------------------------- - A new random variable base class called 'RandomVariableStream', has been - introduced. This base class derives from ns3::Object, unlike the current - 'RandomVariable' class which is a special type of object in the ns-3 - system to date. By making this class derive from ns3::Object, it can be + introduced. This base class derives from ns3::Object, unlike the current + 'RandomVariable' class which is a special type of object in the ns-3 + system to date. By making this class derive from ns3::Object, it can be handled with the Ptr class, can carry attributes, and can have its parameters and initial state saved in the config-store subsystem. A new attribute called "Stream" has been introduced for this class, to allow users to @@ -1847,11 +1849,11 @@ Bugs fixed - bug 101 - random variable initialization - bug 1256 - Unnecessary SND.NXT advance, missing ACK for Out of Order segments - bug 1308 - Nix-vector; do not process packets to self - - bug 1386 - assert if PositionAllocator not provided to + - bug 1386 - assert if PositionAllocator not provided to RandomWaypointMobilityModel - bug 1399 - TCP not backing off retransmissions properly - bug 1441 - IPv4 header length handling - - bug 1464 - ConfigStore Save + Load => Could not set default value + - bug 1464 - ConfigStore Save + Load => Could not set default value for ns3::UdpSocketImpl::IcmpCallback - bug 1470 - define default parameter for constructor in .h file - bug 1473 - GetQueue/SetQueue missing from Csma python bindings @@ -1888,7 +1890,7 @@ Release 3.14 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.14.tar.bz2 Supported platforms @@ -1903,16 +1905,16 @@ available on all platforms; check the Installation page on the project wiki. - Ubuntu 11.10 (32 bit) with g++-4.6.1 - Ubuntu 10.04.4 LTS (64 bit) with g++-4.4.3 - OS X Lion 10.7.4 with g++-4.2.1 -- OS X Snow Leopard 10.6.8 with g++-4.2.1 +- OS X Snow Leopard 10.6.8 with g++-4.2.1 - FreeBSD 8.2 (32 bit) with g++-4.2.1 - Cygwin 1.7.9-1 with g++-4.5.3 New user-visible features ------------------------- - Transport protocol implementations (TCP, UDP) have been refactored to - support also IPv6 connections. Dual-stacked IPv6 sockets are implemented. - An IPv6 socket can accept an IPv4 connection, returning the sender's - address as an IPv4-mapped address (IPV6_V6ONLY socket option is not + support also IPv6 connections. Dual-stacked IPv6 sockets are implemented. + An IPv6 socket can accept an IPv4 connection, returning the sender's + address as an IPv4-mapped address (IPV6_V6ONLY socket option is not implemented). - The LTE code from the LENA project has been merged, bringing in a significant redesign of the LTE module as well as many new features. @@ -1920,15 +1922,15 @@ New user-visible features radiation pattern models. See the corresponding new section of the ns-3 models library documentation for details. - A new buildings module is introduced which allows to model the - presence of buildings in a wireless network topology. + presence of buildings in a wireless network topology. - New propagation models (OkumuraHata, ITU-R P.1411, ITU-R P.1238) have been added - The Dynamic Source Routing (DSR) MANET routing protocol for IPv4 was added. - A Random Early Detection (RED) queue model has been added. -- Ipv6RoutingHelper is now in-line with Ipv4RoutingHelper concerning the RT - print functions. Various minor changes were made in Ipv6RoutingProtocol and +- Ipv6RoutingHelper is now in-line with Ipv4RoutingHelper concerning the RT + print functions. Various minor changes were made in Ipv6RoutingProtocol and derived classes to make this possible. -- New "SendIcmpv6Redirect" attribute (and getter/setter functions) to +- New "SendIcmpv6Redirect" attribute (and getter/setter functions) to Ipv6L3Protocol. The behavior is similar to Linux's conf "send_redirects", i.e., enable/disable the ICMPv6 Redirect sending. - Longer and more descriptive names are used for error units in RateErrorModel @@ -1948,27 +1950,27 @@ Bugs fixed - bug 1180 - LTE: Add TX/RX trace support - bug 1273 - Better error message on missing Python development files - bug 1282 - Sleep state and CCA - - bug 1283 - PacketSocket::SendTo should return number of bytes + - bug 1283 - PacketSocket::SendTo should return number of bytes - bug 1302 - Flow monitor bug - bug 1304 - Tag information changed after transmission - bug 1313 - Stddev (average.h) returning NaN - bug 1318 - Asserts for IPv6 malformed packets - bug 1319 - Fix Ipv6RawSocketImpl Icmpv6 filter - - bug 1325 - Python examples get valgrind errors when build subdirectories + - bug 1325 - Python examples get valgrind errors when build subdirectories are specified in waf - bug 1339 - test.py uses the old name for the test runner - - bug 1348 - python bindings: deprecated conversion from string constant + - bug 1348 - python bindings: deprecated conversion from string constant to ‘char*’ - bug 1349 - TypeId.LookupAttributeByName Python bindings missing - bug 1350 - Simulator.ScheduleWithContext Python binding missing - bug 1351 and 1333 - TCP not able to take RTT samples on long delay network - - bug 1352 - Fixed MapAttributes, previously was mapped to a vector in - ObjectPtrContainer and (and key information was dropped). + - bug 1352 - Fixed MapAttributes, previously was mapped to a vector in + ObjectPtrContainer and (and key information was dropped). Now the container is a map. - bug 1354 - Building scratch subdir programs is broken - bug 1355 - Visualizer dependencies not detected at buildtime - bug 1357 - IPv6 fragmentation fails due to checks about malformed extensions - - bug 1362 - ICMPv6 does not forward ICMPs to upper layers (and minor + - bug 1362 - ICMPv6 does not forward ICMPs to upper layers (and minor fixes to ICMPv6) - bug 1376 - wrong wind variable's name - bug 1378 - UdpEchoClient::SetFill () does not set packet size correctly @@ -1981,11 +1983,11 @@ Bugs fixed - bug 1396 - ARP with hardware addresses longer than 6 bytes - bug 1399 - TCP not backing off retransmissions properly - bug 1404 - Bound user input in tutorial third.cc program - - bug 1406 - waf exits with maximum recursion depth exceeded + - bug 1406 - waf exits with maximum recursion depth exceeded - bug 1415 - examples-to-run.py doesn't work with command line arguments - bug 1420 - no python bindings for csma-layout - bug 1441 - IPv4 header length handling - + Known issues ------------ In general, known issues are tracked on the project tracker available @@ -1996,7 +1998,7 @@ Release 3.13 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.13.tar.bz2 Supported platforms @@ -2005,12 +2007,12 @@ ns-3.13 has been tested on the following platforms. Not all features are available on all platforms; check the Installation page on the project wiki. - Ubuntu 11.10 (32 bit) with g++-4.5.2 -- Ubuntu 11.04 (32/64 bit) with g++-4.5.2 -- Ubuntu 10.04.3 LTS (64 bit) with g++-4.4.3, g++-3.4.6 +- Ubuntu 11.04 (32/64 bit) with g++-4.5.2 +- Ubuntu 10.04.3 LTS (64 bit) with g++-4.4.3, g++-3.4.6 - OS X Lion with g++-4.2.1 -- OS X Snow Leopard with g++-4.2.1 +- OS X Snow Leopard with g++-4.2.1 - Fedora Core 16 (32/64 bit) with g++-4.6.2 - -- however, g++-3.4.6 fails on Fedora 16 i686 + -- however, g++-3.4.6 fails on Fedora 16 i686 - Fedora Core 14 (64 bit) with g++-4.5.1 - FreeBSD 9.0-RC1 (AMD64) with g++-4.2.1 @@ -2025,10 +2027,10 @@ Bugs fixed - bug 1010 - Uan model sleep patch - bug 1020 - Wrong usage of the originator sequence number in HWMP PREP - bug 1021 - Beacon collision avoidance in Mesh module works incorrectly - - bug 1039 - Nagle's algorithm in TCP + - bug 1039 - Nagle's algorithm in TCP - bug 1055 - Wrong UAN's Thorp absorption loss model formula - bug 1059 - Unable to load trace files created from SUMO and TraNS Lite - - bug 1112 - Advance m_nextTxSequence upon retransmit after RTO + - bug 1112 - Advance m_nextTxSequence upon retransmit after RTO - bug 1137 - mpi module is hard-coded for openmpi - bug 1166 - IPV4 TCP failed to send a RST when connect arrives before listen - bug 1186 - Ipv4Header lacks DSCP and ECN @@ -2048,13 +2050,13 @@ Bugs fixed - bug 1281 - Checksum not calculated when doing IP fragmentation - bug 1285 - IPv6 Localhost is marked as GLOBAL instead of HOST - bug 1290 - buffer-test.cc gets a valgrind error - - bug 1295 - Missing const qualifiers in TopologyRead + - bug 1295 - Missing const qualifiers in TopologyRead - bug 1299 - EnableAsciiIpv4All tracing doesn't show transmitted/recvd packets - - bug 1300 - HalfDuplexIdealPhy notify SpectrumInterference of AbortRx + - bug 1300 - HalfDuplexIdealPhy notify SpectrumInterference of AbortRx - bug 1301 - Ns2MobilityHelper causes Node GetPosition() to return NaN - bug 1305 - do not list modules built upon exiting waf shell - bug 1312: TopologyRead Assert condition fix - - IPv4 packets double fragmentation was broken + - IPv4 packets double fragmentation was broken - Fix wifi-clear-channel-cmu.cc example - NetAnim: fix for bcast packet reuse - Missing PropagationLossModel.CalcRxPower in Python bindings @@ -2071,7 +2073,7 @@ Release 3.12.1 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.12.1.tar.bz2 Bugs fixed @@ -2084,7 +2086,7 @@ Release 3.12 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.12.tar.bz2 Supported platforms @@ -2092,13 +2094,13 @@ Supported platforms ns-3.12 has been tested on the following platforms. Not all features are available on all platforms; check the Installation page on the project wiki. -- Fedora Core 15 (32/64 bit) with g++-4.6.0 -- Ubuntu 11.04 (32/64 bit) with g++-4.5.2 -- OS X Lion with g++-4.2.1 -- Fedora Core 14 (64 bit) with g++-4.3.4, g++-4.5.3, g++-4.4.6 -- Fedora Core 12 (64 bit) with g++-4.4.4 -- OS X Snow Leopard with g++-4.2.1 -- Ubuntu 10.04.3 LTS (64 bit) with g++-4.4.3, g++-3.4.6 +- Fedora Core 15 (32/64 bit) with g++-4.6.0 +- Ubuntu 11.04 (32/64 bit) with g++-4.5.2 +- OS X Lion with g++-4.2.1 +- Fedora Core 14 (64 bit) with g++-4.3.4, g++-4.5.3, g++-4.4.6 +- Fedora Core 12 (64 bit) with g++-4.4.4 +- OS X Snow Leopard with g++-4.2.1 +- Ubuntu 10.04.3 LTS (64 bit) with g++-4.4.3, g++-3.4.6 New user-visible features ------------------------- @@ -2108,7 +2110,7 @@ New user-visible features class. These model can be used in conjunction with the frequency-dependent propagation loss model based on the SpectrumPropagationLossModel class already supported by - SpectrumChannel. + SpectrumChannel. - Extend the attribute system extend the attribute system to store map container objects in addition to vector containers. The ObjectMap @@ -2169,7 +2171,7 @@ Release 3.11 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.11.tar.bz2 Supported platforms @@ -2188,7 +2190,7 @@ available on all platforms; check the Installation page on the project wiki. - Linux x86_64 Fedora Core 10 - g++-3.4.6, 4.0.4, 4.1.2, 4.2.4, 4.3.2, 4.4.0 - OS X Snow Leopard - - g++-4.2.1 + - g++-4.2.1 New user-visible features ------------------------- @@ -2196,14 +2198,14 @@ New user-visible features - The build system has been modularized, and the source code reorganized, to allow for modular libraries instead of a single monolithic ns-3 library. User programs now link a number of smaller, per-module - libraries depending on the dependencies expressed to the build system. + libraries depending on the dependencies expressed to the build system. Source code is now being maintained in individual modules with consistent directory structures. - Python bindings have also been modularized, and the bindings are now generated into a 'ns' namespace instead of 'ns3' for the old (monolithic) bindings. By default the bindings are now modular, with - a backward compatibility layer for older programs. + a backward compatibility layer for older programs. - By default, example and test programs are disabled from the build. Users can enable them via the use of a waf command at configure time, @@ -2219,13 +2221,13 @@ New user-visible features been added to allow the simulation of OpenFlow switches in ns-3. - ns-3 coding style requirements have been applied to the entire coding - base, resulting in a large number of whitespace changes. The coding - style has been automatically enforced by running a style checking + base, resulting in a large number of whitespace changes. The coding + style has been automatically enforced by running a style checking program (utils/check-style.py) that uses the uncrustify (v. 0.58) - program to apply changes. + program to apply changes. - Some documentation reorganization to split documentation between - the ns-3 manual (primarily focusing on the ns-3 core) and a new + the ns-3 manual (primarily focusing on the ns-3 core) and a new "model library" document has been started. Bugs fixed @@ -2234,13 +2236,13 @@ The following lists many of the bugs fixed or small feature additions since ns-3.10, in many cases referencing the Bugzilla bug number. - bugfix: CsmaNetDevice ErrorModel not discarding packet - - bugfix: do not call RouteOutput() twice - - Workaround gccxml bug scanning Seconds(0) as default value - - Copy a bug fix from ns3modulescan.py into ns3modulescan-modular.py - - Modular Python bindings work (many bug fixes, more modules tested) - - Modular bindings: bug fixes, more verbose scanning + - bugfix: do not call RouteOutput() twice + - Workaround gccxml bug scanning Seconds(0) as default value + - Copy a bug fix from ns3modulescan.py into ns3modulescan-modular.py + - Modular Python bindings work (many bug fixes, more modules tested) + - Modular bindings: bug fixes, more verbose scanning - ./waf --apiscan: fix bug in detection of whether the per-module - - Remove the 'Modules to build' debug print + - Remove the 'Modules to build' debug print - CsmaNetDevice ReceiveErrorModel was not dropping the packet - Several "set but not used" bugs for newer compilers quick-fixed @@ -2253,7 +2255,7 @@ since ns-3.10, in many cases referencing the Bugzilla bug number. - bug 1019 - common --> node --> common circular dependency - bug 1038 - Time::Get*Seconds () return signed integer while actually returning unsigned. - bug 1040 - Olsr and multiple interfaces - - bug 1042 - AODV RERR implosion (missing RERR_RATELIMIT) + - bug 1042 - AODV RERR implosion (missing RERR_RATELIMIT) - bug 1044 - Seconds (1e-9) creates Time that is not IsPositive () - bug 1047 - Multicast routes on nodes with >16 interfaces - bug 1048 - suggested MatrixPropagationLossModel::SetLoss() API change @@ -2269,7 +2271,7 @@ since ns-3.10, in many cases referencing the Bugzilla bug number. - bug 1066 - Set Radiotap modulation type flags correctly - bug 1069 - ApWifiMac unduly calls RegularWifiMac::Receive and crashes - bug 1070 - csma/ipv6 examples duplicate NS_LOG_COMPONENT_DEFINE - - bug 1072 - crash upon call to Packet::AddAtEnd of fragmented packets + - bug 1072 - crash upon call to Packet::AddAtEnd of fragmented packets - bug 1075 - Python examples fail when static built is enabled - bug 1076 - Waf gives an error if you enable only a single module - bug 1078 - PacketTagList::Add performs NS_ASSERT counting one byte too few @@ -2283,7 +2285,7 @@ since ns-3.10, in many cases referencing the Bugzilla bug number. - bug 1089 - lwip build issue - bug 1090 - WifiMacQueue is not accessible through the attribute path - bug 1092 - Problem building FreeBSD stack with g++ 4.5.2 (Ubuntu) - - bug 1094 - Object::GetObject upon dlopen + - bug 1094 - Object::GetObject upon dlopen - bug 1097 - AODV routing entry set to be VALID mistakenly. - bug 1098 - when to show users which modules are enabled? - bug 1101 - Sqlite stats disappeared from configuration file src/wscript @@ -2310,7 +2312,7 @@ Release 3.10 Availability ------------ -This release is available from: +This release is available from: http://www.nsnam.org/release/ns-allinone-3.10.tar.bz2 Supported platforms @@ -2327,14 +2329,14 @@ available on all platforms; check the Installation page on the project wiki. - Linux x86_64 Fedora Core 10 - g++-3.4.6, 4.0.4, 4.1.2, 4.2.4, 4.3.4, 4.4.0 - OS X Snow Leopard - - g++-4.2.1 -- OS X powerpc Leopard + - g++-4.2.1 +- OS X powerpc Leopard - g++-4.0, g++-4.2 New user-visible features ------------------------- - - NS-3 PyViz, a live simulation visualizer, has been added. The + - NS-3 PyViz, a live simulation visualizer, has been added. The visualizer interacts with a running simulation, such that it uses no trace files. It can be most useful for debugging purposes, i.e. to figure out if mobility models are what you expect, where packets are @@ -2370,22 +2372,22 @@ New user-visible features - Regression testing is now completely performed within test.py rather than a separate "./waf --regression" that consults reference traces in the ns-3.x-ref-traces directory. In most - cases, the example programs whose traces were included in + cases, the example programs whose traces were included in ns-3.x-ref-traces have a corresponding test called from the test.py program. It is still possible to write trace-based regression tests but they are now called from the test.py program. - - New BulkSendApplication sends data as fast as possible up to - MaxBytes or unlimited if MaxBytes is zero. Think OnOff, but - without the "off" and without the variable data rate. This - application only works with SOCK_STREAM and SOCK_SEQPACKET + - New BulkSendApplication sends data as fast as possible up to + MaxBytes or unlimited if MaxBytes is zero. Think OnOff, but + without the "off" and without the variable data rate. This + application only works with SOCK_STREAM and SOCK_SEQPACKET sockets, for example TCP sockets and not UDP sockets. - - Extensions to the energy models: 1) a new Rakhmatov Vrudhula - non-linear battery model, 2) additional support for modeling - energy consumption in WiFi devices, 3) an example for how to add - energy models to a WiFi-based simulation (in examples/energy/ + - Extensions to the energy models: 1) a new Rakhmatov Vrudhula + non-linear battery model, 2) additional support for modeling + energy consumption in WiFi devices, 3) an example for how to add + energy models to a WiFi-based simulation (in examples/energy/ directory). - New methods to print IPv4 routing tables to an output stream. @@ -2402,27 +2404,27 @@ New user-visible features set for WHOI acoustic transducer. Li-Ion battery model added into energy models folder. - - Destination-Sequenced Distance Vector (DSDV) routing protocol - is a proactive, table-driven routing protocol for MANETs - developed by Charles E. Perkins and Pravin Bhagwat in 1994. - This implementation is for IPv4 routing and was contributed + - Destination-Sequenced Distance Vector (DSDV) routing protocol + is a proactive, table-driven routing protocol for MANETs + developed by Charles E. Perkins and Pravin Bhagwat in 1994. + This implementation is for IPv4 routing and was contributed by ResilNets Research Group. - - A novel model to simulate LTE networks has been added. It focuses - mainly on modeling the E-UTRA part of the system, with a particular - attention on the aspects related to the channel, PHY and MAC layers. - The most important features available at this moment are (i) a basic - implementation of both the UE and the eNB devices, (ii) RRC and - entities for both the UE and the eNB, (iii) an Adaptive Modulation - and Coding (AMC) scheme for the downlink, (iv) the management of the - data radio bearers (with their QoS parameters), the MAC queues and - the RLC instances, (v) Channel Quality Indicator (CQI) management, - (vi) support for both uplink and downlik packet scheduling, - (vii) a PHY layer model with Resource Block level granularity, and - (viii) a channel model with the outdoor E-UTRAN propagation loss + - A novel model to simulate LTE networks has been added. It focuses + mainly on modeling the E-UTRA part of the system, with a particular + attention on the aspects related to the channel, PHY and MAC layers. + The most important features available at this moment are (i) a basic + implementation of both the UE and the eNB devices, (ii) RRC and + entities for both the UE and the eNB, (iii) an Adaptive Modulation + and Coding (AMC) scheme for the downlink, (iv) the management of the + data radio bearers (with their QoS parameters), the MAC queues and + the RLC instances, (v) Channel Quality Indicator (CQI) management, + (vi) support for both uplink and downlik packet scheduling, + (vii) a PHY layer model with Resource Block level granularity, and + (viii) a channel model with the outdoor E-UTRAN propagation loss model. - - Project documentation has been converted from GNU Texinfo to Sphinx. + - Project documentation has been converted from GNU Texinfo to Sphinx. Bugs fixed ---------- @@ -2512,19 +2514,19 @@ New user-visible features from YansErrorRateModel for OFDM modes (802.11a/g). The default YansWifiPhyHelper has been changed to use this model. - - A new NS-2 mobility trace reader supports BonnMotion, SUMO, TraNS, + - A new NS-2 mobility trace reader supports BonnMotion, SUMO, TraNS, etc. traces. - An energy model for nodes and devices, including an energy source model and device energy models allowing energy-aware devices - to notify the energy source about energy consumption. + to notify the energy source about energy consumption. - Rocketfuel topology dataset support for existing topology reader - Rocketfuel project: + Rocketfuel project: http://www.cs.washington.edu/research/networking/rocketfuel/ - - Underwater Acoustic Network (UAN) model, split in to three parts, the - channel, PHY, and MAC models to enable researchers to model a variety + - Underwater Acoustic Network (UAN) model, split in to three parts, the + channel, PHY, and MAC models to enable researchers to model a variety of underwater network scenarios. - the Spectrum framework, which provides support for spectrum-aware @@ -2532,18 +2534,18 @@ New user-visible features allows the mathematical representation of frequency dependent phenomena. Some example channel, propagation and device implementations that make use of this framework are also - included. + included. Bugs fixed ---------- -The following lists many of the bugs fixed or small feature additions +The following lists many of the bugs fixed or small feature additions since ns-3.8, in many cases referencing the Bugzilla bug number - IPv4 global routing code; stub networks were assumed to be /24 and added as /24 networks even if the mask is actually different - OLSR was generating messages on non-OLSR interfaces - ICMPv4 objects not properly registered; affected serialization code - - bug 231 - SocketAddressTag needs to be removed from a packet before + - bug 231 - SocketAddressTag needs to be removed from a packet before forwarding the packet to the user - bug 385 - Add a generic "sequence number" class - bug 473 - [PATCH] Alternative ns-2 trace reader @@ -2557,13 +2559,13 @@ since ns-3.8, in many cases referencing the Bugzilla bug number - bug 828 - PacketSocket::Close does not unregister protocol handler - bug 842 - ns-3-dev crashes using block acks - bug 843 - Most wifi examples change BeaconInterval to unrealistic values - - bug 844 - YansWifiPhy::GetPowerDbm off-by-one problem when calculating Tx + - bug 844 - YansWifiPhy::GetPowerDbm off-by-one problem when calculating Tx power - bug 846 - packet.cc triggers deprecated warning - bug 853 - Rates for Wi-Fi control responses are incorrectly selected - bug 854 - Support DROP_QUEUE reason-code in Ipv4FlowProbe - bug 858 - support MSG_PEEK in IPv4/IPv6 raw socket - - bug 861 - Forwarding drops (due to no route found) were not being logged + - bug 861 - Forwarding drops (due to no route found) were not being logged in IPv4 or IPv6 ascii traces - bug 869 - suggested test framework enhancements - bug 871 - naming for WifiPhyStandard @@ -2586,18 +2588,18 @@ since ns-3.8, in many cases referencing the Bugzilla bug number - bug 918 - samples/main-packet-header.cc is broken - bug 919 - minstrel does not pass valgrind tests - bug 921 - Inconsistent declaration of class/struct Object in object.h - - bug 922 - Inconsistent declaration of class/struct in + - bug 922 - Inconsistent declaration of class/struct in wifi-remote-station-manager.h - bug 923 - Inconsistent declaration of class/struct in mac-low.h - - bug 924 - Inconsistent declaration of class/struct in -wifi-managers + - bug 924 - Inconsistent declaration of class/struct in -wifi-managers - bug 925 - Various IPv6 cc files trigger deprecated warning - - bug 926 - olsr handling of multicast packets + - bug 926 - olsr handling of multicast packets - bug 927 - SimpleOfdmWimaxChannel RxPower computation - - bug 930 - examples/topology-read/topology-example-sim.cc uses variable + - bug 930 - examples/topology-read/topology-example-sim.cc uses variable length array - bug 931 - Abnormal exit reports SIGSEGV on failure - bug 932 - Support IP_HDRINCL option for Ipv4RawSocket - - bug 933 - Flushing ostream and files on abnormal program exit + - bug 933 - Flushing ostream and files on abnormal program exit (ASSERT, ABORT and FATAL_ERROR) - bug 936 - Waf build error for python bindings on "AccessClass" - bug 937 - bugs in ns-3 wimax @@ -2605,26 +2607,26 @@ since ns-3.8, in many cases referencing the Bugzilla bug number - bug 940 - AODV fails to set up a correct path - bug 941 - Wifi Dcf attributes not reachable through configuration namespace - bug 943 - Add a SO_BROADCAST socket option - - bug 944 - change default ErrorRateModel from YansErrorRateModel to + - bug 944 - change default ErrorRateModel from YansErrorRateModel to NistErrorRateModel - bug 946 - Rocketfuel topology dataset support for topology reader - - bug 949 - Node::NonPromiscReceiveFromDevice reports a meaningless - destination address to user callbacks - - bug 950 - PointToPointNetDevice says promisc support is not implemented + - bug 949 - Node::NonPromiscReceiveFromDevice reports a meaningless + destination address to user callbacks + - bug 950 - PointToPointNetDevice says promisc support is not implemented but it is - bug 955 - Install NSC for NS3 in a Itanium Architecture (ia64) with Linux 2.6.16.6 - bug 956 - Bindings failure in core (traced-value) with older gcc - - bug 958 - WiFi uses wrong default values for MTU, FragmentationThreshold + - bug 958 - WiFi uses wrong default values for MTU, FragmentationThreshold and RtsCtsThreshold - bug 959 - Simulation never finishes when using RealtimeSimulatorImpl - bug 960 - V4Ping does not generate checksum - - bug 961 - Problem with MPI activation + - bug 961 - Problem with MPI activation - bug 964 - AODV does not work with host addressed interfaces - bug 965 - Problem building /src/core/callback.cc - - bug 966 - AODV originates new RREQ on each packet, when doesn't have + - bug 966 - AODV originates new RREQ on each packet, when doesn't have valid route - bug 969 - No SocketList is present in UdpL4Protocol class - - bug 971 - fix AODV header Print functions + - bug 971 - fix AODV header Print functions - bug 972 - [flow monitor] assertion fails in pv4-flow-probe.cc Known issues @@ -2652,32 +2654,32 @@ http://www.nsnam.org/wiki/Installation New user-visible features ------------------------- - a) WiMAX net device: Allow to simulated IEEE 802.16 point to multi-point based networks + a) WiMAX net device: Allow to simulated IEEE 802.16 point to multi-point based networks - b) Distributed simulation for point-to-point networks using the Message + b) Distributed simulation for point-to-point networks using the Message Passing Interface (MPI) standard. - - c) Matrix propagation loss model uses a two-dimensional matrix of path loss indexed + + c) Matrix propagation loss model uses a two-dimensional matrix of path loss indexed by source and destination nodes. - d) Topology read system: Allows quick and easy creation of large topologies by reading + d) Topology read system: Allows quick and easy creation of large topologies by reading Inet or Orbis files - e) Gauss-Markov mobility model: Adds 3-d adaptation of Gauss-Markov mobility model which + e) Gauss-Markov mobility model: Adds 3-d adaptation of Gauss-Markov mobility model which has both memory and variability - f) Steady-state random waypoint mobility model: Based on random waypoint mobility (RWM) model for case when - speed, pause and position are uniformly distributed random variables. However, initial values of these + f) Steady-state random waypoint mobility model: Based on random waypoint mobility (RWM) model for case when + speed, pause and position are uniformly distributed random variables. However, initial values of these parameters are not from uniform distribution but from stationary distribution of RWM model. - g) Two-ray ground propagation loss model: Calculates the crossover distance under which Friis is used. - The antenna height is set to the nodes z coordinate, but can be added to using the model parameter + g) Two-ray ground propagation loss model: Calculates the crossover distance under which Friis is used. + The antenna height is set to the nodes z coordinate, but can be added to using the model parameter SetHeightAboveZ, which will affect ALL stations API changes from ns-3.7 ----------------------- -API changes for this release are documented in the file CHANGES.html. +API changes for this release are documented in the file CHANGES.html. Bugs fixed ---------- @@ -2699,7 +2701,7 @@ many cases referencing the Bugzilla bug number - bug 777 - AODV ignores specified outgoing interface in RouteOutput() - bug 778 - OLSR ignores specified outgoing interface in RouteOutput() - bug 787 - Addition of Two Ray Ground model to propagation loss model and tests - - bug 788 - OLSR_NEIGH_HOLD_TIME should be 3 times OLSR_REFRESH_INTERVAL + - bug 788 - OLSR_NEIGH_HOLD_TIME should be 3 times OLSR_REFRESH_INTERVAL - bug 789 - [PATCH] Globalrouting externalroutes to use the new GetRootExitDirections() - bug 794 - Ipv4Mask constructor for "/yy"-notation is wrong - bug 796 - TCP bug in ns-3-dev branch : Crash detected during retesting of Chord on ns-3-dev branch @@ -2739,9 +2741,9 @@ many cases referencing the Bugzilla bug number - bug 850 - Ipv4GlobalRouting::LookupGlobal bug - bug 855 - waf dies badly when switching from debug to optimized build or vice versa - bug 856 - initialize vbl - - bug 857 - Link-Local Multicast handle in Ipv4 Output processing + - bug 857 - Link-Local Multicast handle in Ipv4 Output processing - bug 859 - Output interface estimation for the source address bound socket in IPv4 Raw socket - - bug 860 - waf sometimes dies while executing ns3header or gen_ns3_module_header tasks in case of + - bug 860 - waf sometimes dies while executing ns3header or gen_ns3_module_header tasks in case of parallel jobs - bug 862 - NotifyInterfaceUp() Adds network route even when netmask is /32 - bug 863 - Wrong Scalar arithmetic @@ -2757,7 +2759,7 @@ many cases referencing the Bugzilla bug number - bug 880 - Node sending a packet to itself via 127.0.0.1 aborts - bug 885 - Error in Ascii tracing in Python examples - bug 888 - Writing ascii trace to additional tests fails - - bug 891 - WiMAX device helper does not include propagation loss model by default + - bug 891 - WiMAX device helper does not include propagation loss model by default - bug 894 - ./waf --run error message upon segfault - bug 895 - SimpleOfdmWimaxPhy SNR computation - bug 899 - EmuNetDevice::SetPromiscReceiveCallback not implemented @@ -2799,11 +2801,11 @@ New user-visible features a) Ad hoc On-Demand Distance Vector (AODV) routing model (RFC 3561) - b) IPv6 extensions support to add IPv6 extensions and options. Two + b) IPv6 extensions support to add IPv6 extensions and options. Two examples (fragmentation and loose routing) are available. - c) NetAnim interface: Provides an interface to the Qt-based NetAnim - animator, which supports static, point-to-point topology-based + c) NetAnim interface: Provides an interface to the Qt-based NetAnim + animator, which supports static, point-to-point topology-based packet animations. d) New topology helpers have been introduced @@ -2812,40 +2814,40 @@ New user-visible features - PointToPointStarHelper - CsmaStarHelper - e) Equal-cost multipath for global routing: Enables quagga's equal + e) Equal-cost multipath for global routing: Enables quagga's equal cost multipath for Ipv4GlobalRouting, and adds an attribute that - can enable it with random packet distribution policy across + can enable it with random packet distribution policy across equal cost routes. f) Binding sockets to devices: A method analogous to a SO_BINDTODEVICE socket option has been introduced to class Socket - g) Object::DoStart: Users who need to complete their object setup at - the start of a simulation can override this virtual method, perform their + g) Object::DoStart: Users who need to complete their object setup at + the start of a simulation can override this virtual method, perform their adhoc setup, and then, must chain up to their parent. - h) Ipv4::IsDestinationAddress method added to support checks of whether a - destination address should be accepted as one of the host's own - addresses. + h) Ipv4::IsDestinationAddress method added to support checks of whether a + destination address should be accepted as one of the host's own + addresses. - i) UniformDiscPositionAllocator added; distributes uniformly the nodes - within a disc of given radius. + i) UniformDiscPositionAllocator added; distributes uniformly the nodes + within a disc of given radius. - j) ChannelNumber attribute added to YansWifiPhy. Now it is possible to + j) ChannelNumber attribute added to YansWifiPhy. Now it is possible to setup wifi channel using WifiPhyHelper::Set() method. - k) WaypointMobilityModel provides a method to add mobility as a set of + k) WaypointMobilityModel provides a method to add mobility as a set of (time, position) pairs - l) 802.11p WiFi standards - + l) 802.11p WiFi standards + m) UDP Client/Server application n) Support transactions in the SQLite output interface, making it usable for larger amounts of data API changes from ns-3.6 ----------------------- -API changes for this release are documented in the file CHANGES.html. +API changes for this release are documented in the file CHANGES.html. Bugs fixed ---------- @@ -2854,14 +2856,14 @@ many cases referencing the Bugzilla bug number - bug 752: Object::DoStart is not executed for objects created at t > 0 - bug 767: Incorrect modulation for 802.11a modes - bug 725: wifi fragmentation and RTS cannot be used at the same time - - bug 782: CreateTap () requires IP address in modes other than + - bug 782: CreateTap () requires IP address in modes other than CONFIGURE_LOCAL. - bug 769: Queue::GetTotalReceived{Bytes,Packets}() broken - bug 738 ReceiveErrorModel called too late - Fix NSC improper response to FIN - Fixed bug in serialization of PbbAddressBlock. - - Fix bug 780 (problem in RoutingTableComputation with asymmetric links), - while adding debugging methods to OLSR. + - Fix bug 780 (problem in RoutingTableComputation with asymmetric links), + while adding debugging methods to OLSR. - bug 759: Ipv6 uses wrong outgoing interface. - bug 770: IPv6 size calculation for unknown options is wrong. - bug 771: Radvd does not set ttl value. @@ -2870,21 +2872,21 @@ many cases referencing the Bugzilla bug number - Drop CSMA packets with CRC errors, rescan, dox tweaks - Add FCS capability to CSMA - Mesh:Dot11s: fixed airtime metric - - Get emu working again: Add Dix/Llc option, add and use contextual + - Get emu working again: Add Dix/Llc option, add and use contextual realtime schedule ops, don't refcount realtime simulator impl - bug 695 - DcfManager::UpdateBackoff () uses slow HighPrecision::Div() - bug 674 - EIFS is not handled correctly in DcfManager::GetAccessGrantStart - - bug 739 - OLSR: Strange HTime value in HELLO messages + - bug 739 - OLSR: Strange HTime value in HELLO messages - bug 746 - UDP source address is not set to bound address - bug 735 Update Olsr for local delivery - bug 740 OLSR MprCompute () works wrong: fixed - bug 729 Enable IPv6 over PPP. - bug 645: fixes for opening stats file with OMNeT++ - - bug 689: default energy detection and CCA thresholds are changed to be + - bug 689: default energy detection and CCA thresholds are changed to be more realistic. - bug 733: OLSR MPR Computation give incorrect result - Mesh: HWMP: fixed proactive routes - - Mesh: fixed FLAME PATH_UPDATE procedure, fixed mesh.cc + - Mesh: fixed FLAME PATH_UPDATE procedure, fixed mesh.cc Known issues ------------ @@ -2918,16 +2920,16 @@ New user-visible features ------------------------- a) 802.11 models: - - Add an implementation of the minstrel rate control algorithm + - Add an implementation of the minstrel rate control algorithm (Duy Nguyen for gsoc) - - AthstatsHelper: enables the wifi device to produce periodic + - AthstatsHelper: enables the wifi device to produce periodic reports similar to the ones generated by madwifi's athstats tool (Nicola Baldo) - - 10MHz and 5MHz channel width supported by 802.11a model + - 10MHz and 5MHz channel width supported by 802.11a model (Ramon Bauza and Kirill Andreev) - - Channel switching support. YansWifiPhy can now switch among + - Channel switching support. YansWifiPhy can now switch among different channels (Ramon Bauza and Pavel Boyko) - + b) IPv6 models: - IPv6 interface; - IPv6 layer; @@ -2946,7 +2948,7 @@ New user-visible features - IEEE 802.11s (Draft 3.0) model including Peering Management Protocol and HWMP. - Forwarding Layer for Meshing (FLAME) protocol. - d) Nix-vector routing: + d) Nix-vector routing: - Ipv4NixVectorHelper - Examples (nix-simple, nms-p2p-nix) @@ -2961,7 +2963,7 @@ New user-visible features API changes from ns-3.5 ----------------------- -API changes for this release are documented in the file CHANGES.html. +API changes for this release are documented in the file CHANGES.html. Known issues ------------ @@ -3008,7 +3010,7 @@ New user-visible features d) UdpEcho: allows setting the payload of echo packets e) Ipv4/Ipv4RoutingProtocol: allow fine-grained control over routing policy and arbitrary composition of routing protocols - + API changes from ns-3.4 ----------------------- API changes for this release are documented in the file CHANGES.html. The @@ -3026,7 +3028,7 @@ Future releases --------------- Our next release, which is expected to happen in 2 to 4 months from now, will feature the merging of some of our projects currently in development including -fuller IPv6 support, some smaller features such as a new Global ARP +fuller IPv6 support, some smaller features such as a new Global ARP package, and possibly a new Testing and Validation suite. Release 3.4 @@ -3082,7 +3084,7 @@ ns-3 build is known to fail on the following platforms: - optimized builds on Ubuntu 8.10 alpha 5 x86 gcc4.3.2 - MinGW -The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes in preparation of the merge of the IPv6 API and implementation. Future releases @@ -3120,7 +3122,7 @@ New user-visible features scenarios. See src/devices/emu and examples/emu-udp-echo.cc for details. b) ICMP Support - Support for several ICMP messages has been added to ns-3. See + Support for several ICMP messages has been added to ns-3. See src/internet-stack/icmpv4.h for details. c) IPv6 Address Support @@ -3132,8 +3134,8 @@ New user-visible features e) Star topologies can be created from the topology helper functions f) The global routing code has been made dynamic (not just limited to - (pre-simulation computation) and supports stub network interfaces and - bridge net devices + (pre-simulation computation) and supports stub network interfaces and + bridge net devices g) A MatchContainer has been added to the configuration subsystem @@ -3150,7 +3152,7 @@ ns-3 build is known to fail on the following platforms: - optimized builds on Ubuntu 8.10 alpha 5 x86 gcc4.3.2 - MinGW -The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes in preparation of the merge of the IPv6 API and implementation. Future releases @@ -3188,7 +3190,7 @@ New user-visible features this new mode of operation. (contributed by Gustavo Carneiro) b) Python bindings - It is now possible to write simulation scripts in python using our + It is now possible to write simulation scripts in python using our python bindings (contributed by Gustavo Carneiro). c) Real-time simulator @@ -3196,14 +3198,14 @@ New user-visible features wall-clock time (contributed by Craig Dowell). d) Network Simulation Cradle - It is now possible to use the Network Simulation Cradle - (http://www.wand.net.nz/~stj2/nsc/) in ns-3 and run simulations + It is now possible to use the Network Simulation Cradle + (http://www.wand.net.nz/~stj2/nsc/) in ns-3 and run simulations using various versions of kernel TCP network stacks. (contributed by Florian Westphal as part of his Google Summer of Code work) e) A statistics framework Joseph Kopena contributed a statistics framework which can be used - keep track of simulation data in persistent storage across multiple + keep track of simulation data in persistent storage across multiple runs (database and ascii file backends are available). More information on the wiki: http://www.nsnam.org/wiki/Statistical_Framework_for_Network_Simulation @@ -3221,13 +3223,13 @@ ns-3 build is known to fail on the following platforms: - optimized builds on Ubuntu 8.10 alpha 5 x86 gcc4.3.2 - MinGW -The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes in preparation of the merge of the IPv6 API and implementation. Future releases --------------- Our next release, which is expected to happen in 2 to 4 months from now, will -feature the merging of some of our projects currently in development: IPv6, +feature the merging of some of our projects currently in development: IPv6, emulation, and synchronous posix sockets. Release 3.1 (2008/06/30) @@ -3239,26 +3241,26 @@ The first ns-3 stable release This release is immediately available from: http://www.nsnam.org/release/ns-3.1.tar.bz2 -We dedicate this initial ns-3 release to our late contributor and friend, +We dedicate this initial ns-3 release to our late contributor and friend, Federico Maguolo. What is ns-3 ? -------------- ns-3 is a new discrete-event network simulator designed for supporting network -research and education. ns-3 features a solid, well documented C++ core and -models for TCP/IP (IPv4), several link types including WiFi, and mobility +research and education. ns-3 features a solid, well documented C++ core and +models for TCP/IP (IPv4), several link types including WiFi, and mobility models. -ns-3 is an open source project released under the GNU GPLv2 license which -allows anyone to use ns-3 without having to pay any license fee or royalties. -ns-3 is actively seeking new contributors to extend the range of supported +ns-3 is an open source project released under the GNU GPLv2 license which +allows anyone to use ns-3 without having to pay any license fee or royalties. +ns-3 is actively seeking new contributors to extend the range of supported models and/or to maintain existing models. Where to get more information about ns-3 ---------------------------------------- -All the ns-3 documentation, is accessible from the ns-3 website: +All the ns-3 documentation, is accessible from the ns-3 website: http://www.nsnam.org Including, tutorials: @@ -3281,15 +3283,15 @@ ns-3 is known to fail on the following platforms: - optimized builds on gcc 3.4.4 and 3.4.5 - optimized builds on linux x86 gcc 4.0.x -The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes in preparation of the merge of the IPv6 API and implementation. Future releases --------------- Our next release, which is expected to happen in 2 to 4 months from now, will -feature the merging of some of our projects currently in development: python -scripting, IPv6, emulation, a statistics framework and synchronous posix +feature the merging of some of our projects currently in development: python +scripting, IPv6, emulation, a statistics framework and synchronous posix sockets. Release 3.0.13 (2008/06/02) @@ -3302,21 +3304,21 @@ Release 3.0.13 (2008/06/02) - ARP cache now supports per-entry pending queues - lots of bugfixes and implementation and API cleanups -Warning: among API changes in this release, Application::Start and +Warning: among API changes in this release, Application::Start and Application::Stop now interprets the time argument as a relative instead of absolute simulation time, to align with how Simulator::Schedule -behaves. Any code that calls these APIs in the middle of the simulation -will need to be adapted. +behaves. Any code that calls these APIs in the middle of the simulation +will need to be adapted. -The API of Simulator::StopAt (time) has also changed. Now it is -called Simulator::Stop (time), and takes a relative time, instead of +The API of Simulator::StopAt (time) has also changed. Now it is +called Simulator::Stop (time), and takes a relative time, instead of absolute. Release 3.0.12 (2008/04/07) =========================== - Add Attribute support to the TypeId metadata system and add attribute support to all in-tree models - - Add a mid-level helper API to build simulation topologies + - Add a mid-level helper API to build simulation topologies and perform simple ascii and pcap link-level tracing. - Large amount of structural changes to accommodate the needs of the upcoming python bindings @@ -3327,10 +3329,10 @@ in the 802.11 model (Federico Maguolo). Release 3.0.11 (2008/02/15) =========================== - - Initial port of GTNetS TCP implementation (initial version -that does not support multitasking or delayed acknowledgments yet, + - Initial port of GTNetS TCP implementation (initial version +that does not support multitasking or delayed acknowledgments yet, but supports a reliable stream service) - - Changes to the ns-3 object model to create a TypeId-based + - Changes to the ns-3 object model to create a TypeId-based metadata system - lots of bug fixes throughout the system - tutorial updates @@ -3346,11 +3348,11 @@ Release 3.0.9 (2007/12/15) - A 802.11 model ported from Yans. This model supports: * a rather extensive PHY model * log-distance and friis propagation model - * a simple set of rate control algorithms (ARF, Ideal, + * a simple set of rate control algorithms (ARF, Ideal, AARF, constant-rate) * adhoc and infrastructure mode (beacon+assoc) - Use smart pointer for Packet in the APIs - - A new contrib directory with helper classes: + - A new contrib directory with helper classes: EventGarbageCollector, Gnuplot - Tracing support for Applications - many bugs fixed @@ -3365,7 +3367,7 @@ Release 3.0.7 (2007/10/15) - OLSR routing protocol - A timer class - Additional mobility models (random waypoint, random 2D walk) - - A mobility visualization tool + - A mobility visualization tool Release 3.0.6 (2007/09/15) ========================== @@ -3373,7 +3375,7 @@ Release 3.0.6 (2007/09/15) - Logging overhaul (NS_LOG macros) - Refactoring of tracing subsystem - Tutorial document started - + Release 3.0.5 (2007/08/15) ========================== @@ -3382,14 +3384,14 @@ Release 3.0.5 (2007/08/15) - Generalized, polymorphic Address class - Add CSMA NetDevice model (from Emmanuelle Laprise) - Modularize IPv4 routing support (from Gustavo Carneiro) - - Add mobility framework and basic mobility models - - Global unicast centralized routing + - Add mobility framework and basic mobility models + - Global unicast centralized routing Release 3.0.4 (2007/07/15) ========================== - Enable waf as the default build system. - - Per-packet metadata: a system to track which headers and trailers + - Per-packet metadata: a system to track which headers and trailers are added to a packet - Simplifications to point-to-point devices and channel @@ -3400,9 +3402,9 @@ Release 3.0.3 (2007/06/15) with the "waf" tool. See doc/build-waf.txt. - Add support for variable time precision: it is now possible to run a simulation with an accuracy which is higher or lower - than a nanosecond: seconds, milliseconds, microseconds, + than a nanosecond: seconds, milliseconds, microseconds, femtoseconds and picoseconds are supported. - - Optimize and rework the COM framework, solidify the component + - Optimize and rework the COM framework, solidify the component manager - Many small API cleanups diff --git a/src/antenna/doc/source/antenna-design.rst b/src/antenna/doc/source/antenna-design.rst index d93db0d5d..763cf1c9a 100644 --- a/src/antenna/doc/source/antenna-design.rst +++ b/src/antenna/doc/source/antenna-design.rst @@ -12,7 +12,8 @@ Overview The Antenna module provides: #. a new base class (AntennaModel) that provides an interface for the modeling of the radiation pattern of an antenna; - #. a set of classes derived from this base class that each models the radiation pattern of different types of antennas. + #. a set of classes derived from this base class that each models the radiation pattern of different types of antennas; + #. the class ThreeGppAntennaArrayModel, which implements the antenna model described in 3GPP TR 38.901 ------------ @@ -25,8 +26,8 @@ is obtained by translating the Cartesian coordinate system used by the ns-3 MobilityModel into the new origin :math:`o` which is the location of the antenna, and then transforming the coordinates of every generic point :math:`p` of the space from Cartesian coordinates -:math:`(x,y,z)` into spherical coordinates -:math:`(r, \theta,\phi)`. +:math:`(x,y,z)` into spherical coordinates +:math:`(r, \theta,\phi)`. The antenna model neglects the radial component :math:`r`, and only considers the angle components :math:`(\theta, \phi)`. An antenna radiation pattern is then expressed as a mathematical function @@ -36,15 +37,15 @@ transmission/reception. All angles are expressed in radians. .. _fig-antenna-coordinate-system: - + .. figure:: figures/antenna-coordinate-system.* :align: center Coordinate system of the AntennaModel ---------------- -Provided models ---------------- +--------------------- +Single antenna models +--------------------- In this section we describe the antenna radiation pattern models that are included within the antenna module. @@ -65,19 +66,19 @@ This is the cosine model described in [Chunjian]_: the antenna gain is determined as: .. math:: - + g(\phi, \theta) = \cos^{n} \left(\frac{\phi - \phi_{0}}{2} \right) where :math:`\phi_{0}` is the azimuthal orientation of the antenna (i.e., its direction of maximum gain) and the exponential .. math:: - + n = -\frac{3}{20 \log_{10} \left( \cos \frac{\phi_{3dB}}{4} \right)} determines the desired 3dB beamwidth :math:`\phi_{3dB}`. Note that this radiation pattern is independent of the inclination angle -:math:`\theta`. +:math:`\theta`. A major difference between the model of [Chunjian]_ and the one implemented in the class CosineAntennaModel is that only the element @@ -97,18 +98,35 @@ ParabolicAntennaModel This model is based on the parabolic approximation of the main lobe radiation pattern. It is often used in the context of cellular system to model the radiation pattern of a cell sector, see for instance [R4-092042a]_ and [Calcev]_. The antenna gain in dB is determined as: .. math:: - + g_{dB}(\phi, \theta) = -\min \left( 12 \left(\frac{\phi - \phi_{0}}{\phi_{3dB}} \right)^2, A_{max} \right) where :math:`\phi_{0}` is the azimuthal orientation of the antenna (i.e., its direction of maximum gain), :math:`\phi_{3dB}` is its 3 dB beamwidth, and :math:`A_{max}` is the maximum attenuation in dB of the antenna. Note that this radiation pattern is independent of the inclination angle -:math:`\theta`. - - +:math:`\theta`. +------------------------- +ThreeGppAntennaArrayModel +------------------------- +The class ThreeGppAntennaArrayModel implements the antenna model described in +3GPP TR 38.901 [38901]_, which is used by the classes ThreeGppSpectrumPropagationLossModel +and ThreeGppChannelModel. +Each instance of this class models an isotropic rectangular antenna array with +NxM elements, where N is the number of rows and M is the number of columns, +configurable through the attributes "NumRows" and "NumColumns". +The radiation pattern of the antenna elements follows the model specified in +Sec. 7.3 of 3GPP TR 38.901; only vertical polarization is considered (i.e., +:math:`{\zeta = 0}`). +The directional gain of the antenna elements can be configured through the +attribute "ElementGain" (see formula 2.34 in [Mailloux]_ to choose a proper value). +By default, the array is orthogonal to the x-axis, pointing towards the positive +direction, but the orientation can be changed through the attributes "BearingAngle", +which adjusts the azimuth angle, and "DowntiltAngle", which adjusts the elevation angle. +The spacing between the horizontal and vertical elements can be configured through +the attributes "AntennaHorizontalSpacing" and "AntennaVerticalSpacing". .. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design", Wiley, 2nd Ed. @@ -118,10 +136,11 @@ antenna. Note that this radiation pattern is independent of the inclination angl .. [Calcev] George Calcev and Matt Dillon, "Antenna Tilt Control in CDMA Networks", in Proc. of the 2nd Annual International Wireless - Internet Conference (WICON), 2006 + Internet Conference (WICON), 2006 .. [R4-092042a] 3GPP TSG RAN WG4 (Radio) Meeting #51, R4-092042, Simulation assumptions and parameters for FDD HeNB RF requirements. +.. [38901] 3GPP. 2018. TR 38.901, Study on channel model for frequencies from 0.5 to 100 GHz, V15.0.0. (2018-06). - +.. [Mailloux] Robert J. Mailloux, "Phased Array Antenna Handbook", Artech House, 2nd Ed. diff --git a/src/antenna/model/three-gpp-antenna-array-model.cc b/src/antenna/model/three-gpp-antenna-array-model.cc new file mode 100644 index 000000000..5bdea87df --- /dev/null +++ b/src/antenna/model/three-gpp-antenna-array-model.cc @@ -0,0 +1,223 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2019 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-antenna-array-model.h" +#include "ns3/log.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "ns3/boolean.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ThreeGppAntennaArrayModel"); + +NS_OBJECT_ENSURE_REGISTERED (ThreeGppAntennaArrayModel); + +ThreeGppAntennaArrayModel::ThreeGppAntennaArrayModel (void) +{ + NS_LOG_FUNCTION (this); + m_isOmniTx = false; +} + +ThreeGppAntennaArrayModel::~ThreeGppAntennaArrayModel (void) +{ + NS_LOG_FUNCTION (this); +} + +TypeId +ThreeGppAntennaArrayModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::ThreeGppAntennaArrayModel") + .SetParent () + .AddConstructor () + .AddAttribute ("AntennaHorizontalSpacing", + "Horizontal spacing between antenna elements, in multiples of wave length", + DoubleValue (0.5), + MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disH), + MakeDoubleChecker ()) + .AddAttribute ("AntennaVerticalSpacing", + "Vertical spacing between antenna elements, in multiples of wave length", + DoubleValue (0.5), + MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_disV), + MakeDoubleChecker ()) + .AddAttribute ("NumColumns", + "Horizontal size of the array", + UintegerValue (4), + MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numColumns), + MakeUintegerChecker ()) + .AddAttribute ("NumRows", + "Vertical size of the array", + UintegerValue (4), + MakeUintegerAccessor (&ThreeGppAntennaArrayModel::m_numRows), + MakeUintegerChecker ()) + .AddAttribute ("BearingAngle", + "The bearing angle in radians", + DoubleValue (0.0), + MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_alpha), + MakeDoubleChecker (-M_PI, M_PI)) + .AddAttribute ("DowntiltAngle", + "The downtilt angle in radians", + DoubleValue (0.0), + MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_beta), + MakeDoubleChecker (0, M_PI)) + .AddAttribute ("ElementGain", + "Directional gain of an antenna element in dBi", + DoubleValue (4.97), + MakeDoubleAccessor (&ThreeGppAntennaArrayModel::m_gE), + MakeDoubleChecker (0, 8)) + .AddAttribute ("IsotropicElements", + "If true, use an isotropic radiation pattern (for testing purposes)", + BooleanValue (false), + MakeBooleanAccessor (&ThreeGppAntennaArrayModel::m_isIsotropic), + MakeBooleanChecker ()) + ; + return tid; +} + +bool +ThreeGppAntennaArrayModel::IsOmniTx (void) const +{ + NS_LOG_FUNCTION (this); + return m_isOmniTx; +} + +void +ThreeGppAntennaArrayModel::ChangeToOmniTx (void) +{ + NS_LOG_FUNCTION (this); + m_isOmniTx = true; +} + +void +ThreeGppAntennaArrayModel::SetBeamformingVector (const ComplexVector &beamformingVector) +{ + NS_LOG_FUNCTION (this); + m_isOmniTx = false; + m_beamformingVector = beamformingVector; +} + +const ThreeGppAntennaArrayModel::ComplexVector & +ThreeGppAntennaArrayModel::GetBeamformingVector(void) const +{ + NS_LOG_FUNCTION (this); + return m_beamformingVector; +} + +std::pair +ThreeGppAntennaArrayModel::GetElementFieldPattern (Angles a) const +{ + NS_LOG_FUNCTION (this); + + // normalize phi (if needed) + while (a.phi >= M_PI) + { + a.phi -= 2 * M_PI; + } + while (a.phi < -M_PI) + { + a.phi += 2 * M_PI; + } + + NS_ASSERT_MSG (a.theta >= 0 && a.theta <= M_PI, "The vertical angle should be between 0 and M_PI"); + NS_ASSERT_MSG (a.phi >= -M_PI && a.phi <= M_PI, "The horizontal angle should be between -M_PI and M_PI"); + + // convert the theta and phi angles from GCS to LCS using eq. 7.1-7 and 7.1-8 in 3GPP TR 38.901 + // NOTE we assume a fixed slant angle of 0 degrees + double thetaPrime = std::acos (cos (m_beta)*cos (a.theta) + sin (m_beta)*cos (a.phi-m_alpha)*sin (a.theta)); + double phiPrime = std::arg (std::complex (cos (m_beta)*sin (a.theta)*cos (a.phi-m_alpha) - sin (m_beta)*cos (a.theta), sin (a.phi-m_alpha)*sin (a.theta))); + NS_LOG_DEBUG (a.theta << " " << thetaPrime << " " << a.phi << " " << phiPrime); + + double aPrimeDb = GetRadiationPattern (thetaPrime, phiPrime); + double aPrime = pow (10, aPrimeDb / 10); // convert to linear + + // compute psi using eq. 7.1-15 in 3GPP TR 38.901 + double psi = std::arg (std::complex (cos (m_beta) * sin (a.theta) - sin (m_beta) * cos (a.theta)* cos (a.phi - m_alpha), sin (m_beta)* sin (a.phi-m_alpha))); + NS_LOG_DEBUG ("psi " << psi); + + // compute the antenna element field pattern in the vertical polarization using + // eq. 7.3-4 in 3GPP TR 38.901 + // NOTE we assume vertical polarization, hence the field pattern in the + // vertical polarization is 0 + double fieldThetaPrime = std::sqrt (aPrime); + + // convert the antenna element field pattern to GCS using eq. 7.1-11 + // in 3GPP TR 38.901 + double fieldTheta = cos (psi) * fieldThetaPrime; + double fieldPhi = sin (psi) * fieldThetaPrime; + NS_LOG_DEBUG (a.phi/M_PI*180 << " " << a.theta/M_PI*180 << " " << fieldTheta*fieldTheta + fieldPhi*fieldPhi); + + return std::make_pair (fieldPhi, fieldTheta); +} + +double +ThreeGppAntennaArrayModel::GetRadiationPattern (double thetaRadian, double phiRadian) const +{ + if (m_isIsotropic) + { + return 0; + } + + // convert the angles in degrees + double thetaDeg = thetaRadian * 180 / M_PI; + double phiDeg = phiRadian * 180 / M_PI; + NS_ASSERT_MSG (thetaDeg >= 0 && thetaDeg <= 180, "the vertical angle should be the range of [0,180]"); + NS_ASSERT_MSG (phiDeg >= -180 && phiDeg <= 180, "the horizontal angle should be the range of [-180,180]"); + + // compute the radiation power pattern using equations in table 7.3-1 in + // 3GPP TR 38.901 + double A_M = 30; // front-back ratio expressed in dB + double SLA = 30; // side-lobe level limit expressed in dB + + double A_v = -1 * std::min (SLA,12 * pow ((thetaDeg - 90) / 65,2)); // vertical cut of the radiation power pattern (dB) + double A_h = -1 * std::min (A_M,12 * pow (phiDeg / 65,2)); // horizontal cut of the radiation power pattern (dB) + + double A = m_gE - 1 * std::min (A_M,- A_v - A_h); // 3D radiation power pattern (dB) + + return A; // 3D radiation power pattern in dB +} + +Vector +ThreeGppAntennaArrayModel::GetElementLocation (uint64_t index) const +{ + NS_LOG_FUNCTION (this); + + // compute the element coordinates in the LCS + // assume the left bottom corner is (0,0,0), and the rectangular antenna array is on the y-z plane. + double xPrime = 0; + double yPrime = m_disH * (index % m_numColumns); + double zPrime = m_disV * floor (index / m_numColumns); + + // convert the coordinates to the GCS using the rotation matrix 7.1-4 in 3GPP + // TR 38.901 + Vector loc; + loc.x = cos(m_alpha)*cos (m_beta)*xPrime - sin (m_alpha)*yPrime + cos (m_alpha)*sin (m_beta)*zPrime; + loc.y = sin (m_alpha)*cos(m_beta)*xPrime + cos (m_alpha)*yPrime + sin (m_alpha)*sin (m_beta)*zPrime; + loc.z = -sin (m_beta)*xPrime+cos(m_beta)*zPrime; + return loc; +} + +uint64_t +ThreeGppAntennaArrayModel::GetNumberOfElements (void) const +{ + NS_LOG_FUNCTION (this); + return m_numRows * m_numColumns; +} + +} /* namespace ns3 */ diff --git a/src/antenna/model/three-gpp-antenna-array-model.h b/src/antenna/model/three-gpp-antenna-array-model.h new file mode 100644 index 000000000..236f0a88b --- /dev/null +++ b/src/antenna/model/three-gpp-antenna-array-model.h @@ -0,0 +1,124 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* Copyright (c) 2019 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_ANTENNA_ARRAY_MODEL_H_ +#define THREE_GPP_ANTENNA_ARRAY_MODEL_H_ + +#include +#include + +namespace ns3 { + +/** + * \ingroup antenna + * + * \brief Class implementing the antenna model defined in 3GPP TR 38.901 + */ +class ThreeGppAntennaArrayModel : public Object +{ +public: + + /** + * Constructor + */ + ThreeGppAntennaArrayModel (void); + + /** + * Destructor + */ + virtual ~ThreeGppAntennaArrayModel (void); + + // inherited from Object + static TypeId GetTypeId (void); + + typedef std::vector > ComplexVector; //!< type definition for complex vectors + + /** + * Returns the horizontal and vertical components of the antenna element field + * pattern at the specified direction + * \param a the angle indicating the interested direction + * \return a pair in which the first element is the horizontal component + * of the field pattern and the second element is the vertical + * component of the field pattern + */ + std::pair GetElementFieldPattern (Angles a) const; + + /** + * Returns the normalized location of the antenna element + * with specified index assuming the left bottom corner is (0,0,0). + * \param index index of the antenna element + * \return the 3D vector that represents the position of the element + */ + virtual Vector GetElementLocation (uint64_t index) const; + + /** + * Returns the number of antenna elements + * \return the number of antenna elements + */ + virtual uint64_t GetNumberOfElements (void) const; + + /** + * Returns true if the antenna is configured for omnidirectional transmissions + * \return whether the transmission is set to omni + */ + bool IsOmniTx (void) const; + + /** + * Change the antenna model to omnidirectional (ignoring the beams) + */ + void ChangeToOmniTx (void); + + /** + * Sets the beamforming vector to be used + * \param beamformingVector the beamforming vector + */ + void SetBeamformingVector (const ComplexVector &beamformingVector); + + /** + * Returns the beamforming vector that is currently being used + * \return the current beamforming vector + */ + const ComplexVector & GetBeamformingVector (void) const; + +private: + /** + * Returns the radiation power pattern of a single antenna element in dB, + * generated according to Table 7.3-1 in 3GPP TR 38.901 + * \param vAngleRadian the vertical angle in radians + * \param hAngleRadian the horizontal angle in radians + * \return the radiation power pattern in dB + */ + double GetRadiationPattern (double vAngleRadian, double hAngleRadian) const; + + bool m_isOmniTx; //!< true if the antenna is configured for omni transmissions + ComplexVector m_beamformingVector; //!< the beamforming vector in use + uint32_t m_numColumns; //!< number of columns + uint32_t m_numRows; //!< number of rows + double m_disV; //!< antenna spacing in the vertical direction in multiples of wave length + double m_disH; //!< antenna spacing in the horizontal direction in multiples of wave length + double m_alpha; //!< the bearing angle in radians + double m_beta; //!< the downtilt angle in radians + double m_gE; //!< directional gain of a single antenna element (dBi) + bool m_isIsotropic; //!< if true, antenna elements are isotropic +}; + +} /* namespace ns3 */ + +#endif /* SRC_THREE_GPP_ANTENNA_ARRAY_MODEL_H_ */ diff --git a/src/antenna/wscript b/src/antenna/wscript index b18b94c37..59a6ea0af 100644 --- a/src/antenna/wscript +++ b/src/antenna/wscript @@ -10,8 +10,9 @@ def build(bld): 'model/isotropic-antenna-model.cc', 'model/cosine-antenna-model.cc', 'model/parabolic-antenna-model.cc', + 'model/three-gpp-antenna-array-model.cc', ] - + module_test = bld.create_ns3_module_test_library('antenna') module_test.source = [ 'test/test-angles.cc', @@ -20,7 +21,7 @@ def build(bld): 'test/test-cosine-antenna.cc', 'test/test-parabolic-antenna.cc', ] - + headers = bld(features='ns3header') headers.module = 'antenna' headers.source = [ @@ -29,6 +30,7 @@ def build(bld): 'model/isotropic-antenna-model.h', 'model/cosine-antenna-model.h', 'model/parabolic-antenna-model.h', + 'model/three-gpp-antenna-array-model.h', ] bld.ns3_python_bindings() diff --git a/src/spectrum/doc/spectrum.rst b/src/spectrum/doc/spectrum.rst index 823e718b8..8111dd7b3 100644 --- a/src/spectrum/doc/spectrum.rst +++ b/src/spectrum/doc/spectrum.rst @@ -17,15 +17,15 @@ Spectrum Module -The Spectrum module aims at providing support for modeling the frequency-dependent -aspects of communications in |ns3|. +The Spectrum module aims at providing support for modeling the frequency-dependent +aspects of communications in |ns3|. The model was first introduced in -[Baldo2009Spectrum]_, and has been enhanced and refined over the years. +[Baldo2009Spectrum]_, and has been enhanced and refined over the years. .. _fig-spectrum-analyzer-example: - + .. figure:: figures/spectrum-analyzer-example.* :align: center @@ -39,7 +39,7 @@ Model Description The module provides: -* a set of classes for modeling signals and +* a set of classes for modeling signals and * a Channel/PHY interface based on a power spectral density signal representation that is technology-independent @@ -70,7 +70,7 @@ information for a signal being transmitted/received by PHY devices: * the duration of the signal * its Power Spectral Density (PSD) of the signal, which is assumed to be constant for - the duration of the signal. + the duration of the signal. The PSD is represented as a set of discrete scalar values each corresponding to a certain subband in frequency. The set of frequency subbands @@ -95,7 +95,7 @@ that inherits from ``SpectrumSignalParameters`` and extends it with any technology-specific information that is needed. This design is intended to model the fact that in the real world we have signals of different technologies being simultaneously transmitted and -received over the air. +received over the air. @@ -108,7 +108,7 @@ reception of signals over the medium. The way this interaction works is depicted .. _fig-spectrum-channel-phy-interface: - + .. figure:: figures/spectrum-channel-phy-interface.* :align: center @@ -127,7 +127,7 @@ both provide this functionality: - you can plug models based on ``PropagationLossModel`` on these channels. Only linear models (where the loss value does not - depend on the transmission power) can be used. + depend on the transmission power) can be used. These models are single-frequency in the sense that the loss value is applied equally to all components of the power spectral density. @@ -144,7 +144,7 @@ both provide this functionality: ``SingleModelSpectrumChannel`` and ``MultiModelSpectrumChannel`` are quite similar, the main difference is that -``MultiModelSpectrumChannel`` allows to use different +``MultiModelSpectrumChannel`` allows to use different ``SpectrumModel`` instances with the same channel instance, by automatically taking care of the conversion of PSDs among the different models. @@ -178,23 +178,23 @@ of the available implementations: * ``AlohaNoackNetDevice``: a minimal NetDevice that allows to send packets over ``HalfDuplexIdealPhy`` (or other PHY model based on - the ``GenericPhy`` interface). + the ``GenericPhy`` interface). * ``SpectrumAnalyzer``, ``WaveformGenerator`` and ``MicrowaveOven`` are examples of PHY models other than communication devices - the names should be - self-explaining. + self-explaining. + - References ========== -.. [Baldo2009Spectrum] N. Baldo and M. Miozzo, "Spectrum-aware Channel and PHY layer modeling for ns3", +.. [Baldo2009Spectrum] N. Baldo and M. Miozzo, "Spectrum-aware Channel and PHY layer modeling for ns3", Proceedings of ICST NSTools 2009, Pisa, Italy @@ -205,11 +205,11 @@ Usage The main use case of the spectrum model is for developers who want to develop a new model for the PHY layer of some wireless technology to -be used within ns-3. +be used within ns-3. Here are some notes on how the spectrum module is expected to be used. * ``SpectrumPhy`` and ``SpectrumChannel`` are abstract base classes. Real - code will use classes that inherit from these classes. + code will use classes that inherit from these classes. * If you are implementing a new model for some wireless technology of your interest, and want to use the spectrum module, @@ -221,7 +221,7 @@ Here are some notes on how the spectrum module is expected to be used. instances of ``SpectrumModel`` are typically statically allocated, in order to allow several ``SpectrumValue`` instances to reference the same ``SpectrumModel`` instance. - + - a child class of ``SpectrumPhy`` which will handle transmission and reception of signals (including, if appropriate, interference and error modeling). @@ -238,21 +238,21 @@ Here are some notes on how the spectrum module is expected to be used. are quite generic. Chances are you can use them as-is. Whether you prefer one or the other it is just a matter of whether you will have a single SpectrumModel or multiple ones in your - simulations. + simulations. * Typically, there will be a single SpectrumChannel instance to which several SpectrumPhy instances are plugged. The rule of thumb is that all PHYs that are interfering with each other shall be plugged on the same channel. Multiple SpectrumChannel instances are expected to be used mainly when simulating completely orthogonal - channels; for example, when simulating the uplink and downlink + channels; for example, when simulating the uplink and downlink of a Frequency Division Duplex system, it is a good choice to use two SpectrumChannel instances in order to reduce computational - complexity. + complexity. * Different types of SpectrumPhy (i.e., instances of different child classes) can be plugged on the same SpectrumChannel instance. This - is one of the main features of the + is one of the main features of the spectrum module, to support inter-technology interference. For example, if you implement a WifiSpectrumPhy and a BluetoohSpectrumPhy, and plug both on a SpectrumChannel, then you'll @@ -265,7 +265,7 @@ Here are some notes on how the spectrum module is expected to be used. interference. A PHY device model is expected to use the ``DynamicCast<>`` operator to determine if a signal is of a certain type it can attempt to receive. If not, the signal is normally - expected to be considered as interference. + expected to be considered as interference. @@ -275,7 +275,7 @@ Helpers The helpers provided in ``src/spectrum/helpers`` are mainly intended -for the example implementations described in :ref:`sec-example-model-implementations`. +for the example implementations described in :ref:`sec-example-model-implementations`. If you are developing your custom model based on the spectrum framework, you will probably prefer to define your own helpers. @@ -293,7 +293,7 @@ Attributes interference calculations. Just be careful to choose a value that does not make the interference calculations inaccurate. - * The example implementations described in :ref:`sec-example-model-implementations` also have several attributes. + * The example implementations described in :ref:`sec-example-model-implementations` also have several attributes. @@ -309,7 +309,7 @@ Output calclulated. **Note**: only single-frequency path loss is accounted for, see the attribute description. - * The example implementations described in :ref:`sec-example-model-implementations` also provide some trace sources. + * The example implementations described in :ref:`sec-example-model-implementations` also provide some trace sources. * The helper class ``SpectrumAnalyzerHelper`` can be conveniently used to generate an output text file containing the spectrogram @@ -317,14 +317,14 @@ Output be easily plotted with ``gnuplot``. For example, if your run the example ``adhoc-aloha-ideal-phy-with-microwave-oven`` you will get an output file called ``spectrum-analyzer-output-3-0.tr``. From - this output file, you can generate a figure similar to + this output file, you can generate a figure similar to :ref:`fig-spectrum-analyzer-example` by executing the following gnuplot commands: .. sourcecode:: none unset surface - set pm3d at s + set pm3d at s set palette set key off set view 50,50 @@ -355,7 +355,7 @@ Troubleshooting scenarios, depending on the actual waveforms involved, the number of interferers, etc. Moreover, it is very important to use error models that are consistent with the interference model. The - responsibility of ensuring that the models being used are correct + responsibility of ensuring that the models being used are correct is left to the user. @@ -394,7 +394,7 @@ numerical errors. Describe how the model has been tested/validated. What tests run in the -test suite? How much API and code is covered by the tests? Again, +test suite? How much API and code is covered by the tests? Again, references to outside published work may help here. @@ -411,7 +411,7 @@ cases are created corresponding to different PSDs of the intended signal and different amount of transmitted bytes. The test passes if the output of the error model (successful or failed) coincides with the expected one which was determine offline by manually calculating -the achievable rate using Shannon's formula. +the achievable rate using Shannon's formula. IdealPhy test @@ -434,7 +434,7 @@ following conditions are satisfied: :math:`1\%` of the PHY rate; * if the PHY rate is not achievable, the application throughput shall - be zero. + be zero. @@ -446,57 +446,57 @@ TV Transmitter Model ==================== A TV Transmitter model is implemented by the ``TvSpectrumTransmitter`` class. -This model enables transmission of realistic TV signals to be simulated and can -be used for interference modeling. It provides a customizable power spectral -density (PSD) model, with configurable attributes including the type of -modulation (with models for analog, 8-VSB, and COFDM), signal bandwidth, -power spectral density level, frequency, and transmission duration. A helper -class, ``TvSpectrumTransmitterHelper``, is also provided to assist users in +This model enables transmission of realistic TV signals to be simulated and can +be used for interference modeling. It provides a customizable power spectral +density (PSD) model, with configurable attributes including the type of +modulation (with models for analog, 8-VSB, and COFDM), signal bandwidth, +power spectral density level, frequency, and transmission duration. A helper +class, ``TvSpectrumTransmitterHelper``, is also provided to assist users in setting up simulations. Main Model Class ################ -The main TV Transmitter model class, ``TvSpectrumTransmitter``, provides a -user-configurable PSD model that can be transmitted on the ``SpectrumChannel``. -It inherits from ``SpectrumPhy`` and is comprised of attributes and methods to +The main TV Transmitter model class, ``TvSpectrumTransmitter``, provides a +user-configurable PSD model that can be transmitted on the ``SpectrumChannel``. +It inherits from ``SpectrumPhy`` and is comprised of attributes and methods to create and transmit the signal on the channel. .. _spectrum-tv-cofdm: - + .. figure:: figures/spectrum-tv-cofdm.* :align: center - 8K COFDM signal spectrum generated from ``TvSpectrumTransmitter`` (Left) and + 8K COFDM signal spectrum generated from ``TvSpectrumTransmitter`` (Left) and theoretical COFDM signal spectrum [KoppCOFDM] (Right) -One of the user-configurable attributes is the type of modulation for the TV -transmitter to use. The options are 8-VSB (Eight-Level Vestigial Sideband -Modulation) which is notably used in the North America ATSC digital television -standard, COFDM (Coded Orthogonal Frequency Division Multiplexing) which is -notably used in the DVB-T and ISDB-T digital television standards adopted by -various countries around the world, and analog modulation which is a legacy -technology but is still being used by some countries today. To accomplish -realistic PSD models for these modulation types, the signals’ PSDs were -approximated from real standards and developed into models that are scalable by -frequency and power. The COFDM PSD is approximated from Figure 12 (8k mode) of -[KoppCOFDM], the 8-VSB PSD is approximated from Figure 3 of [Baron8VSB], and the -analog PSD is approximated from Figure 4 of [QualcommAnalog]. Note that the -analog model is approximated from the NTSC standard, but other analog modulation -standards such as PAL have similar signals. The approximated COFDM PSD model is -in 8K mode. The other configurable attributes are the start frequency, -signal/channel bandwidth, base PSD, antenna type, starting time, +One of the user-configurable attributes is the type of modulation for the TV +transmitter to use. The options are 8-VSB (Eight-Level Vestigial Sideband +Modulation) which is notably used in the North America ATSC digital television +standard, COFDM (Coded Orthogonal Frequency Division Multiplexing) which is +notably used in the DVB-T and ISDB-T digital television standards adopted by +various countries around the world, and analog modulation which is a legacy +technology but is still being used by some countries today. To accomplish +realistic PSD models for these modulation types, the signals’ PSDs were +approximated from real standards and developed into models that are scalable by +frequency and power. The COFDM PSD is approximated from Figure 12 (8k mode) of +[KoppCOFDM], the 8-VSB PSD is approximated from Figure 3 of [Baron8VSB], and the +analog PSD is approximated from Figure 4 of [QualcommAnalog]. Note that the +analog model is approximated from the NTSC standard, but other analog modulation +standards such as PAL have similar signals. The approximated COFDM PSD model is +in 8K mode. The other configurable attributes are the start frequency, +signal/channel bandwidth, base PSD, antenna type, starting time, and transmit duration. -``TvSpectrumTransmitter`` uses ``IsotropicAntennaModel`` as its antenna model by -default, but any model that inherits from ``AntennaModel`` is selectable, so -directional antenna models can also be used. The propagation loss models used -in simulation are configured in the ``SpectrumChannel`` that the user chooses to -use. Terrain and spherical Earth/horizon effects may be supported in future ns-3 +``TvSpectrumTransmitter`` uses ``IsotropicAntennaModel`` as its antenna model by +default, but any model that inherits from ``AntennaModel`` is selectable, so +directional antenna models can also be used. The propagation loss models used +in simulation are configured in the ``SpectrumChannel`` that the user chooses to +use. Terrain and spherical Earth/horizon effects may be supported in future ns-3 propagation loss models. -After the attributes are set, along with the ``SpectrumChannel``, -``MobilityModel``, and node locations, the PSD of the TV transmitter signal can +After the attributes are set, along with the ``SpectrumChannel``, +``MobilityModel``, and node locations, the PSD of the TV transmitter signal can be created and transmitted on the channel. .. _sec-tv-helper-class: @@ -504,103 +504,284 @@ be created and transmitted on the channel. Helper Class ############ -The helper class, ``TvSpectrumTransmitterHelper``, consists of features to -assist users in setting up TV transmitters for their simulations. Functionality -is also provided to easily simulate real-world scenarios. +The helper class, ``TvSpectrumTransmitterHelper``, consists of features to +assist users in setting up TV transmitters for their simulations. Functionality +is also provided to easily simulate real-world scenarios. .. _spectrum-tv-8vsb: - + .. figure:: figures/spectrum-tv-8vsb.* :align: center - North America ATSC channel 19 & 20 signals generated using - ``TvSpectrumTransmitterHelper`` (Left) and theoretical 8-VSB signal - [Baron8VSB] (Right). Note that the theoretical signal is not shown in dB + North America ATSC channel 19 & 20 signals generated using + ``TvSpectrumTransmitterHelper`` (Left) and theoretical 8-VSB signal + [Baron8VSB] (Right). Note that the theoretical signal is not shown in dB while the ns-3 generated signals are. -Using this helper class, users can easily set up TV transmitters right after -configuring attributes. Multiple transmitters can be created at a time. Also -included are real characteristics of specific geographic regions that can be -used to run realistic simulations. The regions currently included are -North America, Europe, and Japan. The frequencies and bandwidth of each TV +Using this helper class, users can easily set up TV transmitters right after +configuring attributes. Multiple transmitters can be created at a time. Also +included are real characteristics of specific geographic regions that can be +used to run realistic simulations. The regions currently included are +North America, Europe, and Japan. The frequencies and bandwidth of each TV channel for each these regions are provided. .. _spectrum-tv-rand-geo-points: - + .. figure:: figures/spectrum-tv-rand-geo-points.* :align: center - Plot from MATLAB implementation of CreateRegionalTvTransmitters method in - ``TvSpectrumTransmitterHelper``. Shows 100 random points on Earth’s surface - (with altitude 0) corresponding to TV transmitter locations within a 2000 km + Plot from MATLAB implementation of CreateRegionalTvTransmitters method in + ``TvSpectrumTransmitterHelper``. Shows 100 random points on Earth’s surface + (with altitude 0) corresponding to TV transmitter locations within a 2000 km radius of 35° latitude and -100° longitude. -A method (CreateRegionalTvTransmitters) is provided that enables users to -randomly generate multiple TV transmitters from a specified region with a given -density within a chosen radius around a point on Earth’s surface. The region, -which determines the channel frequencies of the generated TV transmitters, can -be specified to be one of the three provided, while the density determines the -amount of transmitters generated. The TV transmitters' antenna heights -(altitude) above Earth's surface can also be randomly generated to be within a -given maximum altitude. This method models Earth as a perfect sphere, and -generated location points are referenced accordingly in Earth-Centered -Earth-Fixed Cartesian coordinates. Note that bodies of water on Earth are not -considered in location point generation--TV transmitters can be generated +A method (CreateRegionalTvTransmitters) is provided that enables users to +randomly generate multiple TV transmitters from a specified region with a given +density within a chosen radius around a point on Earth’s surface. The region, +which determines the channel frequencies of the generated TV transmitters, can +be specified to be one of the three provided, while the density determines the +amount of transmitters generated. The TV transmitters' antenna heights +(altitude) above Earth's surface can also be randomly generated to be within a +given maximum altitude. This method models Earth as a perfect sphere, and +generated location points are referenced accordingly in Earth-Centered +Earth-Fixed Cartesian coordinates. Note that bodies of water on Earth are not +considered in location point generation--TV transmitters can be generated anywhere on Earth around the origin point within the chosen maximum radius. Examples ######## -Two example simulations are provided that demonstrate the functionality of the -TV transmitter model. ``tv-trans-example`` simulates two 8-VSB TV transmitters -with adjacent channel frequencies. ``tv-trans-regional-example`` simulates -randomly generated COFDM TV transmitters (modeling the DVB-T standard) -located around the Paris, France area with channel frequencies and bandwidths +Two example simulations are provided that demonstrate the functionality of the +TV transmitter model. ``tv-trans-example`` simulates two 8-VSB TV transmitters +with adjacent channel frequencies. ``tv-trans-regional-example`` simulates +randomly generated COFDM TV transmitters (modeling the DVB-T standard) +located around the Paris, France area with channel frequencies and bandwidths corresponding to the European television channel allocations. Testing ####### -The ``tv-spectrum-transmitter`` test suite verifies the accuracy of the -spectrum/PSD model in ``TvSpectrumTransmitter`` by testing if the maximum power -spectral density, start frequency, and end frequency comply with expected values +The ``tv-spectrum-transmitter`` test suite verifies the accuracy of the +spectrum/PSD model in ``TvSpectrumTransmitter`` by testing if the maximum power +spectral density, start frequency, and end frequency comply with expected values for various test cases. -The ``tv-helper-distribution`` test suite verifies the functionality of the -method in ``TvSpectrumTransmitterHelper`` that generates a random number of TV -transmitters based on the given density (low, medium, or high) and maximum -number of TV channels. It verifies that the number of TV transmitters generated +The ``tv-helper-distribution`` test suite verifies the functionality of the +method in ``TvSpectrumTransmitterHelper`` that generates a random number of TV +transmitters based on the given density (low, medium, or high) and maximum +number of TV channels. It verifies that the number of TV transmitters generated does not exceed the expected bounds. -The CreateRegionalTvTransmitters method in ``TvSpectrumTransmitterHelper`` -described in :ref:`sec-tv-helper-class` uses two methods from the -``GeographicPositions`` class in the Mobility module to generate the random -Cartesian points on or above earth's surface around an origin point which -correspond to TV transmitter positions. The first method converts Earth -geographic coordinates to Earth-Centered Earth-Fixed (ECEF) Cartesian -coordinates, and is tested in the ``geo-to-cartesian`` test suite by comparing -(with 10 meter tolerance) its output with the output of the geographic to ECEF -conversion function [MatlabGeo] of the MATLAB Mapping Toolbox for numerous -test cases. The other used method generates random ECEF Cartesian points around -the given geographic origin point, and is tested in the ``rand-cart-around-geo`` -test suite by verifying that the generated points do not exceed the given +The CreateRegionalTvTransmitters method in ``TvSpectrumTransmitterHelper`` +described in :ref:`sec-tv-helper-class` uses two methods from the +``GeographicPositions`` class in the Mobility module to generate the random +Cartesian points on or above earth's surface around an origin point which +correspond to TV transmitter positions. The first method converts Earth +geographic coordinates to Earth-Centered Earth-Fixed (ECEF) Cartesian +coordinates, and is tested in the ``geo-to-cartesian`` test suite by comparing +(with 10 meter tolerance) its output with the output of the geographic to ECEF +conversion function [MatlabGeo] of the MATLAB Mapping Toolbox for numerous +test cases. The other used method generates random ECEF Cartesian points around +the given geographic origin point, and is tested in the ``rand-cart-around-geo`` +test suite by verifying that the generated points do not exceed the given maximum distance radius from the origin point. +3GPP TR 38.901 fast fading model +================================ +The framework described by TR 38.901 [TR38901]_ is a 3D statistical Spatial +Channel Model supporting different propagation environments (e.g., urban, +rural, indoor), multi-antenna operations and the modeling of wireless channels +between 0.5 and 100 GHz. +The overall channel is represented by the matrix H(t,τ), in which each +entry H :sub:`u,s` (t,τ) corresponds to the impulse response of the channel between the +s-th element of the transmitting antenna and the u-th element of the receiving +antenna. H :sub:`u,s` (t,τ) is generated by the superposition of N different multi-path +components, called clusters, each of which composed of M different rays. +The channel matrix generation procedure accounts for large and small scale +propagation phenomena. The classes ThreeGppSpectrumPropagationLossModel and +ThreeGppChannelModel included in the spectrum module takes care of the generation +of the channel coefficients and the computation of the frequency-dependent +propagation loss. + +Implementation +############## + +Our implementation is described in [Zugno]_. It is based on the model described +in [Zhang]_, but the code has been refactored, extended, and aligned to TR 38.901 +[TR38901]_. +The fundamental assumption behind this model is the channel reciprocity, i.e., +the impulse response of the channel between node a and node b is the same as +between node b and node a. +To deal with the equivalence of the channel between a and b, no matter who is +the transmitter and who is the receiver, the model considers the pair of nodes +to be composed by one "s" and one "u" node. The channel matrix, as well as other +parameters, are saved and used under the assumption that, within a pair, the +definition of the "s" and "u" node will always be the same. For more details, +please have a look at the documentation of the classes +ThreeGppChannelModel and ThreeGppSpectrumPropagationLossModel. + +**Note:** + + * Currently, no error model is provided; a link-to-system campaign may be + needed to incorporate it in existing modules. + + * The model does not include any spatial consistency update procedure + (see [TR38901]_, Sec. 7.6.1). The implementation of this feature is left + as future work. + + * Issue regarding the blockage model: according to 3GPP TR 38.901 v15.0.0 + (2018-06) section 7.6.4.1, the blocking region for self-blocking is provided + in LCS. + However, here, clusterAOA and clusterZOA are in GCS and blocking check is + performed for self-blocking similar to non-self blocking, that is in GCS. + One would expect the angles to be transposed to LCS before checking self-blockage. + +ThreeGppSpectrumPropagationLossModel +#################################### + +The class ThreeGppSpectrumPropagationLossModel extends the SpectrumPropagationLossModel +interface and enables the modeling of frequency +dependent propagation phenomena. The main method is DoCalcRxPowerSpectralDensity, +which takes as input the power spectral density (PSD) of the transmitted signal, +the mobility models of the transmitting node and receiving node, and +returns the PSD of the received signal. + +Procedure used to compute the PSD of to compute the PSD of the received signal: + +1. Retrieve the beamforming vectors +To account for the beamforming, ThreeGppSpectrumPropagationLossModel has to +retrieve the beamforming vectors of the transmitting and receiving antennas. +The method DoCalcRxPowerSpectralDensity uses m_deviceAntennaMap to obtain the +antenna objects associated to the transmitting and receiving devices, and calls +the method GetCurrentBeamformingVector to retrieve the beamforming vectors. +For each device using the channel, the m_deviceAntennaMap contains the associated +antenna object of type ThreeGppAntennaArrayModel. Since the mapping is one-to-one, +the model supports a single antenna object for each device. +The m_deviceAntennaMap has to be initialized by inserting the device-antenna +pairs using the method AddDevice. + +2. Retrieve the channel matrix +The ThreeGppSpectrumPropagationLossModel relies on the ThreeGppChannelModel class +to obtain the channel matrix. In particular, it makes use of the method GetChannel, +which returns a ThreeGppChannelMatrix object containing the channel +matrix and other channel parameters. +The ThreeGppChannelModel instance is automatically +created in the the ThreeGppSpectrumPropagationLossModel constructor and it can +be configured using the method SetChannelModelAttribute (). + +4. Compute the long term component +The method GetLongTerm returns the long term component obtained by multiplying +the channel matrix and the beamforming vectors. To reduce the computational +load, the long term components associated to the different channels are +stored in the m_longTermMap and recomputed only if the associated channel +matrix is updated or if the transmitting and/or receiving beamforming vectors +have changed. Given the channel reciprocity assumption, for each node pair a +single long term component is saved in the map. + +5. Apply the small scale fading and compute the channel gain +The method CalcBeamformingGain computes the channel gain in each sub-band and +applies it to the PSD of the transmitted signal to obtain the received PSD. +To compute the sub-band gain, it accounts for the Doppler phenomenon and the +time dispersion effect on each cluster. +In order to reduce the computational load, the Doppler component of each +cluster is computed considering only the central ray. + +ThreeGppChannelModel +#################### + +The class ThreeGppChannelModel implements the channel matrix generation procedure +described in Sec. of [TR38901]_. +The main method is GetChannel, which takes as input the mobility models of +the transmitter and receiver nodes, the associated antenna objects, +and returns a ThreeGppChannelMatrix object containing: + +* the channel matrix of size UxSxN, where U is the number of receiving antenna elements, S is the number of transmitting antenna elements and N is the number of clusters + +* the clusters delays, as an array of size N + +* the clusters arrival and departure angles, as a 2D array in which each row corresponds to a direction (AOA, ZOA, AOD, ZOD) and each column corresponds to a different cluster + +* a time stamp indicating the time at which the channel matrix was generated + +* the node IDs + +* other channel parameters + +The ThreeGppChannelMatrix objects are saved +in the map m_channelMap and updated when the coherence time +expires, or in case the LOS/NLOS channel condition changes. +The coherence time can be configured through +the attribute "UpdatePeriod", and should be chosen by taking into account all the +factors that affects the channel variability, such as mobility, frequency, +propagation scenario, etc. By default, it is set to 0, which means that the +channel is recomputed only when the LOS/NLOS condition changes. +It is possible to configure the propagation scenario and the operating frequency +of interest through the attributes "Scenario" and "Frequency", respectively. + +**Blockage model:** 3GPP TR 38.901 also provides an optional +feature that can be used to model the blockage effect due to the +presence of obstacles, such as trees, cars or humans, at the level +of a single cluster. This differs from a complete blockage, which +would result in an LOS to NLOS transition. Therefore, when this +feature is enabled, an additional attenuation is added to certain +clusters, depending on their angle of arrival. There are two possi- +ble methods for the computation of the additional attenuation, i.e., +stochastic (Model A) and geometric (Model B). In this work, we +used the implementation provided by [Zhang]_, which +uses the stochastic method. In particular, the model is implemented by the +method CalcAttenuationOfBlockage, which computes the additional attenuation. +The blockage feature can be disable through the attribute "Blockage". Also, the +attributes "NumNonselfBlocking", "PortraitMode" and "BlockerSpeed" can be used +to configure the model. + +Testing +####### +The test suite ThreeGppChannelTestSuite includes three test cases: + +* ThreeGppChannelMatrixComputationTest checks if the channel matrix has the +correct dimensions and if it correctly normalized + +* ThreeGppChannelMatrixUpdateTest, which checks if the channel matrix is correctly +updated when the coherence time exceeds + +* ThreeGppSpectrumPropagationLossModelTest, which tests the functionalities of the +class ThreeGppSpectrumPropagationLossModel. It builds a simple network composed of two +nodes, computes the power spectral density received by the +receiving node, and (i) checks if the long term components for the direct and the reverse link +are the same, (ii) checks if the long term component is updated when changing the beamforming +vectors, (iii) checks if the long term is updated when changing the channel matrix + +**Note:** TR 38.901 includes a calibration procedure that can be used to validate +the model, but it requires some additional features which are not currently +implemented, thus is left as future work. + References ########## -.. [Baron8VSB] Baron, Stanley. "First-Hand:Digital Television: The Digital - Terrestrial Television Broadcasting (DTTB) Standard." IEEE Global History +.. [Baron8VSB] Baron, Stanley. "First-Hand:Digital Television: The Digital + Terrestrial Television Broadcasting (DTTB) Standard." IEEE Global History Network. . -.. [KoppCOFDM] Kopp, Carlo. "High Definition Television." High Definition +.. [KoppCOFDM] Kopp, Carlo. "High Definition Television." High Definition Television. Air Power Australia. . -.. [MatlabGeo] "Geodetic2ecef." Convert Geodetic to Geocentric (ECEF) - Coordinates. The MathWorks, Inc. +.. [MatlabGeo] "Geodetic2ecef." Convert Geodetic to Geocentric (ECEF) + Coordinates. The MathWorks, Inc. . -.. [QualcommAnalog] Stephen Shellhammer, Ahmed Sadek, and Wenyi Zhang. - "Technical Challenges for Cognitive Radio in the TV White Space Spectrum." +.. [QualcommAnalog] Stephen Shellhammer, Ahmed Sadek, and Wenyi Zhang. + "Technical Challenges for Cognitive Radio in the TV White Space Spectrum." Qualcomm Incorporated. +.. [TR38901] 3GPP. 2018. TR 38.901. Study on channel for frequencies from 0.5 to + 100 GHz. V.15.0.0. (2018-06). + +.. [Zhang] Menglei Zhang, Michele Polese, Marco Mezzavilla, Sundeep Rangan, + Michele Zorzi. "ns-3 Implementation of the 3GPP MIMO Channel Model for + Frequency Spectrum above 6 GHz". In Proceedings of the Workshop on ns-3 + (WNS3 '17). 2017. + +.. [Zugno] Tommaso Zugno, Michele Polese, Natale Patriciello, Biljana Bojovic, + Sandra Lagen, Michele Zorzi. "Implementation of a Spatial Channel Model for + ns-3". Submitted to the Workshop on ns-3 (WNS3 '20). 2020. + Available: https://arxiv.org/abs/2002.09341 diff --git a/src/spectrum/examples/three-gpp-channel-example.cc b/src/spectrum/examples/three-gpp-channel-example.cc new file mode 100644 index 000000000..2ba7e8e2a --- /dev/null +++ b/src/spectrum/examples/three-gpp-channel-example.cc @@ -0,0 +1,262 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 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 + */ + +/** +* This example shows how to configure the 3GPP channel model classes to +* compute the SNR between two nodes. +* The simulation involves two static nodes which are placed at a certain +* distance from each other and communicates through a wireless channel at +* 2 GHz with a bandwidth of 18 MHz. The default propagation environment is +* 3D-urban macro (UMa) and it can be configured changing the value of the +* string "scenario". +* Each node hosts a SimpleNetDevice and has an antenna array with 4 elements. +*/ + +#include "ns3/core-module.h" +#include "ns3/three-gpp-channel-model.h" +#include "ns3/three-gpp-antenna-array-model.h" +#include +#include "ns3/three-gpp-spectrum-propagation-loss-model.h" +#include "ns3/net-device.h" +#include "ns3/simple-net-device.h" +#include "ns3/node.h" +#include "ns3/node-container.h" +#include "ns3/mobility-model.h" +#include "ns3/constant-position-mobility-model.h" +#include "ns3/lte-spectrum-value-helper.h" +#include "ns3/channel-condition-model.h" +#include "ns3/three-gpp-propagation-loss-model.h" + +NS_LOG_COMPONENT_DEFINE ("ThreeGppChannelExample"); + +using namespace ns3; + +static Ptr m_propagationLossModel; //!< the PropagationLossModel object +static Ptr m_spectrumLossModel; //!< the SpectrumPropagationLossModel 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 posX = bPos.x - aPos.x; + double phiAngle = atan ((bPos.y - aPos.y) / posX); + + if (posX < 0) + { + phiAngle = phiAngle + M_PI; + } + if (phiAngle < 0) + { + phiAngle = phiAngle + 2 * M_PI; + } + + double hAngleRadian = fmod ((phiAngle + M_PI),2 * M_PI - M_PI); // the azimuth angle + 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 txPow the transmitting power in dBm + * \param noiseFigure the noise figure in dB + */ +static void +ComputeSnr (Ptr txMob, Ptr rxMob, double txPow, double noiseFigure) +{ + // Create the tx PSD using the LteSpectrumValueHelper + // 100 RBs corresponds to 18 MHz (1 RB = 180 kHz) + // EARFCN 100 corresponds to 2125.00 MHz + std::vector activeRbs0 (100); + for (int i = 0; i < 100 ; i++) + { + activeRbs0[i] = i; + } + Ptr txPsd = LteSpectrumValueHelper::CreateTxPowerSpectralDensity (2100, 100, txPow, activeRbs0); + Ptr rxPsd = txPsd->Copy (); + NS_LOG_DEBUG ("Average tx power " << 10*log10(Sum (*txPsd) * 180e3) << " dB"); + + // create the noise PSD + Ptr noisePsd = LteSpectrumValueHelper::CreateNoisePowerSpectralDensity (2100, 100, noiseFigure); + NS_LOG_DEBUG ("Average noise power " << 10*log10 (Sum (*noisePsd) * 180e3) << " dB"); + + // 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"); + + // 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 ("snr-trace.txt", std::ios::out | std::ios::app); + f << Simulator::Now ().GetSeconds () << " " << 10 * log10 (Sum (*rxPsd) / Sum (*noisePsd)) << " " << propagationGainDb << std::endl; + f.close (); +} + +int +main (int argc, char *argv[]) +{ + double frequency = 2125.0e6; // operating frequency in Hz (corresponds to EARFCN 2100) + double txPow = 49.0; // tx power in dBm + double noiseFigure = 9.0; // noise figure in dB + double distance = 10.0; // distance between tx and rx nodes in meters + uint32_t simTime = 10000; // simulation time in milliseconds + uint32_t timeRes = 10; // time resolution in milliseconds + std::string scenario = "UMa"; // 3GPP propagation scenario + + Config::SetDefault ("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue(MilliSeconds (1))); // update the channel at each iteration + Config::SetDefault ("ns3::ThreeGppChannelConditionModel::UpdatePeriod", TimeValue(MilliSeconds (0.0))); // do not update the channel condition + + RngSeedManager::SetSeed(1); + RngSeedManager::SetRun(1); + + // create and configure the factories for the channel condition and propagation loss models + ObjectFactory propagationLossModelFactory; + ObjectFactory channelConditionModelFactory; + if (scenario == "RMa") + { + propagationLossModelFactory.SetTypeId (ThreeGppRmaPropagationLossModel::GetTypeId ()); + channelConditionModelFactory.SetTypeId (ThreeGppRmaChannelConditionModel::GetTypeId ()); + } + else if (scenario == "UMa") + { + propagationLossModelFactory.SetTypeId (ThreeGppUmaPropagationLossModel::GetTypeId ()); + channelConditionModelFactory.SetTypeId (ThreeGppUmaChannelConditionModel::GetTypeId ()); + } + else if (scenario == "UMi-StreetCanyon") + { + propagationLossModelFactory.SetTypeId (ThreeGppUmiStreetCanyonPropagationLossModel::GetTypeId ()); + channelConditionModelFactory.SetTypeId (ThreeGppUmiStreetCanyonChannelConditionModel::GetTypeId ()); + } + else if (scenario == "InH-OfficeOpen") + { + propagationLossModelFactory.SetTypeId (ThreeGppIndoorOfficePropagationLossModel::GetTypeId ()); + channelConditionModelFactory.SetTypeId (ThreeGppIndoorOpenOfficeChannelConditionModel::GetTypeId ()); + } + else if (scenario == "InH-OfficeMixed") + { + propagationLossModelFactory.SetTypeId (ThreeGppIndoorOfficePropagationLossModel::GetTypeId ()); + channelConditionModelFactory.SetTypeId (ThreeGppIndoorMixedOfficeChannelConditionModel::GetTypeId ()); + } + else + { + NS_FATAL_ERROR ("Unknown scenario"); + } + + // create the propagation loss model + m_propagationLossModel = propagationLossModelFactory.Create (); + m_propagationLossModel->SetAttribute ("Frequency", DoubleValue (frequency)); + m_propagationLossModel->SetAttribute ("ShadowingEnabled", BooleanValue (false)); + + // create the spectrum propagation loss model + m_spectrumLossModel = CreateObject (); + m_spectrumLossModel->SetChannelModelAttribute ("Frequency", DoubleValue (frequency)); + m_spectrumLossModel->SetChannelModelAttribute ("Scenario", StringValue (scenario)); + + // create the channel condition model and associate it with the spectrum and + // propagation loss model + Ptr condModel = channelConditionModelFactory.Create (); + m_spectrumLossModel->SetChannelModelAttribute ("ChannelConditionModel", PointerValue (condModel)); + m_propagationLossModel->SetChannelConditionModel (condModel); + + // create the tx and rx 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 tx and rx mobility models, set the positions + Ptr txMob = CreateObject (); + txMob->SetPosition (Vector (0.0,0.0,10.0)); + Ptr rxMob = CreateObject (); + rxMob->SetPosition (Vector (distance,0.0,1.6)); + + // assign the mobility models to the nodes + nodes.Get (0)->AggregateObject (txMob); + nodes.Get (1)->AggregateObject (rxMob); + + // create the antenna objects and set their dimensions + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (2), "NumRows", UintegerValue (2)); + + // initialize the devices in the ThreeGppSpectrumPropagationLossModel + m_spectrumLossModel->AddDevice (txDev, txAntenna); + m_spectrumLossModel->AddDevice (rxDev, rxAntenna); + + // set the beamforming vectors + DoBeamforming (txDev, txAntenna, rxDev); + DoBeamforming (rxDev, rxAntenna, txDev); + + for (int i = 0; i < floor (simTime / timeRes); i++) + { + Simulator::Schedule (MilliSeconds (timeRes*i), &ComputeSnr, txMob, rxMob, txPow, noiseFigure); + } + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/src/spectrum/examples/wscript b/src/spectrum/examples/wscript index 6e2b77fa3..ef054b144 100644 --- a/src/spectrum/examples/wscript +++ b/src/spectrum/examples/wscript @@ -20,3 +20,7 @@ def build(bld): obj = bld.create_ns3_program('tv-trans-regional-example', ['spectrum', 'mobility', 'core']) obj.source = 'tv-trans-regional-example.cc' + + obj = bld.create_ns3_program('three-gpp-channel-example', + ['spectrum', 'mobility', 'core', 'lte']) + obj.source = 'three-gpp-channel-example.cc' diff --git a/src/spectrum/model/three-gpp-channel-model.cc b/src/spectrum/model/three-gpp-channel-model.cc new file mode 100644 index 000000000..a8020e273 --- /dev/null +++ b/src/spectrum/model/three-gpp-channel-model.cc @@ -0,0 +1,1811 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering, + * University of Padova + * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering, + * New York University + * + * 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-channel-model.h" +#include "ns3/log.h" +#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/node.h" +#include "ns3/double.h" +#include "ns3/string.h" +#include "ns3/integer.h" +#include +#include +#include "ns3/log.h" +#include +#include "ns3/mobility-model.h" +#include "ns3/pointer.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ThreeGppChannelModel"); + +NS_OBJECT_ENSURE_REGISTERED (ThreeGppChannelModel); + +static const double M_C = 3.0e8; // propagation velocity in free space + +//Table 7.5-3: Ray offset angles within a cluster, given for rms angle spread normalized to 1. +static const double offSetAlpha[20] = { + 0.0447,-0.0447,0.1413,-0.1413,0.2492,-0.2492,0.3715,-0.3715,0.5129,-0.5129,0.6797,-0.6797,0.8844,-0.8844,1.1481,-1.1481,1.5195,-1.5195,2.1551,-2.1551 +}; + +/* + * The cross correlation matrix is constructed according to table 7.5-6. + * All the square root matrix is being generated using the Cholesky decomposition + * and following the order of [SF,K,DS,ASD,ASA,ZSD,ZSA]. + * The parameter K is ignored in NLOS. + * + * The Matlab file to generate the matrices can be found in + * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m + * + */ +static const double sqrtC_RMa_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.5, 0, 0.866025, 0, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0}, + {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0}, + {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661}, +}; + +static const double sqrtC_RMa_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.5, 0.866025, 0, 0, 0, 0}, + {0.6, -0.11547, 0.791623, 0, 0, 0}, + {0, 0, 0, 1, 0, 0}, + {-0.04, -0.138564, 0.540662, -0.18, 0.809003, 0}, + {-0.25, -0.606218, -0.240013, 0.26, -0.231685, 0.625392}, +}; + +static const double sqrtC_RMa_O2I[6][6] = { + {1, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0}, + {0, 0, -0.7, 0.714143, 0, 0}, + {0, 0, 0.66, -0.123225, 0.741091, 0}, + {0, 0, 0.47, 0.152631, -0.393194, 0.775373}, +}; + +static const double sqrtC_UMa_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0, 0}, + {-0.4, -0.4, 0.824621, 0, 0, 0, 0}, + {-0.5, 0, 0.242536, 0.83137, 0, 0, 0}, + {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0}, + {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0}, + {-0.8, 0, -0.388057, -0.367926, 0.238537, -3.58949e-15, 0.130931}, +}; + + +static const double sqrtC_UMa_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.4, 0.916515, 0, 0, 0, 0}, + {-0.6, 0.174574, 0.78072, 0, 0, 0}, + {0, 0.654654, 0.365963, 0.661438, 0, 0}, + {0, -0.545545, 0.762422, 0.118114, 0.327327, 0}, + {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445}, +}; + +static const double sqrtC_UMa_O2I[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.5, 0.866025, 0, 0, 0, 0}, + {0.2, 0.57735, 0.791623, 0, 0, 0}, + {0, 0.46188, -0.336861, 0.820482, 0, 0}, + {0, -0.69282, 0.252646, 0.493742, 0.460857, 0}, + {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515}, + +}; + +static const double sqrtC_UMi_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0.5, 0.866025, 0, 0, 0, 0, 0}, + {-0.4, -0.57735, 0.711805, 0, 0, 0, 0}, + {-0.5, 0.057735, 0.468293, 0.726201, 0, 0, 0}, + {-0.4, -0.11547, 0.805464, -0.23482, 0.350363, 0, 0}, + {0, 0, 0, 0.688514, 0.461454, 0.559471, 0}, + {0, 0, 0.280976, 0.231921, -0.490509, 0.11916, 0.782603}, +}; + +static const double sqrtC_UMi_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.7, 0.714143, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0}, + {-0.4, 0.168034, 0, 0.90098, 0, 0}, + {0, -0.70014, 0.5, 0.130577, 0.4927, 0}, + {0, 0, 0.5, 0.221981, -0.566238, 0.616522}, +}; + +static const double sqrtC_UMi_O2I[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.5, 0.866025, 0, 0, 0, 0}, + {0.2, 0.57735, 0.791623, 0, 0, 0}, + {0, 0.46188, -0.336861, 0.820482, 0, 0}, + {0, -0.69282, 0.252646, 0.493742, 0.460857, 0}, + {0, -0.23094, 0.16843, 0.808554, -0.220827, 0.464515}, +}; + +static const double sqrtC_office_LOS[7][7] = { + {1, 0, 0, 0, 0, 0, 0}, + {0.5, 0.866025, 0, 0, 0, 0, 0}, + {-0.8, -0.11547, 0.588784, 0, 0, 0, 0}, + {-0.4, 0.23094, 0.520847, 0.717903, 0, 0, 0}, + {-0.5, 0.288675, 0.73598, -0.348236, 0.0610847, 0, 0}, + {0.2, -0.11547, 0.418943, 0.541106, 0.219905, 0.655744, 0}, + {0.3, -0.057735, 0.73598, -0.348236, 0.0610847, -0.304997, 0.383375}, +}; + +static const double sqrtC_office_NLOS[6][6] = { + {1, 0, 0, 0, 0, 0}, + {-0.5, 0.866025, 0, 0, 0, 0}, + {0, 0.46188, 0.886942, 0, 0, 0}, + {-0.4, -0.23094, 0.120263, 0.878751, 0, 0}, + {0, -0.311769, 0.55697, -0.249198, 0.728344, 0}, + {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214}, +}; + +ThreeGppChannelModel::ThreeGppChannelModel () +{ + NS_LOG_FUNCTION (this); + m_uniformRv = CreateObject (); + + m_normalRv = CreateObject (); + m_normalRv->SetAttribute ("Mean", DoubleValue (0.0)); + m_normalRv->SetAttribute ("Variance", DoubleValue (1.0)); +} + +ThreeGppChannelModel::~ThreeGppChannelModel () +{ + NS_LOG_FUNCTION (this); +} + +TypeId +ThreeGppChannelModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::ThreeGppChannelModel") + .SetParent () + .SetGroupName ("Spectrum") + .AddConstructor () + .AddAttribute ("Frequency", + "The operating Frequency in Hz", + DoubleValue (500.0e6), + MakeDoubleAccessor (&ThreeGppChannelModel::SetFrequency, + &ThreeGppChannelModel::GetFrequency), + MakeDoubleChecker ()) + .AddAttribute ("Scenario", + "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)", + StringValue ("UMa"), + MakeStringAccessor (&ThreeGppChannelModel::SetScenario, + &ThreeGppChannelModel::GetScenario), + MakeStringChecker ()) + .AddAttribute ("ChannelConditionModel", + "Pointer to the channel condition model", + PointerValue (), + MakePointerAccessor (&ThreeGppChannelModel::SetChannelConditionModel, + &ThreeGppChannelModel::GetChannelConditionModel), + MakePointerChecker ()) + .AddAttribute ("UpdatePeriod", + "Specify the channel coherence time", + TimeValue (MilliSeconds (0)), + MakeTimeAccessor (&ThreeGppChannelModel::m_updatePeriod), + MakeTimeChecker ()) + // attributes for the blockage model + .AddAttribute ("Blockage", + "Enable blockage model A (sec 7.6.4.1)", + BooleanValue (false), + MakeBooleanAccessor (&ThreeGppChannelModel::m_blockage), + MakeBooleanChecker ()) + .AddAttribute ("NumNonselfBlocking", + "number of non-self-blocking regions", + IntegerValue (4), + MakeIntegerAccessor (&ThreeGppChannelModel::m_numNonSelfBlocking), + MakeIntegerChecker ()) + .AddAttribute ("PortraitMode", + "true for portrait mode, false for landscape mode", + BooleanValue (true), + MakeBooleanAccessor (&ThreeGppChannelModel::m_portraitMode), + MakeBooleanChecker ()) + .AddAttribute ("BlockerSpeed", + "The speed of moving blockers, the unit is m/s", + DoubleValue (1), + MakeDoubleAccessor (&ThreeGppChannelModel::m_blockerSpeed), + MakeDoubleChecker ()) + ; + return tid; +} + +void +ThreeGppChannelModel::SetChannelConditionModel (Ptr model) +{ + NS_LOG_FUNCTION (this); + m_channelConditionModel = model; +} + +Ptr +ThreeGppChannelModel::GetChannelConditionModel () const +{ + NS_LOG_FUNCTION (this); + return m_channelConditionModel; +} + +void +ThreeGppChannelModel::SetFrequency (double f) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG (f >= 500.0e6 && f <= 100.0e9, "Frequency should be between 0.5 and 100 GHz but is " << f); + m_frequency = f; +} + +double +ThreeGppChannelModel::GetFrequency () const +{ + NS_LOG_FUNCTION (this); + return m_frequency; +} + +void +ThreeGppChannelModel::SetScenario (const std::string &scenario) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG (scenario == "RMa" || scenario == "UMa" || scenario == "UMi-StreetCanyon" || + scenario == "InH-OfficeOpen" || scenario == "InH-OfficeMixed", + "Unknown scenario, choose between RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen or InH-OfficeMixed"); + m_scenario = scenario; +} + +std::string +ThreeGppChannelModel::GetScenario () const +{ + NS_LOG_FUNCTION (this); + return m_scenario; +} + +Ptr +ThreeGppChannelModel::GetThreeGppTable (bool los, bool o2i, double hBS, double hUT, double distance2D) const +{ + NS_LOG_FUNCTION (this); + + double fcGHz = m_frequency / 1e9; + Ptr table3gpp = Create (); + // table3gpp includes the following parameters: + // numOfCluster, raysPerCluster, uLgDS, sigLgDS, uLgASD, sigLgASD, + // uLgASA, sigLgASA, uLgZSA, sigLgZSA, uLgZSD, sigLgZSD, offsetZOD, + // cDS, cASD, cASA, cZSA, uK, sigK, rTau, uXpr, sigXpr, shadowingStd + + // In NLOS case, parameter uK and sigK are not used and they are set to 0 + if (m_scenario == "RMa") + { + if (los && !o2i) + { + // 3GPP mentioned that 3.91 ns should be used when the Cluster DS (cDS) + // entry is N/A. + table3gpp->m_numOfCluster = 11; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -7.49; + table3gpp->m_sigLgDS = 0.55; + table3gpp->m_uLgASD = 0.90; + table3gpp->m_sigLgASD = 0.38; + table3gpp->m_uLgASA = 1.52; + table3gpp->m_sigLgASA = 0.24; + table3gpp->m_uLgZSA = 0.47; + table3gpp->m_sigLgZSA = 0.40; + table3gpp->m_uLgZSD = 0.34; + table3gpp->m_sigLgZSD = std::max (-1.0, -0.17 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.22); + table3gpp->m_offsetZOD = 0; + table3gpp->m_cDS = 3.91e-9; + table3gpp->m_cASD = 2; + table3gpp->m_cASA = 3; + table3gpp->m_cZSA = 3; + table3gpp->m_uK = 7; + table3gpp->m_sigK = 4; + table3gpp->m_rTau = 3.8; + table3gpp->m_uXpr = 12; + table3gpp->m_sigXpr = 4; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_RMa_LOS[row][column]; + } + } + } + else if (!los && !o2i) + { + table3gpp->m_numOfCluster = 10; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -7.43; + table3gpp->m_sigLgDS = 0.48; + table3gpp->m_uLgASD = 0.95; + table3gpp->m_sigLgASD = 0.45; + table3gpp->m_uLgASA = 1.52; + table3gpp->m_sigLgASA = 0.13; + table3gpp->m_uLgZSA = 0.58, + table3gpp->m_sigLgZSA = 0.37; + table3gpp->m_uLgZSD = std::max (-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28); + table3gpp->m_sigLgZSD = 0.30; + table3gpp->m_offsetZOD = atan ((35 - 3.5) / distance2D) - atan ((35 - 1.5) / distance2D); + table3gpp->m_cDS = 3.91e-9; + table3gpp->m_cASD = 2; + table3gpp->m_cASA = 3; + table3gpp->m_cZSA = 3; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 1.7; + table3gpp->m_uXpr = 7; + table3gpp->m_sigXpr = 3; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_RMa_NLOS[row][column]; + } + } + } + else // o2i + { + table3gpp->m_numOfCluster = 10; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -7.47; + table3gpp->m_sigLgDS = 0.24; + table3gpp->m_uLgASD = 0.67; + table3gpp->m_sigLgASD = 0.18; + table3gpp->m_uLgASA = 1.66; + table3gpp->m_sigLgASA = 0.21; + table3gpp->m_uLgZSA = 0.93, + table3gpp->m_sigLgZSA = 0.22; + table3gpp->m_uLgZSD = std::max (-1.0, -0.19 * (distance2D / 1000) - 0.01 * (hUT - 1.5) + 0.28); + table3gpp->m_sigLgZSD = 0.30; + table3gpp->m_offsetZOD = atan ((35 - 3.5) / distance2D) - atan ((35 - 1.5) / distance2D); + table3gpp->m_cDS = 3.91e-9; + table3gpp->m_cASD = 2; + table3gpp->m_cASA = 3; + table3gpp->m_cZSA = 3; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 1.7; + table3gpp->m_uXpr = 7; + table3gpp->m_sigXpr = 3; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_RMa_O2I[row][column]; + } + } + } + } + else if (m_scenario == "UMa") + { + if (los && !o2i) + { + table3gpp->m_numOfCluster = 12; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -6.955 - 0.0963 * log10 (fcGHz); + table3gpp->m_sigLgDS = 0.66; + table3gpp->m_uLgASD = 1.06 + 0.1114 * log10 (fcGHz); + table3gpp->m_sigLgASD = 0.28; + table3gpp->m_uLgASA = 1.81; + table3gpp->m_sigLgASA = 0.20; + table3gpp->m_uLgZSA = 0.95; + table3gpp->m_sigLgZSA = 0.16; + table3gpp->m_uLgZSD = std::max (-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.75); + table3gpp->m_sigLgZSD = 0.40; + table3gpp->m_offsetZOD = 0; + table3gpp->m_cDS = std::max (0.25, -3.4084 * log10 (fcGHz) + 6.5622) * 1e-9; + table3gpp->m_cASD = 5; + table3gpp->m_cASA = 11; + table3gpp->m_cZSA = 7; + table3gpp->m_uK = 9; + table3gpp->m_sigK = 3.5; + table3gpp->m_rTau = 2.5; + table3gpp->m_uXpr = 8; + table3gpp->m_sigXpr = 4; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMa_LOS[row][column]; + } + } + } + else + { + double uLgZSD = std::max (-0.5, -2.1 * distance2D / 1000 - 0.01 * (hUT - 1.5) + 0.9); + + double afc = 0.208 * log10 (fcGHz) - 0.782; + double bfc = 25; + double cfc = -0.13 * log10 (fcGHz) + 2.03; + double efc = 7.66 * log10 (fcGHz) - 5.96; + + double offsetZOD = efc - std::pow (10, afc * log10 (std::max (bfc,distance2D)) + cfc); + + if (!los && !o2i) + { + table3gpp->m_numOfCluster = 20; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -6.28 - 0.204 * log10 (fcGHz); + table3gpp->m_sigLgDS = 0.39; + table3gpp->m_uLgASD = 1.5 - 0.1144 * log10 (fcGHz); + table3gpp->m_sigLgASD = 0.28; + table3gpp->m_uLgASA = 2.08 - 0.27 * log10 (fcGHz); + table3gpp->m_sigLgASA = 0.11; + table3gpp->m_uLgZSA = -0.3236 * log10 (fcGHz) + 1.512; + table3gpp->m_sigLgZSA = 0.16; + table3gpp->m_uLgZSD = uLgZSD; + table3gpp->m_sigLgZSD = 0.49; + table3gpp->m_offsetZOD = offsetZOD; + table3gpp->m_cDS = std::max (0.25, -3.4084 * log10 (fcGHz) + 6.5622) * 1e-9;; + table3gpp->m_cASD = 2; + table3gpp->m_cASA = 15; + table3gpp->m_cZSA = 7; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 2.3; + table3gpp->m_uXpr = 7; + table3gpp->m_sigXpr = 3; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMa_NLOS[row][column]; + } + } + } + else //(o2i) + { + table3gpp->m_numOfCluster = 12; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -6.62; + table3gpp->m_sigLgDS = 0.32; + table3gpp->m_uLgASD = 1.25; + table3gpp->m_sigLgASD = 0.42; + table3gpp->m_uLgASA = 1.76; + table3gpp->m_sigLgASA = 0.16; + table3gpp->m_uLgZSA = 1.01; + table3gpp->m_sigLgZSA = 0.43; + table3gpp->m_uLgZSD = uLgZSD; + table3gpp->m_sigLgZSD = 0.49; + table3gpp->m_offsetZOD = offsetZOD; + table3gpp->m_cDS = 11e-9; + table3gpp->m_cASD = 5; + table3gpp->m_cASA = 8; + table3gpp->m_cZSA = 3; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 2.2; + table3gpp->m_uXpr = 9; + table3gpp->m_sigXpr = 5; + table3gpp->m_perClusterShadowingStd = 4; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMa_O2I[row][column]; + } + } + + } + + } + + } + else if (m_scenario == "UMi-StreetCanyon") + { + if (los && !o2i) + { + table3gpp->m_numOfCluster = 12; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -0.24 * log10 (1 + fcGHz) - 7.14; + table3gpp->m_sigLgDS = 0.38; + table3gpp->m_uLgASD = -0.05 * log10 (1 + fcGHz) + 1.21; + table3gpp->m_sigLgASD = 0.41; + table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.73; + table3gpp->m_sigLgASA = 0.014 * log10 (1 + fcGHz) + 0.28; + table3gpp->m_uLgZSA = -0.1 * log10 (1 + fcGHz) + 0.73; + table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.34; + table3gpp->m_uLgZSD = std::max (-0.21, -14.8 * distance2D / 1000 + 0.01 * std::abs (hUT - hBS) + 0.83); + table3gpp->m_sigLgZSD = 0.35; + table3gpp->m_offsetZOD = 0; + table3gpp->m_cDS = 5e-9; + table3gpp->m_cASD = 3; + table3gpp->m_cASA = 17; + table3gpp->m_cZSA = 7; + table3gpp->m_uK = 9; + table3gpp->m_sigK = 5; + table3gpp->m_rTau = 3; + table3gpp->m_uXpr = 9; + table3gpp->m_sigXpr = 3; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMi_LOS[row][column]; + } + } + } + else + { + double uLgZSD = std::max (-0.5, -3.1 * distance2D / 1000 + 0.01 * std::max (hUT - hBS,0.0) + 0.2); + double offsetZOD = -1 * std::pow (10, -1.5 * log10 (std::max (10.0, distance2D)) + 3.3); + if (!los && !o2i) + { + table3gpp->m_numOfCluster = 19; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -0.24 * log10 (1 + fcGHz) - 6.83; + table3gpp->m_sigLgDS = 0.16 * log10 (1 + fcGHz) + 0.28; + table3gpp->m_uLgASD = -0.23 * log10 (1 + fcGHz) + 1.53; + table3gpp->m_sigLgASD = 0.11 * log10 (1 + fcGHz) + 0.33; + table3gpp->m_uLgASA = -0.08 * log10 (1 + fcGHz) + 1.81; + table3gpp->m_sigLgASA = 0.05 * log10 (1 + fcGHz) + 0.3; + table3gpp->m_uLgZSA = -0.04 * log10 (1 + fcGHz) + 0.92; + table3gpp->m_sigLgZSA = -0.07 * log10 (1 + fcGHz) + 0.41; + table3gpp->m_uLgZSD = uLgZSD; + table3gpp->m_sigLgZSD = 0.35; + table3gpp->m_offsetZOD = offsetZOD; + table3gpp->m_cDS = 11e-9; + table3gpp->m_cASD = 10; + table3gpp->m_cASA = 22; + table3gpp->m_cZSA = 7; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 2.1; + table3gpp->m_uXpr = 8; + table3gpp->m_sigXpr = 3; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMi_NLOS[row][column]; + } + } + } + else //(o2i) + { + table3gpp->m_numOfCluster = 12; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -6.62; + table3gpp->m_sigLgDS = 0.32; + table3gpp->m_uLgASD = 1.25; + table3gpp->m_sigLgASD = 0.42; + table3gpp->m_uLgASA = 1.76; + table3gpp->m_sigLgASA = 0.16; + table3gpp->m_uLgZSA = 1.01; + table3gpp->m_sigLgZSA = 0.43; + table3gpp->m_uLgZSD = uLgZSD; + table3gpp->m_sigLgZSD = 0.35; + table3gpp->m_offsetZOD = offsetZOD; + table3gpp->m_cDS = 11e-9; + table3gpp->m_cASD = 5; + table3gpp->m_cASA = 8; + table3gpp->m_cZSA = 3; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 2.2; + table3gpp->m_uXpr = 9; + table3gpp->m_sigXpr = 5; + table3gpp->m_perClusterShadowingStd = 4; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_UMi_O2I[row][column]; + } + } + } + } + } + else if (m_scenario == "InH-OfficeMixed"||m_scenario == "InH-OfficeOpen") + { + NS_ASSERT_MSG (!o2i, "The indoor scenario does out support outdoor to indoor"); + if (los) + { + table3gpp->m_numOfCluster = 15; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -0.01 * log10 (1 + fcGHz) - 7.692; + table3gpp->m_sigLgDS = 0.18; + table3gpp->m_uLgASD = 1.60; + table3gpp->m_sigLgASD = 0.18; + table3gpp->m_uLgASA = -0.19 * log10 (1 + fcGHz) + 1.781; + table3gpp->m_sigLgASA = 0.12 * log10 (1 + fcGHz) + 0.119; + table3gpp->m_uLgZSA = -0.26 * log10 (1 + fcGHz) + 1.44; + table3gpp->m_sigLgZSA = -0.04 * log10 (1 + fcGHz) + 0.264; + table3gpp->m_uLgZSD = -1.43 * log10 (1 + fcGHz) + 2.228; + table3gpp->m_sigLgZSD = 0.13 * log10 (1 + fcGHz) + 0.30; + table3gpp->m_offsetZOD = 0; + table3gpp->m_cDS = 3.91e-9; + table3gpp->m_cASD = 5; + table3gpp->m_cASA = 8; + table3gpp->m_cZSA = 9; + table3gpp->m_uK = 7; + table3gpp->m_sigK = 4; + table3gpp->m_rTau = 3.6; + table3gpp->m_uXpr = 11; + table3gpp->m_sigXpr = 4; + table3gpp->m_perClusterShadowingStd = 6; + + for (uint8_t row = 0; row < 7; row++) + { + for (uint8_t column = 0; column < 7; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_office_LOS[row][column]; + } + } + } + else + { + table3gpp->m_numOfCluster = 19; + table3gpp->m_raysPerCluster = 20; + table3gpp->m_uLgDS = -0.28 * log10 (1 + fcGHz) - 7.173; + table3gpp->m_sigLgDS = 0.1 * log10 (1 + fcGHz) + 0.055; + table3gpp->m_uLgASD = 1.62; + table3gpp->m_sigLgASD = 0.25; + table3gpp->m_uLgASA = -0.11 * log10 (1 + fcGHz) + 1.863; + table3gpp->m_sigLgASA = 0.12 * log10 (1 + fcGHz) + 0.059; + table3gpp->m_uLgZSA = -0.15 * log10 (1 + fcGHz) + 1.387; + table3gpp->m_sigLgZSA = -0.09 * log10 (1 + fcGHz) + 0.746; + table3gpp->m_uLgZSD = 1.08; + table3gpp->m_sigLgZSD = 0.36; + table3gpp->m_offsetZOD = 0; + table3gpp->m_cDS = 3.91e-9; + table3gpp->m_cASD = 5; + table3gpp->m_cASA = 11; + table3gpp->m_cZSA = 9; + table3gpp->m_uK = 0; + table3gpp->m_sigK = 0; + table3gpp->m_rTau = 3; + table3gpp->m_uXpr = 10; + table3gpp->m_sigXpr = 4; + table3gpp->m_perClusterShadowingStd = 3; + + for (uint8_t row = 0; row < 6; row++) + { + for (uint8_t column = 0; column < 6; column++) + { + table3gpp->m_sqrtC[row][column] = sqrtC_office_NLOS[row][column]; + } + } + } + } + else + { + NS_FATAL_ERROR ("unkonw scenarios"); + } + + return table3gpp; +} + +bool +ThreeGppChannelModel::ChannelMatrixNeedsUpdate (Ptr channelMatrix, bool los) const +{ + NS_LOG_FUNCTION (this); + + bool update = false; + + // if the los condition is different the channel has to be updated + if (channelMatrix->m_los != los) + { + NS_LOG_DEBUG ("old los condition " << channelMatrix->m_los << " new los condition " << los); + update = true; + } + + // if the coherence time is over the channel has to be updated + if (!m_updatePeriod.IsZero () && Simulator::Now() - channelMatrix->m_generatedTime > m_updatePeriod) + { + NS_LOG_DEBUG ("Generation time " << channelMatrix->m_generatedTime.GetNanoSeconds () << " now " << Simulator::Now ().GetNanoSeconds ()); + update = true; + } + + return update; +} + +Ptr +ThreeGppChannelModel::GetChannel (Ptr aMob, + Ptr bMob, + Ptr aAntenna, + Ptr bAntenna) +{ + NS_LOG_FUNCTION (this); + + // Compute the channel key. The key is reciprocal, i.e., key (a, b) = key (b, a) + uint32_t x1 = std::min (aMob->GetObject ()->GetId (), bMob->GetObject ()->GetId ()); + uint32_t x2 = std::max (aMob->GetObject ()->GetId (), bMob->GetObject ()->GetId ()); + uint32_t channelId = GetKey (x1, x2); + + // retrieve the channel condition + Ptr condition = m_channelConditionModel->GetChannelCondition (aMob, bMob); + bool los = (condition->GetLosCondition () == ChannelCondition::LosConditionValue::LOS); + bool o2i = false; // TODO include the o2i condition in the channel condition model + + // Check if the channel is present in the map and return it, otherwise + // generate a new channel + bool update = false; + bool notFound = false; + Ptr channelMatrix; + if (m_channelMap.find (channelId) != m_channelMap.end ()) + { + // channel matrix present in the map + NS_LOG_DEBUG ("channel matrix present in the map"); + channelMatrix = m_channelMap[channelId]; + + // check if it has to be updated + update = ChannelMatrixNeedsUpdate (channelMatrix, los); + } + else + { + NS_LOG_DEBUG ("channel matrix not found"); + notFound = true; + } + + // If the channel is not present in the map or if it has to be updated + // generate a new realization + if (notFound || update) + { + // channel matrix not found or has to be updated, generate a new one + Angles txAngle (bMob->GetPosition (), aMob->GetPosition ()); + Angles rxAngle (aMob->GetPosition (), bMob->GetPosition ()); + + double x = aMob->GetPosition ().x - bMob->GetPosition ().x; + double y = aMob->GetPosition ().y - bMob->GetPosition ().y; + double distance2D = sqrt (x * x + y * y); + + // NOTE we assume hUT = min (height(a), height(b)) and + // hBS = max (height (a), height (b)) + double hUt = std::min (aMob->GetPosition ().z, bMob->GetPosition ().z); + double hBs = std::max (aMob->GetPosition ().z, bMob->GetPosition ().z); + + // TODO this is not currently used, it is needed for the computation of the + // additional blockage in case of spatial consistent update + // I do not know who is the UT, I can use the relative distance between + // tx and rx instead + Vector locUt = Vector (0.0, 0.0, 0.0); + + channelMatrix = GetNewChannel (locUt, los, o2i, aAntenna, bAntenna, rxAngle, txAngle, distance2D, hBs, hUt); + channelMatrix->m_nodeIds = std::make_pair (aMob->GetObject ()->GetId (), bMob->GetObject ()->GetId ()); + + // store or replace the channel matrix in the channel map + m_channelMap[channelId] = channelMatrix; + } + + return channelMatrix; +} + +Ptr +ThreeGppChannelModel::GetNewChannel (Vector locUT, bool los, bool o2i, + Ptr sAntenna, + Ptr uAntenna, + Angles &uAngle, Angles &sAngle, + double dis2D, double hBS, double hUT) const +{ + NS_LOG_FUNCTION (this); + + NS_ASSERT_MSG (m_frequency > 0.0, "Set the operating frequency first!"); + + // get the 3GPP parameters + Ptr table3gpp = GetThreeGppTable (los, o2i, hBS, hUT, dis2D); + + // get the number of clusters and the number of rays per cluster + uint8_t numOfCluster = table3gpp->m_numOfCluster; + uint8_t raysPerCluster = table3gpp->m_raysPerCluster; + + // create a channel matrix instance + Ptr channelParams = Create (); + channelParams->m_los = los; // set the LOS condition + channelParams->m_o2i = o2i; // set the O2I condition + channelParams->m_generatedTime = Simulator::Now (); + + // compute the 3D distance using eq. 7.4-1 + double dis3D = std::sqrt (dis2D * dis2D + (hBS - hUT) * (hBS - hUT)); + + //Step 4: Generate large scale parameters. All LSPS are uncorrelated. + DoubleVector LSPsIndep, LSPs; + uint8_t paramNum; + if (los) + { + paramNum = 7; + } + else + { + paramNum = 6; + } + //Generate paramNum independent LSPs. + for (uint8_t iter = 0; iter < paramNum; iter++) + { + LSPsIndep.push_back (m_normalRv->GetValue ()); + } + for (uint8_t row = 0; row < paramNum; row++) + { + double temp = 0; + for (uint8_t column = 0; column < paramNum; column++) + { + temp += table3gpp->m_sqrtC[row][column] * LSPsIndep[column]; + } + LSPs.push_back (temp); + } + + // NOTE the shadowing is generated in the propagation loss model + + double DS,ASD,ASA,ZSA,ZSD,K_factor = 0; + if (los) + { + K_factor = LSPs[1] * table3gpp->m_sigK + table3gpp->m_uK; + DS = pow (10, LSPs[2] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS); + ASD = pow (10, LSPs[3] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD); + ASA = pow (10, LSPs[4] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA); + ZSD = pow (10, LSPs[5] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD); + ZSA = pow (10, LSPs[6] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA); + } + else + { + DS = pow (10, LSPs[1] * table3gpp->m_sigLgDS + table3gpp->m_uLgDS); + ASD = pow (10, LSPs[2] * table3gpp->m_sigLgASD + table3gpp->m_uLgASD); + ASA = pow (10, LSPs[3] * table3gpp->m_sigLgASA + table3gpp->m_uLgASA); + ZSD = pow (10, LSPs[4] * table3gpp->m_sigLgZSD + table3gpp->m_uLgZSD); + ZSA = pow (10, LSPs[5] * table3gpp->m_sigLgZSA + table3gpp->m_uLgZSA); + + } + ASD = std::min (ASD, 104.0); + ASA = std::min (ASA, 104.0); + ZSD = std::min (ZSD, 52.0); + ZSA = std::min (ZSA, 52.0); + + channelParams->m_DS = DS; + channelParams->m_K = K_factor; + + NS_LOG_INFO ("K-factor=" << K_factor << ",DS=" << DS << ", ASD=" << ASD << ", ASA=" << ASA << ", ZSD=" << ZSD << ", ZSA=" << ZSA); + + //Step 5: Generate Delays. + DoubleVector clusterDelay; + double minTau = 100.0; + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + double tau = -1*table3gpp->m_rTau*DS*log (m_uniformRv->GetValue (0,1)); //(7.5-1) + if (minTau > tau) + { + minTau = tau; + } + clusterDelay.push_back (tau); + } + + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + clusterDelay[cIndex] -= minTau; + } + std::sort (clusterDelay.begin (), clusterDelay.end ()); //(7.5-2) + + /* since the scaled Los delays are not to be used in cluster power generation, + * we will generate cluster power first and resume to compute Los cluster delay later.*/ + + //Step 6: Generate cluster powers. + DoubleVector clusterPower; + double powerSum = 0; + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + double power = exp (-1 * clusterDelay[cIndex] * (table3gpp->m_rTau - 1) / table3gpp->m_rTau / DS) * + pow (10,-1 * m_normalRv->GetValue () * table3gpp->m_perClusterShadowingStd / 10); //(7.5-5) + powerSum += power; + clusterPower.push_back (power); + } + double powerMax = 0; + + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + clusterPower[cIndex] = clusterPower[cIndex] / powerSum; //(7.5-6) + } + + DoubleVector clusterPowerForAngles; // this power is only for equation (7.5-9) and (7.5-14), not for (7.5-22) + if (los) + { + double K_linear = pow (10,K_factor / 10); + + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + if (cIndex == 0) + { + clusterPowerForAngles.push_back (clusterPower[cIndex] / (1 + K_linear) + K_linear / (1 + K_linear)); //(7.5-8) + } + else + { + clusterPowerForAngles.push_back (clusterPower[cIndex] / (1 + K_linear)); //(7.5-8) + } + if (powerMax < clusterPowerForAngles[cIndex]) + { + powerMax = clusterPowerForAngles[cIndex]; + } + } + } + else + { + for (uint8_t cIndex = 0; cIndex < numOfCluster; cIndex++) + { + clusterPowerForAngles.push_back (clusterPower[cIndex]); //(7.5-6) + if (powerMax < clusterPowerForAngles[cIndex]) + { + powerMax = clusterPowerForAngles[cIndex]; + } + } + } + + //remove clusters with less than -25 dB power compared to the maxim cluster power; + //double thresh = pow(10,-2.5); + double thresh = 0.0032; + for (uint8_t cIndex = numOfCluster; cIndex > 0; cIndex--) + { + if (clusterPowerForAngles[cIndex - 1] < thresh * powerMax ) + { + clusterPowerForAngles.erase (clusterPowerForAngles.begin () + cIndex - 1); + clusterPower.erase (clusterPower.begin () + cIndex - 1); + clusterDelay.erase (clusterDelay.begin () + cIndex - 1); + } + } + uint8_t numReducedCluster = clusterPower.size (); + + channelParams->m_numCluster = numReducedCluster; + // Resume step 5 to compute the delay for LoS condition. + if (los) + { + double C_tau = 0.7705 - 0.0433 * K_factor + 2e-4 * pow (K_factor,2) + 17e-6 * pow (K_factor,3); //(7.5-3) + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + clusterDelay[cIndex] = clusterDelay[cIndex] / C_tau; //(7.5-4) + } + } + + //Step 7: Generate arrival and departure angles for both azimuth and elevation. + + double C_NLOS, C_phi; + //According to table 7.5-6, only cluster number equals to 8, 10, 11, 12, 19 and 20 is valid. + //Not sure why the other cases are in Table 7.5-2. + switch (numOfCluster) // Table 7.5-2 + { + case 4: + C_NLOS = 0.779; + break; + case 5: + C_NLOS = 0.860; + break; + case 8: + C_NLOS = 1.018; + break; + case 10: + C_NLOS = 1.090; + break; + case 11: + C_NLOS = 1.123; + break; + case 12: + C_NLOS = 1.146; + break; + case 14: + C_NLOS = 1.190; + break; + case 15: + C_NLOS = 1.221; + break; + case 16: + C_NLOS = 1.226; + break; + case 19: + C_NLOS = 1.273; + break; + case 20: + C_NLOS = 1.289; + break; + default: + NS_FATAL_ERROR ("Invalide cluster number"); + } + + if (los) + { + C_phi = C_NLOS * (1.1035 - 0.028 * K_factor - 2e-3 * pow (K_factor,2) + 1e-4 * pow (K_factor,3)); //(7.5-10)) + } + else + { + C_phi = C_NLOS; //(7.5-10) + } + + double C_theta; + switch (numOfCluster) //Table 7.5-4 + { + case 8: + C_NLOS = 0.889; + break; + case 10: + C_NLOS = 0.957; + break; + case 11: + C_NLOS = 1.031; + break; + case 12: + C_NLOS = 1.104; + break; + case 15: + C_NLOS = 1.1088; + break; + case 19: + C_NLOS = 1.184; + break; + case 20: + C_NLOS = 1.178; + break; + default: + NS_FATAL_ERROR ("Invalide cluster number"); + } + + if (los) + { + C_theta = C_NLOS * (1.3086 + 0.0339 * K_factor - 0.0077 * pow (K_factor,2) + 2e-4 * pow (K_factor,3)); //(7.5-15) + } + else + { + C_theta = C_NLOS; + } + + + DoubleVector clusterAoa, clusterAod, clusterZoa, clusterZod; + double angle; + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + angle = 2*ASA*sqrt (-1 * log (clusterPowerForAngles[cIndex] / powerMax)) / 1.4 / C_phi; //(7.5-9) + clusterAoa.push_back (angle); + angle = 2*ASD*sqrt (-1 * log (clusterPowerForAngles[cIndex] / powerMax)) / 1.4 / C_phi; //(7.5-9) + clusterAod.push_back (angle); + angle = -1*ZSA*log (clusterPowerForAngles[cIndex] / powerMax) / C_theta; //(7.5-14) + clusterZoa.push_back (angle); + angle = -1*ZSD*log (clusterPowerForAngles[cIndex] / powerMax) / C_theta; + clusterZod.push_back (angle); + } + + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + int Xn = 1; + if (m_uniformRv->GetValue (0,1) < 0.5) + { + Xn = -1; + } + clusterAoa[cIndex] = clusterAoa[cIndex] * Xn + (m_normalRv->GetValue () * ASA / 7) + uAngle.phi * 180 / M_PI; //(7.5-11) + clusterAod[cIndex] = clusterAod[cIndex] * Xn + (m_normalRv->GetValue () * ASD / 7) + sAngle.phi * 180 / M_PI; + if (o2i) + { + clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + 90; //(7.5-16) + } + else + { + clusterZoa[cIndex] = clusterZoa[cIndex] * Xn + (m_normalRv->GetValue () * ZSA / 7) + uAngle.theta * 180 / M_PI; //(7.5-16) + } + clusterZod[cIndex] = clusterZod[cIndex] * Xn + (m_normalRv->GetValue () * ZSD / 7) + sAngle.theta * 180 / M_PI + table3gpp->m_offsetZOD; //(7.5-19) + + } + + if (los) + { + //The 7.5-12 can be rewrite as Theta_n,ZOA = Theta_n,ZOA - (Theta_1,ZOA - Theta_LOS,ZOA) = Theta_n,ZOA - diffZOA, + //Similar as AOD, ZSA and ZSD. + double diffAoa = clusterAoa[0] - uAngle.phi * 180 / M_PI; + double diffAod = clusterAod[0] - sAngle.phi * 180 / M_PI; + double diffZsa = clusterZoa[0] - uAngle.theta * 180 / M_PI; + double diffZsd = clusterZod[0] - sAngle.theta * 180 / M_PI; + + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + clusterAoa[cIndex] -= diffAoa; //(7.5-12) + clusterAod[cIndex] -= diffAod; + clusterZoa[cIndex] -= diffZsa; //(7.5-17) + clusterZod[cIndex] -= diffZsd; + + } + } + + double rayAoa_radian[numReducedCluster][raysPerCluster]; //rayAoa_radian[n][m], where n is cluster index, m is ray index + double rayAod_radian[numReducedCluster][raysPerCluster]; //rayAod_radian[n][m], where n is cluster index, m is ray index + double rayZoa_radian[numReducedCluster][raysPerCluster]; //rayZoa_radian[n][m], where n is cluster index, m is ray index + double rayZod_radian[numReducedCluster][raysPerCluster]; //rayZod_radian[n][m], where n is cluster index, m is ray index + + for (uint8_t nInd = 0; nInd < numReducedCluster; nInd++) + { + for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++) + { + double tempAoa = clusterAoa[nInd] + table3gpp->m_cASA * offSetAlpha[mInd]; //(7.5-13) + while (tempAoa > 360) + { + tempAoa -= 360; + } + + while (tempAoa < 0) + { + tempAoa += 360; + + } + NS_ASSERT_MSG (tempAoa >= 0 && tempAoa <= 360, "the AOA should be the range of [0,360]"); + rayAoa_radian[nInd][mInd] = tempAoa * M_PI / 180; + + double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd]; + while (tempAod > 360) + { + tempAod -= 360; + } + + while (tempAod < 0) + { + tempAod += 360; + } + NS_ASSERT_MSG (tempAod >= 0 && tempAod <= 360, "the AOD should be the range of [0,360]"); + rayAod_radian[nInd][mInd] = tempAod * M_PI / 180; + + double tempZoa = clusterZoa[nInd] + table3gpp->m_cZSA * offSetAlpha[mInd]; //(7.5-18) + + while (tempZoa > 360) + { + tempZoa -= 360; + } + + while (tempZoa < 0) + { + tempZoa += 360; + } + + if (tempZoa > 180) + { + tempZoa = 360 - tempZoa; + } + + NS_ASSERT_MSG (tempZoa >= 0&&tempZoa <= 180, "the ZOA should be the range of [0,180]"); + rayZoa_radian[nInd][mInd] = tempZoa * M_PI / 180; + + double tempZod = clusterZod[nInd] + 0.375 * pow (10,table3gpp->m_uLgZSD) * offSetAlpha[mInd]; //(7.5-20) + + while (tempZod > 360) + { + tempZod -= 360; + } + + while (tempZod < 0) + { + tempZod += 360; + } + if (tempZod > 180) + { + tempZod = 360 - tempZod; + } + NS_ASSERT_MSG (tempZod >= 0&&tempZod <= 180, "the ZOD should be the range of [0,180]"); + rayZod_radian[nInd][mInd] = tempZod * M_PI / 180; + } + } + DoubleVector angle_degree; + double sizeTemp = clusterZoa.size (); + for (uint8_t ind = 0; ind < 4; ind++) + { + switch (ind) + { + case 0: + angle_degree = clusterAoa; + break; + case 1: + angle_degree = clusterZoa; + break; + case 2: + angle_degree = clusterAod; + break; + case 3: + angle_degree = clusterZod; + break; + default: + NS_FATAL_ERROR ("Programming Error"); + } + + for (uint8_t nIndex = 0; nIndex < sizeTemp; nIndex++) + { + while (angle_degree[nIndex] > 360) + { + angle_degree[nIndex] -= 360; + } + + while (angle_degree[nIndex] < 0) + { + angle_degree[nIndex] += 360; + } + + if (ind == 1 || ind == 3) + { + if (angle_degree[nIndex] > 180) + { + angle_degree[nIndex] = 360 - angle_degree[nIndex]; + } + } + } + switch (ind) + { + case 0: + clusterAoa = angle_degree; + break; + case 1: + clusterZoa = angle_degree; + break; + case 2: + clusterAod = angle_degree; + break; + case 3: + clusterZod = angle_degree; + break; + default: + NS_FATAL_ERROR ("Programming Error"); + } + } + + DoubleVector attenuation_dB; + if (m_blockage) + { + attenuation_dB = CalcAttenuationOfBlockage (channelParams, clusterAoa, clusterZoa); + for (uint8_t cInd = 0; cInd < numReducedCluster; cInd++) + { + clusterPower[cInd] = clusterPower[cInd] / pow (10,attenuation_dB[cInd] / 10); + } + } + else + { + attenuation_dB.push_back (0); + } + + //Step 8: Coupling of rays within a cluster for both azimuth and elevation + //shuffle all the arrays to perform random coupling + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + std::shuffle (&rayAod_radian[cIndex][0],&rayAod_radian[cIndex][raysPerCluster],std::default_random_engine (cIndex * 1000 + 100)); + std::shuffle (&rayAoa_radian[cIndex][0],&rayAoa_radian[cIndex][raysPerCluster],std::default_random_engine (cIndex * 1000 + 200)); + std::shuffle (&rayZod_radian[cIndex][0],&rayZod_radian[cIndex][raysPerCluster],std::default_random_engine (cIndex * 1000 + 300)); + std::shuffle (&rayZoa_radian[cIndex][0],&rayZoa_radian[cIndex][raysPerCluster],std::default_random_engine (cIndex * 1000 + 400)); + } + + //Step 9: Generate the cross polarization power ratios + //Step 10: Draw initial phases + Double2DVector crossPolarizationPowerRatios; // vector containing the cross polarization power ratios, as defined by 7.5-21 + Double3DVector clusterPhase; //rayAoa_radian[n][m], where n is cluster index, m is ray index + for (uint8_t nInd = 0; nInd < numReducedCluster; nInd++) + { + DoubleVector temp; // used to store the XPR values + Double2DVector temp2; // used to store the PHI values for all the possible combination of polarization + for (uint8_t mInd = 0; mInd < raysPerCluster; mInd++) + { + double uXprLinear = pow (10, table3gpp->m_uXpr / 10); // convert to linear + double sigXprLinear = pow (10, table3gpp->m_sigXpr / 10); // convert to linear + + temp.push_back (std::pow (10, (m_normalRv->GetValue () * sigXprLinear + uXprLinear) / 10)); + DoubleVector temp3; // used to store the PHI valuse + for (uint8_t pInd = 0; pInd < 4; pInd++) + { + temp3.push_back (m_uniformRv->GetValue (-1 * M_PI, M_PI)); + } + temp2.push_back (temp3); + } + crossPolarizationPowerRatios.push_back (temp); + clusterPhase.push_back (temp2); + } + channelParams->m_clusterPhase = clusterPhase; + + //Step 11: Generate channel coefficients for each cluster n and each receiver + // and transmitter element pair u,s. + + Complex3DVector H_NLOS; // channel coefficients H_NLOS [u][s][n], + // where u and s are receive and transmit antenna element, n is cluster index. + uint64_t uSize = uAntenna->GetNumberOfElements (); + uint64_t sSize = sAntenna->GetNumberOfElements (); + + uint8_t cluster1st = 0, cluster2nd = 0; // first and second strongest cluster; + double maxPower = 0; + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + if (maxPower < clusterPower[cIndex]) + { + maxPower = clusterPower[cIndex]; + cluster1st = cIndex; + } + } + maxPower = 0; + for (uint8_t cIndex = 0; cIndex < numReducedCluster; cIndex++) + { + if (maxPower < clusterPower[cIndex] && cluster1st != cIndex) + { + maxPower = clusterPower[cIndex]; + cluster2nd = cIndex; + } + } + + NS_LOG_INFO ("1st strongest cluster:" << (int)cluster1st << ", 2nd strongest cluster:" << (int)cluster2nd); + + Complex3DVector H_usn; //channel coffecient H_usn[u][s][n]; + // NOTE Since each of the strongest 2 clusters are divided into 3 sub-clusters, + // the total cluster will be numReducedCLuster + 4. + + H_usn.resize (uSize); + for (uint64_t uIndex = 0; uIndex < uSize; uIndex++) + { + H_usn[uIndex].resize (sSize); + for (uint64_t sIndex = 0; sIndex < sSize; sIndex++) + { + H_usn[uIndex][sIndex].resize (numReducedCluster); + } + } + + // The following for loops computes the channel coefficients + for (uint64_t uIndex = 0; uIndex < uSize; uIndex++) + { + Vector uLoc = uAntenna->GetElementLocation (uIndex); + + for (uint64_t sIndex = 0; sIndex < sSize; sIndex++) + { + + Vector sLoc = sAntenna->GetElementLocation (sIndex); + + for (uint8_t nIndex = 0; nIndex < numReducedCluster; nIndex++) + { + //Compute the N-2 weakest cluster, only vertical polarization. (7.5-22) + if (nIndex != cluster1st && nIndex != cluster2nd) + { + std::complex rays (0,0); + for (uint8_t mIndex = 0; mIndex < raysPerCluster; mIndex++) + { + DoubleVector initialPhase = clusterPhase[nIndex][mIndex]; + double k = crossPolarizationPowerRatios[nIndex][mIndex]; + //lambda_0 is accounted in the antenna spacing uLoc and sLoc. + double rxPhaseDiff = 2 * M_PI * (sin (rayZoa_radian[nIndex][mIndex]) * cos (rayAoa_radian[nIndex][mIndex]) * uLoc.x + + sin (rayZoa_radian[nIndex][mIndex]) * sin (rayAoa_radian[nIndex][mIndex]) * uLoc.y + + cos (rayZoa_radian[nIndex][mIndex]) * uLoc.z); + + double txPhaseDiff = 2 * M_PI * (sin (rayZod_radian[nIndex][mIndex]) * cos (rayAod_radian[nIndex][mIndex]) * sLoc.x + + sin (rayZod_radian[nIndex][mIndex]) * sin (rayAod_radian[nIndex][mIndex]) * sLoc.y + + cos (rayZod_radian[nIndex][mIndex]) * sLoc.z); + // NOTE Doppler is computed in the CalcBeamformingGain function and is simplified to only account for the center anngle of each cluster. + + double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta; + std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (rayAoa_radian[nIndex][mIndex], rayZoa_radian[nIndex][mIndex])); + std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (rayAod_radian[nIndex][mIndex], rayZod_radian[nIndex][mIndex])); + + rays += (exp (std::complex (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi + + +exp (std::complex (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi) + * exp (std::complex (0, rxPhaseDiff)) + * exp (std::complex (0, txPhaseDiff)); + } + rays *= sqrt (clusterPower[nIndex] / raysPerCluster); + H_usn[uIndex][sIndex][nIndex] = rays; + } + else //(7.5-28) + { + std::complex raysSub1 (0,0); + std::complex raysSub2 (0,0); + std::complex raysSub3 (0,0); + + for (uint8_t mIndex = 0; mIndex < raysPerCluster; mIndex++) + { + double k = crossPolarizationPowerRatios[nIndex][mIndex]; + + //ZML:Just remind me that the angle offsets for the 3 subclusters were not generated correctly. + + DoubleVector initialPhase = clusterPhase[nIndex][mIndex]; + double rxPhaseDiff = 2 * M_PI * (sin (rayZoa_radian[nIndex][mIndex]) * cos (rayAoa_radian[nIndex][mIndex]) * uLoc.x + + sin (rayZoa_radian[nIndex][mIndex]) * sin (rayAoa_radian[nIndex][mIndex]) * uLoc.y + + cos (rayZoa_radian[nIndex][mIndex]) * uLoc.z); + double txPhaseDiff = 2 * M_PI * (sin (rayZod_radian[nIndex][mIndex]) * cos (rayAod_radian[nIndex][mIndex]) * sLoc.x + + sin (rayZod_radian[nIndex][mIndex]) * sin (rayAod_radian[nIndex][mIndex]) * sLoc.y + + cos (rayZod_radian[nIndex][mIndex]) * sLoc.z); + + double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta; + std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (rayAoa_radian[nIndex][mIndex], rayZoa_radian[nIndex][mIndex])); + std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (rayAod_radian[nIndex][mIndex], rayZod_radian[nIndex][mIndex])); + + switch (mIndex) + { + case 9: + case 10: + case 11: + case 12: + case 17: + case 18: + raysSub2 += (exp (std::complex (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi + + +exp (std::complex (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi) + * exp (std::complex (0, rxPhaseDiff)) + * exp (std::complex (0, txPhaseDiff)); + break; + case 13: + case 14: + case 15: + case 16: + raysSub3 += (exp (std::complex (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi + + +exp (std::complex (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi) + * exp (std::complex (0, rxPhaseDiff)) + * exp (std::complex (0, txPhaseDiff)); + break; + default: //case 1,2,3,4,5,6,7,8,19,20 + raysSub1 += (exp (std::complex (0, initialPhase[0])) * rxFieldPatternTheta * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[1])) * std::sqrt (1 / k) * rxFieldPatternTheta * txFieldPatternPhi + + +exp (std::complex (0, initialPhase[2])) * std::sqrt (1 / k) * rxFieldPatternPhi * txFieldPatternTheta + + +exp (std::complex (0, initialPhase[3])) * rxFieldPatternPhi * txFieldPatternPhi) + * exp (std::complex (0, rxPhaseDiff)) + * exp (std::complex (0, txPhaseDiff)); + break; + } + } + raysSub1 *= sqrt (clusterPower[nIndex] / raysPerCluster); + raysSub2 *= sqrt (clusterPower[nIndex] / raysPerCluster); + raysSub3 *= sqrt (clusterPower[nIndex] / raysPerCluster); + H_usn[uIndex][sIndex][nIndex] = raysSub1; + H_usn[uIndex][sIndex].push_back (raysSub2); + H_usn[uIndex][sIndex].push_back (raysSub3); + + } + } + if (los) //(7.5-29) && (7.5-30) + { + std::complex ray (0,0); + double rxPhaseDiff = 2 * M_PI * (sin (uAngle.theta) * cos (uAngle.phi) * uLoc.x + + sin (uAngle.theta) * sin (uAngle.phi) * uLoc.y + + cos (uAngle.theta) * uLoc.z); + double txPhaseDiff = 2 * M_PI * (sin (sAngle.theta) * cos (sAngle.phi) * sLoc.x + + sin (sAngle.theta) * sin (sAngle.phi) * sLoc.y + + cos (sAngle.theta) * sLoc.z); + + double rxFieldPatternPhi, rxFieldPatternTheta, txFieldPatternPhi, txFieldPatternTheta; + std::tie (rxFieldPatternPhi, rxFieldPatternTheta) = uAntenna->GetElementFieldPattern (Angles (uAngle.phi, uAngle.theta)); + std::tie (txFieldPatternPhi, txFieldPatternTheta) = sAntenna->GetElementFieldPattern (Angles (sAngle.phi, sAngle.theta)); + + double lambda = 3e8 / m_frequency; // the wavelength of the carrier frequency + + ray = (rxFieldPatternTheta * txFieldPatternTheta - rxFieldPatternPhi * txFieldPatternPhi) + * exp (std::complex (0, - 2 * M_PI * dis3D / lambda)) + * exp (std::complex (0, rxPhaseDiff)) + * exp (std::complex (0, txPhaseDiff)); + + double K_linear = pow (10,K_factor / 10); + // the LOS path should be attenuated if blockage is enabled. + H_usn[uIndex][sIndex][0] = sqrt (1 / (K_linear + 1)) * H_usn[uIndex][sIndex][0] + sqrt (K_linear / (1 + K_linear)) * ray / pow (10,attenuation_dB[0] / 10); //(7.5-30) for tau = tau1 + double tempSize = H_usn[uIndex][sIndex].size (); + for (uint8_t nIndex = 1; nIndex < tempSize; nIndex++) + { + H_usn[uIndex][sIndex][nIndex] *= sqrt (1 / (K_linear + 1)); //(7.5-30) for tau = tau2...taunN + } + + } + } + } + + // store the delays and the angles for the subclusters + if (cluster1st == cluster2nd) + { + clusterDelay.push_back (clusterDelay[cluster1st] + 1.28 * table3gpp->m_cDS); + clusterDelay.push_back (clusterDelay[cluster1st] + 2.56 * table3gpp->m_cDS); + + clusterAoa.push_back (clusterAoa[cluster1st]); + clusterAoa.push_back (clusterAoa[cluster1st]); + + clusterZoa.push_back (clusterZoa[cluster1st]); + clusterZoa.push_back (clusterZoa[cluster1st]); + + clusterAod.push_back (clusterAod[cluster1st]); + clusterAod.push_back (clusterAod[cluster1st]); + + clusterZod.push_back (clusterZod[cluster1st]); + clusterZod.push_back (clusterZod[cluster1st]); + } + else + { + double min, max; + if (cluster1st < cluster2nd) + { + min = cluster1st; + max = cluster2nd; + } + else + { + min = cluster2nd; + max = cluster1st; + } + clusterDelay.push_back (clusterDelay[min] + 1.28 * table3gpp->m_cDS); + clusterDelay.push_back (clusterDelay[min] + 2.56 * table3gpp->m_cDS); + clusterDelay.push_back (clusterDelay[max] + 1.28 * table3gpp->m_cDS); + clusterDelay.push_back (clusterDelay[max] + 2.56 * table3gpp->m_cDS); + + clusterAoa.push_back (clusterAoa[min]); + clusterAoa.push_back (clusterAoa[min]); + clusterAoa.push_back (clusterAoa[max]); + clusterAoa.push_back (clusterAoa[max]); + + clusterZoa.push_back (clusterZoa[min]); + clusterZoa.push_back (clusterZoa[min]); + clusterZoa.push_back (clusterZoa[max]); + clusterZoa.push_back (clusterZoa[max]); + + clusterAod.push_back (clusterAod[min]); + clusterAod.push_back (clusterAod[min]); + clusterAod.push_back (clusterAod[max]); + clusterAod.push_back (clusterAod[max]); + + clusterZod.push_back (clusterZod[min]); + clusterZod.push_back (clusterZod[min]); + clusterZod.push_back (clusterZod[max]); + clusterZod.push_back (clusterZod[max]); + + + } + + NS_LOG_INFO ("size of coefficient matrix =[" << H_usn.size () << "][" << H_usn[0].size () << "][" << H_usn[0][0].size () << "]"); + + channelParams->m_channel = H_usn; + channelParams->m_delay = clusterDelay; + + channelParams->m_angle.clear (); + channelParams->m_angle.push_back (clusterAoa); + channelParams->m_angle.push_back (clusterZoa); + channelParams->m_angle.push_back (clusterAod); + channelParams->m_angle.push_back (clusterZod); + + return channelParams; +} + +ThreeGppChannelModel::DoubleVector +ThreeGppChannelModel::CalcAttenuationOfBlockage (Ptr params, + const DoubleVector &clusterAOA, + const DoubleVector &clusterZOA) const +{ + NS_LOG_FUNCTION (this); + + DoubleVector powerAttenuation; + uint8_t clusterNum = clusterAOA.size (); + for (uint8_t cInd = 0; cInd < clusterNum; cInd++) + { + powerAttenuation.push_back (0); //Initial power attenuation for all clusters to be 0 dB; + } + //step a: the number of non-self blocking blockers is stored in m_numNonSelfBlocking. + + //step b:Generate the size and location of each blocker + //generate self blocking (i.e., for blockage from the human body) + double phi_sb, x_sb, theta_sb, y_sb; + //table 7.6.4.1-1 Self-blocking region parameters. + if (m_portraitMode) + { + phi_sb = 260; + x_sb = 120; + theta_sb = 100; + y_sb = 80; + } + else // landscape mode + { + phi_sb = 40; + x_sb = 160; + theta_sb = 110; + y_sb = 75; + } + + //generate or update non-self blocking + if (params->m_nonSelfBlocking.size () == 0) //generate new blocking regions + { + for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++) + { + //draw value from table 7.6.4.1-2 Blocking region parameters + DoubleVector table; + table.push_back (m_normalRv->GetValue ()); //phi_k: store the normal RV that will be mapped to uniform (0,360) later. + if (m_scenario == "InH-OfficeMixed" || m_scenario == "InH-OfficeOpen") + { + table.push_back (m_uniformRv->GetValue (15, 45)); //x_k + table.push_back (90); //Theta_k + table.push_back (m_uniformRv->GetValue (5, 15)); //y_k + table.push_back (2); //r + } + else + { + table.push_back (m_uniformRv->GetValue (5, 15)); //x_k + table.push_back (90); //Theta_k + table.push_back (5); //y_k + table.push_back (10); //r + } + params->m_nonSelfBlocking.push_back (table); + } + } + else + { + double deltaX = sqrt (pow (params->m_preLocUT.x - params->m_locUT.x, 2) + pow (params->m_preLocUT.y - params->m_locUT.y, 2)); + //if deltaX and speed are both 0, the autocorrelation is 1, skip updating + if (deltaX > 1e-6 || m_blockerSpeed > 1e-6) + { + double corrDis; + //draw value from table 7.6.4.1-4: Spatial correlation distance for different m_scenarios. + if (m_scenario == "InH-OfficeMixed" || m_scenario == "InH-OfficeOpen") + { + //InH, correlation distance = 5; + corrDis = 5; + } + else + { + if (params->m_o2i) // outdoor to indoor + { + corrDis = 5; + } + else //LOS or NLOS + { + corrDis = 10; + } + } + double R; + if (m_blockerSpeed > 1e-6) // speed not equal to 0 + { + double corrT = corrDis / m_blockerSpeed; + R = exp (-1 * (deltaX / corrDis + (Now ().GetSeconds () - params->m_generatedTime.GetSeconds ()) / corrT)); + } + else + { + R = exp (-1 * (deltaX / corrDis)); + } + + NS_LOG_INFO ("Distance change:" << deltaX << " Speed:" << m_blockerSpeed + << " Time difference:" << Now ().GetSeconds () - params->m_generatedTime.GetSeconds () + << " correlation:" << R); + + //In order to generate correlated uniform random variables, we first generate correlated normal random variables and map the normal RV to uniform RV. + //Notice the correlation will change if the RV is transformed from normal to uniform. + //To compensate the distortion, the correlation of the normal RV is computed + //such that the uniform RV would have the desired correlation when transformed from normal RV. + + //The following formula was obtained from MATLAB numerical simulation. + + if (R * R * (-0.069) + R * 1.074 - 0.002 < 1) //transform only when the correlation of normal RV is smaller than 1 + { + R = R * R * (-0.069) + R * 1.074 - 0.002; + } + for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++) + { + + //Generate a new correlated normal RV with the following formula + params->m_nonSelfBlocking[blockInd][PHI_INDEX] = + R * params->m_nonSelfBlocking[blockInd][PHI_INDEX] + sqrt (1 - R * R) * m_normalRv->GetValue (); + } + } + + } + + //step c: Determine the attenuation of each blocker due to blockers + for (uint8_t cInd = 0; cInd < clusterNum; cInd++) + { + NS_ASSERT_MSG (clusterAOA[cInd] >= 0 && clusterAOA[cInd] <= 360, "the AOA should be the range of [0,360]"); + NS_ASSERT_MSG (clusterZOA[cInd] >= 0 && clusterZOA[cInd] <= 180, "the ZOA should be the range of [0,180]"); + + //check self blocking + NS_LOG_INFO ("AOA=" << clusterAOA[cInd] << " Block Region[" << phi_sb - x_sb / 2 << "," << phi_sb + x_sb / 2 << "]"); + NS_LOG_INFO ("ZOA=" << clusterZOA[cInd] << " Block Region[" << theta_sb - y_sb / 2 << "," << theta_sb + y_sb / 2 << "]"); + if ( std::abs (clusterAOA[cInd] - phi_sb) < (x_sb / 2) && std::abs (clusterZOA[cInd] - theta_sb) < (y_sb / 2)) + { + powerAttenuation[cInd] += 30; //anttenuate by 30 dB. + NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by self blocking region and reduce 30 dB power," + "the attenuation is [" << powerAttenuation[cInd] << " dB]"); + } + + //check non-self blocking + double phiK, xK, thetaK, yK; + for (uint16_t blockInd = 0; blockInd < m_numNonSelfBlocking; blockInd++) + { + //The normal RV is transformed to uniform RV with the desired correlation. + phiK = (0.5 * erfc (-1 * params->m_nonSelfBlocking[blockInd][PHI_INDEX] / sqrt (2))) * 360; + while (phiK > 360) + { + phiK -= 360; + } + + while (phiK < 0) + { + phiK += 360; + } + + xK = params->m_nonSelfBlocking[blockInd][X_INDEX]; + thetaK = params->m_nonSelfBlocking[blockInd][THETA_INDEX]; + yK = params->m_nonSelfBlocking[blockInd][Y_INDEX]; + NS_LOG_INFO ("AOA=" << clusterAOA[cInd] << " Block Region[" << phiK - xK << "," << phiK + xK << "]"); + NS_LOG_INFO ("ZOA=" << clusterZOA[cInd] << " Block Region[" << thetaK - yK << "," << thetaK + yK << "]"); + + if ( std::abs (clusterAOA[cInd] - phiK) < (xK) + && std::abs (clusterZOA[cInd] - thetaK) < (yK)) + { + double A1 = clusterAOA[cInd] - (phiK + xK / 2); //(7.6-24) + double A2 = clusterAOA[cInd] - (phiK - xK / 2); //(7.6-25) + double Z1 = clusterZOA[cInd] - (thetaK + yK / 2); //(7.6-26) + double Z2 = clusterZOA[cInd] - (thetaK - yK / 2); //(7.6-27) + int signA1, signA2, signZ1, signZ2; + //draw sign for the above parameters according to table 7.6.4.1-3 Description of signs + if (xK / 2 < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= xK) + { + signA1 = -1; + } + else + { + signA1 = 1; + } + if (-1 * xK < clusterAOA[cInd] - phiK && clusterAOA[cInd] - phiK <= -1 * xK / 2) + { + signA2 = -1; + } + else + { + signA2 = 1; + } + + if (yK / 2 < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= yK) + { + signZ1 = -1; + } + else + { + signZ1 = 1; + } + if (-1 * yK < clusterZOA[cInd] - thetaK && clusterZOA[cInd] - thetaK <= -1 * yK / 2) + { + signZ2 = -1; + } + else + { + signZ2 = 1; + } + double lambda = 3e8 / m_frequency; + double F_A1 = atan (signA1 * M_PI / 2 * sqrt (M_PI / lambda * + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (A1 * M_PI / 180) - 1))) / M_PI; //(7.6-23) + double F_A2 = atan (signA2 * M_PI / 2 * sqrt (M_PI / lambda * + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (A2 * M_PI / 180) - 1))) / M_PI; + double F_Z1 = atan (signZ1 * M_PI / 2 * sqrt (M_PI / lambda * + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (Z1 * M_PI / 180) - 1))) / M_PI; + double F_Z2 = atan (signZ2 * M_PI / 2 * sqrt (M_PI / lambda * + params->m_nonSelfBlocking[blockInd][R_INDEX] * (1 / cos (Z2 * M_PI / 180) - 1))) / M_PI; + double L_dB = -20 * log10 (1 - (F_A1 + F_A2) * (F_Z1 + F_Z2)); //(7.6-22) + powerAttenuation[cInd] += L_dB; + NS_LOG_INFO ("Cluster[" << (int)cInd << "] is blocked by no-self blocking, " + "the loss is [" << L_dB << "]" << " dB"); + + } + } + } + return powerAttenuation; +} + +int64_t +ThreeGppChannelModel::AssignStreams (int64_t stream) +{ + NS_LOG_FUNCTION (this << stream); + m_normalRv->SetStream (stream); + m_uniformRv->SetStream (stream + 1); + return 2; +} + +} // namespace ns3 diff --git a/src/spectrum/model/three-gpp-channel-model.h b/src/spectrum/model/three-gpp-channel-model.h new file mode 100644 index 000000000..b142396e8 --- /dev/null +++ b/src/spectrum/model/three-gpp-channel-model.h @@ -0,0 +1,309 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering, + * New York University + * Copyright (c) 2019 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_CHANNEL_H +#define THREE_GPP_CHANNEL_H + +#include +#include "ns3/angles.h" +#include +#include +#include +#include +#include +#include +#include + +namespace ns3 { + +class MobilityModel; + +/** + * \ingroup spectrum + * \brief Channel Matrix Generation following 3GPP TR 38.901 + * + * The class implements the channel matrix generation procedure + * described in 3GPP TR 38.901. + * + * \see GetChannel + */ +class ThreeGppChannelModel : public Object +{ +public: + /** + * Constructor + */ + ThreeGppChannelModel (); + + /** + * Destructor + */ + ~ThreeGppChannelModel (); + + /** + * Get the type ID + * \return the object TypeId + */ + static TypeId GetTypeId (); + + typedef std::vector DoubleVector; //!< type definition for vectors of doubles + typedef std::vector Double2DVector; //!< type definition for matrices of doubles + typedef std::vector Double3DVector; //!< type definition for 3D matrices of doubles + typedef std::vector Complex2DVector; //!< type definition for complex matrices + typedef std::vector Complex3DVector; //!< type definition for complex 3D matrices + + /** + * Data structure that stores a channel realization + */ + struct ThreeGppChannelMatrix : public SimpleRefCount + { + Complex3DVector m_channel; //!< channel matrix H[u][s][n]. + DoubleVector m_delay; //!< cluster delay. + Double2DVector m_angle; //!< cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa), 2(aod), 3(zod) in degree. + Double2DVector m_nonSelfBlocking; //!< store the blockages + Time m_generatedTime; //!< generation time + std::pair m_nodeIds; //!< the first element is the s-node ID, the second element is the u-node ID + bool m_los; //!< true if LOS, false if NLOS + + // TODO these are not currently used, they have to be correctly set when including the spatial consistent update procedure + /*The following parameters are stored for spatial consistent updating*/ + Vector m_preLocUT; //!< location of UT when generating the previous channel + Vector m_locUT; //!< location of UT + Double2DVector m_norRvAngles; //!< stores the normal variable for random angles angle[cluster][id] generated for equation (7.6-11)-(7.6-14), where id = 0(aoa),1(zoa),2(aod),3(zod) + double m_DS; //!< delay spread + double m_K; //!< K factor + uint8_t m_numCluster; //!< reduced cluster number; + Double3DVector m_clusterPhase; //!< the initial random phases + bool m_o2i; //!< true if O2I + Vector m_speed; //!< velocity + double m_dis2D; //!< 2D distance between tx and rx + double m_dis3D; //!< 3D distance between tx and rx + + /** + * Returns true if the ThreeGppChannelMatrix object was generated + * considering node b as transmitter and node a as receiver. + * \param aid id of the a node + * \param bid id of the b node + * \return true if b is the rx and a is the tx, false otherwise + */ + bool IsReverse (const uint32_t aId, const uint32_t bId) const + { + uint32_t sId, uId; + std::tie (sId, uId) = m_nodeIds; + NS_ASSERT_MSG ((sId == aId && uId == bId) || (sId == bId && uId == aId), + "This matrix represents the channel between " << sId << " and " << uId); + return (sId == bId && uId == aId); + } + }; + + /** + * Set the channel condition model + * \param a pointer to the ChannelConditionModel object + */ + void SetChannelConditionModel (Ptr model); + + /** + * Get the associated channel condition model + * \return a pointer to the ChannelConditionModel object + */ + Ptr GetChannelConditionModel () const; + + /** + * Sets the center frequency of the model + * \param f the center frequency in Hz + */ + void SetFrequency (double f); + + /** + * Returns the center frequency + * \return the center frequency in Hz + */ + double GetFrequency (void) const; + + /** + * Sets the propagation scenario + * \param scenario the propagation scenario + */ + void SetScenario (const std::string &scenario); + + /** + * Returns the propagation scenario + * \return the propagation scenario + */ + std::string GetScenario (void) const; + + /** + * Looks for the channel matrix associated to the aMob and bMob pair in m_channelMap. + * If found, it checks if it has to be updated. If not found or if it has to + * be updated, it generates a new uncorrelated channel matrix using the + * method GetNewChannel and updates m_channelMap. + * + * We assume channel reciprocity between each node pair (i.e., H_ab = H_ba^T), + * therefore GetChannel (a, b) and GetChannel (b, a) will return the same + * ThreeGppChannelMatrix object. + * To understand if the channel matrix corresponds to H_ab or H_ba, we provide + * the method ThreeGppChannelMatrix::IsReverse. For instance, if the channel + * matrix corresponds to H_ab, a call to IsReverse (idA, idB) will return + * false, conversely, IsReverse (idB, idA) will return true. + * + * \param aMob mobility model of the a device + * \param bMob mobility model of the b device + * \param aAntenna antenna of the a device + * \param bAntenna antenna of the b device + * \return the channel matrix + */ + Ptr GetChannel (Ptr aMob, + Ptr bMob, + Ptr aAntenna, + Ptr bAntenna); + /** + * \brief Assign a fixed random variable stream number to the random variables + * used by this model. + * + * \param stream first stream index to use + * \return the number of stream indices assigned by this model + */ + int64_t AssignStreams (int64_t stream); + + static const uint8_t AOA_INDEX = 0; //!< index of the AOA value in the m_angle array + static const uint8_t ZOA_INDEX = 1; //!< index of the ZOA value in the m_angle array + static const uint8_t AOD_INDEX = 2; //!< index of the AOD value in the m_angle array + static const uint8_t ZOD_INDEX = 3; //!< index of the ZOD value in the m_angle array + + static const uint8_t PHI_INDEX = 0; //!< index of the PHI value in the m_nonSelfBlocking array + static const uint8_t X_INDEX = 1; //!< index of the X value in the m_nonSelfBlocking array + static const uint8_t THETA_INDEX = 2; //!< index of the THETA value in the m_nonSelfBlocking array + static const uint8_t Y_INDEX = 3; //!< index of the Y value in the m_nonSelfBlocking array + static const uint8_t R_INDEX = 4; //!< index of the R value in the m_nonSelfBlocking array + + /** + * Calculate the channel key using the Cantor function + * \param x1 first value + * \param x2 second value + * \return \f$ (((x1 + x2) * (x1 + x2 + 1))/2) + x2; \f$ + */ + static constexpr uint32_t GetKey (uint32_t x1, uint32_t x2) + { + return (((x1 + x2) * (x1 + x2 + 1)) / 2) + x2; + } + +private: + /** + * Data structure that stores the parameters of 3GPP TR 38.901, Table 7.5-6, + * for a certain scenario + */ + struct ParamsTable : public SimpleRefCount + { + uint8_t m_numOfCluster = 0; + uint8_t m_raysPerCluster = 0; + double m_uLgDS = 0; + double m_sigLgDS = 0; + double m_uLgASD = 0; + double m_sigLgASD = 0; + double m_uLgASA = 0; + double m_sigLgASA = 0; + double m_uLgZSA = 0; + double m_sigLgZSA = 0; + double m_uLgZSD = 0; + double m_sigLgZSD = 0; + double m_offsetZOD = 0; + double m_cDS = 0; + double m_cASD = 0; + double m_cASA = 0; + double m_cZSA = 0; + double m_uK = 0; + double m_sigK = 0; + double m_rTau = 0; + double m_uXpr = 0; + double m_sigXpr = 0; + double m_perClusterShadowingStd = 0; + + double m_sqrtC[7][7]; + }; + + /** + * Get the parameters needed to apply the channel generation procedure + * \param los the LOS/NLOS condition + * \param o2i whether if it is an outdoor to indoor transmission + * \param hBS the height of the BS + * \param hUT the height of the UT + * \param distance2D the 2D distance between tx and rx + * \return the parameters table + */ + Ptr GetThreeGppTable (bool los, bool o2i, double hBS, double hUT, double distance2D) const; + + /** + * Compute the channel matrix between two devices using the procedure + * described in 3GPP TR 38.901 + * \param locUT the location of the UT + * \param los the LOS/NLOS condition + * \param o2i whether if it is an outdoor to indoor transmission + * \param sAntenna the s node antenna array + * \param uAntenna the u node antenna array + * \param uAngle the u node angle + * \param sAngle the s node angle + * \param dis2D the 2D distance between tx and rx + * \param hBS the height of the BS + * \param hUT the height of the UT + * \return the channel realization + */ + Ptr GetNewChannel (Vector locUT, bool los, bool o2i, + Ptr sAntenna, + Ptr uAntenna, + Angles &uAngle, Angles &sAngle, + double dis2D, double hBS, double hUT) const; + + /** + * Applies the blockage model A described in 3GPP TR 38.901 + * \param params the channel matrix + * \param clusterAOA vector containing the azimuth angle of arrival for each cluster + * \param clusterZOA vector containing the zenith angle of arrival for each cluster + * \return vector containing the power attenuation for each cluster + */ + DoubleVector CalcAttenuationOfBlockage (Ptr params, + const DoubleVector &clusterAOA, + const DoubleVector &clusterZOA) const; + + /** + * Check if the channel matrix has to be updated + * \param channelMatrix channel matrix + * \param isLos the current los condition + * \return true if the channel matrix has to be updated, false otherwise + */ + bool ChannelMatrixNeedsUpdate (Ptr channelMatrix, bool isLos) const; + + std::unordered_map > m_channelMap; //!< map containing the channel realizations + Time m_updatePeriod; //!< the channel update period + double m_frequency; //!< the operating frequency + std::string m_scenario; //!< the 3GPP scenario + Ptr m_channelConditionModel; //!< the channel condition model + Ptr m_uniformRv; //!< uniform random variable + Ptr m_normalRv; //!< normal random variable + + // parameters for the blockage model + bool m_blockage; //!< enables the blockage model A + uint16_t m_numNonSelfBlocking; //!< number of non-self-blocking regions + bool m_portraitMode; //!< true if potrait mode, false if landscape + double m_blockerSpeed; //!< the blocker speed +}; +} // namespace ns3 + +#endif /* THREE_GPP_CHANNEL_H */ diff --git a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc new file mode 100644 index 000000000..2fdacafc1 --- /dev/null +++ b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc @@ -0,0 +1,293 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering, + * New York University + * Copyright (c) 2019 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 "ns3/log.h" +#include "three-gpp-spectrum-propagation-loss-model.h" +#include "ns3/net-device.h" +#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/node.h" +#include "ns3/channel-condition-model.h" +#include "ns3/double.h" +#include "ns3/string.h" +#include "ns3/simulator.h" +#include "ns3/pointer.h" +#include + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("ThreeGppSpectrumPropagationLossModel"); + +NS_OBJECT_ENSURE_REGISTERED (ThreeGppSpectrumPropagationLossModel); + +ThreeGppSpectrumPropagationLossModel::ThreeGppSpectrumPropagationLossModel () +{ + NS_LOG_FUNCTION (this); + m_channelModel = CreateObject (); +} + +ThreeGppSpectrumPropagationLossModel::~ThreeGppSpectrumPropagationLossModel () +{ + NS_LOG_FUNCTION (this); +} + +TypeId +ThreeGppSpectrumPropagationLossModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::ThreeGppSpectrumPropagationLossModel") + .SetParent () + .SetGroupName ("Spectrum") + .AddConstructor () + ; + return tid; +} + +void +ThreeGppSpectrumPropagationLossModel::AddDevice (Ptr n, Ptr a) +{ + NS_ASSERT_MSG (m_deviceAntennaMap.find (n->GetNode ()->GetId ()) == m_deviceAntennaMap.end (), "Device is already present in the map"); + m_deviceAntennaMap.insert (std::make_pair (n->GetNode ()->GetId (), a)); +} + +double +ThreeGppSpectrumPropagationLossModel::GetFrequency () const +{ + DoubleValue freq; + m_channelModel->GetAttribute ("Frequency", freq); + return freq.Get (); +} + +void +ThreeGppSpectrumPropagationLossModel::SetChannelModelAttribute (const std::string &name, const AttributeValue &value) +{ + m_channelModel->SetAttribute (name, value); +} + +void +ThreeGppSpectrumPropagationLossModel::GetChannelModelAttribute (const std::string &name, AttributeValue &value) const +{ + m_channelModel->GetAttribute (name, value); +} + +ThreeGppAntennaArrayModel::ComplexVector +ThreeGppSpectrumPropagationLossModel::CalcLongTerm (Ptr params, + const ThreeGppAntennaArrayModel::ComplexVector &sW, + const ThreeGppAntennaArrayModel::ComplexVector &uW) const +{ + NS_LOG_FUNCTION (this); + + uint16_t sAntenna = static_cast (sW.size ()); + uint16_t uAntenna = static_cast (uW.size ()); + + NS_LOG_DEBUG ("CalcLongTerm with sAntenna " << sAntenna << " uAntenna " << uAntenna); + //store the long term part to reduce computation load + //only the small scale fading needs to be updated if the large scale parameters and antenna weights remain unchanged. + ThreeGppAntennaArrayModel::ComplexVector longTerm; + uint8_t numCluster = static_cast (params->m_channel[0][0].size ()); + + for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) + { + std::complex txSum (0,0); + for (uint16_t sIndex = 0; sIndex < sAntenna; sIndex++) + { + std::complex rxSum (0,0); + for (uint16_t uIndex = 0; uIndex < uAntenna; uIndex++) + { + rxSum = rxSum + uW[uIndex] * params->m_channel[uIndex][sIndex][cIndex]; + } + txSum = txSum + sW[sIndex] * rxSum; + } + longTerm.push_back (txSum); + } + return longTerm; +} + +Ptr +ThreeGppSpectrumPropagationLossModel::CalcBeamformingGain (Ptr txPsd, + ThreeGppAntennaArrayModel::ComplexVector longTerm, + Ptr params, + const ns3::Vector &sSpeed, const ns3::Vector &uSpeed) const +{ + NS_LOG_FUNCTION (this); + + Ptr tempPsd = Copy (txPsd); + + //channel[rx][tx][cluster] + uint8_t numCluster = static_cast (params->m_channel[0][0].size ()); + + // compute the doppler term + // NOTE the update of Doppler is simplified by only taking the center angle of + // each cluster in to consideration. + double slotTime = Simulator::Now ().GetSeconds (); + ThreeGppAntennaArrayModel::ComplexVector doppler; + for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) + { + //cluster angle angle[direction][n],where, direction = 0(aoa), 1(zoa). + // TODO should I include the "alfa" term for the Doppler of delayed paths? + double temp_doppler = 2 * M_PI * ((sin (params->m_angle[ThreeGppChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * cos (params->m_angle[ThreeGppChannelModel::AOA_INDEX][cIndex] * M_PI / 180) * uSpeed.x + + sin (params->m_angle[ThreeGppChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * sin (params->m_angle[ThreeGppChannelModel::AOA_INDEX][cIndex] * M_PI / 180) * uSpeed.y + + cos (params->m_angle[ThreeGppChannelModel::ZOA_INDEX][cIndex] * M_PI / 180) * uSpeed.z) + + (sin (params->m_angle[ThreeGppChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * cos (params->m_angle[ThreeGppChannelModel::AOD_INDEX][cIndex] * M_PI / 180) * sSpeed.x + + sin (params->m_angle[ThreeGppChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * sin (params->m_angle[ThreeGppChannelModel::AOD_INDEX][cIndex] * M_PI / 180) * sSpeed.y + + cos (params->m_angle[ThreeGppChannelModel::ZOD_INDEX][cIndex] * M_PI / 180) * sSpeed.z)) + * slotTime * GetFrequency () / 3e8; + doppler.push_back (exp (std::complex (0, temp_doppler))); + } + + // apply the doppler term and the propagation delay to the long term component + // to obtain the beamforming gain + auto vit = tempPsd->ValuesBegin (); // psd iterator + auto sbit = tempPsd->ConstBandsBegin(); // band iterator + while (vit != tempPsd->ValuesEnd ()) + { + std::complex subsbandGain (0.0,0.0); + if ((*vit) != 0.00) + { + double fsb = (*sbit).fc; // center frequency of the sub-band + for (uint8_t cIndex = 0; cIndex < numCluster; cIndex++) + { + double delay = -2 * M_PI * fsb * (params->m_delay[cIndex]); + subsbandGain = subsbandGain + longTerm[cIndex] * doppler[cIndex] * exp (std::complex (0, delay)); + } + *vit = (*vit) * (norm (subsbandGain)); + } + vit++; + sbit++; + } + return tempPsd; +} + +ThreeGppAntennaArrayModel::ComplexVector +ThreeGppSpectrumPropagationLossModel::GetLongTerm (uint32_t aId, uint32_t bId, + Ptr channelMatrix, + const ThreeGppAntennaArrayModel::ComplexVector &aW, + const ThreeGppAntennaArrayModel::ComplexVector &bW) const +{ + ThreeGppAntennaArrayModel::ComplexVector longTerm; // vector containing the long term component for each cluster + + // check if the channel matrix was generated considering a as the s-node and + // b as the u-node or viceversa + ThreeGppAntennaArrayModel::ComplexVector sW, uW; + if (!channelMatrix->IsReverse (aId, bId)) + { + sW = aW; + uW = bW; + } + else + { + sW = bW; + uW = aW; + } + + // compute the long term key, the key is unique for each tx-rx pair + uint32_t x1 = std::min (aId, bId); + uint32_t x2 = std::max (aId, bId); + uint32_t longTermId = ThreeGppChannelModel::GetKey (x1, x2); + + bool update = false; // indicates whether the long term has to be updated + bool notFound = false; // indicates if the long term has not been computed yet + + // look for the long term in the map and check if it is valid + if (m_longTermMap.find (longTermId) != m_longTermMap.end ()) + { + NS_LOG_DEBUG ("found the long term component in the map"); + longTerm = m_longTermMap[longTermId]->m_longTerm; + + // check if the channel matrix has been updated + // or the s beam has been changed + // or the u beam has been changed + update = (m_longTermMap[longTermId]->m_channel->m_generatedTime != channelMatrix->m_generatedTime + || m_longTermMap[longTermId]->m_sW != sW + || m_longTermMap[longTermId]->m_uW != uW); + + } + else + { + NS_LOG_DEBUG ("long term component NOT found"); + notFound = true; + } + + if (update || notFound) + { + NS_LOG_DEBUG ("compute the long term"); + // compute the long term component + longTerm = CalcLongTerm (channelMatrix, sW, uW); + + // store the long term + Ptr longTermItem = Create (); + longTermItem->m_longTerm = longTerm; + longTermItem->m_channel = channelMatrix; + longTermItem->m_sW = sW; + longTermItem->m_uW = uW; + + m_longTermMap[longTermId] = longTermItem; + } + + return longTerm; +} + +Ptr +ThreeGppSpectrumPropagationLossModel::DoCalcRxPowerSpectralDensity (Ptr txPsd, + Ptr a, + Ptr b) const +{ + NS_LOG_FUNCTION (this); + uint32_t aId = a->GetObject ()->GetId (); // id of the node a + uint32_t bId = b->GetObject ()->GetId (); // id of the node b + + NS_ASSERT (aId != bId); + NS_ASSERT_MSG (a->GetDistanceFrom (b) > 0.0, "The position of a and b devices cannot be the same"); + + Ptr rxPsd = Copy (txPsd); + + // retrieve the antenna of device a + NS_ASSERT_MSG (m_deviceAntennaMap.find (aId) != m_deviceAntennaMap.end (), "Antenna not found for node " << aId); + Ptr aAntenna = m_deviceAntennaMap.at (aId); + NS_LOG_DEBUG ("a node " << a->GetObject () << " antenna " << aAntenna); + + // retrieve the antenna of the device b + NS_ASSERT_MSG (m_deviceAntennaMap.find (bId) != m_deviceAntennaMap.end (), "Antenna not found for device " << bId); + Ptr bAntenna = m_deviceAntennaMap.at (bId); + NS_LOG_DEBUG ("b node " << bId << " antenna " << bAntenna); + + if (aAntenna->IsOmniTx () || bAntenna->IsOmniTx () ) + { + NS_LOG_LOGIC ("Omni transmission, do nothing."); + return rxPsd; + } + + Ptr channelMatrix = m_channelModel->GetChannel (a, b, aAntenna, bAntenna); + + // get the precoding and combining vectors + ThreeGppAntennaArrayModel::ComplexVector aW = aAntenna->GetBeamformingVector (); + ThreeGppAntennaArrayModel::ComplexVector bW = bAntenna->GetBeamformingVector (); + + // retrieve the long term component + ThreeGppAntennaArrayModel::ComplexVector longTerm = GetLongTerm (aId, bId, channelMatrix, aW, bW); + + // apply the beamforming gain + rxPsd = CalcBeamformingGain (rxPsd, longTerm, channelMatrix, a->GetVelocity (), b->GetVelocity ()); + + return rxPsd; +} + + +} // namespace ns3 diff --git a/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h new file mode 100644 index 000000000..29da1ca90 --- /dev/null +++ b/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.h @@ -0,0 +1,181 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015, NYU WIRELESS, Tandon School of Engineering, + * New York University + * Copyright (c) 2019 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_SPECTRUM_PROPAGATION_LOSS_H +#define THREE_GPP_SPECTRUM_PROPAGATION_LOSS_H + +#include "ns3/spectrum-propagation-loss-model.h" +#include +#include +#include "ns3/three-gpp-channel-model.h" + +namespace ns3 { + +class NetDevice; +class ChannelConditionModel; +class ChannelCondition; + +/** + * \ingroup spectrum + * \brief 3GPP Spectrum Propagation Loss Model + * + * This class models the frequency dependent propagation phenomena in the way + * described by 3GPP TR 38.901 document. The main method is DoCalcRxPowerSpectralDensity, + * which takes as input the power spectral density (PSD) of the transmitted signal, + * the mobility models of the transmitting node and receiving node, and + * returns the PSD of the received signal. + * + * \see ThreeGppChannelModel + * \see ThreeGppAntennaArrayModel + * \see ChannelCondition + */ +class ThreeGppSpectrumPropagationLossModel : public SpectrumPropagationLossModel +{ +public: + /** + * Constructor + */ + ThreeGppSpectrumPropagationLossModel (); + + /** + * Destructor + */ + ~ThreeGppSpectrumPropagationLossModel (); + + /** + * Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (); + + /** + * Add a device-antenna pair + * \param n a pointer to the NetDevice + * \param a a pointer to the associated ThreeGppAntennaArrayModel + */ + void AddDevice (Ptr n, Ptr a); + + + /** + * Sets the value of an attribute belonging to the associated + * ThreeGppChannelModel instance + * \param name name of the attribute + * \param value the attribute value + */ + void SetChannelModelAttribute (const std::string &name, const AttributeValue &value); + + /** + * Returns the value of an attribute belonging to the associated + * ThreeGppChannelModel instance + * \param name name of the attribute + * \param where the result should be stored + */ + void GetChannelModelAttribute (const std::string &name, AttributeValue &value) const; + + /** + * \brief Computes the received PSD. + * + * This function computes the received PSD by applying the 3GPP fast fading + * model and the beamforming gain. + * In particular, it retrieves the matrix representing the channel between + * node a and node b, computes the corresponding long term component, i.e., + * the product between the cluster matrices and the TX and RX beamforming + * vectors (w_rx^T H^n_ab w_tx), and accounts for the Doppler component and + * the propagation delay. + * To reduce the computational load, the long term component associated with + * a certain channel is cached and recomputed only when the channel realization + * is updated, or when the beamforming vectors change. + * + * \param txPsd tx PSD + * \param a first node mobility model + * \param b second node mobility model + * + * \return the received PSD + */ + virtual Ptr DoCalcRxPowerSpectralDensity (Ptr txPsd, + Ptr a, + Ptr b) const; + +private: + /** + * Data structure that stores the long term component for a tx-rx pair + */ + struct LongTerm : public SimpleRefCount + { + ThreeGppAntennaArrayModel::ComplexVector m_longTerm; //!< vector containing the long term component for each cluster + Ptr m_channel; //!< pointer to the channel matrix used to compute the long term + ThreeGppAntennaArrayModel::ComplexVector m_sW; //!< the beamforming vector for the node s used to compute the long term + ThreeGppAntennaArrayModel::ComplexVector m_uW; //!< the beamforming vector for the node u used to compute the long term + }; + + /** + * Get the operating frequency + * \return the operating frequency in Hz + */ + double GetFrequency () const; + + /** + * Looks for the long term component in m_longTermMap. If found, checks + * whether it has to be updated. If not found or if it has to be updated, + * calls the method CalcLongTerm to compute it. + * \param aId id of the first node + * \param bId id of the second node + * \param channelMatrix the channel matrix + * \param aW the beamforming vector of the first device + * \param bW the beamforming vector of the second device + * \return vector containing the long term compoenent for each cluster + */ + ThreeGppAntennaArrayModel::ComplexVector GetLongTerm (uint32_t aId, uint32_t bId, + Ptr channelMatrix, + const ThreeGppAntennaArrayModel::ComplexVector &aW, + const ThreeGppAntennaArrayModel::ComplexVector &bW) const; + /** + * Computes the long term component + * \param channelMatrix the channel matrix H + * \param sW the beamforming vector of the s device + * \param uW the beamforming vector of the u device + * \return the long term component + */ + ThreeGppAntennaArrayModel::ComplexVector CalcLongTerm (Ptr channelMatrix, + const ThreeGppAntennaArrayModel::ComplexVector &sW, + const ThreeGppAntennaArrayModel::ComplexVector &uW) const; + + /** + * Computes the beamforming gain and applies it to the tx PSD + * \param txPsd the tx PSD + * \param longTerm the long term component + * \param params The channel matrix + * \param sSpeed speed of the first node + * \param uSpeed speed of the second node + * \return the rx PSD + */ + Ptr CalcBeamformingGain (Ptr txPsd, + ThreeGppAntennaArrayModel::ComplexVector longTerm, + Ptr params, + const Vector &sSpeed, const Vector &uSpeed) const; + + std::unordered_map > m_deviceAntennaMap; //!< map containig the associations + mutable std::unordered_map < uint32_t, Ptr > m_longTermMap; //!< map containing the long term components + Ptr m_channelModel; //!< the model to generate the channel matrix +}; +} // namespace ns3 + +#endif /* THREE_GPP_SPECTRUM_PROPAGATION_LOSS_H */ diff --git a/src/spectrum/test/three-gpp-channel-test-suite.cc b/src/spectrum/test/three-gpp-channel-test-suite.cc new file mode 100644 index 000000000..0af4f7270 --- /dev/null +++ b/src/spectrum/test/three-gpp-channel-test-suite.cc @@ -0,0 +1,577 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2019 SIGNET Lab, Department of Information Engineering, + * + * 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/log.h" +#include "ns3/abort.h" +#include "ns3/test.h" +#include "ns3/config.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "ns3/string.h" +#include "ns3/angles.h" +#include "ns3/pointer.h" +#include "ns3/node-container.h" +#include "ns3/constant-position-mobility-model.h" +#include "ns3/three-gpp-antenna-array-model.h" +#include "ns3/three-gpp-channel-model.h" +#include "ns3/simple-net-device.h" +#include "ns3/simulator.h" +#include "ns3/channel-condition-model.h" +#include "ns3/three-gpp-spectrum-propagation-loss-model.h" +#include "ns3/wifi-spectrum-value-helper.h" +#include "ns3/buildings-channel-condition-model.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("ThreeGppChannelTestSuite"); + +/** + * Test case for the ThreeGppChannelModel class. + * 1) check if the channel matrix has the correct dimensions + * 2) check if the channel matrix is correctly normalized + */ +class ThreeGppChannelMatrixComputationTest : public TestCase +{ +public: + /** + * Constructor + */ + ThreeGppChannelMatrixComputationTest (); + + /** + * Destructor + */ + virtual ~ThreeGppChannelMatrixComputationTest (); + +private: + /** + * Build the test scenario + */ + virtual void DoRun (void); + + /** + * Compute the Frobenius norm of the channel matrix and stores it in m_normVector + * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix + * \param txMob the mobility model of the first node + * \param rxMob the mobility model of the second node + * \param txAntenna the antenna object associated to the first node + * \param rxAntenna the antenna object associated to the second node + */ + void DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna); + + std::vector m_normVector; //!< each element is the norm of a channel realization +}; + +ThreeGppChannelMatrixComputationTest::ThreeGppChannelMatrixComputationTest () + : TestCase ("Check the dimensions and the norm of the channel matrix") +{ +} + +ThreeGppChannelMatrixComputationTest::~ThreeGppChannelMatrixComputationTest () +{ +} + +void +ThreeGppChannelMatrixComputationTest::DoComputeNorm (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna) +{ + uint64_t txAntennaElements = txAntenna->GetNumberOfElements (); + uint64_t rxAntennaElements = rxAntenna->GetNumberOfElements (); + + Ptr channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna); + + double channelNorm = 0; + uint8_t numTotClusters = channelMatrix->m_channel.at (0).at (0).size (); + for (uint8_t cIndex = 0; cIndex < numTotClusters; cIndex++) + { + double clusterNorm = 0; + for (uint64_t sIndex = 0; sIndex < txAntennaElements; sIndex++) + { + for (uint32_t uIndex = 0; uIndex < rxAntennaElements; uIndex++) + { + clusterNorm += std::pow (std::abs (channelMatrix->m_channel.at (uIndex).at (sIndex).at (cIndex)), 2); + } + } + channelNorm += clusterNorm; + } + m_normVector.push_back (channelNorm); +} + +void +ThreeGppChannelMatrixComputationTest::DoRun (void) +{ + // Build the scenario for the test + uint8_t txAntennaElements[] {2, 2}; // tx antenna dimensions + uint8_t rxAntennaElements[] {2, 2}; // rx antenna dimensions + uint32_t updatePeriodMs = 100; // update period in ms + + // create the channel condition model + Ptr channelConditionModel = CreateObject (); + + // create the ThreeGppChannelModel object used to generate the channel matrix + Ptr channelModel = CreateObject (); + channelModel->SetAttribute ("Frequency", DoubleValue (60.0e9)); + channelModel->SetAttribute ("Scenario", StringValue ("RMa")); + channelModel->SetAttribute ("ChannelConditionModel", PointerValue (channelConditionModel)); + channelModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (updatePeriodMs-1))); + + // create the tx and rx 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 tx and rx mobility models and set their positions + Ptr txMob = CreateObject (); + txMob->SetPosition (Vector (0.0,0.0,10.0)); + Ptr rxMob = CreateObject (); + rxMob->SetPosition (Vector (100.0,0.0,10.0)); + + // associate the nodes and the mobility models + nodes.Get (0)->AggregateObject (txMob); + nodes.Get (1)->AggregateObject (rxMob); + + // create the tx and rx antennas and set the their dimensions + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true)); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true)); + + // generate the channel matrix + Ptr channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna); + + // check the channel matrix dimensions + NS_TEST_ASSERT_MSG_EQ (channelMatrix->m_channel.at (0).size (), txAntennaElements [0] * txAntennaElements [1], "The second dimension of H should be equal to the number of tx antenna elements"); + NS_TEST_ASSERT_MSG_EQ (channelMatrix->m_channel.size (), rxAntennaElements [0] * rxAntennaElements [1], "The first dimension of H should be equal to the number of rx antenna elements"); + + // test if the channel matrix is correctly generated + uint16_t numIt = 1000; + for (uint16_t i = 0; i < numIt; i++) + { + Simulator::Schedule (MilliSeconds (updatePeriodMs * i), &ThreeGppChannelMatrixComputationTest::DoComputeNorm, this, channelModel, txMob, rxMob, txAntenna, rxAntenna); + } + + Simulator::Run (); + + // compute the sample mean + double sampleMean = 0; + for (auto i : m_normVector) + { + sampleMean += i; + } + sampleMean /= numIt; + + // compute the sample standard deviation + double sampleStd = 0; + for (auto i : m_normVector) + { + sampleStd += ((i - sampleMean) * (i - sampleMean)); + } + sampleStd = std::sqrt (sampleStd / (numIt - 1)); + + // perform the one sample t-test with a significance level of 0.05 to test + // the hypothesis "E [|H|^2] = M*N, where |H| indicates the Frobenius norm of + // H, M is the number of transmit antenna elements, and N is the number of + // the receive antenna elements" + double t = (sampleMean - txAntennaElements [0] * txAntennaElements [1] * rxAntennaElements [0] * rxAntennaElements [1]) / (sampleMean / std::sqrt (numIt)); + + // Using a significance level of 0.05, we reject the null hypothesis if |t| is + // greater than the critical value from a t-distribution with df = numIt-1 + NS_TEST_ASSERT_MSG_EQ_TOL (std::abs (t), 0, 1.65, "We reject the hypothesis E[|H|^2] = M*N with a significance level of 0.05"); + + Simulator::Destroy (); +} + +/** + * Test case for the ThreeGppChannelModel class. + * It checks if the channel realizations are correctly updated during the + * simulation. + */ +class ThreeGppChannelMatrixUpdateTest : public TestCase +{ +public: + /** + * Constructor + */ + ThreeGppChannelMatrixUpdateTest (); + + /** + * Destructor + */ + virtual ~ThreeGppChannelMatrixUpdateTest (); + +private: + /** + * Build the test scenario + */ + virtual void DoRun (void); + + /** + * This method is used to schedule the channel matrix computation at different + * time instants and to check if it correctly updated + * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix + * \param txMob the mobility model of the first node + * \param rxMob the mobility model of the second node + * \param txAntenna the antenna object associated to the first node + * \param rxAntenna the antenna object associated to the second node + * \param update whether if the channel matrix should be updated or not + */ + void DoGetChannel (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update); + + Ptr m_currentChannel; //!< used by DoGetChannel to store the current channel matrix +}; + +ThreeGppChannelMatrixUpdateTest::ThreeGppChannelMatrixUpdateTest () + : TestCase ("Check if the channel realizations are correctly updated during the simulation") +{ +} + +ThreeGppChannelMatrixUpdateTest::~ThreeGppChannelMatrixUpdateTest () +{ +} + +void +ThreeGppChannelMatrixUpdateTest::DoGetChannel (Ptr channelModel, Ptr txMob, Ptr rxMob, Ptr txAntenna, Ptr rxAntenna, bool update) +{ + // retrieve the channel matrix + Ptr channelMatrix = channelModel->GetChannel (txMob, rxMob, txAntenna, rxAntenna); + + if (m_currentChannel == 0) + { + // this is the first time we compute the channel matrix, we initialize + // m_currentChannel + m_currentChannel = channelMatrix; + } + else + { + // compare the old and the new channel matrices + NS_TEST_ASSERT_MSG_EQ ((m_currentChannel != channelMatrix), update, Simulator::Now ().GetMilliSeconds () << " The channel matrix is not correctly updated"); + } +} + +void +ThreeGppChannelMatrixUpdateTest::DoRun (void) +{ + // Build the scenario for the test + + uint8_t txAntennaElements[] {2, 2}; // tx antenna dimensions + uint8_t rxAntennaElements[] {4, 4}; // rx antenna dimensions + uint32_t updatePeriodMs = 100; // update period in ms + + // create the channel condition model + Ptr channelConditionModel = CreateObject (); + + // create the ThreeGppChannelModel object used to generate the channel matrix + Ptr channelModel = CreateObject (); + channelModel->SetAttribute ("Frequency", DoubleValue (60.0e9)); + channelModel->SetAttribute ("Scenario", StringValue ("UMa")); + channelModel->SetAttribute ("ChannelConditionModel", PointerValue (channelConditionModel)); + channelModel->SetAttribute ("UpdatePeriod", TimeValue (MilliSeconds (updatePeriodMs))); + + // create the tx and rx 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 tx and rx mobility models and set their positions + Ptr txMob = CreateObject (); + txMob->SetPosition (Vector (0.0,0.0,10.0)); + Ptr rxMob = CreateObject (); + rxMob->SetPosition (Vector (100.0,0.0,1.6)); + + // associate the nodes and the mobility models + nodes.Get (0)->AggregateObject (txMob); + nodes.Get (1)->AggregateObject (rxMob); + + // create the tx and rx antennas and set the their dimensions + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1]), "IsotropicElements", BooleanValue (true)); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1]), "IsotropicElements", BooleanValue (true)); + + // check if the channel matrix is correctly updated + + // compute the channel matrix for the first time + uint32_t firstTimeMs = 1; // time instant at which the channel matrix is generated for the first time + Simulator::Schedule (MilliSeconds (firstTimeMs), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, true); + + // call GetChannel before the update period is exceeded, the channel matrix + // should not be updated + Simulator::Schedule (MilliSeconds (firstTimeMs + updatePeriodMs / 2), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, false); + + // call GetChannel when the update period is exceeded, the channel matrix + // should be recomputed + Simulator::Schedule (MilliSeconds (firstTimeMs + updatePeriodMs + 1), &ThreeGppChannelMatrixUpdateTest::DoGetChannel, this, channelModel, txMob, rxMob, txAntenna, rxAntenna, true); + + Simulator::Run (); + Simulator::Destroy (); +} + +/** + * Test case for the ThreeGppSpectrumPropagationLossModelTest class. + * 1) checks if the long term components for the direct and the reverse link + * are the same + * 2) checks if the long term component is updated when changing the beamforming + * vectors + * 3) checks if the long term is updated when changing the channel matrix + */ +class ThreeGppSpectrumPropagationLossModelTest : public TestCase +{ +public: + /** + * Constructor + */ + ThreeGppSpectrumPropagationLossModelTest (); + + /** + * Destructor + */ + virtual ~ThreeGppSpectrumPropagationLossModelTest (); + +private: + /** + * Build the test scenario + */ + virtual void DoRun (void); + + /** + * Points the beam of thisDevice towards otherDevice + * \param thisDevice the device to configure + * \param thisAntenna the antenna object associated to thisDevice + * \param otherDevice the device to communicate with + * \param otherAntenna the antenna object associated to otherDevice + */ + void DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna); + + /** + * Test of the long term component is correctly updated when the channel + * matrix is recomputed + * \param lossModel the ThreeGppSpectrumPropagationLossModel object used to + * compute the rx PSD + * \param txPsd the PSD of the transmitted signal + * \param txMob the mobility model of the tx device + * \param rxMob the mobility model of the rx device + * \param rxPsdOld the previously received PSD + */ + void CheckLongTermUpdate (Ptr lossModel, Ptr txPsd, Ptr txMob, Ptr rxMob, Ptr rxPsdOld); + + /** + * Checks if two PSDs are equal + * \param first the first PSD + * \param second the second PSD + * \return true if first and second are equal, false otherwise + */ + static bool ArePsdEqual (Ptr first, Ptr second); +}; + +ThreeGppSpectrumPropagationLossModelTest::ThreeGppSpectrumPropagationLossModelTest () + : TestCase ("Test case for the ThreeGppSpectrumPropagationLossModel class") +{ +} + +ThreeGppSpectrumPropagationLossModelTest::~ThreeGppSpectrumPropagationLossModelTest () +{ +} + +void +ThreeGppSpectrumPropagationLossModelTest::DoBeamforming (Ptr thisDevice, Ptr thisAntenna, Ptr otherDevice, Ptr otherAntenna) +{ + uint8_t noPlane = 1; + ThreeGppAntennaArrayModel::ComplexVector antennaWeights; + + Vector aPos = thisDevice->GetNode ()->GetObject ()->GetPosition (); + Vector bPos = otherDevice->GetNode ()->GetObject ()->GetPosition (); + + Angles completeAngle (bPos,aPos); + + double posX = bPos.x - aPos.x; + double phiAngle = atan ((bPos.y - aPos.y) / posX); + + if (posX < 0) + { + phiAngle = phiAngle + M_PI; + } + if (phiAngle < 0) + { + phiAngle = phiAngle + 2 * M_PI; + } + + double hAngleRadian = fmod ((phiAngle + (M_PI / noPlane)),2 * M_PI / noPlane) - (M_PI / noPlane); + double vAngleRadian = completeAngle.theta; + + int totNoArrayElements = thisAntenna->GetNumberOfElements (); + double power = 1 / sqrt (totNoArrayElements); + + 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); + } + + thisAntenna->SetBeamformingVector (antennaWeights); +} + +bool +ThreeGppSpectrumPropagationLossModelTest::ArePsdEqual (Ptr first, Ptr second) +{ + bool ret = true; + for (uint8_t i = 0; i < first->GetSpectrumModel ()->GetNumBands (); i++) + { + if ((*first) [i] != (*second) [i]) + { + ret = false; + continue; + } + } + return ret; +} + +void +ThreeGppSpectrumPropagationLossModelTest::CheckLongTermUpdate (Ptr lossModel, Ptr txPsd, Ptr txMob, Ptr rxMob, Ptr rxPsdOld) +{ + Ptr rxPsdNew = lossModel->DoCalcRxPowerSpectralDensity (txPsd, txMob, rxMob); + NS_TEST_ASSERT_MSG_EQ (ArePsdEqual (rxPsdOld, rxPsdNew), false, "The long term is not updated when the channel matrix is recomputed"); +} + +void +ThreeGppSpectrumPropagationLossModelTest::DoRun () +{ + // Build the scenario for the test + Config::SetDefault ("ns3::ThreeGppChannelModel::UpdatePeriod", TimeValue (MilliSeconds (100))); + + uint8_t txAntennaElements[] {4, 4}; // tx antenna dimensions + uint8_t rxAntennaElements[] {4, 4}; // rx antenna dimensions + + // create the ChannelConditionModel object to be used to retrieve the + // channel condition + Ptr condModel = CreateObject (); + + // create the ThreeGppSpectrumPropagationLossModel object, set frequency, + // scenario and channel condition model to be used + Ptr lossModel = CreateObject (); + lossModel->SetChannelModelAttribute ("Frequency", DoubleValue(2.4e9)); + lossModel->SetChannelModelAttribute ("Scenario", StringValue("UMa")); + lossModel->SetChannelModelAttribute ("ChannelConditionModel", PointerValue (condModel)); // create the ThreeGppChannelModel object used to generate the channel matrix + + // create the tx and rx 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 tx and rx mobility models and set their positions + Ptr txMob = CreateObject (); + txMob->SetPosition (Vector (0.0,0.0,10.0)); + Ptr rxMob = CreateObject (); + rxMob->SetPosition (Vector (15.0,0.0,10.0)); // in this position the channel condition is always LOS + + // associate the nodes and the mobility models + nodes.Get (0)->AggregateObject (txMob); + nodes.Get (1)->AggregateObject (rxMob); + + // create the tx and rx antennas and set the their dimensions + Ptr txAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (txAntennaElements [0]), "NumRows", UintegerValue (txAntennaElements [1])); + Ptr rxAntenna = CreateObjectWithAttributes ("NumColumns", UintegerValue (rxAntennaElements [0]), "NumRows", UintegerValue (rxAntennaElements [1])); + + // initialize ThreeGppSpectrumPropagationLossModel + lossModel->AddDevice (txDev, txAntenna); + lossModel->AddDevice (rxDev, rxAntenna); + + // set the beamforming vectors + DoBeamforming (txDev, txAntenna, rxDev, rxAntenna); + DoBeamforming (rxDev, rxAntenna, txDev, txAntenna); + + // create the tx psd + WifiSpectrumValue5MhzFactory sf; + double txPower = 0.1; // Watts + uint32_t channelNumber = 1; + Ptr txPsd = sf.CreateTxPowerSpectralDensity (txPower, channelNumber); + + // compute the rx psd + Ptr rxPsdOld = lossModel->DoCalcRxPowerSpectralDensity (txPsd, txMob, rxMob); + + // 1) check that the rx PSD is equal for both the direct and the reverse channel + Ptr rxPsdNew = lossModel->DoCalcRxPowerSpectralDensity (txPsd, rxMob, txMob); + NS_TEST_ASSERT_MSG_EQ (ArePsdEqual (rxPsdOld, rxPsdNew), true, "The long term for the direct and the reverse channel are different"); + + // 2) check if the long term is updated when changing the BF vector + // change the position of the rx device and recompute the beamforming vectors + rxMob->SetPosition (Vector (10.0, 5.0, 10.0)); + ThreeGppAntennaArrayModel::ComplexVector txBfVector = txAntenna->GetBeamformingVector (); + txBfVector [0] = std::complex (0.0, 0.0); + txAntenna->SetBeamformingVector (txBfVector); + + rxPsdNew = lossModel->DoCalcRxPowerSpectralDensity (txPsd, rxMob, txMob); + NS_TEST_ASSERT_MSG_EQ (ArePsdEqual (rxPsdOld, rxPsdNew), false, "Changing the BF vectors the rx PSD does not change"); + + // update rxPsdOld + rxPsdOld = rxPsdNew; + + // 3) check if the long term is updated when the channel matrix is recomputed + Simulator::Schedule (MilliSeconds (101), &ThreeGppSpectrumPropagationLossModelTest::CheckLongTermUpdate, this, lossModel, txPsd, txMob, rxMob, rxPsdOld); + + Simulator::Run (); + Simulator::Destroy (); +} + +/** + * \ingroup spectrum + * + * Test suite for the ThreeGppChannelModel class + */ +class ThreeGppChannelTestSuite : public TestSuite +{ +public: + /** + * Constructor + */ + ThreeGppChannelTestSuite (); +}; + +ThreeGppChannelTestSuite::ThreeGppChannelTestSuite () + : TestSuite ("three-gpp-channel", UNIT) +{ + AddTestCase (new ThreeGppChannelMatrixComputationTest, TestCase::QUICK); + AddTestCase (new ThreeGppChannelMatrixUpdateTest, TestCase::QUICK); + AddTestCase (new ThreeGppSpectrumPropagationLossModelTest, TestCase::QUICK); +} + +static ThreeGppChannelTestSuite myTestSuite; diff --git a/src/spectrum/wscript b/src/spectrum/wscript index de19208f9..085a415b3 100644 --- a/src/spectrum/wscript +++ b/src/spectrum/wscript @@ -12,13 +12,13 @@ def build(bld): 'model/friis-spectrum-propagation-loss.cc', 'model/constant-spectrum-propagation-loss.cc', 'model/spectrum-phy.cc', - 'model/spectrum-channel.cc', + 'model/spectrum-channel.cc', 'model/single-model-spectrum-channel.cc', 'model/multi-model-spectrum-channel.cc', 'model/spectrum-interference.cc', 'model/spectrum-error-model.cc', 'model/spectrum-model-ism2400MHz-res1MHz.cc', - 'model/spectrum-model-300kHz-300GHz-log.cc', + 'model/spectrum-model-300kHz-300GHz-log.cc', 'model/wifi-spectrum-value-helper.cc', 'model/waveform-generator.cc', 'model/spectrum-analyzer.cc', @@ -30,6 +30,8 @@ def build(bld): 'model/microwave-oven-spectrum-value-helper.cc', 'model/tv-spectrum-transmitter.cc', 'model/trace-fading-loss-model.cc', + 'model/three-gpp-spectrum-propagation-loss-model.cc', + 'model/three-gpp-channel-model.cc', 'helper/spectrum-helper.cc', 'helper/adhoc-aloha-noack-ideal-phy-helper.cc', 'helper/waveform-generator-helper.cc', @@ -45,8 +47,9 @@ def build(bld): 'test/spectrum-waveform-generator-test.cc', 'test/tv-helper-distribution-test.cc', 'test/tv-spectrum-transmitter-test.cc', + 'test/three-gpp-channel-test-suite.cc', ] - + headers = bld(features='ns3header') headers.module = 'spectrum' headers.source = [ @@ -59,14 +62,14 @@ def build(bld): 'model/constant-spectrum-propagation-loss.h', 'model/spectrum-phy.h', 'model/spectrum-channel.h', - 'model/single-model-spectrum-channel.h', + 'model/single-model-spectrum-channel.h', 'model/multi-model-spectrum-channel.h', 'model/spectrum-interference.h', 'model/spectrum-error-model.h', 'model/spectrum-model-ism2400MHz-res1MHz.h', 'model/spectrum-model-300kHz-300GHz-log.h', 'model/wifi-spectrum-value-helper.h', - 'model/waveform-generator.h', + 'model/waveform-generator.h', 'model/spectrum-analyzer.h', 'model/aloha-noack-mac-header.h', 'model/aloha-noack-net-device.h', @@ -76,6 +79,8 @@ def build(bld): 'model/microwave-oven-spectrum-value-helper.h', 'model/tv-spectrum-transmitter.h', 'model/trace-fading-loss-model.h', + 'model/three-gpp-spectrum-propagation-loss-model.h', + 'model/three-gpp-channel-model.h', 'helper/spectrum-helper.h', 'helper/adhoc-aloha-noack-ideal-phy-helper.h', 'helper/waveform-generator-helper.h',