2017-08-25 13 views
2

私はOMNeT ++ 5.1.1シミュレータを使用しています。私はbernoulli()関数からいくつかの奇妙な動作を見てきたので、何が起こっているかを見るためにMWEを構築しました。OMNeT ++ RNGが平均に収束しない

MWEは、単一のノードを持つネットワークを作成し、t = 0に1つのタイマー(自己メッセージ)を設定することによって動作します。タイマがオフになると、シミュレーションは成功確率pでいくつかのn回のベルヌーイ試行を実行します。値nとpは、Register_PerRunConfigOption()マクロを使用して定義した実行単位の設定オプションで指定します。 (私は++ OMNeTに新たなんだ)

#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; 
} 

このコードは、私は考えることができように簡単です:

は、ここに私のコードです。ここで

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(私は意図的に3回目を拾い出しています)。ここ.nedファイルです。上記のomnetpp.iniファイルでこれを実行すると、約532,006回の成功が得られます(ただし、この番号は各実行時に軽度に変更されます)。 10^7回の実行については、これは平均からの約46標準偏差(二項分布の平均および分散を用いて計算される)である。

さらに、私がrng-class="cMersenneTwister"行をコメントアウトすると、その数は約531,793回の成功にジャンプし、毎回少しずつ(ただし根本的には変わらない)変更されます。

さらに、私がseed-0-mt=...行をコメントアウトすると、突然シミュレーションが開始され、0.06スタンダード以内の値が生成されます。 dev。平均の!これは、OMNeT ++マニュアルがcMersenneTwisterアルゴリズムを使用すると、期間が非常に長いため、ランダムに種を選択できることを保証するという事実にもかかわらずです。

なぜこれが起こっていますか?私は、(1)cMersenneTwisterがデフォルトであるので、omnetpp.iniファイルに何も変更してはならないこと、(2)毎回同じシード(つまりシード3)を選択しているので、私は同じ結果を得ているはずです。でも僕はそうじゃない! cMersenneTwister乱数ジェネレータの

、生成されたシーケンスが重ならないように種を選択するため、RNGの非常に長い列に、簡単です:OMNeT ++マニュアル状態はので、これは、私を混乱させる。 RNGは、32ビットのシード値seed = runNumber * numRngs + rngNumberから初期化されます。

ありがとうございます!

答えて

2

C++の基本型(int、floatなど)のメンバーがデフォルトで初期化されていないため、nSuccessを0に初期化する必要があります。
また、OMNeT++でパラメータメカニズムを使用することを強くお勧めします。シミュレーションを制御する標準的な方法です。それを使用するには、必要があります。

  1. には、例えば、簡単なモジュールのNEDファイル内のパラメータの定義を追加します。omnetpp.ini

    simple Test 
    { 
        parameters: 
         double bernoulli_mean; 
         int num_trials; 
        gates: 
    } 
    
  2. 設定値:

    **.bernoulli_mean = 0.05 
    **.num_trials = 10000000 
    
  3. 読み取りをあなたのクラスのパラメータ:

    void Test::initialize() 
    { 
        nTrials = par("num_trials"); 
        p = par("bernoulli_mean").doubleValue(); 
        // ... 
    

注:

  • 使用 " - " パラメータの名前で禁止されています。
  • omnetpp.iniには、単純なモジュールのすべてのインスタンスに、そのパラメータの値があります。ただし、すべてのモジュールに同じ値を割り当てるには、**
+0

などを使用できます。パラメータメカニズムについての有益なフィードバックをありがとう。私はうんざりしている。ありがとうございました! –

関連する問題