2017-08-25 82 views
2

我正在使用OMNeT ++ 5.1.1模擬器。我已經看到了bernoulli()函數的一些奇怪行爲,所以我構建了一個MWE以查看發生了什麼。OMNeT ++ RNG不會收斂到意味着

MWE通過創建具有單個節點的網絡並在t = 0時設置一個計時器(自我消息)來工作。當計時器關閉時,仿真運行一些n次伯努利試驗,成功概率爲p。值n和p是通過使用Register_PerRunConfigOption()宏定義的每次運行配置選項指定的。

這裏是我的代碼:

#include <math.h> 
#include <omnetpp.h> 

using namespace omnetpp; 

Register_PerRunConfigOption(CFGID_NUM_TRIALS, "num-trials", CFG_INT, 
    "0", "The number of Bernoulli trials to run"); 
Register_PerRunConfigOption(CFGID_BERNOULLI_MEAN, "bernoulli-mean", 
    CFG_DOUBLE, "0.0", "The mean of the Bernoulli experiments"); 

class Test : public cSimpleModule { 
    private: 
     int nTrials, nSuccess; 
     double p; 
     cMessage *timer; 
    protected: 
     virtual void initialize() override; 
     virtual void handleMessage(cMessage *msg) override; 
}; 

Define_Module(Test); 

void Test::initialize() 
{ 
    nTrials = getEnvir()->getConfig()->getAsInt(CFGID_NUM_TRIALS); 
    p = getEnvir()->getConfig()->getAsDouble(CFGID_BERNOULLI_MEAN); 

    timer = new cMessage("timer"); 
    scheduleAt(0.0, timer); 
} 

void Test::handleMessage(cMessage *msg) 
{ 
    int trial; 

    printf("\n\n"); 

    for (int n = 0; n < nTrials; n++) { 
     trial = bernoulli(p); 
     if (trial) 
      nSuccess++; 
    } 

    double mean  = nTrials * p; 
    double variance = mean * (1.0 - p); 
    double stddev = std::sqrt(variance); 

    printf("nTrials: %12d(%.3e)\n", nTrials, (double) nTrials); 
    printf("nSuccess: %12d(%.3e)\n", nSuccess, (double) nSuccess); 
    printf("Pct.:  %12.5f\n", 100.0 * (double) nSuccess/nTrials); 
    printf("nStdDevs: %12.2f\n", (nSuccess - mean)/stddev); 
    printf("\n\n"); 

    delete msg; 
} 

這段代碼是我能想到的那樣簡單(我是新來的OMNeT ++)。這裏是.ned文件:

simple Test 
{ 
    gates: 
} 

network Bernoulli 
{ 
    submodules: 
     node: Test; 
} 

這裏是omnetpp.ini文件:

[General] 
network = Bernoulli 
bernoulli-mean = 0.05 
num-trials = 10000000 
rng-class = "cMersenneTwister" 
seed-0-mt = ${seed=0,1,2,3,4,5,6,7,8,9} 

我正在用下面的命令代碼:./exe_file -u Cmdenv -r 3(我故意挑了第三次運行)。當我使用上面的omnetpp.ini文件進行此操作時,我獲得了大約532,006次成功(儘管此數字在每次運行時都略有變化)。對於10^7次運行,這與平均值大約有46個標準偏差(使用二項分佈的均值和方差計算)。

此外,如果我註釋掉rng-class="cMersenneTwister"這一行,則跳轉到531,793次成功,每次都會稍微改變(但不是根本)。此外,如果我註釋掉seed-0-mt=...一行,那麼突然模擬開始在0.06標準內產生值。開發。的意思!儘管OMNeT ++手冊確保使用cMersenneTwister算法意味着您可以隨機選擇種子,因爲該期間非常大。

這是怎麼發生的?我期望(1)因爲cMersenneTwister是默認的,所以它包含在omnetpp.ini文件中不應該改變任何東西,並且(2)因爲我每次選擇相同的種子(即種子3),所以我應該得到相同的結果。但我不是!這混淆我,因爲的OMNeT ++手冊指出:

對於cMersenneTwister隨機數發生器,選擇種子以使產生的序列不重疊是容易的,由於RNG的極長的序列。 RNG從32位種子值seed = runNumber * numRngs + rngNumber進行初始化。

謝謝!

回答

2

您應該在使用它之前將nSuccess初始化爲零,因爲在C++中,基本類型(int,float等)的成員默認情況下未初始化。
此外,我強烈建議您使用OMNeT++中的參數機制 - 這是控制模擬的標準方法。要使用它,你應該:

  1. 添加的參數的定義NED文件單模的,例如:

    simple Test 
    { 
        parameters: 
         double bernoulli_mean; 
         int num_trials; 
        gates: 
    } 
    
  2. 設定值omnetpp.ini

    **.bernoulli_mean = 0.05 
    **.num_trials = 10000000 
    
  3. 閱讀您所在班級的參數:

    void Test::initialize() 
    { 
        nTrials = par("num_trials"); 
        p = par("bernoulli_mean").doubleValue(); 
        // ... 
    

注:

  • 使用 「 - 」 中的一個參數的名稱是被禁止的。
  • omnetpp.ini簡單模塊的每個實例都有自己的參數值。但是,要將相同的值分配給所有模塊,可以使用wildcard patterns,例如**
+0

當然。感謝您提供有關參數機制的有用反饋。我一直sl。。謝謝! –