FPGA 的数字信号处理:Verilog 实现简单的 FIR 滤波器

news2024/10/6 0:29:26

c6417f58cbac91a3d14176b8df9b8854.png

该项目介绍了如何使用 Verilog 实现具有预生成系数的简单 FIR 滤波器。

76a999d1e68cea49aaa3fe48972bd0ca.png

绪论

不起眼的 FIR 滤波器是 FPGA 数字信号处理中最基本的模块之一,因此了解如何将具有给定抽头数及其相应系数值的基本模块组合在一起非常重要。因此,在这个关于 FPGA 上 DSP 基础实用入门的教程中,将从一个简单的 15 抽头低通滤波器 FIR 开始,在 Matlab 中为其生成初始系数值,然后转换这些值用于编写 Verilog 模块。

有限脉冲响应或 FIR 滤波器定义为脉冲响应在特定时间段内稳定为零值的滤波器。脉冲响应稳定到零所花费的时间与滤波器阶数(抽头数)直接相关,滤波器阶数是 FIR 的基础传递函数多项式的阶数。FIR 的传递函数不包含反馈,因此如果输入一个值为 1 的脉冲,然后输入一串零值,输出将只是滤波器的系数值。

滤波器的作用基本都是用于信号调节,主要集中在选择滤除或允许通过哪些频率。最简单的例子之一是低通滤波器,它允许低于某个阈值(截止频率)的频率通过,同时大大衰减高于该阈值的频率,如下图所示。

7a2d3a5f49ef1d1acd6f622c33ef348b.png

该项目的主要重点是在 HDL(具体为 Verilog)中实现 FIR,它可以分解为三个主要逻辑组件:一个循环缓冲器,用于将每个样本计时到适当地考虑了串行输入的延迟、每个抽头系数值的乘法器以及每个抽头输出的求和结果的累加器。

39ab59d221fa437ca54ed1cc456eac1f.png

由于本项目专注于 FPGA 逻辑中 FIR 的设计机制,所以只是使用 Simulink 中的 FDA 工具和 Matlab 为低通滤波器插入一些简单参数,然后使用生成的系数值放到 Verilog 模块中完成滤波器的设计(在后面的步骤中完成)。

dbb451b344f2df421639d707fc7020d1.png

选择实现一个简单的 15 抽头低通滤波器 FIR,采样率为 1Ms/s,通带频率为 200kHz,阻带频率为 355kHz,得到以下系数:

-0.0265 
0 
0.0441 
0 
-0.0934 
0 
0.3139 
0.5000 
0.3139 
0 
-0.0934 
0 
0.0441 
0 
-0.0265

为 FIR 模块创建设计文件

在 Vivado 项目中添加源文件。

dce2efd47b557898c3efda49058735a4.png

在确定 FIR 的顺序(抽头数)并获得系数值后,接下来需要定义的下一组参数就是输入样本、输出样本和系数本身的位宽。

对于这个 FIR,选择将输入样本和系数寄存器设置为 16 位宽,并将输出样本寄存器设置为 32 位,因为两个 16 位值的乘积是一个 32 位值(两个值的宽度相乘得到乘积的宽度,所以如果选择了 8 位抽头的 16 位输入样本,那么输出样本将为 24 位宽)。

这些值也都是带符号的,因此 MSB 用作符号位,在选择输入样本寄存器的初始宽度时一定要记住这一点。要在 Verilog 中将这些值设置为有符号数据类型,使用关键字signed :

reg signed [15:0] register_name;

接下来要解决的是如何在 Verilog 中处理系数值,小数点值需要转换为定点值。由于所有系数值都小于 1,因此寄存器的所有 15 位(总共 16 位,MSB 是有符号位)都可以用于小数位。通常,必须决定要将寄存器中的多少位用于数字的整数部分与数字的小数部分。因此,转换分数值抽头的数学是:(fractional coefficient value)*(2^(15))该乘积的小数值被四舍五入,并且如果系数为负,则计算该值的二进制补码:

tap0 = twos(-0.0265 * 32768) = 0xFC9C
tap1 = 0
tap2 = 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
tap3 = 0
tap4 = twos(-0.0934 * 32768) = 0xF40C
tap5 = 0
tap6 = 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
tap7 = 0.5000 * 32768 = 16384 = 0x4000
tap8 = 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
tap9 =  0
tap10 = twos(-0.0934 * 32768) = 0xF40C
tap11 = 0
tap12 = 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
tap13 = 0
tap14 = twos(-0.0265 * 32768) = 0xFC9C

现在我们终于准备好关注 FIR 模块的逻辑,第一个是循环缓冲区,它引入串行输入样本流并为滤波器的 15 个抽头创建一个包含 15 个输入样本的数组。

always @ (posedge clk)
        begin
            if(enable_buff == 1'b1)
                begin
                    buff0 <= in_sample;
                    buff1 <= buff0;        
                    buff2 <= buff1;         
                    buff3 <= buff2;      
                    buff4 <= buff3;      
                    buff5 <= buff4;       
                    buff6 <= buff5;    
                    buff7 <= buff6;       
                    buff8 <= buff7;       
                    buff9 <= buff8;       
                    buff10 <= buff9;        
                    buff11 <= buff10;       
                    buff12 <= buff11;       
                    buff13 <= buff12;       
                    buff14 <= buff13;    
                end
        end

接下来,乘法阶段将每个样本乘以每个系数值:

/* Multiply stage of FIR */
    always @ (posedge clk)
        begin
            if (enable_fir == 1'b1)
                begin
                    acc0 <= tap0 * buff0;
                    acc1 <= tap1 * buff1;
                    acc2 <= tap2 * buff2;
                    acc3 <= tap3 * buff3;
                    acc4 <= tap4 * buff4;
                    acc5 <= tap5 * buff5;
                    acc6 <= tap6 * buff6;
                    acc7 <= tap7 * buff7;
                    acc8 <= tap8 * buff8;
                    acc9 <= tap9 * buff9;
                    acc10 <= tap10 * buff10;
                    acc11 <= tap11 * buff11;
                    acc12 <= tap12 * buff12;
                    acc13 <= tap13 * buff13;
                    acc14 <= tap14 * buff14;
                end
        end

乘法阶段的结果值通过加法累加到寄存器中,最终成为滤波器的输出数据流。

/* Accumulate stage of FIR */   
    always @ (posedge clk) 
        begin
            if (enable_fir == 1'b1)
                begin
                    m_axis_fir_tdata <= acc0 + acc1 + acc2 + acc3 + acc4 + acc5 + acc6 + acc7 + acc8 + acc9 + acc10 + acc11 + acc12 + acc13 + acc14;
                end
        end

最后,逻辑的最后一部分是将数据流进和流出 FIR 模块的接口。AXI Stream 接口是最常见的接口之一。关键方面是允许控制上游和下游设备之间的数据流的tready和tvalid信号。这意味着 FIR 模块需要向其下游设备提供tvalid信号以指示其输出是有效数据,并且如果下游设备解除其tready信号,则能够暂停(但仍保留)其输出。FIR 模块还必须能够与其主端接口上的上游设备以同样的方式运行。

5074f17104d4886628ee02db551971d1.png

以下是 FIR 模块的逻辑设计概述:

322828b1ab5d72fcda50c82f9084be6e.png

请注意tready和tvalid信号如何设置输入循环缓冲器的使能值和 FIR 的乘法级以及数据或系数通过的每个寄存器都被声明为有符号的。

FIR模块Verilog代码:

`timescale 1ns / 1ps

module FIR(
    input clk,
    input reset,
    input signed [15:0] s_axis_fir_tdata, 
    input [3:0] s_axis_fir_tkeep,
    input s_axis_fir_tlast,
    input s_axis_fir_tvalid,
    input m_axis_fir_tready,
    output reg m_axis_fir_tvalid,
    output reg s_axis_fir_tready,
    output reg m_axis_fir_tlast,
    output reg [3:0] m_axis_fir_tkeep,
    output reg signed [31:0] m_axis_fir_tdata
    );


    always @ (posedge clk)
        begin
            m_axis_fir_tkeep <= 4'hf;
        end
        
    always @ (posedge clk)
        begin
            if (s_axis_fir_tlast == 1'b1)
                begin
                    m_axis_fir_tlast <= 1'b1;
                end
            else
                begin
                    m_axis_fir_tlast <= 1'b0;
                end
        end
    
    // 15-tap FIR 
    reg enable_fir, enable_buff;
    reg [3:0] buff_cnt;
    reg signed [15:0] in_sample; 
    reg signed [15:0] buff0, buff1, buff2, buff3, buff4, buff5, buff6, buff7, buff8, buff9, buff10, buff11, buff12, buff13, buff14; 
    wire signed [15:0] tap0, tap1, tap2, tap3, tap4, tap5, tap6, tap7, tap8, tap9, tap10, tap11, tap12, tap13, tap14; 
    reg signed [31:0] acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7, acc8, acc9, acc10, acc11, acc12, acc13, acc14; 

    
    /* Taps for LPF running @ 1MSps with a cutoff freq of 400kHz*/
    assign tap0 = 16'hFC9C;  // twos(-0.0265 * 32768) = 0xFC9C
    assign tap1 = 16'h0000;  // 0
    assign tap2 = 16'h05A5;  // 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
    assign tap3 = 16'h0000;  // 0
    assign tap4 = 16'hF40C;  // twos(-0.0934 * 32768) = 0xF40C
    assign tap5 = 16'h0000;  // 0
    assign tap6 = 16'h282D;  // 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
    assign tap7 = 16'h4000;  // 0.5000 * 32768 = 16384 = 0x4000
    assign tap8 = 16'h282D;  // 0.3139 * 32768 = 10285.8752 = 10285 = 0x282D
    assign tap9 = 16'h0000;  // 0
    assign tap10 = 16'hF40C; // twos(-0.0934 * 32768) = 0xF40C
    assign tap11 = 16'h0000; // 0
    assign tap12 = 16'h05A5; // 0.0441 * 32768 = 1445.0688 = 1445 = 0x05A5
    assign tap13 = 16'h0000; // 0
    assign tap14 = 16'hFC9C; // twos(-0.0265 * 32768) = 0xFC9C
    
    /* This loop sets the tvalid flag on the output of the FIR high once 
     * the circular buffer has been filled with input samples for the 
     * first time after a reset condition. */
    always @ (posedge clk or negedge reset)
        begin
            if (reset == 1'b0) //if (reset == 1'b0 || tvalid_in == 1'b0)
                begin
                    buff_cnt <= 4'd0;
                    enable_fir <= 1'b0;
                    in_sample <= 8'd0;
                end
            else if (m_axis_fir_tready == 1'b0 || s_axis_fir_tvalid == 1'b0)
                begin
                    enable_fir <= 1'b0;
                    buff_cnt <= 4'd15;
                    in_sample <= in_sample;
                end
            else if (buff_cnt == 4'd15)
                begin
                    buff_cnt <= 4'd0;
                    enable_fir <= 1'b1;
                    in_sample <= s_axis_fir_tdata;
                end
            else
                begin
                    buff_cnt <= buff_cnt + 1;
                    in_sample <= s_axis_fir_tdata;
                end
        end   

    always @ (posedge clk)
        begin
            if(reset == 1'b0 || m_axis_fir_tready == 1'b0 || s_axis_fir_tvalid == 1'b0)
                begin
                    s_axis_fir_tready <= 1'b0;
                    m_axis_fir_tvalid <= 1'b0;
                    enable_buff <= 1'b0;
                end
            else
                begin
                    s_axis_fir_tready <= 1'b1;
                    m_axis_fir_tvalid <= 1'b1;
                    enable_buff <= 1'b1;
                end
        end
    
    /* Circular buffer bring in a serial input sample stream that 
     * creates an array of 15 input samples for the 15 taps of the filter. */
    always @ (posedge clk)
        begin
            if(enable_buff == 1'b1)
                begin
                    buff0 <= in_sample;
                    buff1 <= buff0;        
                    buff2 <= buff1;         
                    buff3 <= buff2;      
                    buff4 <= buff3;      
                    buff5 <= buff4;       
                    buff6 <= buff5;    
                    buff7 <= buff6;       
                    buff8 <= buff7;       
                    buff9 <= buff8;       
                    buff10 <= buff9;        
                    buff11 <= buff10;       
                    buff12 <= buff11;       
                    buff13 <= buff12;       
                    buff14 <= buff13;    
                end
            else
                begin
                    buff0 <= buff0;
                    buff1 <= buff1;        
                    buff2 <= buff2;         
                    buff3 <= buff3;      
                    buff4 <= buff4;      
                    buff5 <= buff5;       
                    buff6 <= buff6;    
                    buff7 <= buff7;       
                    buff8 <= buff8;       
                    buff9 <= buff9;       
                    buff10 <= buff10;        
                    buff11 <= buff11;       
                    buff12 <= buff12;       
                    buff13 <= buff13;       
                    buff14 <= buff14;
                end
        end
        
    /* Multiply stage of FIR */
    always @ (posedge clk)
        begin
            if (enable_fir == 1'b1)
                begin
                    acc0 <= tap0 * buff0;
                    acc1 <= tap1 * buff1;
                    acc2 <= tap2 * buff2;
                    acc3 <= tap3 * buff3;
                    acc4 <= tap4 * buff4;
                    acc5 <= tap5 * buff5;
                    acc6 <= tap6 * buff6;
                    acc7 <= tap7 * buff7;
                    acc8 <= tap8 * buff8;
                    acc9 <= tap9 * buff9;
                    acc10 <= tap10 * buff10;
                    acc11 <= tap11 * buff11;
                    acc12 <= tap12 * buff12;
                    acc13 <= tap13 * buff13;
                    acc14 <= tap14 * buff14;
                end
        end    
        
     /* Accumulate stage of FIR */   
    always @ (posedge clk) 
        begin
            if (enable_fir == 1'b1)
                begin
                    m_axis_fir_tdata <= acc0 + acc1 + acc2 + acc3 + acc4 + acc5 + acc6 + acc7 + acc8 + acc9 + acc10 + acc11 + acc12 + acc13 + acc14;
                end
        end     

    
    
endmodule

创建仿真文件

要测试 FIR 模块,需要创建一个测试平台作为其仿真源:

c1cd20f7f71d7f77fedf8f2676096df2.png

在 FIR 模块中有两个主要的东西需要测试:滤波器算法和 AXI 流接口。为实现这一点,测试台中创建了一个状态机,它生成一个简单的 200kHz 正弦波,并切换从属端的有效信号和 FIR 接口主控端的tready信号。

FIR 模块的测试平台:

`timescale 1ns / 1ps

module tb_FIR;

    reg clk, reset, s_axis_fir_tvalid, m_axis_fir_tready;
    reg signed [15:0] s_axis_fir_tdata;
    wire m_axis_fir_tvalid;
    wire [3:0] m_axis_fir_tkeep;
    wire [31:0] m_axis_fir_tdata;
    
    /*
     * 100Mhz (10ns) clock 
     */
    always begin
        clk = 1; #5;
        clk = 0; #5;
    end
    
    always begin
        reset = 1; #20;
        reset = 0; #50;
        reset = 1; #1000000;
    end
    
    always begin
        s_axis_fir_tvalid = 0; #100;
        s_axis_fir_tvalid = 1; #1000;
        s_axis_fir_tvalid = 0; #50;
        s_axis_fir_tvalid = 1; #998920;
    end
    
    always begin
        m_axis_fir_tready = 1; #1500;
        m_axis_fir_tready = 0; #100;
        m_axis_fir_tready = 1; #998400;
    end
    
    /* Instantiate FIR module to test. */
    FIR FIR_i(
        .clk(clk),
        .reset(reset),
        .s_axis_fir_tdata(s_axis_fir_tdata),   
        .s_axis_fir_tkeep(s_axis_fir_tkeep),   
        .s_axis_fir_tlast(s_axis_fir_tlast),   
        .s_axis_fir_tvalid(s_axis_fir_tvalid), 
        .m_axis_fir_tready(m_axis_fir_tready),
        .m_axis_fir_tvalid(m_axis_fir_tvalid), 
        .s_axis_fir_tready(s_axis_fir_tready), 
        .m_axis_fir_tlast(m_axis_fir_tlast),   
        .m_axis_fir_tkeep(m_axis_fir_tkeep),   
        .m_axis_fir_tdata(m_axis_fir_tdata));  
        
    reg [4:0] state_reg;
    reg [3:0] cntr;
    
    parameter wvfm_period = 4'd4;
    
    parameter init               = 5'd0;
    parameter sendSample0        = 5'd1;
    parameter sendSample1        = 5'd2;
    parameter sendSample2        = 5'd3;
    parameter sendSample3        = 5'd4;
    parameter sendSample4        = 5'd5;
    parameter sendSample5        = 5'd6;
    parameter sendSample6        = 5'd7;
    parameter sendSample7        = 5'd8;
    
    /* This state machine generates a 200kHz sinusoid. */
    always @ (posedge clk or posedge reset)
        begin
            if (reset == 1'b0)
                begin
                    cntr <= 4'd0;
                    s_axis_fir_tdata <= 16'd0;
                    state_reg <= init;
                end
            else
                begin
                    case (state_reg)
                        init : //0
                            begin
                                cntr <= 4'd0;
                                s_axis_fir_tdata <= 16'h0000;
                                state_reg <= sendSample0;
                            end
                            
                        sendSample0 : //1
                            begin
                                s_axis_fir_tdata <= 16'h0000;
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample1;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample0;
                                    end
                            end 
                        
                        sendSample1 : //2
                            begin
                                s_axis_fir_tdata <= 16'h5A7E; 
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample2;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample1;
                                    end
                            end 
                        
                        sendSample2 : //3
                            begin
                                s_axis_fir_tdata <= 16'h7FFF;
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample3;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample2;
                                    end
                            end 
                        
                        sendSample3 : //4
                            begin
                                s_axis_fir_tdata <= 16'h5A7E;
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample4;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample3;
                                    end
                            end 
                        
                        sendSample4 : //5
                            begin
                                s_axis_fir_tdata <= 16'h0000;
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample5;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample4;
                                    end
                            end 
                        
                        sendSample5 : //6
                            begin
                                s_axis_fir_tdata <= 16'hA582; 
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample6;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample5;
                                    end
                            end 
                        
                        sendSample6 : //6
                            begin
                                s_axis_fir_tdata <= 16'h8000; 
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample7;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample6;
                                    end
                            end 
                        
                        sendSample7 : //6
                            begin
                                s_axis_fir_tdata <= 16'hA582; 
                                
                                if (cntr == wvfm_period)
                                    begin
                                        cntr <= 4'd0;
                                        state_reg <= sendSample0;
                                    end
                                else
                                    begin 
                                        cntr <= cntr + 1;
                                        state_reg <= sendSample7;
                                    end
                            end                     
                    
                    endcase
                end
        end
    
endmodule

运行行为仿真

FIR 模块及其测试平台文件就位后,从 Flow Navigator 窗口启动 Vivado 中的仿真器,选择 Run Behavioral Simulation 选项。

59568d4dc6b26b5f2332b1f68b771f25.png

如行为仿真所示,FIR 正确过滤信号并正确响应 AXI 流信号。

d0ac89678dd49fc8284a31e328f49425.png

总结

代码都在上面大家有兴趣可以自行运行,但是大家可能会注意到,这个 FIR 模块在设计上运行综合和实现时时序应该是不能通过的。我们将在下一篇文章中详细介绍如何在无法满足时序要求时重新设计你的设计~

297bfa037f7e67437a996ec3b8991360.png

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

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

相关文章

FPGA驱动FT601实现USB3.0通信测速试验 提供工程源码和QT上位机源码

目录 1、前言2、FT601芯片解读和时序分析FT601功能和硬件电路FT601读时序解读FT601写时序解读 3、我这儿的 FT601 USB3.0通信方案4、vivado工程详解5、上板调试验证6、福利&#xff1a;工程代码的获取 1、前言 目前USB3.0的实现方案很多&#xff0c;但就简单好用的角度而言&am…

【见微知著】Android Jetpack - Navigation的架构设计

前言&#xff1a;人总是理所当然的忘记&#xff0c;是谁风里雨里&#xff0c;一直默默的守护在原地。 前言 Navigation 作为 Android Jetpack 组件库中的一员&#xff0c;是一个通用的页面导航框架。为单 Activity 架构而生的端内路由导航&#xff0c;用来管理 Fragment 的切换…

使用IDEA使用Git:Git使用指北——实际操作篇

Git使用指北——实际操作 &#x1f916;:使用IDEA Git插件实际工作流程 &#x1f4a1; 本文从实际使用的角度出发&#xff0c;以IDEA Git插件为基座讲述了如果使用IDEA的Git插件来解决实际开发中的协作开发问题。本文从 远程仓库中拉取项目&#xff0c;在本地分支进行开发&…

数据结构-Redis(一)

Redis除了性能强外&#xff0c;还有数据结构丰富多彩。 一、String 单值缓存 SET key value GET key 存对象 相信大家都存过&#xff0c;我们一般都是把对象value转json&#xff0c;获取的时候&#xff0c;再json转对象 SET user:1 value(json值) 但当我们需要对对象某…

推荐一款可匹敌国际大厂的国产企业级低无代码平台

文章目录 前言&#xff1a;亟待转型的软开创业者什么是低/无代码居高不下的企业级软件搭建成本1. 开发周期较长2. 在需求明确、软件修改、系统集成等方面存在多种卡点3. 数据管理混乱 无代码/低代码开发&#xff0c;时代的潮流无代码平台 smardaten1. smardaten 简介2. smardat…

ATK-MD0096-V21使用手册

ATK-0.96’ OLED_V2.0(V2.0 是版本号&#xff0c;下面均以 OLED 表示该产品)是 ALIENTEK 推出的一款高性能 OLED 显示模块&#xff0c;&#xff0c;尺寸小巧&#xff08;27mm26mm&#xff09;&#xff0c;结构紧凑&#xff0c;模块通过一个28P的排针与外部连接。 8080并口模式…

「Win」Windows环境变量介绍与操作

✨博客主页&#xff1a;何曾参静谧的博客 &#x1f4cc;文章专栏&#xff1a;「Win」Windows程序设计 相关术语 Windows环境变量&#xff1a;是一组用于存储系统和应用程序配置信息的变量&#xff0c;在Windows操作系统中起着非常重要的作用。本文将详细介绍Windows环境变量的概…

机器学习常识 22: 循环神经网络

摘要: 循环神经网络 (Recurrent Neural Network, RNN) 用于处理序列数据. 本贴以前的算法, 我都用 Java 代码实现过. 很遗憾, 从本贴开始, 就只知道一点概念了. 1. 动机 序列数据中, 前后数据之间不是独立的, 而是会产生上下文影响. 如: 文本, 机器翻译一个句子的时候, 不是…

寻访 | 北京量子信息研究院

前言&#xff1a;为了普及科学技术知识、传播科学思想&#xff0c;光子盒特开启「寻访」专栏&#xff0c;带领各位读者探访全球的量子工厂和实验室。 2023年5月30日下午&#xff0c;为期6天的“2023中关村论坛主会期”落下帷幕。 量子计算、区块链、脑机接口、新能源材料——围…

最优化简明版(下)

最优化方法 牛顿法和拟牛顿法都是求解无约束最优化问题的常用方法&#xff0c;具有收敛速度快的优点。牛顿法是迭代算法&#xff0c;每一步需要求解目标函数的海森矩阵的逆矩阵&#xff0c;计算比较复杂&#xff0c;而且有时候海森矩阵不一定存在逆阵。拟牛顿法通过正定矩阵近…

【软件测试】测试经验:「测试用例」设计、审查、管理

目录 一、测试用例的设计 &#xff08;1&#xff09;测试用例 ① 测试用例的概念 ② 测试用例的功能 ③ 良好测试用例的特征 ④ 测试用例设计的概念 &#xff08;2&#xff09;测试用例设计考虑因素 ① 测试用例设计的主要影响因素 ② 测试用例设计的基本思想 &…

C#,码海拾贝(36)——求“实对称矩阵““特征值与特征向量“的“雅可比过关法“之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 矩阵类 /// 作者&#xff1a;周长发 /// 改进&#xff1a;深度混淆 /// https://blog.csdn.net/beijinghorn /// </summary> public partial class Matrix {…

【SpringBoot+MyBatis】项目的Invalid bound statement (not found)错误

一、注意&#xff1a;我的mapper.xml在静态资源resources文件夹下 二、报错原因&#xff1a; 1、没有在 MyBatis 配置文件中正确配置 Mapper.xml 文件的位置或者配置了错误的位置 (本人出现的问题) 解决方案&#xff1a;在application.yml中添加 mapper-locations。 mybatis:…

MongoDB 基本介绍和操作

目录 1、mongodb 简介 2、mongodb 概念解析 3、mongodb 连接 4、mongodb 数据库操作 5、mongodb 文档操作 6、mongodb 条件操作符 7、mongodb Limit与Skip 方法 8、mongodb 排序 9、mongodb 索引 10、mongodb 聚合 11、mongodb 复制&#xff08;副本集&#xff09; …

chatgpt赋能python:Python字符串非空——为何重要?

Python字符串非空——为何重要&#xff1f; 在Python编程中&#xff0c;我们经常要处理字符串。而有时候我们需要判断一个字符串是否为空&#xff0c;这个需要在处理输入、文件读写等场景下进行。本文将介绍如何在Python中判断字符串是否为空&#xff0c;并探讨字符串非空的重…

java并发编程:CAS与原子操作

文章目录 乐观锁与悲观锁CASUnsafe类AtomicInteger类CAS实现原子操作的三大问题ABA问题循环时间长开销大只能保证一个共享变量的原子操作 乐观锁与悲观锁 锁可以从不同的角度分类。其中&#xff0c;乐观锁和悲观锁是一种分类方式。 悲观锁就是我们常说的锁。对于悲观锁来说&a…

全网最详细的商业智能BI知识讲解

有一点可能很多人没有想到&#xff0c;实际上商业智能BI的相关概念已经有了数十年的发展历史。在这段发展过程中&#xff0c;商业智能BI形成了一套成熟的理论和产品体系&#xff0c;并且在现代的信息化、数字化加成下&#xff0c;成为了各行各业企业的成熟产品。 一、商业智能…

剑指offer打卡

这里写目录标题 day1 二叉树和为某一路径day2复杂链表的复刻day3二叉搜索树与双向链表day4数字排列day5找出出现次数超过一半的次数day6 二进制中1的个数day7 二叉树的最近公共祖先day8 字符串转换为整数day9 构建乘积数组day10不用加减乘除的加法day11求12....nday11 股票的最…

7.1「实战」图书录入和修改API --如何优雅处理校验逻辑?

文章目录 前言一、service层BookServiceImpl.saveBook()BookBO 二、web层BookAdminControllerBookVO 最后 前言 在做了这么多架构铺垫之后&#xff0c;一位订阅同学非常期待我能更新主线API&#xff0c;我觉得他的想法非常合理&#xff0c;所以今天就来安排~~~ 我主要考虑的是…

数据库期末复习(10)数据库规范化理论

函数依赖(概念):FD 范式分解(评估准则): 模式分解(工具): 函数依赖 如何衡量一个数据库好不好:准确 高效如果一个数据库设计的不好的话的&#xff0c;会带来哪些问题 删除异常 数据冗余为什么会导致出现上方的问题:数据依赖数据依赖的分类:完全依赖&#xff0c;部分依赖&am…