【问题标题】:OMNeT++ RNG not converging to meanOMNeT++ RNG 没有收敛到意思
【发布时间】:2017-08-25 13:36:01
【问题描述】:

我正在使用 OMNeT++ 5.1.1 模拟器。我从 bernoulli() 函数中看到了一些奇怪的行为,所以我构建了一个 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 std 以内的值。开发。的意思!尽管事实上 OMNeT++ 手册确保使用 cMersenneTwister 算法意味着您可以随机选择种子,因为周期是如此之大。

为什么会这样??我希望(1)因为 cMersenneTwister 是默认设置,包括它在 omnetpp.ini 文件中不应该改变任何东西,并且(2)因为我每次都选择相同的种子(即种子 3),那我应该得到相同的结果。但我不是!这让我很困惑,因为 OMNeT++ 手册指出:

对于 cMersenneTwister 随机数生成器,由于 RNG 的序列非常长,因此选择种子以使生成的序列不重叠很容易。 RNG 从 32 位种子值 seed = runNumber*numRngs + rngNumber 初始化。

谢谢!

【问题讨论】:

    标签: omnet++


    【解决方案1】:

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

    1. 在simple模块的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,例如**

    【讨论】:

    • 当然。感谢您提供有关参数机制的有用反馈。我一直马虎。谢谢!
    猜你喜欢
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    相关资源
    最近更新 更多