基于FPGA的求模运算器

这篇具有很好参考价值的文章主要介绍了基于FPGA的求模运算器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、 简介

1.1 系统的目的

1.2 系统的背景

2、 需求概括

2.1 系统需求

2.2 当前系统问题

3、 建议的系统

3.1 设计重点

3.2 系统的原理

3.2.1 算法框图

3.3 数据预处理部分

3.4 迭代算法的核心部分

3.5 收敛判断

3.6 输出格式化

3.7 模块接口信号

3.9 仿真测试

4、 系统分析

4.1 精度分析

4.2 资源分析

4.3 时延分析

5、代码



1、 简介

1.1 系统的目的

        在实际算法中,有很多地方需要用到求模的算法,以及开根的数学计算。本设计在FPGA上实现一款基于Cordic算法的两个向量的求模计算方法,旨在替代传统的计算公式,优化面积和速度。

1.2 系统的背景

        在电机控制算法中,有很多地方需要用到开根和平方差开根的运算,然而FPGA内部却没有专门的硬件资源来实现这种算法。目前系统使用的方案是a2+b2然后开根,开根使用的是xilinx的Cordic IP,Xilinx提供的IP保密性太高,使用者无法进行项目FPGA平台的灵活切换

2、 需求概括

2.1 系统需求

        在FPGA开发板上实现一种面积小,性能高,精度满足要求的求模计算模块,要求自主源码实现,后期易于切换平台,易于维护。

其它要求:

数据位宽8-32位可配

主频:100MHz

延迟: 小于32 cycle

支持定点小数,小数位可配

2.2 当前系统问题

同提出的设计相比,目前的系统普遍存在以下问题:

  1. 计算精度低
  2. 资源消耗高
  3. 可移植性差
  4. 计算延迟高
  • 3、 建议的系统

3.1 设计重点

  1.  通过提高内部运算数据宽度和舍入方法来提高运算精度。
  2.  将各参数预留有接口,方面移植到各种设计场合。
  3.  利用Cordic圆周旋转方式进行结果逼近。
  4.  输入与输出数据的格式化。

3.2 系统的原理

        CORDIC算法是一个化繁为简的算法,将许多复杂的运算转化为一种仅需要移位和加法的迭代操作。CORDIC算法有旋转和向量两个模式,分别可以在圆坐标系、线性坐标系和双曲线坐标系使用,从而可以演算出8种运算,而结合这8种运算也可以衍生出其他许多运算。在这里我们只介绍求模运算在CORDIC算法中实现的条件。

        CORDIC算法有两种工作模式:旋转模式和向量模式,旋转模式是给定旋转角,计算旋转后的坐标,而向量模式相当于旋转模式的变体(倒推得到),根据旋转后的坐标,得到向量的角度和模值。

        由于CORDIC算法只有移位和加法运算,所以比较适合于在硬件上实现。

基于FPGA的求模运算器,fpga开发

        如上图所示,若已知点矢量终点A0(X0,Y0),若将该矢量逆时针旋转θ 可以根据三角运算得到B0(X1,Y1)点坐标:

基于FPGA的求模运算器,fpga开发

令θ1 = − θ即顺时针旋转θ角度,则:

基于FPGA的求模运算器,fpga开发

联立上述两个式子,引入常数$ d (d=-1,+1)$ ,因此可得:

基于FPGA的求模运算器,fpga开发

        这个算法的核心在于将一系列已知的t a nθ作为表格键值进行存储,而t a nθ可以约等于1/2-n并且1/2-n在FPGA中可以通过右移进行快速运算。t a nθ各个已知存储值如下:

i

θ

t a nθ

cosθ

accosθ

0

45

1

0.707106781186548

0.707106781186548

1

25.56505

0.50

0.894427190999916

0.632455532033676

2

14.03243

0.25

0.970142500145332

0.613571991077897

3

7.125016

0.125000000000000

0.992277876713668

0.608833912517753

4

3.576334

0.0625000000000000

0.998052578482889

0.607648256256168

5

1.789910

0.0312500000000000

0.999512076087079

0.607351770141296

6

0.895173

0.0156250000000000

0.999877952034695

0.607277644093526

7

0.447614

0.00781250000000000

0.999969483818788

0.607259112298893

8

0.223810

0.00390625000000000

0.999992370692779

0.607254479332563

9

0.111905

0.00195312500000000

0.999998092656824

0.607253321089875

10

0.055952

0.000976562500000000

0.999999523163183

0.607253031529135

11

0.027976

0.000488281250000000

0.999999880790732

0.607252959138945

12

0.013988

0.000244140625000000

0.999999970197679

0.607252941041397

13

0.006994

0.000122070312500000

0.999999992549420

0.607252936517011

14

0.003497

6.10351562500000e-05

0.999999998137355

0.607252935385914

15

0.001748

3.05175781250000e-05

0.999999999534339

0.607252935103140

        而多次旋转过程中,每次旋转的c o sθ需要连续相乘,而多次相乘极限也趋近与0.607252这一个常数,因此也可做近似处理。那么现在还有最后一个问题,这一系列角度能够通过多次旋转得到任意的角度吗?可以看到每个角度是不断降低减半的,呈递减的分布,从宏观上观察大致是可以进行趋近到某一个常数的。

        cordic算法向量模式,已知点坐标(x0,y0),可以求得该向量的角度即arctan(y0/x0)。这种可以理解为需要通过多次旋转,将该向量旋转至x轴上,即y0 = 0,此时旋转过的角度即为向量角度,x最终坐标即为向量的长度。

最终迭代公式如下:

基于FPGA的求模运算器,fpga开发

只要y趋向于0,那么x的值就是最终所求的模长。

3.2.1 算法框图

        系统的算法框图如图1所示,主要分为数据预处理模块,旋转迭代模块,收敛判断,输出格式化。

基于FPGA的求模运算器,fpga开发

3.3 数据预处理部分

        数据预处理模块主要负责将输入的数据变换到第一区间,即0-0.5pi的区间。

       由于求模运算,都是基于正数去算的,所以需要将负数求绝对值,这样下来输入数据都为正,确保能够落在第一区间。针对特殊情况,x为0或者y为0的,可以直接给出模值,这里就不再详述了。

关键代码:

直接给出模值得情况

If(x==0)

         Result <= y;

Else if(y==0)

         Result <=x;

Else

Result <=r_result;

变换到第一区间的代码:

r_x <= abs(x);

r_y <= abs(y);

3.4 迭代算法的核心部分

设置初始值让x0=data_a,y0=data_b;

        根据以上3.2节迭代公式,每次迭代计算出x和y的值,还有d的值,判断下一次运算是加还是减。

核心代码如下:

Assign s_dx=r_Z[DWIDTH-1]==1’B0? r_data_y: - r_data_y;

Assign s_dy=r_Z[DWIDTH-1]==1’B0? r_data_x: - r_data_x;

Assign s_dz=r_Z[DWIDTH-1]==1’B0? actan: - actan;



If(cvt_end == 1’b1)begin

         R_data_x <= r_data_x;

R_data_y <= r_data_y;

R_Z <= R_Z;

End else begin

         R_data_x <= r_data_x – (s_dx>>>cycle);

R_data_y <= r_data_y+ (s_dy>>>cycle);;

R_Z <= R_Z-s_dz;

end

3.5 收敛判断

       根据大量的测试数据,统计出迭代需要的次数以及精度之间的关系设置一个最大迭代次数,达到这个次数就停止计算,输出结果。

If(start_pulse| r_cvt_end)
    Cycle <= 0;
Else
    Cycle <= Cycle + 1’b1;


If(start_pulse | r_cvt_end)
    Reach_max  <= 0;
Else if(cycle == MAX_CYCLE)
    Reach_max  <= 1;

     第二种方案是判断角度值是否小于一个接近于0的数,如果条件满足则停止计算,输出结果。

If(start_pulse|cvt_end)

         r_cvt_end <= 0;

else if(cycle >8’d5 && abs(r_Z)<3)

         r_cvt_end <= 1;

      有一种特殊情况就是迭代一次或者极少的次数就收敛了,经过实际测量,这种情况测出来得数据不准确,误差很大,可能跟算法的最终补偿因子有关系。这里我们跳过迭代次数小于5的情况,让其继续迭代计算。

3.6 输出格式化

        到目前为止,输出的数据并不是最终的结果,因为每次旋转的时候都少算了一个乘数cosθ,所以我们算出来的结果需要补偿回来。

        3.2.2节中提到过这个补偿值大约为0.607252,所以我们需要将最终的结果乘以这个值再输出。

        输出模长信号需要经过用户要求的格式去整理一下才能输出,不然内部运算的数据位宽和小数点位置与输出要求的不一样,后级很容易发生错误。

        首先由用户输入的参数来计算出输出数据的位宽和小数位置

例如默认配置下:

Parameter FRACTION_BIT =20

Parameter DIN_WIDTH =32

Parameter DOUT_WIDTH =32

表示输入数据位宽是32位,其中低20为为小数,即Q20

基于FPGA的求模运算器,fpga开发

        假如系统为了提高运算精度,在迭代的时候将运算数据小数位扩展到50位,整数位不变,则迭代收敛后,所得出来的数据62位宽,50位小数。

基于FPGA的求模运算器,fpga开发

        在我们输出时候需要根据输出的参数DOUT_WIDTH及FRACTION_BIT整理输出的数据格式,直接对最后的30bit进行四舍五入:

R_result<= r_data_x[30+ DIN_WIDTH-1:30]+ r_data_x[29];

3.7 模块接口信号

参数

方向

位宽

描述

DIN_WIDTH

整型

输入位宽

DOUT_WIDTH

整型

输出位宽

FRACTION_BIT

整型

小数位数

信号

方向

位宽

描述

Clk

In

1

时钟输入

Rst

In

1

复位输入

Start

In

1

开始计算脉冲指令

Data_a

In

X

输入数据a

Data_b

In

X

输入数据a

Result

Out

X

输出数据

Ovalid

Out

1

输出数据有效信号

3.9 仿真测试

基于vivado下仿真出来的波形如下:

基于FPGA的求模运算器,fpga开发

计算开始时的仿真波形

基于FPGA的求模运算器,fpga开发

计算收敛后的仿真波形

        从图上看,给的输入信号是3和4,计算出来的模长是5,非常精确,收敛速度也非常快,在第5个cycle时候已经达到4.996了。

        其中start脉冲过来后,busy开始拉高,计算开始,数据收敛后ovalid信号拉高一次,busy信号拉低。

        中间数据位宽比较大,62位的,本设计为了提高计算精度,过程中小数位采用50位定点小数。

4、 系统分析

4.1 精度分析

输入1

输入2

计算结果

理论结果

精度

17.071110725

20.328888893

26.545932769

26.5459327395

1.11e-9

19.071110725

22.328888893

29.364715576

29.3647159612

1.31e-8

21.071110725

24.328888893

32.18519115448

32.1851913456

5.9e-9

23.071110725

26.328888893

35.006949424

35.0069498875

1.32e-8

25.071110725

28.328888893

37.829704284668

37.8297044516

4.4e-9

27.071110725

30.328888893

40.653247833252

40.6532475624

6.66e-9

29.071110725

32.328888893

43.477425575

43.4774255889

3.197e-10

31.071110725

34.328888893

46.302122116

46.3021223521

5.1e-9

有以上测试数据可知,精度最低已经达到1.32e-8,已经完全满足大部分场景了。

4.2 资源分析

系统在VIVADO平台下选择xczu5eg系列的FPGA,并将本模块设为顶层,综合后资源报告如下:

基于FPGA的求模运算器,fpga开发

因为节省了da*da+db*db的运算,所以节省了两大位宽乘法器和一个加法运算,目前lut消耗了585个 dsp 为4个,较之前有很大程度改善。

4.3 时延分析

本设计固定延迟32个cycle,但是在大多数情况下,10个周期内就能够收敛了,所以可以根据实际情况做更改,在时延和计算精度上做折中文章来源地址https://www.toymoban.com/news/detail-819210.html

5、代码

Module sincos_cordic #(

         Parameter MAX_CYCLE=8’d40,

         Parameter FRACTION_BIT=20,

         Parameter DIN_WIDTH=12,

Parameter DOUT_WIDTH=22

)(

Input wire       clk,

Input wire       ce,

Input wire       reset,

Input wire       start,

Input wire [DIN_WIDTH-1:0]  data_a,

Input wire [DIN_WIDTH-1:0]  data_b,

output wire [DOUT_WIDTH-1:0]              result,

output wire               busy,

output wire               ovalid



);



Localparam DWIDTH = 30+DIN_WIDTH;

Localparam AMP_WIDTH = DWIDTH- DIN_WIDTH;

Localparam Kn = =32’h26dd3b6a;



Reg                 r_start_sft;

Reg                 r_start_pulse;

Reg                 r_busy;

Reg [DIN_WIDTH-1:0] r_data_a;

Reg [DIN_WIDTH-1:0] r_data_b;

Reg signed [DWIDTH -1:0] r_data_x;

Reg signed [DWIDTH -1:0] r_data_y;



Wire signed [DWIDTH -1:0] s_dx;

Wire signed [DWIDTH -1:0] s_dy;



Reg [7:0] cycle;

Reg [7:0] repeat_point;

Wire cvt_end;

Reg r_busy1;

Reg  [DOUT_WIDTH-1:0]                r_result;

Reg reach_max=0;

Function [DWIDTH -1:0] abs;

         Input [DWIDTH -1:0] din;

         Abs= (din[DWIDTH -1:0])==1’b1)?-din:din;

Endfuction



always@(posedge clk) begin
   r_data_a <= abs(data_a);
   r_data_b <= abs(data_b);
end



always@(*)
    r_start_pulse <= start & ~r_start_sft;



always@(posedge clk) begin
    if(reset == 1’b1)
        cycle <= 0;
    else begin
        if(r_start_pulse | cvt_end)
            cycle <= 0;
         else
            cycle <= cycle + 1’b1;
    end
end



always@(posedge clk) begin
    if(r_start_pulse)
       reach_max <= 1’b0;
    else if(cycle == MAX_CYCLE)
       reach_max <= 1’b1;
    else
       reach_max <= reach_max;

end

assign cvt_end = reach_max;



assign s_dx = (r_data_y[DWIDTH-1]==1’B1)?r_data_y:- r_data_y;

assign s_dy = (r_data_y[DWIDTH-1]==1’B1)?r_data_x:- r_data_x;

always@(posedge clk) begin
    if(r_start_pulse)begin
         r_data_x <= { r_data_a ,{AMP_WIDTH{1’b0}}};
         r_data_x <= { r_data_b ,{AMP_WIDTH{1’b0}}};
    end else if(cvt_end == 1’b1)begin
         r_data_x <= r_data_x;
         r_data_y <= r_data_y;
    end else begin
         r_data_x <= r_data_x – (s_dx>>>cycle);
         r_data_y <= r_data_y + (s_dy>>>cycle);
    end
end


always@(posedge clk) begin
    if(reset== 1’b1)begin
        r_busy <= 1’b0;
        r_busy1 <= 1’b0;
    end else begin
        r_busy1 <= r_busy;
        if(r_start_pulse)
        r_busy <= 1’b1;
    else if(cvt_end == 1;b1)
        r_busy <= 1’b0;
    else
        r_busy <= r_busy;
    end

end



wire [DWIDTH-1:0] s_result;

wire [DWIDTH+AMP_WIDTH-1:0] s_result0;

assign s_result0 = r_data_x*kn;

assign s_result = s + result0[DWIDTH + AMP_WIDTH-1: AMP_WIDTH];

always@(posedge clk)
         r_result <= s_result [DWIDTH -1: AMP_WIDTH]+ s_result [AMP_WIDTH-1];

assign busy = r_busy;

assign ovalid = r_busy1&~r_busy;

assign result = r_result;

endmodule

到了这里,关于基于FPGA的求模运算器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Logism · MIPS运算器设计 实验

        利用前面实验封装好的32位加法器以及 Logisim 平台中现有运算部件,构建一个32位算术逻辑运算单元(禁用 Logisim 系统自带的加法器,减法器),可支持算术加、减、乘、除,逻辑与、或、非、异或运算、逻辑左移、逻辑右移、算术右移运算,支持常用程序状态标志(有符

    2023年04月26日
    浏览(41)
  • 西电计组实验二 运算器实验

    一.实验目的   1.了解简单运算器的数据传输通路。   2.验证运算功能发生器的组合功能。   3.掌握算术逻辑运算加、减、与的工作原理。   4.验证实验台运算的8位加、减、与、直通功能。   5.按给定数据,完成几种指定的算术和逻辑运算。 二.实验原理   算

    2024年02月06日
    浏览(41)
  • CPU运算器、控制器、寄存器

    CPU内部主要由运算器、控制器、寄存器三大部分组成。 运算器 负责算术运算(+ - * / 基本运算和附加运算)和逻辑运算(包括 移位、逻辑测试或比较两个值等)。 控制器 负责应对所有的信息情况,调度运算器把计算做好。 寄存器 它们可用来暂存指令、数据和地址。既要对

    2024年02月15日
    浏览(34)
  • 计算机组成原理实验——实验1 运算器实验

    (1)掌握算术逻辑运算单元的工作原理。 (2)熟悉简单运算器的电路组成。 (3)熟悉4位运算功能发生器(74LS181)的算术、逻辑运算功能。 (1)做好实验预习,看懂电路图,熟悉实验中所用芯片各引脚的功能和连接方法。 (2)按照实验内容与步骤的要求,认真仔细地完

    2024年02月12日
    浏览(39)
  • 数据结构实验之矩阵的运算器(二维数组)

    实验目的 掌握并学会运用数组及相关知识 掌握矩阵相关运算的代码实现 学会小组的分工与合作 体会封装的好处 实验任务及要求 要求实现矩阵的计算器,能供用户选择不同菜单,进而实现不同存储形式及调用相应计算的算法,并记录运算过程。 运算程序主要包括:①矩阵的

    2024年01月15日
    浏览(37)
  • 计算机组成与结构实验一《运算器组成》

    一、实验目的与要求 一、实验目的 (1)熟悉TEC-8模型计算机的节拍脉冲T1T2T3 (2)熟悉TEC-8模型机双端口通用寄存器组的读写操作 (3)熟悉TEC-8模型机运算器的数据传送通路 (4)验证74181的加、减、与、或功能 (5)按给定的数据,完成几种指定的算术运算和逻辑运算 二、

    2024年02月04日
    浏览(43)
  • 头歌计组运算器设计(HUST) 1-11关实验答案

    本实验使用 Verilog HDL 实现了单周期 54 条 MIPS 指令的 CPU 的设计、前仿真、后仿真和下板调试运行。CPU 可实现 54 条 MIPS 指令。(详细论述所设计作品的功能) 本实训项目帮助学生从可控加减法单元,先行进位电路,四位快速加法器逐步构建 16 位、32 位快速加法器。学生还可

    2023年04月23日
    浏览(39)
  • 计算机组成与体系结构第一次试验:运算器实验

    为了帮助同学们完成痛苦的实验课程设计,本作者将其作出的实验结果及代码贴至CSDN中,供同学们学习参考。如有不足或描述不完善之处,敬请各位指出,欢迎各位的斧正! 掌握使用算术逻辑运算器 74LS181 进行算术运算、 逻辑运算的方法。 掌握基于“累加-移位”原理的串

    2024年02月04日
    浏览(50)
  • Python四则运算“计算器”——整数口算练习“小程序”

    设定练习题目数量、最大取值整数数,即时判定,答对鼓励答错打印正确结果。 【学习的细节是欢悦的历程】 Python 官网 :https://www.python.org/ Free :大咖免费“ 圣经 ”教程《 python 完全自学教程 》,不仅仅是基础那么简单…… 地址:https://lqpybook.readthedocs.io/   自学并不是

    2024年02月07日
    浏览(80)
  • 微信小程序计算器(含源码)、含js精确运算代码

    目录 一、引言与效果图  二、源码 0.目录结构: 1.xxxx.wxml文件  2.样式文件 (1)xxxx.less文件 (2)xxxx.wxss文件 (不会使用 less 的可以用这个) 3.xxxx.json文件 4.accurate.js 5.xxxx.js文件 三、结语        最近在做一个记账本小程序,其中需要用到计算器,但是在网上找的代码,用

    2024年02月01日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包