FPGA_学习_13_方差计算小模块

测距器件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.mfbz.cn/a/45582.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

桥梁安全生命周期监测解决方案

一、方案背景 建筑安全是人们生产、经营、居住等经济生活和人身安全的基本保证&#xff0c;目前我国越来越多的建筑物逐 步接近或者已经达到了使用年限&#xff0c;使得建筑物不断出现各种安全隐患&#xff0c;对居民的人身安全和财产安全产 生不利影响&#xff0c;因此房…

gitee 配置ssh 公钥(私钥)

步骤1&#xff1a;添加/生成SSH公钥&#xff0c;码云提供了基于SSH协议的Git服务&#xff0c;在使用SSH协议访问项目仓库之前&#xff0c;需要先配置好账户/项目的SSH公钥。 绑定账户邮箱&#xff1a; git config --global user.name "Your Name" git config --glob…

看了2023年的一线互联网公司时薪排行榜!值得思考

前言 根据最近针对国内的一线互联网企业做的调研&#xff0c;汇总了他们的平均时薪水平&#xff0c;最终出了一个排行榜&#xff01; 首先我们来看下&#xff0c;排行榜分哪几个Level&#xff0c;分别为初级、中级、高级、资深、专家/架构这五个&#xff0c;主要根据工程师的…

opencv对相机进行畸变矫正,及矫正前后的坐标对应

文章目录 1.背景2.需求分析3.解决方案3.1.镜头畸变矫正3.2.知道矫正后的画面坐标&#xff08;x&#xff0c;y&#xff09;&#xff0c;求其在原画面的坐标&#xff08;x&#xff0c;y&#xff09;3.2.知道原画面坐标&#xff08;x1&#xff0c;y1&#xff09;&#xff0c;求其在…

fastadmin框架重定向

由于&#xff0c;我们一打开fastadmin框架就进入到前端页面很麻烦&#xff0c;下面这种方法可以解决这个问题。 首先我们找到这个路径 找到重定向&#xff0c; application》index》controller》index 原本文件是这个样子&#xff1a; <?phpnamespace app\index\controll…

【ArcGIS Pro二次开发】(53):村规制表、制图【福建省】

这篇算是村规入库的一个延续。 村庄规划中有一些图纸是需要严格按照规范制图&#xff0c;或形成一定规范格式的。 这些图纸的制作基本算是机械式的工作&#xff0c;可以用工具来代替人工。 一、要实现的功能 如上图所示&#xff0c;在【村庄规划】组&#xff0c;新增了两个工…

配置代理——解决跨域问题(详解)

之前写项目的时候总会遇到配置代理的问题&#xff0c;可是配置了之后有时有用&#xff0c;有时就没有用&#xff0c;自己之前学的也是懵懵懂懂&#xff0c;于是专门花了一个小时去了解了如何配置代理跨域&#xff0c;然后在此记录一下&#xff0c;方便自己以后查阅。 一、 常用…

pytorch实现梯度下降算法例子

如题&#xff0c;利用pytorch&#xff0c;通过代码实现机器学习中的梯度下降算法&#xff0c;求解如下方程&#xff1a; f ′ ( x , y ) x 2 20 y 2 {f}(x,y) x^2 20 y^2 f′(x,y)x220y2 的最小值。 Latex语法参考&#xff1a;https://blog.csdn.net/ViatorSun/article/d…

推荐系统(十)用户行为序列建模-Pooling 路线

对推荐系统而言&#xff0c;准确捕捉用户兴趣是其面临的核心命题。不管是样本、特征还是模型结构等方面的优化&#xff0c;本质上做的事情都是在提高推荐系统对用户兴趣的捕捉能力&#xff0c;因此如何提高这种能力&#xff0c;对推荐效果的提升有重要作用&#xff0c;也是算法…

tp6 实现excel 导入功能

在项目根目录安装 composer require phpoffice/phpspreadsheet 我们看一下郊果图&#xff0c;如下 点击导入excel表格数据 出现弹窗选择文件&#xff0c;控制台打开输出文档内容 前端layui代码 <form id"uploadForm" class"form-horizontal" encty…

7.25 Qt

制作一个登陆界面 login.pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on …

如何高效地查询IP归属地

高效识别IP归属地是网络安全领域中的一项重要工作。准确地识别IP的归属地不仅可以帮助网络管理员追踪和定位潜在的网络攻击者&#xff0c;还可以用于网络流量分析、地理定位服务等方面。 以下将介绍几种高效识别IP归属地的方法。 使用IP归属地数据库 IP归属地数据库是一种存储…

Clion开发STM32之W5500系列(综合实验)

说明 此为w5500模块的综合实验测试模块,包含dhcp、dns、ntp以上三个模块的驱动参考之前的文章&#xff0c;本篇不做说明.使用的开发芯片 stm32f103vet6系列,外设接口使用的spi2 实验内容: 通过dhcp动态获取ip,通过dns解析NTP服务域名的ip通过NTP服务ip获取时间 w5500配置驱…

国密SSL优势及应用场景

国密SSL的优势主要有以下几点&#xff1a; 更高的安全性&#xff1a;国密算法采用的是国家密码管理局推荐的算法&#xff0c;相对于传统的SSL协议更加安全。 更好的性能&#xff1a;国密算法是国家密码管理局推荐的算法&#xff0c;其加密效率与密钥长度相比传统算法更高。 更…

微服务架构演变

微服务架构筑基 软件架构演进 软件架构的发展经历了从单体结构、垂直架构、SOA架构到微服务架构的过程. 什么是微服务&#xff1f;&#xff1f; Spring Cloud Netfilx Spring Cloud Alibaba service Mesh 架构的发展&#xff1a;基于某一种因素 技术是服务于业务的 业务又是…

Vue mixin 混入

可以复用的组件&#xff0c;我们一般会抽离&#xff0c;写成公共的模块。 可以复用的方法&#xff0c;我们一般会抽离&#xff0c;写成公共的函数。 那么 在 Vue 中&#xff0c;如果 某几个组件实例 VueComponent 中、或者 整个 Vue 项目中 都存在相同的配置&#xff0c;那就…

数据结构(二)

目录 Trie树 并查集 堆 Trie树 作用:用来高效地存储和查找字符串集合的数据结构 基本形式: 模板代码如下: #include<iostream> using namespace std;const int N 100010;//idx代表当前用到哪个下标 //既是根节点&#xff0c;又是空节点 //cnt存储的是以当前点结尾的…

Mac 系统钥匙串证书不受信任

Mac 系统钥匙串证书不受信任 解决办法 通过尝试安装 Apple PKI 的 Worldwide Developer Relations - G4 (Expiring 12/10/2030 00:00:00 UTC) 解决该异常问题 以上便是此次分享的全部内容&#xff0c;希望能对大家有所帮助!

移动端商品详情页设计

效果图 代码如下 页面设计 <div class"container"><!--商品详情 start--><van-image class"goods-item-image" :src"goods.goodsHeadImg"></van-image><div class"goods-price">&#xffe5;<span&…

【VUE】npm打包报错 Syntax Error: Error: Cannot find module ‘imagemin-gifsicle‘

一. Syntax Error: Error: Cannot find module ‘imagemin-gifsicle’ npm run build 报错&#xff0c;报错如下 原因 这个错误消息显示缺少了 imagemin-gifsicle 模块&#xff0c;而它是 image-webpack-loader 的依赖项&#xff0c;导致构建失败。解决 &#xff08;1&#xf…