OMNeT++ RNG 未收敛到均值

标签 omnet++

我正在使用 OMNeT++ 5.1.1 模拟器。我从 bernoulli() 函数中看到了一些奇怪的行为,因此我构建了一个 MWE 来看看发生了什么。

MWE 的工作原理是创建一个具有单个节点的网络,并在 t=0 时设置一个计时器(自身消息)。当计时器响起时,模拟会以成功概率 p 运行 n 次伯努利试验。值 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 std 以内的值。开发人员。中庸之道!尽管 OMNeT++ 手册确保使用 cMersenneTwister 算法意味着您可以随机选择种子,因为周期太大。

为什么会出现这种情况?我希望(1)由于 cMersenneTwister 是默认值,将其包含在 omnetpp.ini 文件中不应更改任何内容,并且(2)由于我每次都选择相同的种子(即种子 3),因此我应该得到相同的结果。但我不是!这让我很困惑,因为 OMNeT++ 手册指出:

For the cMersenneTwister random number generator, selecting seeds so that the generated sequences don't overlap is easy, due to the extremely long sequence of the RNG. The RNG is initialized from the 32-bit seed value 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 ,例如 **

关于OMNeT++ RNG 未收敛到均值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45882677/

相关文章:

runtime-error - 静脉试图读取字节缓冲区的结尾

java - Omnet++ 5.2 mac安装: Error

c++ - OMNET++: 如何在 INET 4.0 中获取帧的源 MAC 地址?

omnet++ - RSU 放置在静脉/SUMO 中

omnet++ - 构建 omnet++ 静脉时出错

omnet++ - 如何在 t > 0 时开始静脉模拟

linux - 发出 "make"命令时发生错误

java - 使用 Traci4j 在 SUMO 中获取车辆的角度

multithreading - 从工作/子线程访问主 OMNET++ 模拟线程

omnet++ - 在 Veins 中运行模拟时,可以将控制台输出转储到文件中