精华内容
下载资源
问答
  • 测量某个函数或某段代码的cycles消耗是经常要做的 事情,常用的profiling和clock()一般在simulation下使用,真正到了板子上做emulation时,因为要考虑到数据和被测 code在板子上的存放位置和读取时间,这种方法测...

    利用TSCL和TSCH来计算时钟周期,这两天看了一下如何他们

    DSP开发,测量某个函数或某段代码的cycles消耗是经常要做的 事情,常用的profiling和clock()一般在simulation下使用,真正到了板子上做emulation时,因为要考虑到数据和被测 code在板子上的存放位置和读取时间,用这种方法测结果就不那么可靠了。其实在c64x+ core上有两个计数寄存器TSCL/TSCH,它们与CPU同频,共同表示一个64-bit数,CPU运行一个cycle,该寄存器就加1,因此可以用 它们来准确的测量cpu在某个执行段中消耗的cycles。一般我们只会用到TSCL这个寄存器,594MHz下,32-bit可以测试到7s,而 TSCH是高32位,除非测试整个工程,一般用不到它。

    使用方法:长时间宽范围时钟测定

    unsigned long long t1,t2;

    t1=_itoll(TSCH,TSCL);

    code_wait_test;

    t2=_itoll(TSCH,TSCL);

    printf(“#cycle=%d”,t2-t1);

    短时间(7秒)窄范围时钟测定:

    T1=TSCL;

    …process code …

    T2=TSCL;

    Printf(“#cycle=%d”,t2-t1);

    方法二,也可以采用biosAPI方式

    LgUns time1=CLK_gethtime();

    …process code …

    LgUns time2=CLK_gethtime();

    Cpucycles=(time2-time1)*CLK_cpucyclePerhtime;

    Prinf(“#cycle=%d”,Cpucycle);

    关于测量CPU时钟周期中我们用的变量类型和函数我们都可以在C6000DSP/bios的API文档和BIOS提供的源码找到,可以详细去查阅。

    #include "c6x.h"


    void YourFunc (void)
    {
    unsigned long long start;
    unsigned long long end;

    start = _itoll (TSCH, TSCL);

    /* put your code here */

    end = _itoll (TSCH, TSCL);

    printf ("Hi mate, I just wasted %d DSP-cycles in your punny code.
    Optimize me!\n", end-start);
    }

    inline long long read_time(void)
    {
    extern cregister volatile unsigned int TSCL;
    extern cregister volatile unsigned int TSCH;
    long long l = (TSCH << 32) | TSCL;
    return l;
    }
    在使用TSCL和TSCH时首先需要向TSCL中写入数据,使能TSC寄存器。
    在DSP手册中说明:
    The counter is enabled by writing to TSCL. The value written is ignored.

    展开全文
  • Chisel实践——利用CORDIC算法计算对数函数一、介绍在本专栏之前的文章中: Chisel快速搭建FFT流水线电路 Chisel实践 —— 短时傅里叶变换模块的实现与测试 已经介绍到了如何使用Chisel开发FFT运算模块和STFT模块,...

    Chisel实践——利用CORDIC算法计算对数函数

    一、介绍

    在本专栏之前的文章中:
    用Chisel快速搭建FFT流水线电路
    Chisel实践 —— 短时傅里叶变换模块的实现与测试
    已经介绍到了如何使用Chisel开发FFT运算模块和STFT模块,此篇文章将详细介绍如何使用Chisel进行对数运算模块的开发。
    如何使用硬件语言实现对数运算,在兼顾精度的同时又要节约面积,这是极其困难的一件事。目前工业界比较流行的方法有查表法、泰勒展开以及线性近似法等,这些算法各有优缺点:
    · 查表法:实现简单,但是所需要的存储单元随着精度的增加或输入值范围的增大而成指数增加,在计算高精度,多位宽的数据时,查表法是显然不合适的;
    · 泰勒公式展开法:需要乘法器,面积大且不易实现;
    · 线性近似法:精度有限,且需要误差校正电路,仍要耗费大量的面积,实现上较为困难。
    本篇文章将介绍采用CORDIC(Coordinate Rotation Digital Computer)算法 , 即标旋转数字计算方法进行对数运算,该算法主要通过基本的加和移位运算代替乘法运算, 用矢量的旋转和定向间接计算三角函数、双曲线、指数、对数等函数。采用CORDIC算法来实现这类函数时,无需使用乘法器,它只需要一个最小的查找表(LUT),利用简单的移位和相加运算,即可产生高精度的结果,尤其适合FPGA的实现。 本文将简要阐述CORDIC算法,以及如何使用Chisel语言实现基于CORDIC算法的对数函数实现。

    二、算法说明

    CORDIC算法是基于移位加法和矢量旋转技术进行计算的。它主要有旋转模式(Rotation Mode)向量模式(Vectoring Mode),两种模式又可以应用在圆坐标系、线性坐标系以及双曲坐标系。两种模式分别应用在三个坐标系,进行迭代运算,可以分别演算出8种运算。主要如下表总结(主要是各个模式应用在不同坐标系可以实现的函数说明)。

    28e8460a3c49defad21422b2a25c788d.png

    2.1 旋转模式

    如图所示,假设在一个圆周系统中,若是想求得30°的cos值与sin值,那需要得到30°角在单位圆上交点的x轴坐标与y轴坐标。
    首先,赋予初值x0 = 1,y0 = 0,z0 = θ(此个例子中θ为30,zi执行加或者减操作,使得z的最终值为0 ,该条件由di决定)
    为了得到30°角在单位园上的x轴坐标与y轴坐标,我们先将初始线逆时针旋转45度,得到相应的x1、y1、z1值。其次比较得出45°角比30°角大,因此要进行第二次旋转,进行顺时针旋转26.6°角,得到x2、y2、z2值。又发现新得到的角度比30°角小,再次旋转。就依靠这种模式进行N次迭代,迭代次数越大,那么实现的精度就会越高,以此类推。z的迭代过程是将z收敛于零的过程,也正是将θ分解为一系列θi的过程, 故zi可认为是第i次旋转剩余的角度。
    此过程具体的数学推导,有兴趣的读者可以参考这篇文章。

    ee1af176e48d0ad3900da45e9d56a2e9.png

    2.2 向量模式

    与旋转模式相比,向量模式下的目的是使y趋向于 0。 为了达到这一目标, 每次迭代通过y值的正负性确定旋转方向, 最终使初始向量旋转至 x轴的正半轴, 这一过程也使得每次微旋转的旋转角度累加和存储在变量 z 中。

    如图当设置初始值y0 = 2 ,x0 = 1的时候,经过n(n–>∞)次旋转,开始的点靠近x轴。因此,当迭代结束之后,P将近似接近x轴的正半轴,此时P点纵坐标yn = 0,在这个过程中可知旋转了θ,即zn = z0 +θ = z0+arctan(y0/x0) (z0为初始化角度)。

    acb3f9193888cddfa22ee9d9a98be272.png

    2.3 双曲系统

    与圆周系统和线性系统有所不同, 双曲系统的迭代较为复杂。但是利用双曲系统可求取一系列超越函数。例如 在旋转模式下, 可求取双曲正弦函数和双曲余弦函数, 进而可求取 e 指 数,在向量模式下, CORDIC 算法可实现反双曲正切函数的计算。当我们要实现对数函数求解时,可以从如下公式出发:

    c7f65f05d057389429157da955bc7525.png

    将求解ln的值转化为求解arctanh的值。在双曲模式下的算法迭代涉及到发散收敛问题,且从N为4开始,每当3k+1的项需要重复迭代,即1,2,3,4,4,5,6,7.....13,13.....。与此同时仅进行正数迭代,那么当输入值大于9的时候就会出现严重发散的现象,这也不是我们所期望的。因此需要添加负数次的迭代,扩大定义域。在此论文中有详细说明。

    三、算法过程:

    3.1 逻辑说明

    · 取x0 = r + 1, y0 = r-1, z0 = 0,其中r为我们想求得的值。当y经过多次迭代逼近0的时候,zn的输出值即为对数函数值的一半。本次研究取迭代次数为16次,n=-5为起始迭代数,事先通过计算求解出相应的arctanh值,作为常量供迭代方程加减。需要注意的地方是,如果输入的r值太小,可能会在迭代过程中因为移位操作导致值的丢失,建议将x值与y值同时放大, 结果并不会发生改变,但可以使得迭代更多次,保证精度。当然预先做个数值范围判定移位更佳,为了避免精度损失,本次实验研究将数值放大

    用以计算。下图为迭代表格,读者在编写代码时,可用于事先输入到ROM中用于调取。

    89fdd58d7abccd1595e7791d91b37312.png

    · 为了抑制迭代过程发散的情况, 我们选取负数次处开始迭代,则有如下迭代公式:

    73f35c6195211f4e3acf5ff5432a843a.png

    注意事项:使用Verilog编写此份算法,若是定义signed要注意算术移位的问题,建议使用拼接截位操作。

    3.2代码实现

    import chisel3._
    import chisel3.experimental._
    
    class Mylog extends Module {
      val io = IO(new Bundle {
        val in = Input(SInt(32.W))
        val out = Output(SInt(32.W))
      })

    在上述代码中,自定义类Mylog继承自Chisel的Bundle类,输入、输出采用32位的符号数。若是读者想要进行更高精度的迭代计算,需要增加位宽以及迭代次数。但是会极大的增加电路的面积,因此视实际情况进行取舍。

    val x0 = io.in + 65536.S(32.W)
      val y0 = io.in - 65536.S(32.W)
      val z0 = 0.S(32.W)
      val taps_x = Seq(x0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
      val taps_y = Seq(y0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
      val taps_z = Seq(z0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
    
      io.out := taps_z(16)

    我们先将x0、y0 、z0进行初始化,用于后面的迭代计算,通过Seq函数搭建各个位置的节点,这是类似于搭建移位寄存器,但是各个节点间的连接关系我们仍然可以自行定义,这样有利于不同计算间的输入定义,是编写Chisel代码很有效的一种技巧。最后将输出连接z16节点的输出,得到解值。

    val taps_xy = taps_x.zip(taps_y).zip(taps_z)
      taps_xy.zip(taps_xy.tail).zipWithIndex.foreach { case((((x0,y0),z0),((x1,y1),z1)),index) =>
        when (y0(31) === 1.U) { 
          if (index <= 5) {
            x1 := x0 + y0 - (y0 >> (7 - index))
            y1 := y0 + x0 - (x0 >> (7 - index))
            z1 := z0 - rot(index).S
          }
          else if (index <= 9) {
            x1 := x0  + (y0 >> (index - 5))
            y1 := y0  + (x0 >> (index - 5))
            z1 := z0 - rot(index).S
          }
          else {
            x1 := x0  + (y0 >> (index - 6))
            y1 := y0  + (x0 >> (index - 6))
            z1 := z0 - rot(index).S
          }
        }
        .......

    笔者先将前15位节点与后15位节点捆绑在一个元组中,类似于(x0,y0,x1),这样可以很方便的将x1的输入与x0,y0联系起来。然后再包裹一个zipWithIndex函数用于标记元组位置,可以方便迭代位移操作。最后使用foreach函数进行移位连接赋值操作,即可快速搭建迭代电路逻辑。下图为迭代设计实现结构图,描述电路工作状态。

    01e3d49c9898b5b095121174961d4f87.png

    四、模块测试与说明

    4.1 基于Chisel实现16次迭代32位输入CORDIC模块测试

    首先运行测试脚本,使用scansion对生成波形进行测试。将输入测试值放大

    倍,同时在模块输入端口连续发送测试数据,经过16个周期后输出端口得到结果,此处在输出端口处添加FIFO,可以有效处理数据延迟问题。

    输出端口得到的数据是经过放大处理后的值,将其输出值除以

    为最终所求值。

    图示为部分波形截图,io_out输出为ln(3)、ln(4)...ln(16)的解值。

    bbb88c4c17b3b2e7e0ff2f58fdb7982e.png

    下图为整体测试运行波形图,将输出波形与精确值进行对比分析,误差在0.5%上下浮动。

    9ca48c446856125daa5f4355799ac15f.png

    4.2 Berkeley dsptools模块测试

    在此连接提供了berkeley研发的dsptools库。 dsptools库是一个可以和任何Chisel工程混合使用的库。该库提供了包括流水线延迟检查,DSP设计和验证等功能,以及更多针对不同数值类型的验证平台。

    要说明的是,dsptools中函数部分继承于BlackBox,通过BlackBox导入Verilog模块的端口列表给Chisel模块使用。其中,ln函数就是通过BlackBox导入,同时其调用的Verilog代码使用了scala系统函数,因此实际上该函数仅作为验证,其代码不可综合的,读者需引起注意。

    在Chisel中写dsptools的测试脚本时,可以直接输入双精度浮点数,利用FixedPoint.fromDouble(value , DataWidth.W, BinaryPoint.BP) 将其转为定点数进行输入。输出可以利用波形显示工具转为 float 64 类型观察测试。

    下图为berkeley dsptools库中调取ln函数测试波形图,截取ln(3)至ln(16)输入输出波形图,用于对比分析。

    aa743a7dbe52500938a4b23864415015.png

    CORDIC算法实现的ln(6)的输出为118260,将其除以

    的值为1.80450,而通过dsptools计算的ln(6)值为1.79176,差值为0.01274。再以相同的方法测试多组数据,差值均在0.5%上下浮动。

    4.3 与Vivado CORDIC IP对比测试

    Vivado提供的CORDIC IP 6.0,同样可以完成三角函数、双曲线、指数、对数等函数的计算。
    Vivado CORDIC IP核有两种架构配置:并行架构(Parallel),具有单周期多数据的吞吐量但是耗费较大面积。字串行架构(Word Serial) ,具有多周期的吞吐量但是面积消耗小。本次实验选择字串行架构,配置32位有符号定点二进制数作为输入、输出,选择16次迭代次数。
    (特别要注意的是,输入X_IN以及输出Y_IN被限制在如下表格给出的范围内,超出这些范围的输入会产生不可预测的输出。 此外,|Y_IN|必须小于或者等于(4/5*X_IN),否则CORDIC算法输出会有不收敛的情况。)

    03a5ec54bfa60e5f2893f8fed45bb2c8.png

    X_IN以及Y_IN输入为宽度2位的定点二进制补码,PHASE_OUT输出为宽度3位定点二进制补码。举个例子:

    若求ln(K),其中K = 0.625,则 K+1 = 1.625 ,K - 1 = -0.375。

    X_IN = K + 1 = '01,10 1000 0000 0000 0000 0000 0000 0000 ' = 32'h6800 0000
    
    Y_IN = K - 1  =  '11,10 1000 0000 0000 0000 0000 0000 0000 ' = 32'hE800 0000  (负数已经做过补码处理)
    
    PHASE_OUT = '111,0 1101 0110 0011 1110 0011 0110 0010 ' = 32'hED63E362

    另外要说明的是,若是求解超出范围的整数值,要先实现一个预处理模块,将K转换为P*2N (P ∈[0.5 , 1) ,N为偶数 ),倘若K值转换出来的等式中N为奇数,则将P值除以2使得N = N + 1,此时P∈[0.25 , 0.5) 。

    举个例子: 计算ln(160),则K = 160,可以换算为0.625 * 28,即P = 0.625,N = 8,此时ln(160) = ln(0.625) + 8 * ln(2)。 此时需要:

    1. 预先存储ln(2) 的值
    2. 使用Vivado CORDIC IP核计算ln(0.625)
    3. 通过乘法与加法得到最终结果

    4.3.1 精度对比测试
    使用Vivado CORDIC IP 6.0搭建测试模块,采用16次迭代32位输入,IP核将会产生20个周期的延迟,将随机值(此处取5个随机点作为展示)与Chisel实现的16次迭代32位输入CORDIC模块比较(产生16个周期的延迟)。图中横坐标表示测试的数值,纵坐标表示不同运算结果误差绝对值。

    59a89a538c7106f52f71990713532ded.png

    可以发现:32位输入20周期延迟的Vivado CORDIC IP 6.0,在精确度上是远优于32位输入16周期延迟基于Chisel实现的CORDIC模块。
    通过实验研究,我们发现Vivado提供的IP输入值限定最大值为1.00,原因是通过增加定点小数位(30位)来提高精度,而我们设计的Chisel CORDIC模块输入定点值格式为32位宽,16位小数,动态范围更大,但是计算精度更低。 为此我们进行代码的改进,基于Chisel实现32位输入20周期延迟的CORDIC模块,将模块的输入值范围限定为30位小数的32位定点数,重新对其误差以及资源进行了分析。注:下文出现的VIVADO IP表示30位小数的32位定点数输入,20周期延迟的CORDIC IP 6.0模块; Chisel-16表示输入为16位小数的32位定点数,16周期延迟Chisel实现的CORDIC模块; Chisel-20表示输入为30位小数的32位定点数,20周期延迟Chisel实现的CORDIC模块。

    我们一共测试了92组数据(数据由Python随机函数产生),在同样的延迟周期和同样的定点范围下得到和Vivado IP的误差对比(下图表示VIVADOC IP 以及Chisel-20 输出值与实际的误差):

    923d7bf1d4226a6d65c6756a355cff69.png

    下述为各个模块的均方误差值

    MSE of VIVADO IP:4.177e-07
    MSE of chisel-16:4.004e-05
    MSE of chisel-20:2.872e-08

    此时的Chisel-20模块误差已经和Vivado CORDIC IP的误差为一个量级。从均方误差方面分析,Chisel-20的精确度是最具有优势的。

    4.3.2 资源对比测试

    通过Vivado进行FPGA评估,我们选定FPGA元件为v7xc7vx485tffg1761-2,工作频率为200MHz,通过综合工具和实现工具,对三种不同IP进行资源评估和功耗分析。

    三种方式的资源消耗关键数值对比如下所示:

    9a0823ecbb7ad161ef031df6284ad4da.png

    3f00f6949ad67f7e68d01373fbff0fba.png

    对比分析得知,相对于Chisel-16、Chisel-20模块,Vivado IP的LUT、FF资源消耗少,LUTRAM、IO资源占用高。
    分析Chisel-16和Chisel-20模块可知,随着Chisel-20模块精度提升,其LUT、FF资源消耗也相应增加。
    总的来说基于Chisel设计的CORDIC模块需要更多LUT和FIFO资源,更少的IO资源

    4.3.3 总结分析

    通过数据对比分析,在同样的延迟周期和同样的定点范围条件下,我们设计的CORDIC模块和Vivado提供的IP核区别如下:

    Chisel-16 CORDICVivado CORDIC IPChisel-20 CORDIC
    延迟周期1620 (字串行)20
    是否需要预处理
    求值范围ln(K)K∈(0 , 32768]K∈(0 , 1]K∈(0 , 1]
    总功耗(200MHz)0.531W0.381W0.565W
    精度
    WNS2.408ns1.781ns1.191ns
    WHS0.054ns0.145ns0.093ns
    WPWS1.100ns1.100ns1.100ns

    总的来说三种方式设计的CORDIC模块在200MHz的工作频率下,S/H时序都满足要求,总功耗为Chisel-20 CORDIC模块最大, Vivado CORDIC IP core 与 Chisel-20 CORDIC精度相近。

    4.3.4 注意事项

    进行FPGA评估需要通过修改Vivado的tcl脚本fft.tcl中的参数,具体设置以及流程可以看此文档中的说明,主要修改tcl中的路径以及top文件名。同时要注意的是,引用Verilog文件中的顶层的模块时,需要添加时钟模块来驱动clock,主要代码参考如下:

    wire clock;
      clk_wiz_0 clk_wiz_0_inst0( 
        .clk_out1(clock),
          .clk_in1_p(clk_in1_p),
          .clk_in1_n(clk_in1_n)
      );
    

    五、结语

    本文简单介绍了CORDIC算法的应用实现,通过数十行Chisel代码实现了对数函数的电路设计。同时,笔者尝试编写了一份实现相同功能的Verilog代码,发现Chisel在代码量上以及效率上是具有极大优势的,使用Chisel设计结构重复性硬件大大简化了电路的设计过程。

    六、参考文献

    -[1]Mopuri, S., Acharyya, A. Configurable Rotation Matrix of Hyperbolic CORDIC for Any Logarithm and Its Inverse computation.
    -[2]CORDIC v6.0 Document

    展开全文
  • 展开全部python使用dlib进行人脸检测与人脸关键点标记Dlib简介:首先给大家介绍一下DlibDlib是一个跨平32313133353236313431303231363533e4b893e5b19e31333363393662台的C++公共库...,提供测试以及大量工具等等优点...

    展开全部

    python使用dlib进行人脸检测与人脸关键点标记

    Dlib简介:

    首先给大家介绍一下Dlib

    Dlib是一个跨平32313133353236313431303231363533e4b893e5b19e31333363393662台的C++公共库,除了线程支持,网络支持,提供测试以及大量工具等等优点,Dlib还是一个强大的机器学习的C++库,包含了许多机器学习常用的算法。同时支持大量的数值算法如矩阵、大整数、随机数运算等等。

    Dlib同时还包含了大量的图形模型算法。

    最重要的是Dlib的文档和例子都非常详细。

    Dlib主页:

    这篇博客所述的人脸标记的算法也是来自Dlib库,Dlib实现了One Millisecond Face Alignment with an Ensemble of Regression Trees中的算法

    这篇论文非常出名,在谷歌上打上One Millisecond就会自动补全,是CVPR 2014(国际计算机视觉与模式识别会议)上的一篇国际顶级水平的论文。毫秒级别就可以实现相当准确的人脸标记,包括一些半侧脸,脸很不清楚的情况,论文本身的算法十分复杂,感兴趣的同学可以下载看看。

    Dlib实现了这篇最新论文的算法,所以Dlib的人脸标记算法是十分先进的,而且Dlib自带的人脸检测库也很准确,我们项目受到硬件所限,摄像头拍摄到的画面比较模糊,而在这种情况下之前尝试了几个人脸库,识别率都非常的低,而Dlib的效果简直出乎意料。

    相对于C++我还是比较喜欢使用python,同时Dlib也是支持python的,只是在配置的时候碰了不少钉子,网上大部分的Dlib资料都是针对于C++的,我好不容易才配置好了python的dlib,这里分享给大家:

    Dlib for python 配置:

    因为是用python去开发计算机视觉方面的东西,python的这些科学计算库是必不可少的,这里我把常用的科学计算库的安装也涵盖在内了,已经安装过这些库的同学就可以忽略了。

    我的环境是Ubuntu14.04:

    大家都知道Ubuntu是自带python2.7的,而且很多Ubuntu系统软件都是基于python2.7的,有一次我系统的python版本乱了,我脑残的想把python2.7卸载了重装,然后……好像是提醒我要卸载几千个软件来着,没看好直接回车了,等我反应过来Ctrl + C 的时候系统已经没了一半了…

    所以我发现想要搞崩系统,这句话比rm -rf 还给力…

    sudo apt-get remove python2.71

    首先安装两个python第三方库的下载安装工具,ubuntu14.04好像是预装了easy_install

    以下过程都是在终端中进行:

    1.安装pip

    sudo apt-get install python-pip1

    2.安装easy-install

    sudo apt-get install python-setuptools1

    3.测试一下easy_install

    有时候系统环境复杂了,安装的时候会安装到别的python版本上,这就麻烦了,所以还是谨慎一点测试一下,这里安装一个我之前在博客中提到的可以模拟浏览器的第三方python库测试一下。

    sudo easy_install Mechanize1

    4.测试安装是否成功

    在终端输入python进入python shell

    python1

    进入python shell后import一下刚安装的mechanize

    >>>import mechanize1

    没有报错,就是安装成功了,如果说没有找到,那可能就是安装到别的python版本的路径了。

    同时也测试一下PIL这个基础库

    >>>import PIL1

    没有报错的话,说明PIL已经被预装过了

    5.安装numpy

    接下来安装numpy

    首先需要安装python-dev才可以编译之后的扩展库

    sudo apt-get install python-dev1

    之后就可以用easy-install 安装numpy了

    sudo easy_install numpy1

    这里有时候用easy-install 安装numpy下载的时候会卡住,那就只能用 apt-get 来安装了:

    sudo apt-get install numpy1

    不推荐这样安装的原因就是系统环境或者说python版本多了之后,直接apt-get安装numpy很有可能不知道装到哪个版本去了,然后就很麻烦了,我有好几次遇到这个问题,不知道是运气问题还是什么,所以风险还是很大的,所以还是尽量用easy-install来安装。

    同样import numpy 进行测试

    python

    >>>import numpy1234

    没有报错的话就是成功了

    下面的安装过程同理,我就从简写了,大家自己每步别忘了测试一下

    6.安装scipy

    sudo apt-get install python-scipy1

    7.安装matplotlib

    sudo apt-get install python-matplotlib1

    8.安装dlib

    我当时安装dlib的过程简直太艰辛,网上各种说不知道怎么配,配不好,我基本把stackoverflow上的方法试了个遍,才最终成功编译出来并且导入,不过听说18.18更新之后有了setup.py,那真是极好的,18.18我没有亲自配过也不能乱说,这里给大家分享我配置18.17的过程吧:

    1.首先必须安装libboost,不然是不能使用.so库的

    sudo apt-get install libboost-python-dev cmake1

    2.到Dlib的官网上下载dlib,会下载下来一个压缩包,里面有C++版的dlib库以及例子文档,Python dlib库的代码例子等等

    我使用的版本是dlib-18.17,大家也可以在我这里下载:

    之后进入python_examples下使用bat文件进行编译,编译需要先安装libboost-python-dev和cmake

    cd to dlib-18.17/python_examples

    ./compile_dlib_python_module.bat 123

    之后会得到一个dlib.so,复制到dist-packages目录下即可使用

    这里大家也可以直接用我编译好的.so库,但是也必须安装libboost才可以,不然python是不能调用so库的,下载地址:

    将.so复制到dist-packages目录下

    sudo cp dlib.so /usr/local/lib/python2.7/dist-packages/1

    最新的dlib18.18好像就没有这个bat文件了,取而代之的是一个setup文件,那么安装起来应该就没有这么麻烦了,大家可以去直接安装18.18,也可以直接下载复制我的.so库,这两种方法应该都不麻烦~

    有时候还会需要下面这两个库,建议大家一并安装一下

    9.安装skimage

    sudo apt-get install python-skimage1

    10.安装imtools

    sudo easy_install imtools1

    Dlib face landmarks Demo

    环境配置结束之后,我们首先看一下dlib提供的示例程序

    1.人脸检测

    dlib-18.17/python_examples/face_detector.py 源程序:

    #!/usr/bin/python# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt##   This example program shows how to find frontal human faces in an image.  In#   particular, it shows how you can take a list of images from the command#   line and display each on the screen with red boxes overlaid on each human#   face.##   The examples/faces folder contains some jpg images of people.  You can run#   this program on them and see the detections by executing the#   following command:#       ./face_detector.py ../examples/faces/*.jpg##   This face detector is made using the now classic Histogram of Oriented#   Gradients (HOG) feature combined with a linear classifier, an image#   pyramid, and sliding window detection scheme.  This type of object detector#   is fairly general and capable of detecting many types of semi-rigid objects#   in addition to human faces.  Therefore, if you are interested in making#   your own object detectors then read the train_object_detector.py example#   program.  ### COMPILING THE DLIB PYTHON INTERFACE#   Dlib comes with a compiled python interface for python 2.7 on MS Windows. If#   you are using another python version or operating system then you need to#   compile the dlib python interface before you can use this file.  To do this,#   run compile_dlib_python_module.bat.  This should work on any operating#   system so long as you have CMake and boost-python installed.#   On Ubuntu, this can be done easily by running the command:#       sudo apt-get install libboost-python-dev cmake##   Also note that this example requires scikit-image which can be installed#   via the command:#       pip install -U scikit-image#   Or downloaded from . import sys

    import dlib

    from skimage import io

    detector = dlib.get_frontal_face_detector()

    win = dlib.image_window()

    print("a");for f in sys.argv[1:]:

    print("a");

    print("Processing file: {}".format(f))

    img = io.imread(f)

    # The 1 in the second argument indicates that we should upsample the image

    # 1 time.  This will make everything bigger and allow us to detect more

    # faces.

    dets = detector(img, 1)

    print("Number of faces detected: {}".format(len(dets)))    for i, d in enumerate(dets):

    print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(

    i, d.left(), d.top(), d.right(), d.bottom()))

    win.clear_overlay()

    win.set_image(img)

    win.add_overlay(dets)

    dlib.hit_enter_to_continue()# Finally, if you really want to you can ask the detector to tell you the score# for each detection.  The score is bigger for more confident detections.# Also, the idx tells you which of the face sub-detectors matched.  This can be# used to broadly identify faces in different orientations.if (len(sys.argv[1:]) > 0):

    img = io.imread(sys.argv[1])

    dets, scores, idx = detector.run(img, 1)    for i, d in enumerate(dets):

    print("Detection {}, score: {}, face_type:{}".format(

    d, scores[i], idx[i]))123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081

    我把源代码精简了一下,加了一下注释: face_detector0.1.py

    # -*- coding: utf-8 -*-import sys

    import dlib

    from skimage import io#使用dlib自带的frontal_face_detector作为我们的特征提取器detector = dlib.get_frontal_face_detector()#使用dlib提供的图片窗口win = dlib.image_window()#sys.argv[]是用来获取命令行参数的,sys.argv[0]表示代码本身文件路径,所以参数从1开始向后依次获取图片路径for f in sys.argv[1:]:    #输出目前处理的图片地址

    print("Processing file: {}".format(f))    #使用skimage的io读取图片

    img = io.imread(f)    #使用detector进行人脸检测 dets为返回的结果

    dets = detector(img, 1)    #dets的元素个数即为脸的个数

    print("Number of faces detected: {}".format(len(dets)))    #使用enumerate 函数遍历序列中的元素以及它们的下标

    #下标i即为人脸序号

    #left:人脸左边距离图片左边界的距离 ;right:人脸右边距离图片左边界的距离

    #top:人脸上边距离图片上边界的距离 ;bottom:人脸下边距离图片上边界的距离

    for i, d in enumerate(dets):

    print("dets{}".format(d))

    print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}"

    .format( i, d.left(), d.top(), d.right(), d.bottom()))    #也可以获取比较全面的信息,如获取人脸与detector的匹配程度

    dets, scores, idx = detector.run(img, 1)

    for i, d in enumerate(dets):

    print("Detection {}, dets{},score: {}, face_type:{}".format( i, d, scores[i], idx[i]))

    #绘制图片(dlib的ui库可以直接绘制dets)

    win.set_image(img)

    win.add_overlay(dets)    #等待点击

    dlib.hit_enter_to_continue()1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

    分别测试了一个人脸的和多个人脸的,以下是运行结果:

    运行的时候把图片文件路径加到后面就好了

    python face_detector0.1.py ./data/3.jpg12

    一张脸的:

    两张脸的:

    这里可以看出侧脸与detector的匹配度要比正脸小的很多

    2.人脸关键点提取

    人脸检测我们使用了dlib自带的人脸检测器(detector),关键点提取需要一个特征提取器(predictor),为了构建特征提取器,预训练模型必不可少。

    除了自行进行训练外,还可以使用官方提供的一个模型。该模型可从dlib sourceforge库下载:

    arks.dat.bz2

    也可以从我的连接下载:

    这个库支持68个关键点的提取,一般来说也够用了,如果需要更多的特征点就要自己去训练了。

    dlib-18.17/python_examples/face_landmark_detection.py 源程序:

    #!/usr/bin/python# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt##   This example program shows how to find frontal human faces in an image and#   estimate their pose.  The pose takes the form of 68 landmarks.  These are#   points on the face such as the corners of the mouth, along the eyebrows, on#   the eyes, and so forth.##   This face detector is made using the classic Histogram of Oriented#   Gradients (HOG) feature combined with a linear

    展开全文
  • Chisel实践——利用CORDIC算法计算对数函数一、介绍在本专栏之前的文章中: Chisel快速搭建FFT流水线电路 Chisel实践 —— 短时傅里叶变换模块的实现与测试 已经介绍到了如何使用Chisel开发FFT运算模块和STFT模块,...

    Chisel实践——利用CORDIC算法计算对数函数

    一、介绍

    在本专栏之前的文章中:
    用Chisel快速搭建FFT流水线电路
    Chisel实践 —— 短时傅里叶变换模块的实现与测试
    已经介绍到了如何使用Chisel开发FFT运算模块和STFT模块,此篇文章将详细介绍如何使用Chisel进行对数运算模块的开发。
    如何使用硬件语言实现对数运算,在兼顾精度的同时又要节约面积,这是极其困难的一件事。目前工业界比较流行的方法有查表法、泰勒展开以及线性近似法等,这些算法各有优缺点:
    · 查表法:实现简单,但是所需要的存储单元随着精度的增加或输入值范围的增大而成指数增加,在计算高精度,多位宽的数据时,查表法是显然不合适的;
    · 泰勒公式展开法:需要乘法器,面积大且不易实现;
    · 线性近似法:精度有限,且需要误差校正电路,仍要耗费大量的面积,实现上较为困难。
    本篇文章将介绍采用CORDIC(Coordinate Rotation Digital Computer)算法 , 即标旋转数字计算方法进行对数运算,该算法主要通过基本的加和移位运算代替乘法运算, 用矢量的旋转和定向间接计算三角函数、双曲线、指数、对数等函数。采用CORDIC算法来实现这类函数时,无需使用乘法器,它只需要一个最小的查找表(LUT),利用简单的移位和相加运算,即可产生高精度的结果,尤其适合FPGA的实现。 本文将简要阐述CORDIC算法,以及如何使用Chisel语言实现基于CORDIC算法的对数函数实现。

    二、算法说明

    CORDIC算法是基于移位加法和矢量旋转技术进行计算的。它主要有旋转模式(Rotation Mode)向量模式(Vectoring Mode),两种模式又可以应用在圆坐标系、线性坐标系以及双曲坐标系。两种模式分别应用在三个坐标系,进行迭代运算,可以分别演算出8种运算。主要如下表总结(主要是各个模式应用在不同坐标系可以实现的函数说明)。

    7a4e6d8d5f02b172e415cfe83c2ae6f7.png

    2.1 旋转模式

    如图所示,假设在一个圆周系统中,若是想求得30°的cos值与sin值,那需要得到30°角在单位圆上交点的x轴坐标与y轴坐标。
    首先,赋予初值x0 = 1,y0 = 0,z0 = θ(此个例子中θ为30,zi执行加或者减操作,使得z的最终值为0 ,该条件由di决定)
    为了得到30°角在单位园上的x轴坐标与y轴坐标,我们先将初始线逆时针旋转45度,得到相应的x1、y1、z1值。其次比较得出45°角比30°角大,因此要进行第二次旋转,进行顺时针旋转26.6°角,得到x2、y2、z2值。又发现新得到的角度比30°角小,再次旋转。就依靠这种模式进行N次迭代,迭代次数越大,那么实现的精度就会越高,以此类推。z的迭代过程是将z收敛于零的过程,也正是将θ分解为一系列θi的过程, 故zi可认为是第i次旋转剩余的角度。
    此过程具体的数学推导,有兴趣的读者可以参考这篇文章。

    bc9c6e041627d8e3a678c101a2d01afb.png

    2.2 向量模式

    与旋转模式相比,向量模式下的目的是使y趋向于 0。 为了达到这一目标, 每次迭代通过y值的正负性确定旋转方向, 最终使初始向量旋转至 x轴的正半轴, 这一过程也使得每次微旋转的旋转角度累加和存储在变量 z 中。

    如图当设置初始值y0 = 2 ,x0 = 1的时候,经过n(n–>∞)次旋转,开始的点靠近x轴。因此,当迭代结束之后,P将近似接近x轴的正半轴,此时P点纵坐标yn = 0,在这个过程中可知旋转了θ,即zn = z0 +θ = z0+arctan(y0/x0) (z0为初始化角度)。

    148e7304af951c1791af2023c49d6d87.png

    2.3 双曲系统

    与圆周系统和线性系统有所不同, 双曲系统的迭代较为复杂。但是利用双曲系统可求取一系列超越函数。例如 在旋转模式下, 可求取双曲正弦函数和双曲余弦函数, 进而可求取 e 指 数,在向量模式下, CORDIC 算法可实现反双曲正切函数的计算。当我们要实现对数函数求解时,可以从如下公式出发:

    f68774818d413a95929489ade8b2d050.png

    将求解ln的值转化为求解arctanh的值。在双曲模式下的算法迭代涉及到发散收敛问题,且从N为4开始,每当3k+1的项需要重复迭代,即1,2,3,4,4,5,6,7.....13,13.....。与此同时仅进行正数迭代,那么当输入值大于9的时候就会出现严重发散的现象,这也不是我们所期望的。因此需要添加负数次的迭代,扩大定义域。在此论文中有详细说明。

    三、算法过程:

    3.1 逻辑说明

    · 取x0 = r + 1, y0 = r-1, z0 = 0,其中r为我们想求得的值。当y经过多次迭代逼近0的时候,zn的输出值即为对数函数值的一半。本次研究取迭代次数为16次,n=-5为起始迭代数,事先通过计算求解出相应的arctanh值,作为常量供迭代方程加减。需要注意的地方是,如果输入的r值太小,可能会在迭代过程中因为移位操作导致值的丢失,建议将x值与y值同时放大, 结果并不会发生改变,但可以使得迭代更多次,保证精度。当然预先做个数值范围判定移位更佳,为了避免精度损失,本次实验研究将数值放大

    用以计算。下图为迭代表格,读者在编写代码时,可用于事先输入到ROM中用于调取。

    d45aeb45ff10ecc01090360b1dd953ea.png

    · 为了抑制迭代过程发散的情况, 我们选取负数次处开始迭代,则有如下迭代公式:

    db84a5102f32d67e68e423361534b7e5.png

    注意事项:使用Verilog编写此份算法,若是定义signed要注意算术移位的问题,建议使用拼接截位操作。

    3.2代码实现

    import chisel3._
    import chisel3.experimental._
    
    class Mylog extends Module {
      val io = IO(new Bundle {
        val in = Input(SInt(32.W))
        val out = Output(SInt(32.W))
      })

    在上述代码中,自定义类Mylog继承自Chisel的Bundle类,输入、输出采用32位的符号数。若是读者想要进行更高精度的迭代计算,需要增加位宽以及迭代次数。但是会极大的增加电路的面积,因此视实际情况进行取舍。

    val x0 = io.in + 65536.S(32.W)
      val y0 = io.in - 65536.S(32.W)
      val z0 = 0.S(32.W)
      val taps_x = Seq(x0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
      val taps_y = Seq(y0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
      val taps_z = Seq(z0) ++ Seq.fill(16)(RegInit(0.S(32.W)))
    
      io.out := taps_z(16)

    我们先将x0、y0 、z0进行初始化,用于后面的迭代计算,通过Seq函数搭建各个位置的节点,这是类似于搭建移位寄存器,但是各个节点间的连接关系我们仍然可以自行定义,这样有利于不同计算间的输入定义,是编写Chisel代码很有效的一种技巧。最后将输出连接z16节点的输出,得到解值。

    val taps_xy = taps_x.zip(taps_y).zip(taps_z)
      taps_xy.zip(taps_xy.tail).zipWithIndex.foreach { case((((x0,y0),z0),((x1,y1),z1)),index) =>
        when (y0(31) === 1.U) { 
          if (index <= 5) {
            x1 := x0 + y0 - (y0 >> (7 - index))
            y1 := y0 + x0 - (x0 >> (7 - index))
            z1 := z0 - rot(index).S
          }
          else if (index <= 9) {
            x1 := x0  + (y0 >> (index - 5))
            y1 := y0  + (x0 >> (index - 5))
            z1 := z0 - rot(index).S
          }
          else {
            x1 := x0  + (y0 >> (index - 6))
            y1 := y0  + (x0 >> (index - 6))
            z1 := z0 - rot(index).S
          }
        }
        .......

    笔者先将前15位节点与后15位节点捆绑在一个元组中,类似于(x0,y0,x1),这样可以很方便的将x1的输入与x0,y0联系起来。然后再包裹一个zipWithIndex函数用于标记元组位置,可以方便迭代位移操作。最后使用foreach函数进行移位连接赋值操作,即可快速搭建迭代电路逻辑。下图为迭代设计实现结构图,描述电路工作状态。

    3b2e89335af8a659f2c338deaea50c54.png

    四、模块测试与说明

    4.1 基于Chisel实现16次迭代32位输入CORDIC模块测试

    首先运行测试脚本,使用scansion对生成波形进行测试。将输入测试值放大

    倍,同时在模块输入端口连续发送测试数据,经过16个周期后输出端口得到结果,此处在输出端口处添加FIFO,可以有效处理数据延迟问题。

    输出端口得到的数据是经过放大处理后的值,将其输出值除以

    为最终所求值。

    图示为部分波形截图,io_out输出为ln(3)、ln(4)...ln(16)的解值。

    2157e77b3ea5bc6835da0ae9820db3f0.png

    下图为整体测试运行波形图,将输出波形与精确值进行对比分析,误差在0.5%上下浮动。

    1b7c315b0e2328581df30406c8a304dc.png

    4.2 Berkeley dsptools模块测试

    在此连接提供了berkeley研发的dsptools库。 dsptools库是一个可以和任何Chisel工程混合使用的库。该库提供了包括流水线延迟检查,DSP设计和验证等功能,以及更多针对不同数值类型的验证平台。

    要说明的是,dsptools中函数部分继承于BlackBox,通过BlackBox导入Verilog模块的端口列表给Chisel模块使用。其中,ln函数就是通过BlackBox导入,同时其调用的Verilog代码使用了scala系统函数,因此实际上该函数仅作为验证,其代码不可综合的,读者需引起注意。

    在Chisel中写dsptools的测试脚本时,可以直接输入双精度浮点数,利用FixedPoint.fromDouble(value , DataWidth.W, BinaryPoint.BP) 将其转为定点数进行输入。输出可以利用波形显示工具转为 float 64 类型观察测试。

    下图为berkeley dsptools库中调取ln函数测试波形图,截取ln(3)至ln(16)输入输出波形图,用于对比分析。

    6c47a309b40640ada5d996b373d1b795.png

    CORDIC算法实现的ln(6)的输出为118260,将其除以

    的值为1.80450,而通过dsptools计算的ln(6)值为1.79176,差值为0.01274。再以相同的方法测试多组数据,差值均在0.5%上下浮动。

    4.3 与Vivado CORDIC IP对比测试

    Vivado提供的CORDIC IP 6.0,同样可以完成三角函数、双曲线、指数、对数等函数的计算。
    Vivado CORDIC IP核有两种架构配置:并行架构(Parallel),具有单周期多数据的吞吐量但是耗费较大面积。字串行架构(Word Serial) ,具有多周期的吞吐量但是面积消耗小。本次实验选择字串行架构,配置32位有符号定点二进制数作为输入、输出,选择16次迭代次数。
    (特别要注意的是,输入X_IN以及输出Y_IN被限制在如下表格给出的范围内,超出这些范围的输入会产生不可预测的输出。 此外,|Y_IN|必须小于或者等于(4/5*X_IN),否则CORDIC算法输出会有不收敛的情况。)

    8f9c36cb23bc58a62ce78d3debffbd40.png

    X_IN以及Y_IN输入为宽度2位的定点二进制补码,PHASE_OUT输出为宽度3位定点二进制补码。举个例子:

    若求ln(K),其中K = 0.625,则 K+1 = 1.625 ,K - 1 = -0.375。

    X_IN = K + 1 = '01,10 1000 0000 0000 0000 0000 0000 0000 ' = 32'h6800 0000
    
    Y_IN = K - 1  =  '11,10 1000 0000 0000 0000 0000 0000 0000 ' = 32'hE800 0000  (负数已经做过补码处理)
    
    PHASE_OUT = '111,0 1101 0110 0011 1110 0011 0110 0010 ' = 32'hED63E362

    另外要说明的是,若是求解超出范围的整数值,要先实现一个预处理模块,将K转换为P*2N (P ∈[0.5 , 1) ,N为偶数 ),倘若K值转换出来的等式中N为奇数,则将P值除以2使得N = N + 1,此时P∈[0.25 , 0.5) 。

    举个例子: 计算ln(160),则K = 160,可以换算为0.625 * 28,即P = 0.625,N = 8,此时ln(160) = ln(0.625) + 8 * ln(2)。 此时需要:

    1. 预先存储ln(2) 的值
    2. 使用Vivado CORDIC IP核计算ln(0.625)
    3. 通过乘法与加法得到最终结果

    4.3.1 精度对比测试
    使用Vivado CORDIC IP 6.0搭建测试模块,采用16次迭代32位输入,IP核将会产生20个周期的延迟,将随机值(此处取5个随机点作为展示)与Chisel实现的16次迭代32位输入CORDIC模块比较(产生16个周期的延迟)。图中横坐标表示测试的数值,纵坐标表示不同运算结果误差绝对值。

    b3f5532be94900b36e9e581416fd7927.png

    可以发现:32位输入20周期延迟的Vivado CORDIC IP 6.0,在精确度上是远优于32位输入16周期延迟基于Chisel实现的CORDIC模块。
    通过实验研究,我们发现Vivado提供的IP输入值限定最大值为1.00,原因是通过增加定点小数位(30位)来提高精度,而我们设计的Chisel CORDIC模块输入定点值格式为32位宽,16位小数,动态范围更大,但是计算精度更低。 为此我们进行代码的改进,基于Chisel实现32位输入20周期延迟的CORDIC模块,将模块的输入值范围限定为30位小数的32位定点数,重新对其误差以及资源进行了分析。注:下文出现的VIVADO IP表示30位小数的32位定点数输入,20周期延迟的CORDIC IP 6.0模块; Chisel-16表示输入为16位小数的32位定点数,16周期延迟Chisel实现的CORDIC模块; Chisel-20表示输入为30位小数的32位定点数,20周期延迟Chisel实现的CORDIC模块。

    我们一共测试了92组数据(数据由Python随机函数产生),在同样的延迟周期和同样的定点范围下得到和Vivado IP的误差对比(下图表示VIVADOC IP 以及Chisel-20 输出值与实际的误差):

    e401574cbf2e4b6aa45678b67f9169b4.png

    下述为各个模块的均方误差值

    MSE of VIVADO IP:4.177e-07
    MSE of chisel-16:4.004e-05
    MSE of chisel-20:2.872e-08

    此时的Chisel-20模块误差已经和Vivado CORDIC IP的误差为一个量级。从均方误差方面分析,Chisel-20的精确度是最具有优势的。

    4.3.2 资源对比测试

    通过Vivado进行FPGA评估,我们选定FPGA元件为v7xc7vx485tffg1761-2,工作频率为200MHz,通过综合工具和实现工具,对三种不同IP进行资源评估和功耗分析。

    三种方式的资源消耗关键数值对比如下所示:

    7b99c2b573c8463101d12b0f5b85a106.png

    23cddab65cf900a3c543a128faf01684.png

    对比分析得知,相对于Chisel-16、Chisel-20模块,Vivado IP的LUT、FF资源消耗少,LUTRAM、IO资源占用高。
    分析Chisel-16和Chisel-20模块可知,随着Chisel-20模块精度提升,其LUT、FF资源消耗也相应增加。
    总的来说基于Chisel设计的CORDIC模块需要更多LUT和FIFO资源,更少的IO资源

    4.3.3 总结分析

    通过数据对比分析,在同样的延迟周期和同样的定点范围条件下,我们设计的CORDIC模块和Vivado提供的IP核区别如下:

    Chisel-16 CORDICVivado CORDIC IPChisel-20 CORDIC
    延迟周期1620 (字串行)20
    是否需要预处理
    求值范围ln(K)K∈(0 , 32768]K∈(0 , 1]K∈(0 , 1]
    总功耗(200MHz)0.531W0.381W0.565W
    精度
    WNS2.408ns1.781ns1.191ns
    WHS0.054ns0.145ns0.093ns
    WPWS1.100ns1.100ns1.100ns

    总的来说三种方式设计的CORDIC模块在200MHz的工作频率下,S/H时序都满足要求,总功耗为Chisel-20 CORDIC模块最大, Vivado CORDIC IP core 与 Chisel-20 CORDIC精度相近。

    4.3.4 注意事项

    进行FPGA评估需要通过修改Vivado的tcl脚本fft.tcl中的参数,具体设置以及流程可以看此文档中的说明,主要修改tcl中的路径以及top文件名。同时要注意的是,引用Verilog文件中的顶层的模块时,需要添加时钟模块来驱动clock,主要代码参考如下:

    wire clock;
      clk_wiz_0 clk_wiz_0_inst0( 
        .clk_out1(clock),
          .clk_in1_p(clk_in1_p),
          .clk_in1_n(clk_in1_n)
      );
    

    五、结语

    本文简单介绍了CORDIC算法的应用实现,通过数十行Chisel代码实现了对数函数的电路设计。同时,笔者尝试编写了一份实现相同功能的Verilog代码,发现Chisel在代码量上以及效率上是具有极大优势的,使用Chisel设计结构重复性硬件大大简化了电路的设计过程。

    六、参考文献

    -[1]Mopuri, S., Acharyya, A. Configurable Rotation Matrix of Hyperbolic CORDIC for Any Logarithm and Its Inverse computation.
    -[2]CORDIC v6.0 Document

    展开全文
  • 为了验证遗传算法的寻优能力,这里常用的非线性函数Beale Function进行测试。 目标函数为: 该函数在搜索域内的最小值已知为f(3,0.5)=0 函数在搜索域内的图像如下: 遗传算法求解优化问题的一个关键在于如何对...
  • 对多数内建的基本函数对象模板提供了简单的测试 这种方式如何使用每个模板 并取得相应的操作结果 //: C06:Generators.h // From "Thinking in C++, Volume 2", by Bruce Eckel &amp; Chuck ...
  • (2)至于什么加密算法,这个要根据产品和自己的业务场景和需求不管是AES或者公钥私钥也好看自己的选择(3)也可能是编码的问题,就直接base64码把需要传输加密的东西通过base64返回base64码...
  • 然而题目要求n最大为250,所以只能高精度算法,我的char*类型,并且一个add函数计算两个字符串的和。但是是有问题的。 因而,想知道如何处理这种函数返回值过大必须字符串储存,并且还要使用递归的问题。 ...
  • 展示了使用Python进行函数式编程的几个概念,例如:* args和** kwargs,迭代器,生成器,修饰器,列表推导和内置函数。 通过单元测试解决问题。 大多数问题任务都来自,其中一些任务也来自 。 如何设置虚拟环境并...
  • Rosenbrock函数到底什么

    千次阅读 2019-07-22 19:09:20
    Rosenbrock函数是一个用来测试最优化算法性能的非凸函数 Rosenbrock函数的每个等高线大致呈抛物线形,其全域最小值也位在抛物线形的山谷中...优化算法对RosenBrock函数进行测试,看看效果咋样. Reference: [1] ...
  • 初学数据挖掘算法时,在具体工作中常常不清楚如何选择算法,本文将从耗时的角度进行测试,选择的基础算法有DecisionClassifier、LogisticRegression、LinearSVC、SVC(高斯核函数)。并没有再SVC(kernel = linear)...
  • 程序内容: 编写一个函数,返回储存在double类型数组中最大值的下标,并在一个简单的程序中测试函数。 程序为C Primer Plus第十章第四题的答案示例附:程序代码为本人亲自编写,并非书内标准答案,仅供参考。如果...
  • 六.算法题 1....请编写能直接实现strstr()函数功能的代码。 5.编写反转字符串的程序,要求优化速度、优化空间。 6.在链表里如何发现循环链接? 7.给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。
  • 分治算法-计算Fibonacci数列 ...编写函数实现朴素递归算法计算Fibonacci数列; 编写函数实现自底向上算法计算Fibonacci数列; 编写函数实现分治算法计算Fibonacci数列; 测试n取10、40、45...
  • 如何测试我们所实现算法的性能?查找表是什么?为什么要它? 测试用例 这里我们测试的,是一种简单的颜色缩减方法。如果矩阵元素存储的是单通道像素,使用C或C++的无符号字符类型,那么像素可有256个...
  • 1、编写函数实现迭代算法计算x的n次幂; 2、编写函数实现分治算法计算x的n次幂; 3、测试计算1的n次幂,分别令n取1000、1万、10万、100万、1000万的情况下两种算法各自的运行时间,通过对比分析研...
  • 遗传算法与粒子群算法的实现

    热门讨论 2013-09-04 17:22:43
    各个测试算法都被加入到TestBatch以后,batch.run()开始执行算法比较过程并输出结果Excel文件到C盘根目录(输出路径可在Testable接口中配置,除了生成Excel文件外,还可以通过修改log4j.properties在制定的位置产生...
  • //顺序表测试用 const int MaxSize=100; //100只是示例性的数据,可以根据实际问题具体定义 const int Increasement=10; typedef struct{ ElemType *elem; int length; int listsize; }SeqList; Status ...
  • 算法笔记 胡凡 曾磊

    2018-10-16 17:38:13
    第1章 如何使用本书 1 1.1 本书的基本内容 1 1.2 如何选择编程语言和编译器 1 1.3 在线评测系统 2 1.4 常见的评测结果 3 1.5 如何高效地做题 4 第2章 C/C++快速入门 5 2.1 基本数据类型 7 2.1.1 变量的定义 7 2.1.2...
  • 算法导论中文版

    2016-10-26 10:13:58
     14.2 如何扩张数据结构  14.3 区间树  思考题  本章注记 第四部分 高级设计和分析技术 第15章 动态规划  15.1 钢条切割  15.2 矩阵链乘法  15.3 动态规划原理  15.4 最长公共子序列  15.5 最优...
  • 本文对如何用银行家算法来处理操作系统给进程分配资源做了详细的说明,包括需求分析、概要设计、详细设计、测试与分析、总结、源程序清单。 首先做了需求分析,解释了什么是银行家算法,并指出它在资源分配中的...
  • 如何衡量我们算法的性能? 什么是查询表,为什么使用它们? 测试用例   让我们考虑一种简单的色彩量化(颜色空间缩减)方法。通过使用unsigned char C和C++类型存储矩阵项(图片),像素通道可以有多达256个不同的...
  • 这几天看了A*搜索的寻路算法,发现精华在于f = g + h,我觉得难点在于如何确定估价函数的h。 本段代码是迷宫找路。估价函数:h是的曼哈顿距离 贴出自己的代码,分享一下。可以讨论 文章会附上:代码.rar和测试 ...
  • Chisel快速搭建FFT流水线电路 Chisel实践——短时傅里叶变换模块的实现与测试 Chisel实践——利用CORDIC算法计算对数函数 已经介绍了如何使用Chisel开发FFT运算模块和STFT模块,以及对于Chisel实现CORDIC算法的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 446
精华内容 178
关键字:

如何用测试函数测试算法