首页 文章

OMNeT RNG没有收敛到意味着

提问于
浏览
2

我正在使用OMNeT 5.1.1模拟器 . 我一直在看bernoulli()函数的一些奇怪的行为,所以我 Build 了一个MWE来看看发生了什么 .

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初始化 .

谢谢!

1 回答

  • 2

    在使用它之前应该将 nSuccess 初始化为零,因为在 C++ 中,默认情况下不会初始化基类型(int,float等)的类成员 .
    此外,我强烈建议您在 OMNeT++ 中使用参数机制 - 它是控制模拟的标准方法 . 要使用它你应该:

    • 在简单模块的 NED 文件中添加参数定义,例如:
    simple Test
    {
        parameters: 
           double bernoulli_mean;
           int num_trials;
        gates:
    }
    
    • omnetpp.ini 中设置值:
    **.bernoulli_mean = 0.05
    **.num_trials = 10000000
    
    • 阅读 class 中的参数:
    void Test::initialize()
    {
      nTrials = par("num_trials");
      p = par("bernoulli_mean").doubleValue();
      // ...
    

    笔记:

    • 禁止在参数名称中使用"-" .

    • omnetpp.ini 中,简单模块的每个实例都有自己的参数值 . 但是,要为所有模块分配相同的值,可以使用wildcard patterns,例如 **

相关问题