FPGA_学习_13_方差计算小模块

news2024/11/25 11:35:45

测距器件APD的性能与器件本身的温度、施加在APD的偏置电压息息相关。 在不同的温度下,APD的偏压对测距性能的影响非常大。 要确定一个合适的APD的偏压Vopt,首先你要知道当前温度下,APD的击穿电压Vbr,一般来讲,Vopt = Vbr – ΔV,ΔV基本是个固定的值。如果要使用算法找到Vbr,通过寻找APD采集信号的噪声方差的剧变点去寻找Vbr是一个不错的方式。 如下图所示,当方差从10以下,突然剧变到45.31,信号噪声方差剧变4倍不止。我们就可以定义此处偏压43.8V为击穿电压Vbr。 那么要在FPGA实现此功能,首先需要在FPGA中实现方差的计算,这也是本文的内容。 这算是脱离例程,第一个本人自己设计的FPGA小模块。

1 CSDN C知道

ChatGPT已经火爆的不行了,猪如何在ChatGPT的风口起飞,这个问题还真是为难。 不过使用ChatGPT倒是不难,CSDN推出了基于ChatGPT的C知道,功能还是比较强大的。我也赶一下时髦,我对C知道问了一个问题:请帮我用Verilog写一个计算方差的算法。

module VarianceCalculator (
  input clk,
  input rst,
  input [N-1:0] data_in,
  input valid_in,
  output reg [31:0] variance,
  output reg valid_out
);

  reg [N-1:0] sum;
  reg [N-1:0] square_sum;
  reg [31:0] mean;
  reg [31:0] count;

  always @(posedge clk or posedge rst) begin
    if (rst) begin
      sum <= 'b0;
      square_sum <= 'b0;
      mean <= 'b0;
      count <= 'b0;
      valid_out <= 0;
    end else if (valid_in) begin
      sum <= sum + data_in;
      square_sum <= square_sum + (data_in * data_in);
      count <= count + 1;
      if (count == N-1) begin
        mean <= sum / N;
        variance <= square_sum / N - (mean * mean);
        valid_out <= 1;
      end
    end
  end

endmodule

 从算法上来讲,计算方差倒不是一个很难的问题,比如用平方的均值减去均值的平方(平方的期望减去期望的平方)。 C知道提供的Verilog代码就是这样算的,是没有问题的。 但直接拿来用,还是存在少许问题。 不过C知道已经很强大了,是很有参考价值的。

2 纯时序逻辑实现 V1.0

我已记不清从哪里接受了一个写Verilog代码的观念,就是:一个时序逻辑(always块),只写一个变量。这样做的好处是,修改调试非常方便,可以根据仿真结果看哪个变量有问题,然后我就专门去修改那个变量对应的时序逻辑。 不过坏处是,它不如全部变量写到一个时序逻辑里面那样,一眼看到算法的全貌。不过,我不管它的坏处是啥,总之这是我接受的观念,也是我后续编写FPGA代码的风格和态度。

下面给出,我用纯时序逻辑写的方差计算FPGA代码。

2.1 Verilog代码

`timescale 1ns / 1ps

module VarCalculatorV1(
        input   wire            clk             ,
        input   wire            rst_n           ,
        input   wire    [7:0]   data_in         ,
        input   wire            valid_in        ,
        output  reg     [15:0]  variance        ,
        output  reg             valid_out
);

//==================================================================
//                        Parameter define
//==================================================================
parameter       N = 256;

//==================================================================
//                        Internal Signals
//==================================================================
reg     [31:0]  count;
reg     [15:0]  sum;
reg     [31:0]  square_sum;
reg     [7:0]   mean;

//----------------------------- valid_out -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                valid_out <= 1'b0;     
        end
        else if (count == N+1)begin
                valid_out <= 1'b1;
        end
        else begin
                valid_out <= 1'b0;
        end
end

//----------------------------- variance -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                variance <= 'd0;     
        end
        else if (valid_in==1'b1 && count >= N+1 )begin
                variance <= (square_sum >> 8) - (mean * mean);
        end
        else begin
                variance <= 'd0;
        end
end

//----------------------------- count -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                count <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count == N+2) begin
                        count <= 'd0;
                end
                else begin
                        count <= count + 1'b1;
                end
        end
        else begin
                count <= 'd0;
        end
end

//----------------------------- sum -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                sum <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count < N) begin
                        sum <= sum + data_in;
                end
                else if(count == N || count == N+1) begin
                        sum <= sum;
                end
                else if(count == N+2) begin
                        sum <= 'd0;
                end
        end
        else begin
                sum <= 'd0;
        end
end


//----------------------------- square_sum -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                square_sum <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count < N) begin
                        square_sum <= square_sum + data_in*data_in;
                end
                else if(count == N || count == N+1) begin
                        square_sum <= square_sum;
                end
                else if(count == N+2) begin
                        square_sum <= 'd0;
                end
        end
        else begin
                square_sum <= 'd0;
        end
end


//----------------------------- mean -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                mean <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count >= N) begin
                        mean <= sum >> 8;
                end
                else begin
                        mean  <= 'd0;
                end
        end
        else begin
                sum <= 'd0;
        end
end


endmodule

啰嗦几句废话哈,由于需要验证代码的准确性,因此我们对其进行了ModelSim仿真。 本来呢,由于ModelSim的仿真代码我不是很熟悉, 我还不太会使用仿真代码来创建一个我想要的data_in。所以,我在仿真的时候,在用到data_in的地方,我都是用模块内部的计数变量count来代替的。(也就是说,我们计算的是从0~255这256个数的方差)。后来仿真成功确定了代码的准确性之后,我重新去调整我的仿真代码,使得我给到这个模块的data_in变量和模块内部的count变量是一样的。

下面给出对应的ModelSim仿真代码。

2.2 ModelSim仿真代码

`timescale 1ns/1ps
module tb_VarCalculator (); /* this is automatically generated */

    // clock
    reg clk;
    reg rst_n;
    reg  [7:0] data_in;
    reg        valid_in;
    wire [15:0] variance;
    wire        valid_out;

    parameter N = 256;

    VarCalculatorV1 #(
            .N(N)
        ) inst_VarCalculator (
            .clk       (clk),
            .rst_n     (rst_n),
            .data_in   (data_in),
            .valid_in  (valid_in),
            .variance  (variance),
            .valid_out (valid_out)
        );

    initial begin
        clk <= 1'b0;
        forever #(10) clk = ~clk;
    end

    initial begin
        rst_n <= 1'b0;
        #10
        rst_n <= 1'b1;
    end

    initial begin
        valid_in <= 1'b0;
        #10
        valid_in <= 1'b1;
    end

    
    reg [15:0] tb_count;
    initial begin
        tb_count <= 'd0;
        data_in <= 'd0;
        #10
        // 仿真代码中for循环是比较值得后续学习参考的
        for(tb_count = 1; tb_count <= N+3; tb_count = tb_count + 1) begin
            #20
            if(tb_count<='d255) begin
                data_in <= tb_count; 
            end
            else begin
                if (tb_count=='d258) begin
                    tb_count <= 'd0;
                end
                data_in <= 'd0; 
            end                
        end
    end

endmodule

仿真的时候,有个小技巧,真的好方便,特别提高仿真效率。

2.3 高效仿真小技巧

首先找到如下图所示的仿真编译文件 tb_VarCalculator_compile.do。

 打开这个文件,注释最后一行。

 修改完这个编译文件后, 后续你如果你的仿真代码或者你的功能模块代码有任何的改动,你改了之后先保存。

然后在ModelSim命令行输入三个命令(第一次输入后,后面你用上键↑下键↓就能快速输入了),编译 → 重启 → 运行。

就可以实现快速修改代码仿真。

2.4 仿真结果

 

分析一下仿真结果

1、可以看到仿真代码给出的data_in在0~255部分是和咱们模块内部的count变量一模一样的。仿真代码里面的for循环还是有点东西的,相信以后的仿真肯定可以借鉴。

2、仿真结果5588也是非常接近咱们用MatLAB算的0~255的方差的。 不能完全相等的原因是,我们的数据量个数是2^8,所以我们的除法是用的位移运算实现的。肯定会存在一定的误差。

3、咱们方差的计算结果延迟的3帧,

        1 首先时序逻辑肯定是要延迟1帧的,所以我在求所有数据的和、求所有数据的平方和的时候,就已经延迟了1帧。  

        2 其次,得到所有数据的和之后,我计算了所有数据的均值,这里又延迟了一帧。

        3 最后,在得到所有数据的均值之后,我又求了所有数据的平方和的均值 减去 均值的平方。

因此咱们总共延迟了三帧。 甚至我都担心最后一步在一个时钟周期内算不过来,还能再进行拆分,不过呢,这样延迟更多了,可能变成4帧或者5帧的。

这个很多帧延迟经常让人难以接受,所以我们下面用组合逻辑进行优化。

3 时序逻辑+组合逻辑 V2.0

组合逻辑是没有时钟延迟的。

当我用时序逻辑,求了所有数据的和,以及所有数据的平方和之后(延迟1帧)。

我可以用组合逻辑,就在当前时钟周期,立即得到:均值、均值的平方、平方和的均值、以及用平方和的均值减去均值的平方得到方差。

那么最终得到的方差,也只会延迟1帧。

3.1 Verilog代码

`timescale 1ns / 1ps

module VarCalculator(
        input   wire            clk      ,
        input   wire            rst_n    ,
        input   wire    [7:0]   data_in ,
        input   wire            valid_in,
        output  wire    [15:0]  variance,
        output  reg             valid_out
);

//==================================================================
//                        Parameter define
//==================================================================
parameter       N = 256;

//==================================================================
//                        Internal Signals
//==================================================================
reg     [31:0]  count;
reg     [15:0]  sum;
reg     [31:0]  square_sum;
wire    [7:0]   mean;
wire    [23:0]  square_mean;
wire    [15:0]  mean_square;


assign square_mean = square_sum >> 8;
assign mean_square = mean * mean;
assign variance = ( valid_in==1'b1 && count == N ) ? (square_mean - mean_square) : 'd0;
assign mean = (valid_in==1'b1 && count == N) ? (sum >> 8) : 'd0;

//----------------------------- valid_out -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                valid_out <= 1'b0;     
        end
        else if (count == N-1)begin
                valid_out <= 1'b1;
        end
        else begin
                valid_out <= 1'b0;
        end
end

//----------------------------- count -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                count <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count == N) begin
                        count <= 'd0;
                end
                else begin
                        count <= count + 1'b1;
                end
        end
        else begin
                count <= 'd0;
        end
end


//----------------------------- sum -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                sum <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count == N) begin
                        sum <= 'd0;                       
                end
                else begin
                        sum <= sum + data_in;
                end
        end
        else begin
                sum <= 'd0;
        end
end


//----------------------------- square_sum -----------------------------
always @(posedge clk or negedge rst_n) begin
        if (rst_n == 1'b0) begin
                square_sum <= 'd0;     
        end
        else if (valid_in==1'b1)begin
                if (count == N) begin
                        square_sum <= 'd0;                     
                end
                else begin
                        square_sum <= square_sum + data_in*data_in;
                end
        end
        else begin
                square_sum <= 'd0;
        end
end

endmodule

3.2 仿真结果

从仿真结果可看出,方差计算仍然正确,但是延迟只有1帧。 另外,其实咱们的verilog代码也要比V1.0版本精简一些。

本文之所得:

                1、ModelSim高效仿真小技巧(其实在前面的博文已经强调过一次,再次强调一遍,真的很高效)

                2、一个时序逻辑模块里面,尽量只给一个变量赋值。

                3、用组合逻辑可以优化时序逻辑的延迟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Zerotier】通过docker自建PLANET服务器

在如今全球互联的时代&#xff0c;我们对于互联网的依赖程度越来越高。然而&#xff0c;传统的网络连接方式在某些情况下可能会受到一些限制&#xff0c;例如局域网的范围限制、防火墙的阻断或者设备所处的多层NAT等。但是&#xff0c;现在有一个名为ZeroTier的工具出现了&…

yolov7 详解(1):yolov7 网络结构及创新点

文章目录 0. 概述1. 网络整体结构2.创新点2.1 创新点1:E-ELAN结构 (Extended efficient layer aggregation networks)ELAN结构2.2 创新点2: 模型缩放2.3 创新点3: 计划的重参数化卷积2.3.1 结构重参化原理2.3.2 什么是计划的重参数化卷积2.4 标签匹配策略论文: Trainable bag-…

【网络】协议与序列化反序列化

目录 一、相关概念 二、自定义协议 三、编写服务器 四、编写客户端 五、JSON 六、补充内容 一、相关概念 在《网络编程套接字》中&#xff0c;我们实现了服务器与客户端之间字符串的通信。但是更多的时候&#xff0c;需要传输的不仅仅是字符串&#xff0c;而是结构化的数…

奇思 妙想

一. main方法可以被其它方法调用吗&#xff1f; 在C语言中&#xff0c;一个工程内只能声明一个main函数&#xff0c;如果声明多个&#xff0c;则程序无法运行然后报错。Java则不同&#xff0c;Java在一个工程内&#xff0c;可以声明多个main方法&#xff0c;但在程序执行时&am…

搭建OIDC Provider,以Golang为例

搭建OIDC Provider&#xff0c;以Golang为例 1 需求 结合对OIDC&#xff1a;https://blog.csdn.net/weixin_45747080/article/details/131810562的理解&#xff0c;我尝试自己搭建OIDC的demo。在搭建demo之前&#xff0c;我需要先确定我想要实现成什么样子。以上文提到的http…

【算法|动态规划No.6】leetcode63. 不同路径Ⅱ

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

使用diagrams画架构图

序 最近发现一个画架构图的神器diagrams&#xff0c;提供了很多云厂商及开源组件的图标&#xff0c;相比于C4-PlantUML显得更专业一点。 之前写过技术文档画图工具箱&#xff0c;diagrams属于diagram as code工具派别。 mac安装 brew install graphviz pip install diagrams…

【Matlab】基于遗传算法优化 BP 神经网络的时间序列预测(Excel可直接替换数据)

【Matlab】基于遗传算法优化 BP 神经网络的时间序列预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.文件结构3.Excel数据4.分块代码4.1 arithXover.m4.2 delta.m4.3 ga.m4.4 gabpEval.m4.5 initializega.m4.6 maxGenTerm.m4.7 nonUnifMutation.m4.8 normGeomSel…

【模型压缩】 LPPN论文阅读笔记

LPPN论文阅读笔记 LPPN: A Lightweight Network for Fast Phase Picking 背景 深度学习模型的问题在于计算复杂度较高&#xff0c;在实际数据处理中需要面临较高的处理代价&#xff0c;且需要专用的加速处理设备&#xff0c;如GPU。随着数据累积&#xff0c;迫切需要设计一种…

IDE/mingw下动态库(.dll和.a文件)的生成和部署使用(对比MSVC下.dll和.lib)

文章目录 概述问题的产生基于mingw的DLL动态库基于mingw的EXE可执行程序Makefile文件中使用Qt库的\*.a文件mingw下的*.a 文件 和 *.dll 到底谁起作用小插曲 mingw 生成的 \*.a文件到底是什么为啥mingw的dll可用以编译链接过程转换为lib引导文件 概述 本文介绍了 QtCreator mi…

17 界面布局--登录界面

要点&#xff1a; 利用widgets做布局&#xff1a;水平&#xff0c;垂直&#xff0c;栅格 利用弹簧设置收缩 widget宽高比实际控件大很多&#xff1a;设置Fixed 如果需要去除其余边框间隙可以设置layout 将最小尺寸和最大尺寸设置为固定即为固定尺寸 设置窗口标题&#xff1a;wi…

基于DeepFace模型设计的人脸识别软件

完整资料进入【数字空间】查看——baidu搜索"writebug" 人脸识别软件(无外部API) V2.0 基于DeepFace模型设计的人脸识别软件 V1.0 基于PCA模型设计的人脸识别软件 V2.0 更新时间&#xff1a;2018-08-15 在观看了吴恩达老师的“深度学习课程”&#xff0c;了解了深…

关于新手学习Ubuntu使用vim,如何使用c/cpp的编译器以及如何使用makefile的详细记录

ubuntu下 首先如何编辑 1.启动vim编辑器 打开终端&#xff0c;输入vim&#xff0c;按回车键。 vim gcc.c 2.进入编辑模式 输入i ,进入插入模式。就可以修改文件内容了。 按“ESC”退出编辑模式。 3.退出 Shift键 “:”&#xff0c;切换到命令模式。 输入“q”后回车&…

基于OpenCV的红绿灯识别

基于OpenCV的红绿灯识别 技术背景 为了实现轻舟航天机器人实现红绿灯的识别&#xff0c;决定采用传统算法OpenCV视觉技术。 技术介绍 航天机器人的红绿灯识别主要基于传统计算机视觉技术&#xff0c;利用OpenCV算法对视频流进行处理&#xff0c;以获取红绿灯的状态信息。具…

【Linux】Tcp服务器的三种与客户端通信方法及守护进程化

全是干货~ 文章目录 前言一、多进程版二、多线程版三、线程池版四、Tcp服务器日志的改进五、将Tcp服务器守护进程化总结 前言 在上一篇文章中&#xff0c;我们实现了Tcp服务器&#xff0c;但是为了演示多进程和多线程的效果&#xff0c;我们将服务器与客户通通信写成了一下死循…

【Linux】 由“进程”过渡到“线程” -- 什么是线程(thread)?

知识引入初识线程1.什么叫做进程&#xff1f;2.什么叫做线程&#xff1f;3.如何看待我们之前学习的进程&#xff1f; 理解线程创建线程函数调用1.线程一旦被创建&#xff0c;几乎所有资源都是被线程所共享的2.与进程之间切换相比&#xff0c;线程的切换 初识线程总结&#xff1…

JWT 的使用

一、简介 JWT将用户的一些信息存储在客户端&#xff0c;访问后台时会带着JWT&#xff0c;服务器要对这个JWT进行检验。 由于signKey是存放在服务器端的&#xff0c;所以比较安全只要JWT被篡改就会立刻发现。 JWT认证的优势 1.简洁&#xff1a;JWT Token数据量小&#xff0c;传…

WebRTC带宽评估 -- Transport-wide Congestion Control

简述&#xff1a;在RTP包中增加transport-wide-cc扩展头&#xff0c;放置传输层面的包序号。视频接收端记录RTP包的接收时间&#xff0c;并通过RTCP Feedback消息反馈到视频发送端&#xff0c;发送端结合缓存的RTP包发送时间&#xff0c;基于丢包和延迟估算当前带宽&#xff0c…

zabbix 企业级监控 (3)Zabbix-server监控mysql及httpd服务

目录 web界面设置 server.zabbix.com 服务器操作 编辑 chk_mysql.sh脚本 查看web效果 web界面设置 1. 2. 3. 4. 5. 6. 7. 8. server.zabbix.com 服务器操作 [rootserver ~]# cd /usr/local/zabbix/etc/ [rootserver etc]# vim zabbix_agentd.conf UnsafeUserParameters1 Us…

Java当中的栈

栈的理解 栈&#xff08;Stack&#xff09;是一种受限的线性数据结构&#xff0c;所谓受限是指栈只暴露栈顶和栈底的操作&#xff0c;其底层是由数组实现的。栈的特性是先进后出。 常用方法 注意上面的peek()方法和pop()方法的区别&#xff01; 实例 import java.util.Stack…