OMNeT ++ RNG不会收敛到意味着

问题描述:

我正在使用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进行初始化。

谢谢!

您应该在使用它之前将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。。谢谢! –