ns-3中隨機數機制


前言

ns-3是離散事件仿真平台,它由內核部分和常用模塊兩個部分組成。它的內核是用C++實現的。可以在src/core目錄下查看,也可以在ns3的在線doxygen文檔中查閱。

內核包含很多部分,實現了很多底層API供用戶使用。因為仿真中經常需要模擬現實環境中的不確定行為,因而隨機數機制是ns-3中非常重要的部分。了解隨機數機制對仿真模擬真實隨機情況非常重要,本文將詳細講解關於ns-3隨機數的內容。

本文之后的部分將按照以下章節展開:

1.隨機數生成器的背景 
2.ns-3中的偽隨機數生成器(PRNG,Pseudo Random Number Generator) 
3.ns-3中常用的隨機變量()

在第1點中將結合ns-3討論常見的隨機數生成器;在第2點中首先簡單講述ns-3中PRNG的特性,然后講述ns-3中PNRG的常見使用方法;在第3點中介紹ns-3中常用的隨機變量,包括滿足均勻分布、正態分布、等差分布等的隨機變量


一、背景:隨機數生成器RNG

在了解ns-3中隨機數機制之前,如果你之前對隨機數生成器(RNG,Random Number Generator)理解的不是很清楚,非常有必要了解什么是隨機數生成器。

計算機是按照事先確定的算法和程序進行確定的運算,都是確定性的計算。那么計算機到底是怎么得到隨機數的?作為人類,我們大可提筆隨便在紙上寫一大串數字,也許就算是隨機數了,但是計算機可沒有這本事,它必須有一個科學穩定的隨機數來源,才能得到隨機數,這個來源,我們稱為隨機數生成器。

作為編程愛好者,應該會發現,每一門編程語言必然會有自己的隨機數生成函數,常用的比如:C語言stdlib庫中的rand()函數,java中Random類中的nextInt () 方法,Python中random模塊的randint()方法等等。作為各種編程語言的“官方標配”,這小小的隨機函數作用那也是大大的,不光而這看似簡單的東西背后學問還真不少。

常見的計算機隨機數生成器有三種: 
參考文章 : 解密隨機數生成器

一是使用物理方法,稱為真隨機數生成器(True Random Number Generator),生成的算是真正意義上的隨機數,無法預測且無周期性;

與真隨機數對應的是偽隨機數生成器(Pseudo Random Number Generator),它是由算法計算得來的,但這種方法生成的隨機數是可預測、有周期的,並不能算真的隨機數,因此得名偽隨機數;

還有第三種方法,叫隨機數表法,就是用真隨機數生成器事先生成好大量隨機數,存到數據庫中,使用時再從庫中調用。記得高中數學書第三冊后附有一個叫隨機數表的東西,使用時直接查閱就行,這種方法簡單,但缺點是內存占用大,因此不常采用。

在編程當中常常使用的就是偽隨機數生成器。

偽隨機數算法中重要術語:

PRNG中常常需要給定一個種子,映射出一個不確定的隨機數。需要划重點的是:不同的種子映射的數值可以認為是沒有規律的,可以認為是隨機的。在這樣的映射條件下,才有我們所說的隨機數生成器,否則如果是確定的一一映射,完全無法體現隨機這樣一個概念。

每一個偽隨機數生成器(PRNG)都會提供一個相當長的隨機數序列,這個序列的長度稱為循環周期或者循環長度,RNG在完成一次循環后將自動進行下一次重復。這個序列可以被分隔為幾個相互獨立的數據流。一個RNG的隨機數據流是這個RNG序列的連續子集。例如,一個RNG隊列長度為N,同時RNG提供2個數據流,第一個數據流使用序列的前半部分,第二個數據流使用序列的后半部分,這兩個數據流是相互獨立的。同樣,每一個數據流還可以被分為更小的子流。

一個RNG最希望做到的就是提供一個非常長的循環序列,並有效的分配給每一個數據流。

偽隨機數生成器有很多種算法,包括同余法、梅森旋轉算法等多種多樣的方法,我們此處重點介紹一下prerre L’Ecuyer提出的MRG32k3a生成器。它提供1.8*1 019相互獨立的數據流,每個數據流又包含2.3*1 015個子數據流,並且每一個子數據流用甘油7.6*1 022的長度,因此整個生成器的循環周期為3.1*1 057。正因為RNG擁有這么長的序列,才保證了RNG產生的隨機數具有很高的可信度。

MRG32k3生成器需要一個隨機數種子,

敲黑板!敲黑板!敲黑板! 
1.計算機一般都是確定性的計算和運行,只有借助隨機數生成器才可以產生隨機數 
2.三種隨機數生成器中,偽隨機數生成器PRNG在編程中使用最頻繁 
3.偽隨機數中,由種子映射到隨機數時候可以認為映射是沒有規律、是隨機的 
4.偽隨機數生成器的循環周期足夠長能夠保證RNG的隨機數具有更高的可信度


二、詳解:ns-3中PRNG的使用

在ns-3中,仿真程序通常使用固定的種子,也就是產生固定的隨機數,也就是固定的數值,所以仿真也就不存在不確定性,也即確定性仿真。

如果需要模擬不確定的情況,則需要改變PRNG的種子或者運行標識。

ns-3的隨機數通過調用類ns3::RandomVariableStream來提供(在3.14版本及之前有ns3::Random Variable提供)。ns3::RandomVariableStream是對底層的隨機數生成器進行封裝之后向用戶提供的使用接口。

PRNG的種子和運行標識分別存儲在類GlobalValue的g_rngSeed和g_rngRun中,改變PRNG的種子或者運行標識通過ns3::RngSeedManager::SetSeed()和ns3::RngSeedmanager::SetRun()進行,下面對兩種改變方式分別做介紹。

2.1 通過ns3::RngSeedManager::SetSeed()改變種子實現隨機性

#include "ns3/simulator.h" #include "ns3/nstime.h" #include "ns3/command-line.h" #include "ns3/rng-seed-manager.h" #include "ns3/random-variable-stream.h" #include <iostream> using namespace ns3; int main(int argc, char *argv[]) { CommandLine cmd; cmd.Parse(argc,argv); RngSeedManager::SetSeed(1); Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable>(); std::cout<<uv->GetValue()<<std::endl; return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上述代碼中,首先通過RngSeedManager::SetSeed(1)設置種子為1,然后創建了一個類型為UniformRandomVariable的智能指針Ptr,其中UniformRandomVariable是ns3::RandomVariableStream的子類,所以通過uv調用GetValue()函數獲得對應的值。 
運行結果如下:

這里寫圖片描述

對於這個例子,在不改變SetSeed()函數參數的情況下連續運行兩次,得到的隨機數是一樣的,如上圖中所示,結果都是0.816532。將SetSeed()函數的參數修改為2,在運行一下,運行結果如下圖,發現改變種子之后,得到的隨機數結果是不一樣的,seed=2的時候的結果變成0.633064。

這里寫圖片描述

2.2 通過ns3::RngSeedmanager::SetRun()改變運行標識實現隨機性

在不改變種子的條件下,也可以通過改變 運行標識 來實現隨機性,改變運行運行標識的方法也有4種:

①通過函數RngSeedManager::SetRun(4)改變運行標識 
以下的實驗中,分別使用RngSeedManager::SetRun(3)和RngSeedManager::SetRun(4)運行得到結果。

圖1

②通過修改環境變量NS_GLOBAL_VALUE的值來修改運行標識 
這種方法不需要對代碼做修改,只需要在運行時候,在命令窗口進行設置。

NS_GLOBAL_VALUE="RngRun=3"./waf --run program-name
  • 1

圖2

③通過命令行傳遞參數來修改運行標識 
這種方法也不需要對代碼做修改,只需要在運行時候,在命令窗口進行設置。

./waf --run "program-name --RngRun=3"
  • 1

這里寫圖片描述 
④這種方式不使用waf,而是直接使用build

./build/optimized/scratch/program-name --RngRun=3
  • 1

這種方法不太適用,此處不做演示。

**針對上述4種方式,第1種與改變方式的方式基本上是一致的,只需要把代碼行RngSeedManager::SetSeed()用代碼行RngSeedManager::SetRun()替換就可以,每次進行獨立運行時改變參數就行。第二種方式比較繁瑣,每次都要修改環境變量,所以建議還是使用第三種方法。

**需要注意的是:提倡使用改變運行標識的方法實現隨機性。因為在改變種子的情況下進行重復試驗,ns-3無法保證每個種子對應的RNG序列不會重復。而修改運行標識是使用RNG序列的不同的子序列,同一個RNG序列的子序列是不會重復的。


三、詳解:ns-3中的隨機變量類型

ns-3中一共有5種常用的隨機變量,這5種都是

1.滿足均勻分布的隨機數 
2.滿足正態分布的隨機數 
3.滿足指數分布的隨機數 
4.滿足等差序列的隨機數 
5.返回一個固定的數值

以上5種分別對應了RandomVariableStream類的5個子類,下面一一進行解釋。

1.UniformRandomVariable:給定最大值和最小值,按均勻分布的方式返回一個隨機數 
UniformRandomVariable是從RandomVariableStream繼承的派生類,也是最基礎和最常用的類。它有兩個屬性:

屬性名稱 含義 類型
Max 均勻分布區間的上界 ns3::DoubleValue
Min 均勻分布區間的下界 ns3::DoubleValue

以下是一個實例:

這里寫圖片描述

2.NormalRandomVariable:根據正態分布返回隨機數 
需要設置的屬性值包括:

屬性名稱 含義 類型 初始值
Mean 返回值的均值 ns3::DoubleValue 0
Valance 返回值的方差 ns3::DoubleValue 1
Bound 返回值的上界 ns3::DoubleValue 1*10^307

3.ExponentialRandomVariable:根據指數概率分布返回隨機數 
需要設置的屬性值包括:

屬性名稱 含義 類型 初始值
Mean 返回值的均值 ns3::DoubleValue 1
Bound 返回值的上界 ns3::DoubleValue 0

4.SequentialRandomVariable:返回一串等差序列 
如果超過了給定的最大上限,則重新從給定的最小值開始循環。序列隨機變量的常用屬性如下:

屬性名稱 含義 類型 初始值
Min 序列的最小值 ns3::DoubleValue 0
Max 序列最大值的上限 ns3::DoubleValue 0
Increment 序列的差值 ns3::PointerValue 1
consecutive 序列中每個數重復的次數 ns3::StringeValue 1

5.ConstantRandomVariable:返回一個固定的數 
其默認值是0,使用方法和均勻分布的例子一樣。

RngSeedManager::SetSeed(3); double dValue=10.0 //把默認初始值改為10 Ptr<ConstantRandomVariable> uv = CreateObject<ConstantRandomVariable>(); uv->SetAttribute("Constant",DoubleValue(dValue)); 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM