You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LFSR与中心极限定理实现均匀转正态分布失败问题排查

中心极限定理生成正态分布Verilog实现问题
  • 背景:在大型Verilog项目中尝试用中心极限定理生成正态随机变量,已知AWGN、Box-Muller等更优方案,但为学习目的选择该方法,请勿推荐替代方案,除非实现存在严重错误。
  • 思路:用32个不同种子的LFSR生成独立均匀伪随机变量,根据中心极限定理,对这些变量取均值得到正态分布,参考过成功的VHDL实现,认为该方法可行(精度有限)。
  • 现象:已确认LFSR模块波形正常,但将输出导入Python绘制直方图后,结果仍是均匀分布而非正态分布。

以下是实现模块代码:

`timescale 1ns / 1ps

module CLTuniformToNormal(output [31:0] o_Mean, input i_Clock, input i_Reset);
    reg [36:0] r_Accumulator = 0;
    wire [31:0] o_LFSR_Out[31:0];
    parameter c_SEED0 = 32'h2b5f712d; parameter c_SEED1 = 32'h1834a06b; parameter c_SEED2 = 32'h9c82b0a3; parameter c_SEED3 = 32'hf33e3930;
    parameter c_SEED4 = 32'hf5cc2528; parameter c_SEED5 = 32'h6b21a119; parameter c_SEED6 = 32'hf874c4ea; parameter c_SEED7 = 32'h8b5d0748;
    parameter c_SEED8 = 32'hdf4c754a; parameter c_SEED9 = 32'hc1cfb4b8; parameter c_SEED10 = 32'h2097bf95; parameter c_SEED11 = 32'h9bc45a55;
    parameter c_SEED12 = 32'hb49c15c4; parameter c_SEED13 = 32'h0a7b9340; parameter c_SEED14 = 32'h7f658627; parameter c_SEED15 = 32'hee57af5a;
    parameter c_SEED16 = 32'hd8b427bb; parameter c_SEED17 = 32'he793836a; parameter c_SEED18 = 32'hf4e3e39f; parameter c_SEED19 = 32'h2987b38b;
    parameter c_SEED20 = 32'h173ac4ce; parameter c_SEED21 = 32'hdb53d09e; parameter c_SEED22 = 32'h5af5fd7f; parameter c_SEED23 = 32'h1352a672;
    parameter c_SEED24 = 32'h2ab03e34; parameter c_SEED25 = 32'hdd03bb9b; parameter c_SEED26 = 32'h6b72eaca; parameter c_SEED27 = 32'hb5e22b2e;
    parameter c_SEED28 = 32'hfa232aea; parameter c_SEED29 = 32'h067db0f8; parameter c_SEED30 = 32'hed09559a; parameter c_SEED31 = 32'hfacf5eaa;
      
    // Instantiate 32 LFSR modules
    genvar i;
    generate
        for (i = 0; i < 32; i = i + 1) begin : INST_LFSR
            LFSR #(.c_SEED((i==0) ? c_SEED0 : (i==1) ? c_SEED1 : (i==2) ? c_SEED2 : (i==3) ? c_SEED3 : (i==4) ? c_SEED4 :
            (i==5) ? c_SEED5 : (i==6) ? c_SEED6 : (i==7) ? c_SEED7 : (i==8) ? c_SEED8 :
            (i==9) ? c_SEED9 : (i==10) ? c_SEED10 : (i==11) ? c_SEED11 : (i==12) ? c_SEED12 :
            (i==13) ? c_SEED13 : (i==14) ? c_SEED14 : (i==15) ? c_SEED15 : (i==16) ? c_SEED16 :
            (i==17) ? c_SEED17 : (i==18) ? c_SEED18 : (i==19) ? c_SEED19 : (i==20) ? c_SEED20 :
            (i==21) ? c_SEED21 : (i==22) ? c_SEED22 : (i==23) ? c_SEED23 : (i==24) ? c_SEED24 : 
            (i==25) ? c_SEED25 : (i==26) ? c_SEED26 : (i==27) ? c_SEED27 : (i==28) ? c_SEED28 :
            (i==29) ? c_SEED29 : (i==30) ? c_SEED30 : c_SEED31))
            LFSR_inst (
                .o_LFSR_Out(o_LFSR_Out[i]),
                .i_Clock(i_Clock),
                .i_Reset(r_Reset)
            );
        end
    endgenerate

    always @(posedge i_Clock or posedge i_Reset) begin
        if (i_Reset) begin
            r_Accumulator <= 0;
        end else begin
            // Accumulate outputs
            r_Accumulator <= r_Accumulator + o_LFSR_Out[0] + o_LFSR_Out[1] + o_LFSR_Out[2] + o_LFSR_Out[3] + o_LFSR_Out[4] + o_LFSR_Out[5] +
            o_LFSR_Out[6] + o_LFSR_Out[7] + o_LFSR_Out[8] + o_LFSR_Out[9] + o_LFSR_Out[10] +
            o_LFSR_Out[11] + o_LFSR_Out[12] + o_LFSR_Out[13] + o_LFSR_Out[14] + o_LFSR_Out[15] +
            o_LFSR_Out[16] + o_LFSR_Out[17] + o_LFSR_Out[18] + o_LFSR_Out[19] + o_LFSR_Out[20] +
            o_LFSR_Out[21] + o_LFSR_Out[22] + o_LFSR_Out[23] + o_LFSR_Out[24] + o_LFSR_Out[25] +
            o_LFSR_Out[26] + o_LFSR_Out[27] + o_LFSR_Out[28] + o_LFSR_Out[29] + o_LFSR_Out[30] +             
            o_LFSR_Out[31];
        end
    end

    // Calculate mean
    assign o_Mean = (r_Accumulator >> 5);// - 2**31; // Divide by 32 and shift mean to 0
    
endmodule

问题分析与修正建议

  1. 累加逻辑错误(核心问题)
    当前代码中r_Accumulator是持续累加所有时钟周期的LFSR输出总和,而非每个时钟周期取32个LFSR的当前值相加。这导致o_Mean实际上是所有历史样本的累积均值,随着时间推移会趋近于均匀分布的期望,不会呈现正态分布。
    修正方法:每个时钟周期重新计算32个LFSR的和,而非持续累加:

    always @(posedge i_Clock or posedge i_Reset) begin
        if (i_Reset) begin
            r_Accumulator <= 0;
        end else begin
            // 每个周期重新计算32个LFSR的和,而非持续累加
            r_Accumulator <= o_LFSR_Out[0] + o_LFSR_Out[1] + o_LFSR_Out[2] + o_LFSR_Out[3] + 
                            o_LFSR_Out[4] + o_LFSR_Out[5] + o_LFSR_Out[6] + o_LFSR_Out[7] + 
                            o_LFSR_Out[8] + o_LFSR_Out[9] + o_LFSR_Out[10] + o_LFSR_Out[11] + 
                            o_LFSR_Out[12] + o_LFSR_Out[13] + o_LFSR_Out[14] + o_LFSR_Out[15] + 
                            o_LFSR_Out[16] + o_LFSR_Out[17] + o_LFSR_Out[18] + o_LFSR_Out[19] + 
                            o_LFSR_Out[20] + o_LFSR_Out[21] + o_LFSR_Out[22] + o_LFSR_Out[23] + 
                            o_LFSR_Out[24] + o_LFSR_Out[25] + o_LFSR_Out[26] + o_LFSR_Out[27] + 
                            o_LFSR_Out[28] + o_LFSR_Out[29] + o_LFSR_Out[30] + o_LFSR_Out[31];
        end
    end
    
  2. 复位信号连接错误
    LFSR实例中使用的复位信号是r_Reset,但模块的复位输入是i_Reset,属于笔误,会导致LFSR无法正确响应复位。修正为:

    LFSR_inst (
        .o_LFSR_Out(o_LFSR_Out[i]),
        .i_Clock(i_Clock),
        .i_Reset(i_Reset)
    );
    
  3. 均值偏移未处理
    原始代码注释了- 2**31,导致输出均值为均匀分布的中心(约2^31),虽然不影响分布形状,但如果需要零均值的正态分布,需要取消注释该部分:

    assign o_Mean = (r_Accumulator >> 5) - 32'h80000000; // 32'h80000000等于2^31
    

测试平台会将每个时钟周期的o_Mean写入文本文件,再用Python绘制直方图,修正上述问题后应该能得到符合预期的正态分布直方图。

内容的提问来源于stack exchange,提问作者Sishmasquash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:02:01