精华内容
下载资源
问答
  • 基于MATLABDCT变换在JPEG图像压缩中的应用,利用DCT变换进行压缩
  • 交互式原理与应用的实际操作。本文件采用Matlab的代码进行操作。实现了DCT变换。 中间Huffman编码略有精简
  • 介绍JPEG图像压缩算法,并在MATLAB数学分析工具环境下从实验角度出发,较为直观地探讨了DCT在JPEG图像压缩中的应用。仿真实验表明,用MATLAB来实现离散余弦变换的图像压缩,具有方法简单、速度快、误差小的优点,...
  • MATLAB在数字水印中的应用.pdf MATLAB在数字水印技术研究的应用.pdf 一个面像识别系统的实现.pdf 一种JPEG图像边缘检测算法.pdf 一种人脸识别的新方法.pdf 一种可抵抗MP3压缩的音频水印算法.pdf 一种基于DCT变换的...
  • dct变换matlab程序

    2013-06-27 14:06:55
    信息压缩课程设计里的dct和idct在图像压缩里的应用matlab程序
  • 数字图像处理实验报告 DCT和 DWT 的 MATLAB仿真 实验目的 学习 DCT变换基本原理 掌握 DCT变换的特性 理解 DCT变换在图像图理中的应用 学习 DWT变换基本原理 掌握 DWT变换的特性 理解 DWT变换在图像图理中的应用 1 ...
  • 多媒体技术原理应用MATLAB的DCT变化代码示例
  • 大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣资源,或者一起煮酒言欢。...直接序列扩频技术是应用最广一种扩频技术...
    1fcc8a7df6e349746dec72f52c10ead4.gif大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。

    今天给大侠带来基于FPGA的扩频系统设计,由于篇幅较长,分三篇。今天带来第一篇,下篇话不多说,上货。

    导读 

    在无线通信系统中,普遍使用扩频通信技术,因此扩频技术对通信系统具有重要的现实意义。直接序列扩频技术是应用最广的一种扩频技术,FPGA具备高速度的并行性特点在无线通信系统中的优势日益增强,利用FPGA实现直接序列扩频技术,可增大传输速率,可以使扩频技术有更好的发展与应用。

    本篇利用本原多项式产生伪随机序列用作扩频,通过同步模块对扩频后的信号进行捕获,通过直接序列解扩模块进行解扩。本给出了编解码、扩频解扩、同步的整体方案,使用Quartus实现功能,并结合Matlab和ModelSim对模块进行调试和测试,实现扩频通信模块的搭建仿真,验证其设计的正确性。首先概述了方案设计与论证、整体方案的设计、各个模块的设计、个别模块的调试与各个模块的仿真验证。本主要实现的模块有:汉明编码模块、直接序列扩频模块、量化器模块、同步模块、直接序列解扩模块和汉明译码模块。各位大侠可依据自己的需要进行阅读,参考学习。

    第三篇内容摘要:本篇会介绍分析调试,包括汉明码解码模块调试、直接序列扩频模块调试、同步模块调试、整体设计资源占用率、整体设计RTL设计图,还会介绍系统测试,包括汉明编码模块测试、直接序列扩频模块测试、量化器模块测试、同步模块测试、直接序列解扩模块测试、汉明译码模块测试、系统整体测试相关内容

    四、分析调试

    4.1 汉明编解码模块调试

    首先利用Matlab该模块进行调试,利用随机函数生成10个随机数,通过74汉明码编码函数对10个随机函数进行编码,随机数分别为4’h0、4’hb、4’h6、4’h1、4’h3、4’h9、4’h7、4’h9、4’h7和4’hd,编码后分别为7’h00、7’h4b、7’h46、7’h51、7’h23、7’h39、7’h17、7’h39、7’h17和7’h0d。具体如图4.1所示,对应Matlab代码详见附录A。

    dccd9c0bf79341011ee99530338413fd.png

    图4.1  汉明码编码Matlab仿真图

    利用Matlab的随机函数生成10个随机数,通过74汉明码编码函数对10个随机函数进行编码,编码后引入噪声如图4.2所示:

    e234ec3883027d7b710789f98ccb6723.png

    图4.2  编码后与加入噪声后对比图

    通过译码函数进行译码,如下图4.3所示:

    8ef58f59a9ca74f92279fe2246407003.png

    图4.3  编码前与译码后对比图

    根据图4.3可知,当发生一位码值错误时,汉明译码模块可以正确纠错;当发生一位以上码值错误时,汉明译码模块不能正确纠错,导致译码错误。利用Matlab可知汉明译码模块具有译码能力和一位码值的纠错能力。

    利用Verilog对汉明码编码模块和汉明译码模块进行编写,然后一同进行调试,在两个模块中间加一噪声模块,保证编码后数据任意一位发生错误,通过译码模块后,判断是否能够进行正确纠错,编码前数据与编码后的数据是否一致,判断两个模块的正确性,调试模型如图4.4所示:

    b1b40a0ad609dd1682cf06b571c195dc.png

    图4.4  断言调试模型

    ModelSim仿真波形截图如图4.5所示:

    d5ad236ba9fa9b03aabc2096acfc1b8a.png

    图4.5  汉明编解码模块仿真波形图

    利用断言的仿真方式打印报告如图4.6所示,通过确认编解码前后数据一致,也证明汉明编码模块和汉明译码模块正确性。

    9626a71d77eb4c22ba35d5382d62dff7.png

    图4.6  打印结果图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    4.2 直接序列扩频模块调试

    利用Matlab对该模块进行调试,利用Matlab伪随机函数生成伪随机数,通过设置初始值来与3.4.2节表3.2的结果进行对比,通过对比可以确定生成伪随机序列满足要求,为采用Verilog设计打好坚实的基础。如图4.7为Matlab生成的伪随机数,对应Matlab代码详见附录A。

    76acf5bdeec32da4eee459d1887486ae.png

    图4.7  Matlab生成伪随机数图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    4.3 同步模块调试

    在进行同步调试时出现对不齐同步头的问题,例如计算所延时时间应为29个系统时钟周期,即计数器仅需要延时29个时钟周期,因为计数器是从“0”开始进行计数,当计数值等于延时时间-1时,模块可以进行同步头解扩处理,由于没有对齐同步头,导致利用最小二乘法计算结果均大于预设阈值,系统无法进行下去。仿真波形截图如图4.8所示:

    7017025dcf553e031013fc31ad8fa146.png

    图4.8  同步错误情况仿真波形图

    根据仿真波形结合设计代码最终找到原因,由于同步模块对延时时间信号进行捕获也需要一个系统时钟周期,所以计数器的计数值应该等于延时时间-2,模块才可以进行同步头解扩处理,仿真波形截图如图4.9所示:

    9c7e69d4a332da05cc7ca695636f218f.png

    图4.9  同步修改正确仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    4.4 整体设计资源占用率

    在设计完成后,在如图4.10所示,该整体设计共使用3735个组合逻辑,占5%;使用1782个寄存器,占3%;使用39个I/O引脚,占6%;使用5888个存储器,约占1%;使用2个9bit嵌入式硬件乘法器,约占1%。

    845f466ad374229b4316a2e46aedc062.png

    图4.10  FPGA资源占用率

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    4.5 整体设计RTL视图

    由于例化的原因导致与整体设计框图不一致,因为例化对其整体设计功能无影响。所以设计整体RTL视图如图4.11所示:

    30e7c068258fb4ee1b2873e88791860a.png

    图4.11  设计整体RTL图

    79d36aca8c4144408ccdeead05236134.gif

    五、系统测试

    对整体系统设计进行测试,通过发送端到接收端的各个模块逐级进行测试,确保每个环节的正确性。

    5.1 汉明编码模块模块测试

    利用Verilog进行汉明码编码模块进行编写。在testbench测试文件总输入数据初始化为8’h55,通过时钟上升沿到来进行取反,所以数据依次为8’h55、8’haa、8’h55…8’haa等,接口采用同步fifo进行数据缓冲,如图5.1所示,在测试文件中通过判断t_full信号高有效来判断fifo是否为满状态,若不是满状态,则置写操作的使能信号t_wrreq高电平有效,对fifo进行写操作,否则不进行写操作。汉明码编码模块通过判断h_empty信号来判断fifo是否为空状态,若不为空,则置读操作使能信号h_rdreq高电平有效对fifo进行读操作,否则不进行读操作。

    c09d8d74d60decfaa9e254490798919b.png

    图5.1  fifo接口图

    通过汉明码编码模块对数据进行汉明码编码,如图5.2所示,信号ha_data为对应编码结果。4’h5编码为7’h2d,4’ha编码为7’h52,如图5.2表明,汉明编码模块能够正确编码。

    49c0b6d141e53ffab0bd26a6897d177e.png

    图5.2  汉明码编码模块ModelSim仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.2 直接序列扩频模块测试

    利用Verilog进行伪随机数模块编写,初始值为5’b00001,生成序列为如图5.3所示。信号m_bit为伪随机数,在进行编码数据信号进行扩频之前,应将数据信息加上帧头14’b11111111111110,信号m_data为汉明编码模块编码后的7bits数据信息,信号s_bit为帧头或编码数据信息并串转换后的信号,信号bc控制信号s_bit哪个数据位于信号m_bit相异或,得到的结果为输出信号q_data,从而实现直接序列扩频的功能。如图5.3表明,直接序列扩频模块能够正确完成扩频。

    33cf0852b6d1e2bb3ad6e5ec837f2ba6.png

    1220b68b3676517490103eeee34cd597.png

    图5.3  直接序列扩频模块ModelSim仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.3 量化器模块测试

    量化器模块将单比特的信号变为8bits有符号数,仿真波形截图如图5.4所示,可以确定量化器模块能够正确进行对信号量化。

    66c691dfa3007fb8fe5501e5e42463a3.png

    图5.4  量化器模块ModelSim仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.4 同步模块测试

    为了模拟实际传输过程,扩频信号再进入同步模块前引入±46的噪声,实际输入值信号line如图5.5所示:

    793acb3046476ced12b3097172d1fe49.png

    图5.5  加入噪声后ModelSim仿真波形图

    利用最小二乘法对输入信号与31个模板进行计算,得到小于阈值的唯一的延时数据信号xx如图5.6所示,模板2满足要求,信号xx计算值为29,因此要进行29拍解扩时钟周期的延时,来对齐同步头。

    17709595181dfc88b73b99f24cd292d9.png

    92bb063a90a7d94ca82ab73378127eae.png

    21e88be1b10cbdef74231cf7a81cedac.png

    图5.6  计算延时ModelSim仿真波形图

    通过延时达到对齐同步头的目的,对齐使能信号en_m为高电平,说明已对齐。如图5.7所示:

    c655f0052be9072cc8f54ae1403ebfd0.png

    图5.7  同步头对齐ModelSim仿真波形图

    对齐后将数据信号每31bits与模板“0”模板“1”进行最小二乘法计算,如图5.8所示:

    c8bb8725275f5b02a6071927cb7767b1.png

    图5.8  同步头解扩ModelSim仿真波形图

    信号data_tm为判断出的信号数据,当检测到同步头最后一位的“0”数据信息后,说明同步头已结束,同步功能已实现。如图5.9所示,同步模块能够正确实现同步。

    21d9a4cacfa8c7a172e7e53f4e10b370.png

    图5.9  同步头识别ModelSim仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.5 直接序列解扩模块测试

    当检测到最后一位为“0”后,进入数据信号解扩过程,与同步头解扩相类似,只是把解扩后的数据利用计数器的计数值,写到寄存器对应的位置,同时进行串并转换功能,信号bc为计数器,信号hdata_reg1为串并转换后存储数据的寄存器。如图5.10所示,直接序列解扩模块能够正确实现解扩。

    45449f19beda27ac3ad73045d8e9e0ff.png

    63f245d89c279d682b8dd5fcaca9629e.png

    图5.10  数据信息解扩ModelSim仿真波形图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.6 汉明译码模块测试

    利用Verilog对汉明译码模块进行编写。通过直接序列解扩模块后的数据经过汉明译码模块后,如图5.11所示:

    08dc96c7e2ce4f72814bfdef7ed2b4f3.png

    图5.11  汉明译码ModelSim仿真波形图

    信号data_reg被译码正确后通过对fifo的满标志信号H_full高电平进行判断,若为高电平则不进行写操作,若为低电平则将fifo的写使能信号置高进行写操作,将译码后的数据写入fifo中。如图5.12所示,汉明译码模块能够对数据进行正确译码。

    0eeea191fcc640b300fed14f37a2857b.png

    图5.12  数据输出端口仿真截图

    ce00d52cb9af4a7c5368c0cd4fb4eedf.gif

    5.7 系统整体测试

    通过打印信息确认,原始数据与译码后的数据一致,能够确认系统整体设计正确,如图5.13所示:

    e0dba9e9fbf5680cd571667a7cccb136.png

    图5.13  打印结果截图

    引用2.1节设计要求,总结系统整体设计完成对应功能情况,如表5.1所示:

    表5.1  系统功能测试表

    7c589a7e3aa906892f80b8f24b972b87.png

    结  论

    直接序列扩频是主流的扩频通信之一,有着许多重要特点与优点,本篇利用FPGA的处理速度和并行运行等特点,设计完成了一个基于FPGA扩频模块设计。在利用Quartus II、Matlab和ModelSim对直接序列扩频模块进行了仿真分析。利用伪随机序列进行扩频,是扩频模块获得高抗噪声性能和抗干扰性能的关键。

    本文首先对直接序列扩频模块一般原理进行介绍,然后重点分析直接序列扩频解扩,合理分配功能模块、准确掌握各个模块之间的控制和被控制的关系,以及整体时序关系。通过从接口fifo读取数据后,采用汉明编码模块,完成了对数据的编码,在完成编码后加入同步头,为同步做准备。利用本原多项式产生伪随机数,伪随机数与编码后的数据进行异或处理,已达到扩频的目的,扩频后的数据进行量化且引入噪声送入同步模块同步模块利用31个伪随机数的模板,采用最小二乘法对数据进行计算,计算值小于预定阈值,则该数据对应的信息为接收端需要进行延拍的个数,对齐后利用2个伪随机数的模板对数据进行“0”和“1”的判断,当同步头数据值出现“0”后,代表下一位开始为数据信息,直接序列解扩模块开始进行解扩处理,和同步模块同理,将数据与2个伪随机进行最小二乘法的计算,从而达到解扩的目的。解扩后的数据通过汉明译码模块进行译码后写入接口fifo,再通过fifo输出。经过验证该整体模块达到扩频的目的,提高了抗噪声的能力,各个模块能够正确完成对应功能。

    附录部分源代码

    伪随机数Matlab代码:

    polynomial=[1 0 0 1 0 1];reg=[0 0 0 0 1];grade=length(polynomial)-1;PN_Length=(2^grade-1); pn=zeros(1,PN_Length);n=0; c=zeros(1,grade);for i=grade:-1:1    if polynomial(i)==1        n=n+1;        c(n)=grade+1-i;    endend  q=0; for i=1:PN_Length    p(i)=reg(1)    m=reg(grade+1-c(1));    for q=2:grade        if (c(q)>0) & (reg(grade+1-c(q))==1)            m=~m;        end    end    for q=1:(grade-1)        reg(q)=reg(q+1);    end    reg(5)=m;end

    汉明码编码译码Matlab代码:

    k=4;n=7;msg=randint(10,4,2)code=encode(msg,n,k)code_noise=rem(code+rand(10,7)>0.95,2)rcv=decode(code_noise,n,k)disp(['Error rate in the received code:' num2str(symerr(code,code_noise)/length(code))])disp(['Error rate after decode:' num2str(symerr(msg,rcv)/length(msg))])

    汉明码编码Verilog代码:

    module hamming74(clk_10, rst_n, hi_data, ha_data, hm_sel);  input clk_10;  input rst_n;  input [7:0] hi_data;  output reg [6:0] ha_data;  input hm_sel;    wire [3:0] hm_data;  wire q0,q1,q2;    assign hm_data = hm_sel ? hi_data[7:4] : hi_data[3:0];    always @ (posedge clk_10)  begin    if(!rst_n)      begin        ha_data <= 0;      end    else       begin        ha_data[6] <= hm_data[3];        ha_data[5] <= hm_data[2];        ha_data[4] <= hm_data[1];        ha_data[3] <= q2;        ha_data[2] <= hm_data[0];        ha_data[1] <= q1;        ha_data[0] <= q0;      end  end  assign  q0 = hm_data[0] ^ hm_data[1] ^ hm_data[3];  assign  q1 = hm_data[0] ^ hm_data[2] ^ hm_data[3];  assign  q2 = hm_data[1] ^ hm_data[2] ^ hm_data[3];endmodule

    伪随机数产生Verilog代码:

    module m_generator(clk_10, rst_n, m_bit);  input clk_10;  input rst_n;  output m_bit;    reg [4:0] q;  parameter KEY = 5'b00001;  always @ (posedge clk_10)  begin    if(!rst_n)      begin        q <= KEY;//        q <= 0;      end    else  begin        q[0] <= q[1];        q[1] <= q[2];        q[2] <= q[3];        q[3] <= q[4];        q[4] <= q[3] ^ q[0];      end  end    assign m_bit = q[0];  endmodule

    伪随机序列与数据信息异或处理Verilog代码:

    module me_xor(clk, rst_n, s_bit, m_bit, q_data);  input clk, rst_n;  input s_bit, m_bit;  output  reg q_data;  always @ (posedge clk)  begin    if (!rst_n)      q_data <= 0;    else      q_data <= s_bit ^ m_bit;  endendmodule

    量化器模块Verilog代码:

    module quantizer(clk, rst_n, qdata, line_out);  input clk, rst_n;  input qdata;  output reg signed [7:0] line_out;    always @ (posedge clk)  begin    if (!rst_n)      line_out <= 0;    else      if (qdata)        line_out <= 63;      else        line_out <= -64;  endendmodule

    最小二乘法Verilog代码:

    module m_leastsquare(clk_10, rst_n, line, distance);  input clk_10, rst_n;  input signed [7:0] line;  output reg signed [21:0] distance;  parameter KEY = 5'b00001;  wire m;  reg [4:0] count;  reg signed [21:0] int_distance;    always @ (posedge clk_10)  begin    if (!rst_n || count >= 5'd30)      count <= 0;    else       count <= count + 5'd1;  end  m_generator #(.KEY(KEY)) u_mg(.clk_10(clk_10), .rst_n(rst_n), .m_bit(m));   always @ (posedge clk_10)  begin    if (!rst_n)      begin        int_distance <= 0;        distance <= 0;      end    else      if (count < 5'd30)        if (!m)          int_distance <= int_distance + (line - 63) * (line - 63);        else          int_distance <= int_distance + (line + 64) * (line + 64);      else        begin          int_distance <= 0;          if (!m)            distance <= int_distance +  (line - 63) * (line - 63);          else            distance <= int_distance +  (line + 64) * (line + 64);        end  endendmodule

    同步模块Verilog部分代码:

    module test_mdecoder_ls(clk_10, rst_n, line, xx);   input clk_10, rst_n;  input signed [7:0] line;  output reg [5:0] xx;  wire signed [21:0] distance [30:0];  wire [30:0] xx_reg;  integer i; m_leastsquare #(.KEY(5'h01)) u0(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[0]));  m_leastsquare #(.KEY(5'h10)) u1(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[1]));  m_leastsquare #(.KEY(5'h08)) u2(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[2]));  m_leastsquare #(.KEY(5'h14)) u3(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[3]));  m_leastsquare #(.KEY(5'h0A)) u4(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[4]));  m_leastsquare #(.KEY(5'h15)) u5(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[5]));  m_leastsquare #(.KEY(5'h1A)) u6(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[6]));  m_leastsquare #(.KEY(5'h1D)) u7(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[7]));  m_leastsquare #(.KEY(5'h0E)) u8(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[8]));  m_leastsquare #(.KEY(5'h17)) u9(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[9]));  m_leastsquare #(.KEY(5'h1B)) u10(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[10]));  m_leastsquare #(.KEY(5'h0D)) u11(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[11]));  m_leastsquare #(.KEY(5'h06)) u12(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[12]));  m_leastsquare #(.KEY(5'h03)) u13(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[13]));  m_leastsquare #(.KEY(5'h11)) u14(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[14]));  m_leastsquare #(.KEY(5'h18)) u15(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[15]));  m_leastsquare #(.KEY(5'h1C)) u16(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[16]));  m_leastsquare #(.KEY(5'h1E)) u17(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[17]));  m_leastsquare #(.KEY(5'h1F)) u18(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[18]));  m_leastsquare #(.KEY(5'h0F)) u19(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[19]));  m_leastsquare #(.KEY(5'h07)) u20(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[20]));  m_leastsquare #(.KEY(5'h13)) u21(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[21]));  m_leastsquare #(.KEY(5'h19)) u22(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[22]));  m_leastsquare #(.KEY(5'h0C)) u23(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[23]));  m_leastsquare #(.KEY(5'h16)) u24(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[24]));  m_leastsquare #(.KEY(5'h0B)) u25(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[25]));  m_leastsquare #(.KEY(5'h05)) u26(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[26]));  m_leastsquare #(.KEY(5'h12)) u27(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[27]));  m_leastsquare #(.KEY(5'h09)) u28(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[28]));  m_leastsquare #(.KEY(5'h04)) u29(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[29]));  m_leastsquare #(.KEY(5'h02)) u30(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[30]));  assign xx_reg[0] = (distance[0]>0 && distance[0]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[1] = (distance[1]>0 && distance[1]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[2] = (distance[2]>0 && distance[2]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[3] = (distance[3]>0 && distance[3]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[4] = (distance[4]>0 && distance[4]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[5] = (distance[5]>0 && distance[5]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[6] = (distance[6]>0 && distance[6]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[7] = (distance[7]>0 && distance[7]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[8] = (distance[8]>0 && distance[8]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[9] = (distance[9]>0 && distance[9]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[10] = (distance[10]>0 && distance[10]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[11] = (distance[11]>0 && distance[11]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[12] = (distance[12]>0 && distance[12]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[13] = (distance[13]>0 && distance[13]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[14] = (distance[14]>0 && distance[14]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[15] = (distance[15]>0 && distance[15]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[16] = (distance[16]>0 && distance[16]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[17] = (distance[17]>0 && distance[17]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[18] = (distance[18]>0 && distance[18]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[19] = (distance[19]>0 && distance[19]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[20] = (distance[20]>0 && distance[20]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[21] = (distance[21]>0 && distance[21]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[22] = (distance[22]>0 && distance[22]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[23] = (distance[23]>0 && distance[23]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[24] = (distance[24]>0 && distance[24]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[25] = (distance[25]>0 && distance[25]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[26] = (distance[26]>0 && distance[26]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[27] = (distance[27]>0 && distance[27]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[28] = (distance[28]>0 && distance[28]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[29] = (distance[29]>0 && distance[29]< 19'd50000)? 1'b1:1'b0;  assign xx_reg[30] = (distance[30]>0 && distance[30]< 19'd50000)? 1'b1:1'b0;  always @ (*)  begin    if(!rst_n)      begin        xx <= 6'd32;      end    else      begin        for(i=0;i<30;i=i+1)          if(xx_reg[i]==1)            xx <= 31-i;      end  end  endmodule

    直接序列解扩模块部分Verilog代码:

    module test_mdecoder_2s(clk_10, rst_n, line, data_tm, en_m); //测试,最小二乘法    input clk_10, rst_n;  input signed [7:0] line;  output data_tm;  input en_m;  wire signed [30:0] distance [1:0];  wire [30:0] reg1 , reg0 ;    m_leastsquare_nl #(.KEY(5'h01)) u32(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[0]), .en_m(en_m));//0  m_leastsquare_no #(.KEY(5'h01)) u33(.clk_10(clk_10), .rst_n(rst_n), .line(line), .distance(distance[1]), .en_m(en_m));//1  assign data_tm = ( distance[1]>distance[0])? 1'b0:1'b1;//比较俩数据大小endmodule

    汉明码译码Verilog代码:

    module deserialzer(clk_10, rst_n, data_tm, en_m, hdata, h_full, h_wrreq);/*    串转并模块加汉明译码模块    */  input clk_10;  input rst_n;  input data_tm;  input en_m;  output reg [7:0] hdata;  input h_full;  output reg h_wrreq;  reg [5:0] count;  reg [2:0] bc;  reg [6:0] hdata_reg1;  reg start;  wire c0,c1,c2;  reg lh;  reg [3:0] data_reg;  /*  用来计算数据位  */  always @ (posedge clk_10)  begin    if(!rst_n)      begin        count <= 0;        bc <= 0;      end      else if(en_m && count < 30)      count <= count + 6'd1;    else      begin        if(count == 6'd30 && bc < 3'd6)          bc <= bc + 3'd1;        else          bc <= 0;      count <= 0;      end  end    /*  用来缓冲数据  */  always @ (posedge clk_10)  begin    hdata_reg1[bc] <= data_tm;  end    /*  用来控制数据写在高低位,同时控制发送写使能  */  always @ (posedge clk_10)  begin    if(!rst_n)      begin        h_wrreq <= 0;        lh <= 1;      end    else if(!h_full && bc == 3'd6 && count == 6'd30)        begin          lh <= ~lh;           if(lh)            h_wrreq <= 0;          else            h_wrreq <= 1;        end    else      h_wrreq <= 0;  end  /*  用来控制译码的使能  */  always @ (posedge clk_10)  begin    if(!rst_n)      begin        start <= 0;              end    else if(!h_full && bc == 3'd6 && count == 6'd29)        begin          start <= 1;        end    else      start <= 0;  end  assign c0 = hdata_reg1[0] ^ hdata_reg1[2] ^ hdata_reg1[4] ^ hdata_reg1[6];  assign c1 = hdata_reg1[1] ^ hdata_reg1[2] ^ hdata_reg1[5] ^ hdata_reg1[6];  assign c2 = hdata_reg1[3] ^ hdata_reg1[4] ^ hdata_reg1[5] ^ hdata_reg1[6];  /*  用来高低位数据赋值  */  always @ (*)  begin    if(lh)      hdata[7:4] <= data_reg;    else      hdata[3:0] <= data_reg;  end      always @ (posedge clk_10)  begin    if(!rst_n)      begin        data_reg <= 0;      end    else if (start)        case({c2,c1,c0})      3'b000:begin//没错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b001:begin//校验位hc_in[0]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b010:begin//校验位hc_in[1]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b011:begin//校验位hc_in[0]、hc_in[1]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= ~hdata_reg1[2];      end        3'b100:begin//校验位hc_in[2]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b101:begin//校验位hc_in[0]、hc_in[2]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= ~hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b110:begin//校验位hc_in[1]、hc_in[2]有错误        data_reg[3] <= hdata_reg1[6];        data_reg[2] <= ~hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end        3'b111:begin//校验位hc_in[1]、hc_in[2]、hc_in[0]有错误        data_reg[3] <= ~hdata_reg1[6];        data_reg[2] <= hdata_reg1[5];        data_reg[1] <= hdata_reg1[4];        data_reg[0] <= hdata_reg1[2];      end      endcase  end      endmodule

    79d36aca8c4144408ccdeead05236134.gif

    本篇到此结束,各位大侠,有缘再见!END后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!e5c979b31a2508340816ab93ad23edff.png精彩推荐《冈萨雷斯数字图像处理MATLAB版》中文版(第二版) 电子版今日说“法”:FPGA芯片如何选型?FPGA Xilinx Zynq 系列 PART C 操作系统 & 系统集成(后四篇)汇总篇  暨总汇总篇“FPGA产品设计与研发 ” 零基础入门及就业31dd59b97ead3aff6af75b21a69dafc2.gif

    c971adbc1c3e8a05b6b625c19b0a0bf3.png

    FPGA技术江湖广发江湖帖

    无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,QQ微信双选,FPGA技术江湖打造最纯净最专业的技术交流学习平台。

    FPGA技术江湖微信交流群

    82fe97919b9e6c5eda1cbf41994deb46.png

    加群主微信,备注职业+方向+名字进群

    FPGA技术江湖QQ交流群

    55e08d13373e12fcede17b6082d07065.png

    备注地区+职业+方向+名字进群

    855b6ef48268faab146e2c70567cb21f.png

    展开全文
  • MATLAB 产品族可以用来进行以下各种工作 数值分析 数值和符号计算 工程与科学绘图 控制系统的设计与仿真 数字图像处理技术 数字信号处理技术 通讯系统设计与仿真 \o "查看图片" MATLAB在通讯系统设计与仿真的应用 ...
  • 本论文主要结合小波变换的基本概念和基本原理,详细讨论小波在图像处理领域的应用,并结合MATLAB程序设计语言来说明其应用。
  • 随着数字水印技术的发展,数字水印的应用领域也得到了扩展,数字水印的基本应用领域是版权保护、隐藏标识、认证和安全不可见通信。 当数字水印应用于版权保护时,潜在的应用市场在于电子商务、在线或离线地分发...
  • 原创 ​小周 明德扬FPGA科教 实验简述:本实验目的是实现汉明纠错码编码和解码一、...由于汉明编码简单,他们被广泛应用于内存。与其他错误校验码类似,汉明码也利用了奇偶校验位概念,通过在数据位后面增加...

    原创 ​小周 明德扬FPGA科教

    实验简述:

    本实验的目的是实现汉明纠错码的编码和解码

    一、汉明码简介

    汉明码,是在电信领域的一种线性调试码,以发明者理查德 卫斯理 汉明的名字命名。汉明码在传输的消息流中插入验证码,当计算机存储或移动数据时,可能会产生数据位错误,以侦测并更正单一比特错误。由于汉明编码简单,他们被广泛应用于内存。

    与其他的错误校验码类似,汉明码也利用了奇偶校验位的概念,通过在数据位后面增加一些比特,可以验证数据的有效性。利用一个以上的校验位,汉明码不仅可以检验数据是否有效,还能在数据出错的情况下指明错误的位置。(汉明码可以检测两位错误,纠正一位错误)。

    二、编码规则

    理解汉明码首先要理解奇偶校验,奇校验就是在一串编码里增加一位校验位使这一串编码里的1的个数位奇数。偶校验同理,使编码里1的个数为偶数。

    汉明码的编码位数n与纠错码的位数k的关系:2^k >= n+k+1。这里给出常用的n和k的值:

    d311941ef91c10cbc9470d35aa830483.png

    我们将纠错码加入到相应的编码里,纠错码的位置必须在2^n位置上。以10101100为例进行编码。这个序列为8位,需要4个纠错码。

    我们先将序列从1到8编号

    f637019c9827d139bba01be88f331619.png

    然后将纠错码(p1,p2,p3,p4)加到这个序列里 的2^n的位置,并用二进制重新编号

    b649d960e7bc3ad5abd251b60d607d33.png

    然后我们要求出p1,p2,p3,p4的值,先将上面的序列分组编号为xxx1的分为一组,xx1x的分为一组,x1xx的分为一组,1xxx的分为一组:

    xxx1:p1,1,0,0,1,0

    xx1x:p2,1,1,0,1,0

    x1xx:p3,0,1,0,0

    1xxx:p4,1,1,0,0

    我们采用偶校验,所以p1 = 1,p2 = 1, p3 = 1, p4 = 0。这样我们就得到了10101100的汉明码111101001100。

    那么汉明码是如何来纠错的呢?

    我们将p4,p3,p2,p1按这个顺序排列得到0111,这个就是出错的位数,由于是二进制传输,所以就将相应位取反就可以得到正确的序列了。

    三、FPGA实现

    对于p1,p2,p3,p4的计算在用fpga实现时只需进行按位异或就行。输入数据位8位,需要四个纠错位。

    1、顶层架构

    23dc18873ab22f5e22bec931c834e21a.png

    信号说明:

    1522425c23efafb5eb4d09061a21d09f.png

    顶层代码:

    module humming_coder12_8(clk, rst_n, data, q, rden, wren, hc_out, hc_in);

    input clk, rst_n;

    input [7:0] data;

    output [7:0] q;

    input rden, wren;

    output [11:0] hc_out;

    input [11:0] hc_in;

    hamming_encoder HE(

    .clk(clk),

    .rst_n(rst_n),

    .wren(wren),

    .data(data),

    .hc_out(hc_out)

    );

    hamming_decoder HD(

    .clk(clk),

    .rst_n(rst_n),

    .rden(rden),

    .q(q),

    .hc_in(hc_in)

    );

    endmodule

    2、 编码模块

    编码模块只需将分组之后的每一组数据(不包括p)按位异或后赋值给p就可以。

    编码模块代码:

    module hamming_encoder(clk, rst_n, wren, data, hc_out);

    input clk, rst_n;

    input wren;

    input [7:0] data;

    output reg [11:0] hc_out;

    wire p0, p1, p2, p3;

    assign p0 = data[6] ^ data[4] ^ data[3] ^ data[1] ^ data[0];

    assign p1 = data[6] ^ data[5] ^ data[3] ^ data[2] ^ data[0];

    assign p2 = data[7] ^ data[3] ^ data[2] ^ data[1];

    assign p3 = data[7] ^ data[6] ^ data[5] ^ data[4];

    always @ (posedge clk or negedge rst_n)begin

    if(!rst_n)

    hc_out <= 0;

    else if(wren)

    hc_out <= {data[7:4], p3, data[3:1],p2, data[0], p1, p0};

    else

    hc_out <= 0;

    end

    endmodule

    61ccea700e3fa68b3c48cae4679fbc8f.png

    3、解码模块

    解码模块只需判断哪位出错,然后取反,并将纠错位删除即可。

    解码模块代码:

    module hamming_decoder(clk, rst_n, rden, q, hc_in);

    input clk, rst_n;

    input rden;

    output reg [7:0] q;

    input [11:0] hc_in;

    wire g0_error, g1_error, g2_error,g3_error;

    assign g0_error = hc_in[10] ^ hc_in[8] ^ hc_in[6] ^ hc_in[4] ^ hc_in[2] ^ hc_in[0];

    assign g1_error = hc_in[10] ^ hc_in[9] ^ hc_in[6] ^ hc_in[5] ^ hc_in[2] ^ hc_in[1];

    assign g2_error = hc_in[11] ^ hc_in[6] ^ hc_in[5] ^ hc_in[4] ^ hc_in[3];

    assign g3_error = hc_in[11] ^ hc_in[10] ^ hc_in[9] ^ hc_in[8] ^ hc_in[7];

    always @ (posedge clk or negedge rst_n)begin

    if(!rst_n)

    q <= 0;

    else if(rden)

    case ({g3_error, g2_error, g1_error, g0_error})

    4'b0000 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};

    4'b0001 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};

    4'b0010 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};

    4'b0011 : q <= {hc_in[11:8], hc_in[6:4], ~hc_in[2]};

    4'b0100 : q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};

    4'b0101 : q <= {hc_in[11:8], hc_in[6:5], ~hc_in[4], hc_in[2]};

    4'b0110 : q <= {hc_in[11:8], hc_in[6], ~hc_in[5], hc_in[4], hc_in[2]};

    4'b0111 : q <= {hc_in[11:8], ~hc_in[6], hc_in[5], hc_in[4], hc_in[2]};

    4'b1000 : q <= {hc_in[11:8], hc_in[6], hc_in[5], hc_in[4], hc_in[2]};

    4'b1001 : q <= {hc_in[11:9], ~hc_in[8], hc_in[6:4], hc_in[2]};

    4'b1010 : q <= {hc_in[11:10], ~hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};

    4'b1011 : q <= {hc_in[11], ~hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};

    4'b1100 : q <= {~hc_in[11], hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};

    default : q <= 0;

    endcase

    else

    q <= 0;

    end

    endmodule

    四、仿真验证

    我们用$random系统函数产生的随机数来作为编码模块数据,用$random系统函数产生的随机数来将hc_out的哪一位取反来模拟噪声。并判断输入的数据和输出的数据是否相等,以验证纠错功能。用$display和$error系统函数来生成报告。

    测试文件代码:

    module humming_coder12_8_tb;

    reg clk, rst_n;

    reg [7:0] data;

    reg rden, wren;

    wire [11:0] hc_out;

    reg [11:0] hc_in;

    wire [7:0] q;

    reg [7:0] temp1, temp2;

    humming_coder12_8 DUT(

    .clk(clk),

    .rst_n(rst_n),

    .data(data),

    .wren(wren),

    .q(q),

    .rden(rden),

    .hc_out(hc_out),

    .hc_in(hc_in)

    );

    integer pn, i;

    initial begin

    pn = 0;

    hc_in = 0;

    forever begin

    @ (posedge clk)

    pn = {$random} %12;

    #1

    for (i=0; i<12; i=i+1) begin

    if (i!= pn)

    hc_in[i] = hc_out[i];

    else

    hc_in[i] = ~hc_out[i];

    end

    end

    end

    always @ (posedge clk)

    begin

    temp1 <= data;

    temp2 <= temp1;

    end

    always @ (*)

    begin

    if (wren) begin

    #1

    if (temp2 == q)

    $display("OK:time=%0t data=%0d q=%0d", $time, temp2, q);

    else

    $error("ERROR:time=%0t data=%0d q=%0d", $time, temp2, q);

    end

    end

    initial begin

    clk = 1;

    rst_n = 0;

    data = 0;

    rden = 0;

    wren = 0;

    #200

    @ (posedge clk)

    rst_n = 1;

    #200

    forever begin

    @ (posedge clk)

    wren = 1;

    data = {$random} % 9'b10000_0000;

    @ (posedge clk)

    wren = 1;

    data = {$random} % 9'b10000_0000;

    rden = 1;

    end

    end

    always #10 clk = ~clk;

    initial #5000 $stop;

    endmodule

    生成的报告,我们可以看到错误的数据可以被修改成原来正确的数据,证明我们的编码解码模块功能正确。

    b86e6be45c4326b61d855de255dadd54.png
    展开全文
  • 一、背景意义 随着数字技术和Internet网络发展,各种形式多媒体数字作品(图像、视频、音频等)纷纷以网络形式发表,然而数字作品便利...数字水印技术研究就是在这种应用要求下迅速发展起来。 数字水印(digi...

    一、背景意义

    随着数字技术和Internet网络的发展,各种形式的多媒体数字作品(图像、视频、音频等)纷纷以网络形式发表,然而数字作品的便利性和不安全性是并存的,它可以低成本、高速度地被复制和传播,而这些特性也容易被盗版者所利用。因而,采用多种手段对数字作品进行保护、对侵权者进行惩罚己经成为十分迫切的工作。数字水印技术的研究就是在这种应用要求下迅速发展起来的。 数字水印(digital watermarking)技术也称为数字指纹技术,它将具有特定意义的水印标记不可感知地嵌入到被保护的数字产品中,在产生版权纠纷时,通过相应的算法提取该水印,用以证明作者对该数字产品的所有权,并可作为鉴证、起诉非法侵权的证据。数字水印技术基本上应当满足隐蔽性、安全性、鲁棒性和水印容量等几个方面的要求。

    二、算法流程

    离散余弦dct和小波变换dwt的原理;、数字水印的流程步骤,即包括水印的嵌入,攻击,提取和评价指标是怎样的;、GUI界面的设计与制作;解决思路:、上网或者图书馆了解小波变换dwt和离散余弦dct算法原理及嵌入,攻击和提取以及评价鲁棒性指标的方法;、购买相关书籍,学习GUI界面的封装制作;

    三、GUI界面设计

    主要包括3个界面,一个主界面,主界面上面有2个按钮,调用dct和dwt算法的子界面

    四、运行视频

    展开全文
  • 代码来源:《数字图像处理高级应用》- 清华大学出版社 资源内容:1. Matlab代码,并带有中文注释 2. 测试图片
  • 该系统实现了字符编解码,同时可被应用于各种多媒体信息编解码。通过ModelSim仿真,Xilinx ISE实现后进行硬件实测,对计算精度、资源消耗、计算速度和功耗等进行分析。实验测试结果表明,所设计解码器能够正确...
    425525fe44a9763097bd087f320653a1.gif8b9f928d6413cf979db14de01bc38b41.png

    摘要: 针对传统编解码算法复杂度高、不易扩展等问题,对自编码神经网络前向传播算法和结构进行了研究,提出了一种以自编码神经网络为编解码算法,以FPGA为实现平台的低功耗高速解码器系统。该系统实现了字符的编解码,同时可被应用于各种多媒体信息的编解码。通过ModelSim仿真,Xilinx ISE实现后进行硬件实测,对计算精度、资源消耗、计算速度和功耗等进行分析。实验测试结果表明,所设计的解码器能够正确完成数据解码功能,算法简洁高效,扩展能力强,系统具有低功耗、速度快等特点,可广泛应用于各种低功耗、便携式产品。

    中文引用格式:周松江,李圣辰,刘明. 一种基于FPGA的低功耗高速解码器设计[J].电子技术应用,2018,44(4):27-32.

    英文引用格式:Zhou Songjiang,Li Shengchen,Liu Ming. A low power and high speed decoder design based on FPGA[J]. Application of Electronic Technique,2018,44(4):27-32.

    0 引言

    计算机处理多媒体或文字信息的基础是对相关信息进行编码和解码,以利于信息的传输、显示和保护[1]。面对巨大信息量的处理需求,快速高效的编解码系统能够有效提高信息处理能力。近年来,随着神经网络的发展和应用,利用神经网络进行数学函数回归的方案,为信息的编解码提供了简单有效的途径[2]。自编码神经网络是一种无监督的人工神经网络,其利用反向传播算法训练使得网络的输出值等于输入值,从而为输入数据学习到一种特征表示,广泛应用于图像压缩和数据降维等领域[3-4]。自编码神经网络输出等于输入的特点适合用于数据编码和解码,相比于传统的编解码方法,如熵编码[5],该算法更简洁高效,结构可扩展,实用性更强[3]

    而随着编解码器在一些低功耗、便携式产品中的应用,高速、高精度和低功耗已经成为编解码器的一种发展趋势。现场可编程门阵列(Field Programmable Gate Array,FPGA)是一种可编程逻辑器件,用户可通过硬件描述语言完成硬件电路设计。FPGA内部集成了具有高性能的数字信号处理器和大量存储资源,可以高效低成本地实现定点运算和数据存储,因此目前FPGA是一种理想的编解码器实现平台[5-6]。FPGA中各个硬件模块并行执行,可将计算量大的算法映射到FPGA中实现硬件加速。有学者尝试采用FPGA作为神经网络的实现平台,并取得了优异的性能,尤以速度和功耗突出[7-8]。综上所述,基于自编码神经网络,以FPGA为实现平台的编解码系统,具有灵活性高、高速、低功耗等特点,可广泛应用于各种低功耗、便携式应用中。

    本文通过分析自编码神经网络的结构和特点,提出了一种用于数据解码的硬件实现架构。根据网络计算过程中包含的运算和神经元间的并行性特点,结合FPGA高并行、低功耗和高速数据处理的优势,将自编码神经网络的解码部分映射到FPGA中。该架构具有速度快、功耗低等特点,除文中论述的文字信息解码外,该架构具备扩展到图像编解码的可能性。

    1 自编码神经网络

    人工神经网络是基于生物神经网络的基本原理,通过模拟人脑神经系统的结构和功能而建立的一个数学模型,该模型拥有以任意精度逼近一个离散值、实数值或者目标函数的功能[9-10]。自编码神经网络是一种无监督的人工神经网络,其采用反向传播算法,通过学习试图使得网络的输出值等于输入值,从而为输入数据学习到一种特征表示[3-4]

    自编码神经网络模型是一种对称结构,中间为隐含层,输入输出层神经元节点数相等且通过训练使得网络输出值和输入值相等。如图1所示为自编码神经网络的结构图,输入层和输出层含有m个神经元,隐含层含有n个神经元,输入层和隐含层下方的“+1”是偏置节点。自编码神经网络的输入层到隐含层构成编码器,隐含层到输出层构成解码器,对自编码神经网络的训练过程就是通过调整编码器和解码器中的权值和偏置,使其逼近一个恒等函数,从而使得网络输出值等于输入值,这样网络隐含层的输出数据为原始输入数据的另一种特征表示,即该数据经过自编码神经网络的解码器可以恢复原始的输入数据[11]

    d658061ad1dba25cab95bda8248a04c8.png

    在本文中,利用自编码神经网络的编码器对输入数据进行编码,所得到隐含层的输出数据称为原始数据的编码;该编码数据经过自编码神经网络的解码器实现数据解码,从而恢复原始输入数据。下面参照图1所示的自编码神经网络结构,介绍自编码神经网络的前向计算过程,首先计算隐含层n个神经元的输出如式(1):

    523d9f17d516030400d9f60cd52f615d.png

    输出层m个神经元的输出如式(2):

    98382144d48abaab3f59487dbd254204.png

    通过对网络前向计算过程式(1)和式(2)的分析可以看出:自编码神经网络对信息的处理为从输入层开始,经过隐含层直到输出层输出为止,每一层各个神经元之间的计算具有独立性和并行性;式(1)和式(2)的计算包括乘加运算和激励函数运算,且两者按照顺序依次进行。

    2 FPGA设计方案

    本章对基于FPGA的硬件解码系统的设计需求进行分析,介绍整个系统的硬件架构设计、系统工作原理,最后对设计中的网络计算模块进行详细介绍。

    2.1 系统分析

    本文在FPGA中设计实现图1所示自编码神经网络的解码器部分,从而实现数据解码功能。在软件端对自编码神经网络进行训练,得到网络模型后将对现今最通用的单字节编码ASCII码归一化后的数据输入至自编码神经网络的编码器以获得编码数据,最后将编码数据送至FPGA端实现数据解码以恢复原始输入的ASCII码。

    通过对自编码神经网络前向计算的分析,其计算过程中包括乘加运算和激励函数运算,网络每层中各个神经元之间的计算具有独立性和并行性。而对编码数据进行解码操作的过程中,要求所设计的硬件系统具有实时性特点。FPGA作为一个分布式并行处理系统,其内部包含大量逻辑单元和计算单元,且具有可编程、速度快、灵活性高、易配置、设计周期短等特点,因此本文选用FPGA作为所设计数据解码器的硬件实现平台。

    所设计的解码器为图1所示自编码神经网络的隐含层到输出层部分,其所包含的权值参数有n×m个,偏置参数有m个,n和m分别表示网络隐含层和输出层神经元的个数。由于实现解码功能仅需要网络的前向计算,因此网络的权值和偏置为固定值,所以在设计中可利用FPGA内部资源对网络权值和偏置进行存储并以固定值的形式参与网络运算。

    解码器一次完整的解码过程可简述为:输入数据→解码计算→输出结果。在实际应用中往往包含有多组编码数据,因此设计中将编码数据存储在外部存储器中以供FPGA读取。SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备,由于它具有体积小、数据传输快、可热插拔等优良特性,被广泛应用于便携式设备中[13]。因此本设计选择使用SD卡来存储编码数据。SD卡读操作为每次读取一个扇区的数据,而网络计算模块的输入数据的个数与图1所示隐含层神经元个数相同,两个数据量并不匹配。另外,SD卡读数据操作和网络计算为异步关系,因此本设计中加入FIFO模块,作为SD卡读数据模块和网络计算模块两个异步模块之间的数据缓存器,这样的设计也易于扩展到其他不同神经元数量的网络结构。

    另外,为了便于人为控制对多组编码数据进行解码,系统设计中利用按键来产生一次解码操作的起始信号。本设计是以ASCII码的编码和解码对系统进行测试,因此设计中采用专门显示字母、数字和符号等的工业字符型液晶LCD1602显示解码结果。最后为了增加FPGA硬件系统稳定性,减少系统时钟的抖动和倾斜,设计中增加混合模式时钟管理器(MMCM),用于在与输入时钟信号有设定的相位和频率关系的情况下,生成不同的时钟信号,该信号用于各个模块工作。

    2.2 硬件系统架构

    基于上述分析,所设计FPGA硬件系统结构如图2所示。系统外围模块包括存储编码数据的SD卡,产生差分时钟信号的晶振,产生复位信号和控制系统工作的按键,和显示网络计算结果的LCD1602显示器。FPGA内部包含三大模块,分别是:数据加载模块、数据处理模块和混合模式时钟管理器。

    83b8b9f7efd44ab62d64c15df9042aea.png

    设计中利用SD卡来存储编码数据,对SD卡的操作采用简单的命令/响应协议[13],全部命令由FPGA发起,SD卡接收到命令后返回响应数据。要读取SD卡中的数据,需要首先完成SD卡的初始化,该系统按照功能分别设计SD卡初始化模块和SD卡读数据模块,其符合FPGA模块化的设计原则。FIFO模块作为SD卡和网络计算模块之间的数据缓存器,同时又用于异步数据传输,因此在设计中采用独立的读时钟和写时钟,以用于异步操作。

    按键检测模块不断读取外部按键输出信号key_in的值,当检测到按键按下时该模块产生一个高脉冲信号,该信号将作为一次解码操作的起始信号。网络计算模块按照神经网络的计算方法对读入的数据进行计算。显示驱动模块设计中采用有限状态机的方式控制LCD1602的初始化和数据显示操作,该模块与网络计算模块之间有信号线连接,以实现将计算结果送至显示驱动模块,显示驱动模块控制LCD1602对计算结果进行显示。

    在图2所示的硬件架构图中,混合模式时钟管理器将外部时钟分频产生各个模块工作所需要的时钟信号,其通过两个时钟线分别与数据加载模块和数据处理模块连接,而数据加载模块和数据处理模块之间通过data_en、data和read_clk 3个信号连接。

    2.3 系统工作原理

    FPGA的特点是可以实现并行操作,在图2所示的系统架构图中,数据加载模块和数据处理模块以并行异步的方式工作,下面对其工作原理分别介绍。

    数据加载模块:系统上电后,数据加载模块首先控制SD卡初始化模块对SD卡进行初始化,其初始化操作包含有一系列的命令,在初始化完成后SD卡初始化模块输出初始化完成信号。由于SD卡中的编码数据是在PC端以FAT32文件系统的形式写入的,因此在对SD卡初始化完成后,数据加载模块控制SD卡读数据模块读取SD卡中的FAT32文件系统信息,获取编码数据的长度,即文件所包含的字节数,该数据将用于控制对编码数据的读取。最后,数据加载模块不断检测FIFO中缓存数据的数量,当数据的数量不足设定值时便控制SD卡读数据模块将SD卡中的编码数据读入FIFO中进行缓存。

    数据处理模块:当按键检测模块检测到外部按键被按下时会产生一个高脉冲信号,然后数据处理模块会通过data_en、data和read_clk 3个信号从FIFO中读取数据到网络计算模块进行计算,然后通过显示驱动模块控制将计算结果显示在外部的LCD1602上。数据加载模块和数据处理模块之间data_en、data和read_clk 3个信号的时序关系如图3所示,当data_en为高电平时,代表FIFO中存在有效的数据可以读取,此时每当read_clk信号的上升沿到达时,从data端口可以读取一个数据。

    49966d478125940a1047a8111c7fd286.png

    如图4所示为FPGA硬件系统工作流程图,其中SD卡读操作和网络计算之间为异步关系,系统中所加入的FIFO模块作为SD卡读数据模块和网络计算模块两个异步模块之间的数据缓存器。

    4ba04b31237224236adb8f1d51a16c3a.png

    2.4 网络计算模块设计

    网络计算模块是本设计中的核心模块,用于实现图1中的解码器,将编码数据和解码器部分的权值与偏置按式(2)进行乘加运算,并经过激励函数得到输出值。

    通过对网络前向计算分析可知其包括乘加运算和激励函数运算。由于本设计中自编码神经网络的输入是对ASCII码归一化后的数据,即原ASCII码值除以128后的值,因此在FPGA模块中激励函数的输出值需要扩大128倍才是真正的ASCII码值。由于128=27,在FPGA中乘操作可通过移位实现,因此对计算结果扩大128倍相当于将二进制格式的小数点右移7位。更进一步,直接截取小数点后7位即为计算结果扩大128倍后的ASCII码值。因此在网络计算模块将计算分为3部分:乘加运算、激励函数运算和截位运算,如图5所示为一个输出层神经元的计算结构示意图,输出层各个神经元按照图5所示的计算结构以并行、独立的方式进行计算。

    7b6f1ca6a816fa97de20cdf1ae92eacd.png

    模块中的乘加运算是将编码数据、解码器部分权值和偏置按照式(2)中激励函数内部的乘加运算规则进行计算。本设计输出层神经元的激励函数为hard_sigmoid函数[12],表达式为式(3):

    809164646b832de80efd6775c06cc2ce.png

    根据定义,hard_sigmoid函数为分段函数,且各段均为线性关系,其非常便于在FPGA系统中实现,即利用条件判断语句对输入进行判断并输出不同的值,如图6所示为hard_sigmoid函数硬件实现示意图。

    a1e80668a0ef978fee8d1bf6eb501192.png

    3 系统测试分析

    为了测试所设计自编码神经网络在FPGA平台上的实现,本文选择的网络结构为输入层、输出层含有4个神经元节点,隐含层含有8个神经元节点。所选择的应用背景为对ASCII码的编码和解码,其中软件端完成对ASCII码的编码,所得到的编码数据在FPGA端实现解码。

    本实验测试集由软件生成,软件环境下对ASCII码中非控制字符(码值为32~127,共96个)做归一化处理,然后按照随机组合的方式4个一组输入至所设计的自编码神经网络并获得隐含层的输出,将该输出作为FPGA的测试输入数据保存在SD卡中。所选择的FPGA硬件平台是Xilinx VC707 FPGA开发板,系统开发环境为Xilinx ISE 14.7,仿真环境为ModelSim SE 10.1c,如图7所示为硬件系统测试图。

    546c2e820f96b53fa6c82c900b731b18.png

    在图7所示的硬件系统测试图中,①为SD卡,②为LCD1602显示屏,③为控制按键。系统上电后,通过控制按键的按下操作不断从SD卡中读取数据,经过网络计算模块计算后将结果显示在LCD1602显示屏上,每次显示4个字符,如图7中LCD1602显示屏的第二行即为解码后的4个数据,对应于图1所示神经网络的4个输出。

    3.1 网络计算结果分析

    神经网络经过训练得到一组最优参数,包括网络权值和偏置。为了在FPGA中实现所设计自编码神经网络的解码器部分,需要获取对ASCII码编码后的数据(神经网络隐含层的输出数据)和解码器部分的网络权值与偏置。另外由于FPGA仅能对二进制数据识别和计算,因此需要将上述数据转换为二进制数据。

    在FPGA设计中,数据的表示方式与FPGA逻辑资源消耗直接相关的。数据表示位数越多,数据精度越高,逻辑资源的消耗也就越多,因此在FPGA设计中需要权衡FPGA资源消耗和数据精度之间的关系。结合本文的实际应用,同时为了更好地权衡FPGA设计中的精度、资源占用和功耗,本设计采用定点数表示上述数据。

    由于在FPGA设计中采用有限位定点数来表示数据时,对原数据进行定点量化的过程中会因为数据的截断而产生误差。根据网络计算模块的设计,其输出为计算结果二进制小数点后7位,因此在设计中需要保证这7位数据正确,即与原始输入数据相比,经过解码后输出结果的误差需要小于2-7,即应小于7.812 5×10-3。本文利用MATLAB下的Fixed Point Toolbox对数据进行量化,然后分析本设计中数据不同的量化位数对计算结果误差的影响,如图8所示为定点数表示中小数点的位数和最大误差之间的关系。

    c1645a7a4fc30ed482e971b02ec00dcf.png

    从图8可以看出:

    (1)随着定点数小数位数的增加,最大误差值不断降低,即数据精度越来越高;

    (2)定点数小数位变为12位之后,其最大误差基本保持不变;

    (3)定点数小数位为9位时,其最大误差与7.812 5×10-3基本一致;定点数小数位为10位时,其最大误差已符合小于7.812 5×10-3的要求。

    基于图8所示的分析结果,本文在对设计中的网络权值、偏置和编码数据进行定点数量化时,小数位均设计为10位。进一步通过对网络的权值、偏置和编码数据的大小范围进行分析可以确定其整数位的位数,3种数据的二进制定点数格式如表1所示。

    30115a3ef55ef21d6b26aa1f54536421.png

    本设计在ModelSim环境下对网络计算模块进行仿真,并对模块输出的计算结果与软件中的原始输入数据进行分析比对,所测试数据中的绝对误差最大值小于7.812 5×10-3,符合设计中的误差要求。另外通过硬件实测,所有被编码后的数据经过FPGA计算后均被正确解码,并将结果显示在LCD1602上,即所设计的FPGA硬件系统正确地完成了解码功能,从而验证了对所设计网络计算模块的误差分析。

    3.2 系统性能分析

    如表2所示为Xilinx ISE对系统工程综合实现后列出的主要资源占用情况。可以看出,DSP资源占用较大,主要原因是网络计算模块中的乘加计算和激励函数运算均含有定点数乘法和加法操作,因此会占用较多的DSP资源。另外,BRAM资源的占用主要来自于FIFO模块的实现和网络计算模块中网络权值与偏置的存储。

    05875fc9ec2b0ca5fe0b10600d00aa85.png

    如表3所示为FPGA硬件实现数据解码的速度和软件解码速度的比较,软件解码是在MATLAB软件中测试所得,CPU为Intel Core i7,主频为2.5 GHz。FPGA硬件解码速度是通过在FPGA中设置计数器,对从读取解码器输入数据到最后输出结果的时钟进行计数,然后利用ChipScope工具查看计数值来计算工作时间。表3中的结果显示,相比于CPU软件解码,本文所设计的FPGA硬件解码器加速了7倍以上。

    6772e190fa3a68579d4eb12c9570ade5.png

    通过Xilinx ISE自带的XPower工具可以得到FPGA的运行功耗大致为0.389 W,所设计系统的外围设备中LCD1602功耗大致为0.693 W,其余外设的功耗可忽略不计,因此整个系统总功耗为1 W左右。而相比之下,Intel Core i7-6500U主频为2.5 GHz的CPU的功耗可高达65 W,可见本系统功耗仅为通用CPU的1.5%,因此特别适合将本文所设计的基于FPGA的解码器应用于低功耗便携式设备中。

    4 结论

    利用神经网络所具有的输入输出之间的映射关系,可以简单高效地实现数据编码和解码。本文根据自编码神经网络的结构和特点,将其用于编码和解码,并在FPGA中实现自编码神经网络的解码器部分。通过对软件算法的设计和网络计算过程的分析,按照功能和需求对FPGA模块进行设计。利用ModelSim软件对所设计的各个FPGA模块进行仿真验证,利用Xilinx ISE对整个工程进行设计、综合和实现,并将编程文件下载至Xilinx VC707 FPGA开发板中进行验证,同时对FPGA系统的资源占用、计算速度和功耗进行评估。通过测试,对于在软件中经过编码的数据,在FPGA系统中可以正确解码。同时相比于通用CPU,该系统计算过程加速了7倍以上,而运行功耗仅为CPU的1.5%,因此具有速度快、功耗低的特点,特别适合将其应用于实时性、低功耗便携式设备中。

    参考文献

    [1] 曹雪虹,张宗橙.信息论与编码[M].北京:清华大学出版社,2016.

    [2] 张定会,李敬红,左小五.神经网络编码和解码[C].全国青年通信学术会议.2002.

    [3] 王雅思.深度学习中的自编码器的表达能力研究[D].哈尔滨:哈尔滨工业大学,2014.

    [4] 李时峰.基于自编码神经网络文本特征选择的研究[D].天津:天津科技大学,2016.

    [5] 白玉婷,张刚.AVS熵编码的FPGA实现[J].软件,2012,33(2):102-104,156.

    [6] 陈章进,钟国海,毕卓.一种基于低成本FPGA的高速8B/10B编解码器设计[J].微计算机信息,2012,28(10):189-190,480.

    [7] Li Huimin,Fan Xitian,Jiao Li,et al.A high performance FPGA-based accelerator for large-scale convolutional neural networks[C].Field Programmable Logic and Applications(FPL),2016 26th International Conference on.IEEE,2016:1-9.

    [8] NURVITADHI E,VENKATESH G,SIM J,et al.Can FPGAs beat GPUs in accelerating next-generation deep neural networks?[C].Proceedings of the 2017 ACM/SIGDA International Symposium on Field-Programmable Gate Arrays.ACM:5-14.

    [9] CYBENKO G.Approximation by superpositions of a sigmoidal function[J].Mathematics of Control,Signals,and Systems(MCSS),1989,2(4):303-314.

    [10] BENGIO Y.Learning deep architectures for AI[J].Foundations and trends? in Machine Learning,2009,2(1):1-127.

    [11] 鲁亚平.面向深度网络的自编码器研究[D].苏州:苏州大学,2016.

    [12] Tensorflow.hard_sigmoid definition[EB/OL].[2017-07-26].https://www.tensorflow.org/api_docs/python/tf/contrib/keras/backend/hard_sigmoid.

    [13] 张锋,潘冀宁,朱振荣.基于SPI模式的Micro SD卡驱动设计与验证[J].通讯世界,2017(12):3-4.

    作者信息:

    周松江,李圣辰,刘 明

    (北京邮电大学 信息光子学与光通信研究院,北京100876)

    639bac0fd432ae01181bd24df6aae320.png6ccfc00bcd4338f1d069fd59ea22aecc.gifffd1790ba8cd91e4349f2c95fde8012e.gif8c8f3c579112bc588590212b1b18bf98.png
    展开全文
  • 前言去年图像处理DLL,有学弟问我做思路,便放到博客里github地址,欢迎star图像增强处理:设计一套空间域与频率域结合图像增强算法,处理以下任一组图片中带噪声图像,去除噪声,提高图像质量。(1)已知:...
  • 摘 要 : 介绍 了数字水印产生、 发展及其应用, 讨论 了数字水印分类 , 提 出了图像预处 理思想, 利用 MA T L A B中剪切函数 、 缩放 函数 , 以及调 整 图像 直方图方法对 图像进行预 处 理, 并用 ...
  • 对图像压缩时进行8*8分块,用DCT实现压缩。用matlab实现。
  • 基于的DCT水印算法实现

    万次阅读 多人点赞 2015-10-26 20:38:11
    上学期帮同校本科同学做了毕业设计实验部分,用MATLAB实现DCT水印算法,并且包含了攻击测试。先讲一个大体概念,然后放出具体代码。一、DCTDCT(离散余弦变换),这里只以二维DCT为例。 信号经过DCT后,从空间...
  • 本博客主要是自己看的,看了下面这些...基于DCT的JPEG图像压缩的研究_马媛媛.pdf基于MATLAB的DCT变换在JPEG图像压缩中的应用_李秀敏.pdf基于DCT的JPEG图像压缩编码算法的MATLAB实现_钱裕禄.pdf基于Matlab的JPEG图像压
  • 本文介绍了数字水印原理和应用方法,研究了一种基于离散余弦变换(DCT)数字图像水印算法,并借助 MATLAB 编程工具实现数字水印嵌入、提取和攻击测试。实验结果表明,对于JPEG 压缩和噪声处理,本算法具有较好...
  • 专业班级 通信1001班 指导教师 魏洪涛 工作单位 信息工程学院 题 目: 通信工程应用技术综合训练与实习 初始条件MATLAB软件平台 设计任务与要求: 图像通信之前需要进行数据量压缩编程实现JPEG图像压缩标准主要环节...
  • 在图像的变换和压缩中,常常用到离散余弦变换(DCT)。DCT具有能使图像的最重要的信息集中在DCT的几个系数上的性能。正是基于此,DCT通常应用于图像的压缩.
  • 第2章和笫3章介绍语音信号特征分析基本处理技术,包括时域分析、频域分析、同态分析、DCT和MFCC分析、小波和小波包变换分析以及EMD分析等方法。 第4章介绍线性预测分析方法。介绍了线性预测模型、方程建立...
  • 二维图像的DCT变换一.实验目的1.学会用MATLAB软件对图像灰度进行变换;2.熟悉傅里叶变换概念和原理;3.熟悉DCT变换概念和原理。二.实验原理1.应用傅立叶变换进行图像处理。傅里叶变换是线性系统分析一个有力...
  • DCT变换在图像压缩中

    2014-05-27 11:00:58
    利用matlab编程语言,实现基于DCT变换在图像压缩中的应用
  • 相关知识1.1DCT变换在数字图像应用1.2数字图像处理主要方法............................11.3DCTMATLAB的实现................................12.课程设计分析..........................................32.1...
  • matlab强化训练

    2010-01-26 22:48:16
    本报告通过运用MATLAB7软件进行图像处理的一般步骤,对图像相关参数做了计算,同时运输数据分析的常用算法,通过对MATLAB中FFT,DCT,DWT的程序编写使得整个分析过程快捷... hist等的应用使得程序的编写过程也大大简化。

空空如也

空空如也

1 2 3
收藏数 55
精华内容 22
关键字:

matlabdct的应用

matlab 订阅