Verilog 隨機數(shù)及概率分布

2022-05-20 14:38 更新

隨機數(shù)

Verilog 中使用系統(tǒng)任務(wù) ?$random?(seed) 產(chǎn)生隨機數(shù),seed 為隨機數(shù)種子。

seed 值不同,產(chǎn)生的隨機數(shù)也不同。如果 seed 相同,產(chǎn)生的隨機數(shù)也是一樣的。

可以為 seed 賦初值,也可以忽略 seed 選項,seed 默認初始值為 0。

不使用 seed 選項和指定 seed 并對其修改來調(diào)用 ?$random? 的代碼如下所示:

   //seed var
   integer seed ;
   initial begin
      seed = 2 ;
      #30 ;
      seed = 10 ;
   end
   //no seed
   reg [15:0]   randnum_noseed ;
   always@(posedge clk) begin
      randnum_noseed <= $random(); //不指定隨機種子
   end
   //with seed
   reg [15:0]   randnum_wtseed ;
   always@(posedge clk) begin
      randnum_wtseed <= $random(seed); //指定隨機種子
   end

仿真波形圖如下。


無論是否賦初值,每產(chǎn)生一次隨機數(shù)后,seed 值改變,隨機數(shù)也隨之改變。

每改變一次 seed 值,當(dāng)前輸出的隨機值會改變;但是下一個狀態(tài)時,隨機數(shù)的走向又恢復(fù)成系統(tǒng)內(nèi)部產(chǎn)生的隨機序列。

例如仿真圖中 t1 和 t2 時刻隨機種子不同,產(chǎn)生是隨機數(shù)也不同。但是其他時鐘周期,產(chǎn)生的隨機數(shù)都是相同的。

建議調(diào)用系統(tǒng)任務(wù) ?$random? 時,不指定 seed 選項,或指定 seed 選項時使用變量傳遞參數(shù)。

不建議調(diào)用 ?$random? 時,將常數(shù)項寫到 seed 參數(shù)處。此時 seed 值被固定,可能只會產(chǎn)生一個隨機數(shù)。例如以下寫法是不建議的:

      randnum_wtseed <= $random(2); //不建議將常數(shù)項指定給 seed

可以使用取余的方法,將隨機數(shù)限定在一定的數(shù)據(jù)范圍內(nèi)。例如:

   //with a range
   parameter    MAX_NUM = 512;
   parameter    MIN_NUM = 256;
   reg [15:0]   num_range1, num_range2, num_range3 ;
   always@(posedge clk) begin
      //產(chǎn)生的隨機數(shù)范圍為 -511 ~ 511, ±(MAX_NUM-1)
      num_range1 <= $random() % MAX_NUM;
      //產(chǎn)生的隨機數(shù)范圍為 0 ~ 511, (0 ~ MAX_NUM-1)
      num_range2 <= {$random()} % MAX_NUM;
      //產(chǎn)生的隨機數(shù)范圍為 MIN_NUM ~ MAX_NUM,包含邊界
      num_range3 <= MIN_NUM + {$random()} % (MAX_NUM-MIN_NUM+1);
   end

隨機數(shù)按照有符號、十進制格式顯示,前幾個數(shù)據(jù)結(jié)果如下:


概率分布

Verilog 提供了許多按一定概率分布產(chǎn)生數(shù)據(jù)的系統(tǒng)任務(wù),簡單描述如下:

系統(tǒng)任務(wù) 調(diào)用格式 任務(wù)描述
均勻分布 $dist_uniform(seed, start, end); start、end 為數(shù)據(jù)的起始、結(jié)尾
正態(tài)分布 $dist_normal (seed, mean, std_dev); mean 為期望值,std_dev 為標(biāo)準(zhǔn)差
泊松分布 $dist_poisson(seed, mean); mean 為期望 (等于標(biāo)準(zhǔn)差)
指數(shù)分布 $dist_exponential(seed , mean); mean 為單位時間內(nèi)事件發(fā)生的次數(shù)
卡方分布 $dist_chi_square(seed, free_deg); free_deg 為自由度
t 分布 $dist_t(seed, free_deg); free_deg 為自由度
埃爾朗分布 $dist_erlang(seed, k_stage, mean); k_stage 為階數(shù),mean 為期望

均勻分布(Uniform Distribution)

均勻分布在等長區(qū)間上的取值概率是相同的。

概率密度函數(shù)及概率分布圖如下所示:


其實,系統(tǒng)任務(wù) ?$random? 實現(xiàn)的就是均勻分布。

調(diào)用 ?$dist_uniform? 在(256,512)區(qū)間上產(chǎn)生均勻分布數(shù)據(jù)的代碼如下:

   //2.1 uniform dis
   reg [15:0]   data_uniform;
   always@(posedge clk) begin //在 MIN_NUM ~ MAX_NUM 產(chǎn)生隨機數(shù)
      data_uniform <= $dist_uniform(seed_dis, MIN_NUM, MAX_NUM);
   end

正態(tài)分布(Normal Distribution)

正態(tài)分布數(shù)學(xué)期望為 μ,標(biāo)準(zhǔn)差為 σ,記做 N (μ, σ2)。

數(shù)學(xué)期望為 0、標(biāo)準(zhǔn)差為 1 的正態(tài)分布稱為標(biāo)準(zhǔn)正態(tài)分布。

正態(tài)分布曲線呈鐘型,兩邊低,中間高,左右對稱。

正態(tài)分布概率密度函數(shù)及分布圖如下所示:


調(diào)用 ?$dist_normal? 產(chǎn)生期望為 0、標(biāo)準(zhǔn)差為 1 的標(biāo)準(zhǔn)正態(tài)分布數(shù)據(jù)的代碼如下:

   //2.2 normal dis
   reg [15:0]   data_normal;
   always@(posedge clk) begin //期望為0、標(biāo)準(zhǔn)差為1 的標(biāo)準(zhǔn)正態(tài)分布
      data_normal <= $dist_normal(seed_dis, 0, 1);
   end

泊松分布(Poisson Distribution)

泊松分布用于描述某個時間或空間范圍內(nèi),某事件發(fā)生 X 次的概率。

泊松分布的數(shù)學(xué)期望和標(biāo)準(zhǔn)差相同,均為 λ,其概率密度函數(shù)及分布圖如下所示:


調(diào)用 ?$dist_poisson? 產(chǎn)生期望為 4 的泊松分布數(shù)據(jù)的代碼如下:

   //2.3 poisson dis
   reg [15:0]   data_poisson;
   always@(posedge clk) begin
      data_poisson <= $dist_poisson(seed_dis, 4);
   end

指數(shù)分布(Exponential Distribution)

指數(shù)分布用以描述泊松過程中隨機事件發(fā)生的時間間隔的概率。泊松過程即事件以恒定的平均速率連續(xù)且獨立地發(fā)生的過程。例如等公交車時兩輛車到來的時間間隔,就符合指數(shù)分布。

設(shè) λ>0 為單位時間內(nèi)事件發(fā)生的次數(shù)(又稱為率參數(shù)),x 為事件發(fā)生的時間間隔,則其概率密度函數(shù)及分布圖如下所示:


調(diào)用 ?$dist_exponential? 產(chǎn)生率參數(shù)為 1 的指數(shù)分布數(shù)據(jù)的代碼如下:

   //2.4 exp dis
   reg [15:0]   data_exp;
   always@(posedge clk) begin
      data_exp <= $dist_exponential(seed_dis, 1);
   end

卡方分布(Chi-Square Distribution)

n 個服從標(biāo)準(zhǔn)正態(tài)分布的隨機變量的平方和構(gòu)成新的隨機變量的分布規(guī)律稱為卡方分布,記做,其中 n 稱為自由度。

卡方分布概率密度函數(shù)及分布圖如下所示:


調(diào)用 ?$dist_chi_square? 產(chǎn)生自由度為 6 的卡方分布數(shù)據(jù)的代碼如下:

   //2.5 chi-square dis
   reg [15:0]   data_chi_sq;
   always@(posedge clk) begin
      data_chi_sq <= $dist_chi_square(seed_dis, 6);
   end

t 分布(T-Distribution)

假設(shè) X 服從標(biāo)準(zhǔn)正態(tài)分布 N (0, 1),Y 服從卡方分布的分布稱為自由度為 n 的 t 分布,記為 Z ~ t(n) 。

t 分布用于根據(jù)小樣本來估計呈正態(tài)分布且方差未知的數(shù)據(jù)變量總體的均值。如果樣本數(shù)量足夠多且總體方差已知,則應(yīng)該用正態(tài)分布來估計總體均值。

t 分布是對稱的鐘形分布,與正態(tài)分布類似,但尾部較重,這意味著它更容易產(chǎn)生遠低于平均值的值。其概率密度函數(shù)及分布圖如下所示:


調(diào)用 ?$dist_t? 產(chǎn)生自由度為 5 的 t 分布數(shù)據(jù)的代碼如下:

   //2.6 t dis
   reg [15:0]   data_t;
   always@(posedge clk) begin
      data_t <= $dist_t(seed_dis, 5);
   end

埃爾朗分布(Erlang Distribution)

設(shè)參數(shù)為 λ 泊松過程 V1, V2, ..., V3, Vn 相互獨立,N (t) 表示 [0, t) 內(nèi)隨機點出現(xiàn)的個數(shù),則 N (t) = V1 + V2 + ... + Vn 的分布稱為 Erlang 分布。

Erlang 分布與指數(shù)分布一樣,多用來表示獨立隨機事件發(fā)生的時間間隔。遵循 Erlang 分布的隨機變量可以被分解為多個相同參數(shù)的指數(shù)分布的隨機變量之和,使得 Erlang 分布被廣泛應(yīng)用于可靠性理論和排隊論中。

Erlang 分布概率密度函數(shù)及分布圖如下所示:


Why The Face? 你竟然拿這樣的水果 idea 來充數(shù) Erlang 分布?

上述概率分布任務(wù)都只列舉了調(diào)用方法,并沒有對數(shù)據(jù)進行分析驗證。下面有介紹借助 Matlab 畫圖工具,自己動手去分析概率分布任務(wù) ?$dist_erlang? 所產(chǎn)生數(shù)據(jù)的特性。

調(diào)用 ?$dist_erlang? 產(chǎn)生階數(shù)為 3、期望為 6 的 Erlang 分布數(shù)據(jù)的代碼如下:

   //2.7 Erlang dis
   reg [15:0]   data_erlang;
   always@(posedge clk) begin
      data_erlang <= $dist_erlang(seed_dis, 3, 6);
   end

數(shù)據(jù)分析

現(xiàn)實證明,還是熟知的分布數(shù)據(jù)分析起來比較方便。一些平臺關(guān)于 Erlang 分布相關(guān)的可參考性集成函數(shù)是少之又少。明知沒有愛(爾朗),偏向愛而行!

Verilog 數(shù)據(jù)文件

首先,在 Verilog 模型中產(chǎn)生 4 組服從 Erlang 分布的數(shù)據(jù),并打印到文件中。

   //generating data file of Erlang dis
   integer fd1, fd2, fd3, fd30 ;
   initial begin
      fd1 = $fopen("data_erlang1.hex", "w");
      fd2 = $fopen("data_erlang2.hex", "w");
      fd3 = $fopen("data_erlang3.hex", "w");
      fd30 = $fopen("data_erlang30.hex", "w");
      repeat(1000) begin //取1000個數(shù)據(jù)分析
         @(posedge clk) ;
         #1 ;
         $fdisplay(fd1, "%h", data_erlang1);
         $fdisplay(fd2, "%h", data_erlang2);
         $fdisplay(fd3, "%h", data_erlang3);
         $fdisplay(fd30, "%h", data_erlang30);
      end
      $fclose(fd1);
      $fclose(fd2);
      $fclose(fd3);
      $fclose(fd30);
   end

   reg [15:0]   data_erlang1;
   reg [15:0]   data_erlang2;
   reg [15:0]   data_erlang3;
   reg [15:0]   data_erlang30;
   always@(posedge clk) begin
      data_erlang1  <= $dist_erlang(seed_dis, 1, 6);
      data_erlang2  <= $dist_erlang(seed_dis, 2, 6);
      data_erlang3  <= $dist_erlang(seed_dis, 3, 6);
      data_erlang30 <= $dist_erlang(seed_dis, 30, 6);
   end

Verilog 數(shù)據(jù)分析

Matlab 中可以使用柱狀圖函數(shù) hist 直接對各個數(shù)據(jù)進行統(tǒng)計畫圖顯示,但對于概率分布情況該函數(shù)實際畫圖效果并不是很好(歡迎提供良好的畫圖方法)。這里使用 Matlab 數(shù)量統(tǒng)計函數(shù) tabulate 對各個數(shù)據(jù)進行統(tǒng)計,然后使用普通畫圖函數(shù) plot 顯示其百分比。

Matlab 讀取 Verilog 模塊產(chǎn)生的數(shù)據(jù)并對其進行分布圖顯示的代碼如下。

clear all;close all;clc;
%=======================================================
% data analysis from $dist_erlang in Verilog
%=======================================================

%按字符串讀取,再進行十六進制到十進制的轉(zhuǎn)換
data_erlang1_hex    = textread('data_erlang1.hex', '%s') ;
data_erlang2_hex    = textread('data_erlang2.hex', '%s') ;
data_erlang3_hex    = textread('data_erlang3.hex', '%s') ;
data_erlang30_hex   = textread('data_erlang30.hex', '%s') ;
data_erlang1        = hex2dec(data_erlang1_hex);
data_erlang2        = hex2dec(data_erlang2_hex);
data_erlang3        = hex2dec(data_erlang3_hex);
data_erlang30       = hex2dec(data_erlang30_hex);

%統(tǒng)計數(shù)據(jù)數(shù)量,并畫圖顯示
num_erlang1  = tabulate(data_erlang1) ;
num_erlang2  = tabulate(data_erlang2) ;
num_erlang3  = tabulate(data_erlang3) ;
num_erlang30 = tabulate(data_erlang30) ;
figure;  plot(num_erlang1(:,1)/6, num_erlang1(:,3));
hold on; plot(num_erlang2(:,1)/6, num_erlang2(:,3), 'r');
hold on; plot(num_erlang3(:,1)/6, num_erlang3(:,3), 'g');
hold on; plot(num_erlang30(:,1)/6, num_erlang30(:,3), 'y');
legend('n=1', 'n=2', 'n=3', 'n=30');

Verilog 模型產(chǎn)生的 Erlang 數(shù)據(jù)分布圖如下所示。


Erlang 分布期望

千萬要注意的是,λ 參數(shù)是泊松分布的期望,而不是 Erlang 分布的期望。

Verilog 系統(tǒng)任務(wù) ?$dist_erlang(seed, k_stage, mean)? 中第三個參數(shù)為期望值。如果直接將期望值帶入到 λ 參數(shù),將得到錯誤的分布結(jié)果。

下面簡(偷)單(懶)推(參)導(dǎo)(考)下 Erlang 分布的數(shù)學(xué)期望。


附 Erlang 分布方差的推導(dǎo)過程。


Matlab 理論分布

使用 Matlab 內(nèi)置函數(shù) random,可以產(chǎn)生多種類型的分布數(shù)據(jù),然而偏偏沒有 Erlang 分布。

下面利用概率密度分布函數(shù)產(chǎn)生服從 Erlang 分布的數(shù)據(jù)。

其中,Verilog 模型中期望值為 6,則實際參數(shù) λ = n/6 。

Matlab 產(chǎn)生 Erlang 分布數(shù)據(jù)的代碼如下。

clear all;close all;clc;
%=======================================================
% generating data of Erlang distribution
%=======================================================
NUM         = 400 ;
EXPECT      = 6 ;
for n=[1, 2, 3, 30]         //產(chǎn)生4組數(shù)據(jù)
    lamda   = n/EXPECT;     //期望值轉(zhuǎn)換
    t       = (0:NUM-1)*0.1 ;
    pt(n,:) = (lamda).^n *(t).^(n-1)/factorial(n-1) .* exp(-lamda * t) ;
end

figure; plot(t, pt(1,:)*100);
hold on;plot(t, pt(2,:)*100, 'r');
hold on;plot(t, pt(3,:)*100, 'g');
hold on;plot(t, pt(n,:)*100, 'y');
xlabel('t');
ylabel('f(t) / 100%');
legend('n=1', 'n=2', 'n=3', 'n=30');

Matlab 產(chǎn)生 Erlang 的數(shù)據(jù)分布圖如下所示。

對比 Verilog 模型產(chǎn)生的數(shù)據(jù),兩者的分布區(qū)間、分布概率及分布曲線走勢基本是一致的。只是 Verilog 中產(chǎn)生的是時間間隔較大的數(shù)據(jù),分布圖不是平滑的曲線。


點擊這里下載源碼


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號