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++
中的参数机制 - 这是控制模拟的标准方法。要使用它,你应该:
-
添加的参数的定义
NED
文件单模的,例如:simple Test { parameters: double bernoulli_mean; int num_trials; gates: }
-
设定值
omnetpp.ini
:**.bernoulli_mean = 0.05 **.num_trials = 10000000
-
阅读您所在班级的参数:
void Test::initialize() { nTrials = par("num_trials"); p = par("bernoulli_mean").doubleValue(); // ...
注:
- 使用 “ - ” 中的一个参数的名称是被禁止的。
- 在
omnetpp.ini
简单模块的每个实例都有自己的参数值。但是,要将相同的值分配给所有模块,可以使用wildcard patterns,例如**
当然。感谢您提供有关参数机制的有用反馈。我一直sl。。谢谢! –