【 序列检测总结】

序列检测总结

基础知识补充

状态分类

摩尔状态机(Moore):输出只与当前的状态有关。输入对输出的影响要到下一个时钟周期才能反映出来;
米利状态机(Mealy):输出不仅与当前状态有关,还和当前输入有关。输出是在输入信号变化以后立刻发生变化,且输入变化可能出现在任何状态的时钟周期内,常用三段式状态机
状态机参考链接

三段式状态机

(0) 首先,根据状态机的个数确定状态机编码。利用编码给状态寄存器赋值,代码可读性更好。
(1) 状态机第一段,时序逻辑,非阻塞赋值(<=),传递寄存器的状态。
(2) 状态机第二段,组合逻辑,阻塞赋值(=),根据当前状态和当前输入,确定下一个状态机的状态。
(3) 状态机第三代,时序逻辑,非阻塞赋值(<=),因为是 Mealy 型状态机,根据当前状态和当前输入,确定输出信号。

序列检测分类

重复检测:一串序列1011011需要检测出1011的个数,第一个的1011和第二个的1011有一个共用的“1”,这就是重复检测。
非重复检测:反之当检测序列1011011中1011的个数时只会检测到有一个1011,而不是两个。

重复序列检测

状态机实现重复序列检测

代码如下:

module Squence_detect_rep(
input clk,reset,dataIn,
output detect_flag
    );

parameter s_idle = 5'b0_0001;
parameter s1 = 5'b0_0010;
parameter s2 = 5'b0_0100;
parameter s3 = 5'b0_1000;
parameter s4 = 5'b1_0000;

reg [4:0] c_s;
reg [4:0] n_s;
reg detect_flag_tep ;


// 第一段 时序逻辑,状态转移
always @(posedge clk or posedge reset)
if (reset)
    c_s <= s_idle;
else
    c_s <= n_s;
    
// 第二段 组合逻辑,确定n_s的状态
always @(*) begin
//是否在组合逻辑中不需要考虑reset
case(c_s)
s_idle : n_s = (dataIn==1'b1) ? s1 : s_idle;
s1     : n_s = (dataIn==1'b0) ? s2 : s1;
s2     : n_s = (dataIn==1'b1) ? s3 : s_idle;
s3     : n_s = (dataIn==1'b1) ? s4 : s2;
s4     : n_s = (dataIn==1'b1) ? s1 : s2;
endcase
end

// 第三段 时序逻辑,判断c_s状态和输出
always @(posedge clk or negedge reset) begin
if (reset)
    detect_flag_tep <= 1'b0;
else if (n_s == s4)
    detect_flag_tep <= 1'b1;
else
    detect_flag_tep <= 1'b0;
end

assign detect_flag = detect_flag_tep; // 此处的赋值没有延时
endmodule

移位寄存器实现重复序列检测

代码如下:

module Squence_detect_rep_shift
(input clk,reset,dataIn,
output detect_flag
);

reg [3:0] shift_reg;
reg detect_flag_tep;

always @(posedge clk or negedge reset) begin
if (reset)
    shift_reg <= 4'b0000;
else
    shift_reg <= {shift_reg[2:0],dataIn};
end

always @(posedge clk or negedge reset) begin
if (reset)
    detect_flag_tep <= 1'b0;
else if (shift_reg == 4'b1011)
    detect_flag_tep <= 1'b1;
else 
    detect_flag_tep <= 1'b0; //不要忘了else!!!!!
end

assign detect_flag = detect_flag_tep;
endmodule

不重复序列检测

状态机实现不重复序列检测

代码如下:

module Squence_detect_no_rep
(
    input clk,reset,dataIn,
    output detect_flag
);
// 状态机实现

parameter s_idle= 5'b0_0001;
parameter s1 = 5'b0_0010;
parameter s2 = 5'b0_0100;
parameter s3 = 5'b0_1000;
parameter s4 = 5'b1_0000;

reg [4:0] c_s;
reg [4:0] n_s;
reg detect_flag_tep;

// 时序逻辑,更新状态
always @(posedge clk or posedge reset) begin
    if (reset) 
    c_s <= s_idle;
    else
    c_s <= n_s;
end

// 组合逻辑,状态跳转
always @(*) begin
    case(c_s) 
    s_idle : n_s = (dataIn == 1'b1) ? s1:s_idle;
    s1 : n_s = (dataIn == 1'b0) ? s2:s1;
    s2 : n_s = (dataIn == 1'b1) ? s3:s_idle;
    s3 : n_s = (dataIn == 1'b1) ? s4:s2;
    s4 : n_s = (dataIn == 1'b1) ? s1:s_idle;
    endcase
end

// 时序逻辑,输出赋值
always @(posedge clk or negedge reset) begin
    if (reset)
    detect_flag_tep <= 1'b0;
    else if (n_s == s4)
    detect_flag_tep <= 1'b1;
    else
    detect_flag_tep <= 1'b0;
end
assign detect_flag = detect_flag_tep;
endmodule

寄存器实现不重复序列检测

代码如下:

module Squence_detect_no_shift
(
    input clk,reset,dataIn,
    output detect_flag
);

reg [3:0] shift_reg;
reg detect_flag_tep;
reg [2:0] cnt,cnt_max;

always @(posedge clk or negedge reset) begin
    if (reset)
    shift_reg <= 4'b0000;
    else
    shift_reg <= {shift_reg[2:0],dataIn};
end

always @(posedge clk or posedge reset) begin
    if (reset)
    cnt <= 3'd0;
    else if (shift_reg == 4'b1011 && cnt==3'd0) 
    cnt <= 3'd4;        // 当检测到一次后,需要移位寄存器左移四次,再进行下一次检测
    else if (cnt>0)
    cnt <= cnt - 1'd1;
    else
    cnt <=  3'd0;
end

always @(posedge clk or posedge reset) begin
    if (reset)
    detect_flag_tep <= 1'b0;
    else if (shift_reg == 4'b1011 && cnt==3'd0)
    detect_flag_tep <= 1'b1;
    else
    detect_flag_tep <= 1'b0;
end 

assign detect_flag = detect_flag_tep;

endmodule

testbench 生成

代码如下:

module Squence_detect_tb();

reg clk,reset,dataIn;
wire flag_out;
wire flag_out_repeat_shift;
wire flag_out_no_repeat;
wire flag_out_no_repeat_shift;
integer clk_period_half = 10;

// generate clk
always begin
clk = 1'b0;
# clk_period_half;
clk = 1'b1;
# clk_period_half;
end

// generate reset and data
initial begin
reset = 1'b0;
dataIn = 1'b0;
# (clk_period_half * 10); // 出现某些中间运算时,需要括号
reset = 1'b1;
dataIn = 1'b0;
# clk_period_half;
reset = 1'b0;
dataIn = 1'b0;
#20 dataIn=1;
#20 dataIn=0;
#20 dataIn=1;
#20 dataIn=0;
#20 dataIn=1;
#20 dataIn=1;
#20 dataIn=0;
#20 dataIn=1;
#20 dataIn=1;
#20 dataIn=0;
#20 dataIn=1;
#20 dataIn=1;
end

// 例化 instantiate
Squence_detect_rep u_Squence_detect_rep
(
    .clk (clk),
    .reset (reset),
    .dataIn(dataIn),
    .detect_flag(flag_out)
);

Squence_detect_rep_shift u_Squence_detect_rep_shift
(
    .clk (clk),
    .reset (reset),
    .dataIn(dataIn),
    .detect_flag(flag_out_repeat_shift)
);

Squence_detect_no_rep u_Squence_detect_no_rep
(
    .clk (clk),
    .reset (reset),
    .dataIn(dataIn),
    .detect_flag(flag_out_no_repeat)
);

Squence_detect_no_rep_shift u_Squence_detect_no_rep_shift
(
    .clk (clk),
    .reset (reset),
    .dataIn(dataIn),
    .detect_flag(flag_out_no_repeat_shift )
);

endmodule

仿真总结

  1. 如果是可重叠序列检测,移位寄存器的方式代码更加简洁,面积也更小。
  2. 如果是不可重叠序列检测,三段式状态机的实现方式思路更加清晰,不易出错。
  3. 对于不可重叠序列检测,如果采用移位寄存器的方式,要保证每检测到一次序列后,都需要将移位寄存器左移四位以后,再进行下一次的检测和判断。(需要不断更新计数器)
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STL(Seasonal and Trend decomposition using Loess)是一种用于时间序列分解的统计方法。它被广泛应用于经济学、气象学等领域,用于分析和预测时间序列数据的季节性、趋势性和残差成分。 STL算法的流程图如下: 1. 数据准备:首先,需要收集时间序列数据,并对数据进行预处理。这包括去除异常值、填补缺失值等。 2. 序列分解:使用LOESS(局部加权回归平滑)方法对时间序列数据进行分解。LOESS是一种非参数的回归方法,通过拟合局部多项式回归来估计数据中的季节性和趋势性成分。分解后的数据包括趋势、季节和残差成分。 3. 季节性调整:对分解后的数据进行季节性调整,以消除季节性对趋势分析和预测的影响。调整的方法可以采用差分或比率方法,以提取出季节性成分。 4. 趋势分析:对季节性调整后的数据进行趋势分析。可以使用简单移动平均、加权移动平均、指数平滑等方法来估计和预测趋势分量。 5. 残差分析:对趋势分析后的数据进行残差分析。残差表示未被趋势和季节性解释的波动成分。可以用来检测是否存在模型中未捕捉到的信息,并进行进一步的模型修正。 6. 预测:最后,利用趋势分析和残差分析的结果,可以进行未来时间点的数据预测。可以搭建ARIMA、VAR、GARCH等时间序列模型来进行预测。 总结起来,STL方法通过拟合LOESS回归来分解时间序列数据,并对分解后的数据进行季节性调整、趋势分析和残差分析,以及未来数据的预测。它在许多实际问题中都具有很好的效果,是一种强大的时间序列分析工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值