当前位置:   article > 正文

基于Xilinx vivado FFT ip进行信号频谱测量_xilinx官方fft

xilinx官方fft

本文章使用Xilinx的fft ip完成了经过参数化的任意个信号的基频测量,完整代码以及代码解释在文章中给出。如有错误,希望指出。

	SIGNAL_NUM = 2,   //*需要检测的信号个数
    FFT_LEN    = 8192,//*fft运算采样长度
    FFT_WIDTH = 32,   //*fft ip输出数据宽度,实部和虚部位宽为FFT_WIDTH/2
    SAMPLE_RATE = 50, //*ADC采样率,单位Mhz,比如此时为50Mhz
    ADC_WIDTH = 16,   //*ADC数据位宽
    FFT_CONFIG_WIDTH = 8 //*FFT ip的配置信号位宽(未使用)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ps:只使用了fft ip进行频率测量未测量幅度,为防止错误不对幅度测量进行讲解,且幅度测量因为未使用其中获得的幅度是未经处理的原始数据,直接使用应该会出现问题。该代码无法满足所有场景需求,仅起到抛砖引玉的作用。

1.FFT ip的配置

对于FFT ip核的各个配置的介绍在网上已经有很多,故不再详细解释各个配置定义,直接附上我对这个ip的配置。


因为使用ADC为20M采样率,需要测到kHz级别的精度,所以这里目标时钟速率为20Mhz,采样点数为8192。这里根据自己需求设定即可。

2.FFT ip的使用介绍

FFT ip输入为时域信息,而输出为信号的频域信号,所以需要自己针对频域信号来分析出傅里叶变换后的结果,在FFT ip配置中勾选了XK_INDEX这里后面将配合测试出信号的频率。
对于fft ip直接输出的实部数据和虚部数据是不可以直接进行频率的获取,需要经过一部分处理才可以得到信号的频谱,傅里叶变换的结果是一个复数,包括实部和虚部,信号的频谱是通过计算复数的模得到的。对于信号频谱的计算,按以下公式: abs(fft_P)= sqrt(实部的平方+虚部的平方)
然后根据这个得到的频谱,得到最大值的点,这个点转换后对应的频率,就是信号的频率,比如对于20k的信号,会在x_index指代20k的地方幅度达到最大值,而对于多个信号,比如一个混合信号(20k的正弦波+50k的正弦波),这样就检查这个频谱的两个最大值的位置,就可以得到这两个信号的频率。
得到实部虚部的平方和并使用vivado的cordic ip进行求根获得绝对值:

always @(posedge clk) begin : re2_im2_end
   if(rst) begin
       fft_im_end <= 'd0;
       fft_re_end <= 'd0;
       fft_end    <= 'd0;
   end
   else if(m_axis_data_tvalid) begin
       fft_im_end <= $signed(fft_im[ADC_WIDTH-1:0])*$signed(fft_im[ADC_WIDTH-1:0]);  //*one
       fft_re_end <= $signed(fft_re[ADC_WIDTH-1:0])*$signed(fft_re[ADC_WIDTH-1:0]);
       fft_end    <= fft_im_end + fft_re_end;          //*two
   end
end

cordic_0 u_cordic (
   .aclk                              (clk                       ),// input wire aclk
   .aresetn                           (~rst                      ),// input wire aresetn
   .s_axis_cartesian_tvalid           (cordic_valid_reg[1]       ),// input wire s_axis_cartesian_tvalid
   .s_axis_cartesian_tdata            (fft_end                   ),// input wire [39 : 0] s_axis_cartesian_tdata

   .m_axis_dout_tvalid                (cordic_valid              ),// output wire m_axis_dout_tvalid
   .m_axis_dout_tdata                 (cordic_data               ) // output wire [23 : 0] m_axis_dout_tdata
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

获得检测频率使用的频谱后,传到下面一个自定义的信号处理部分,这部分主要是根据信号的频谱,获取频谱的最大值位置(如果有多个信号就获取多个极值点),之后根据这个位置对应的x_index来计算出信号的频率。

比如对于50Mhz的采样率,8192点的采样深度,这样的话每一个x_index值对应的频率便是50M/8192≈6.1kHz,这样的话FFT运算精度大概就在6kHz
,比如对于X_index值未2的点,该信号的频率就是12kHz。
  • 1
  • 2

下面为得到x_index后,根据采样率的参数定义来计算出具体的信号频率部分代码。

always @(posedge clk) begin : result
    if (rst) begin
        for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
            post_fft_freq[i] <= 0;
            post_fft_mag[i] <= 0;
            post_fft_index[i] <= 0;
        end
    end
    else if(max_valid) begin
        for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
            post_fft_freq[i]  <= SAMPLE_RATE*detect_index[i]*(1000>>($clog2(FFT_SIZE)-10)); 
            //乘1000为M转K单位,因为MHz相比于KHz后面多3个0,所以乘1000转换单位,其中FFT_SIZE为采样深度
            //右移的时候-10是为了左移10bit,左移十位为了表示为低10位代表小数,高位代表整数
            post_fft_mag[i]   <= detect_data[i];
            post_fft_index[i] <= detect_index[i];
        end
    end
end
always @(posedge clk) begin
    if(rst) begin
        for(integer i = 0;i < SIGNAL_NUM;i++) begin
            {fft_int[i],fft_real[i]} <= 0;
            fft_mag[i] <= 0;
        end
    end
    else if(post_fft_valid) begin
        for(integer i = 0;i < SIGNAL_NUM;i++) begin
            {fft_int[i],fft_real[i]} <= post_fft_freq[i];//*计算出信号频率后,高六位为整数部分,后面为小数部分
            fft_mag[i] <= post_fft_mag[i];
        end
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

3.代码仿真

为了便于观察出仿真结果,所以使用了两个Xilinx的dds ip分别输出了20kHz的信号和50kHz的信号,然后将这两个信号的输出混合后作为输入,一次性测量两个信号的频率。参数配置如文章顶部的参数,未作更改。
下图为输入的20kHz和50kHz信号,混合信号为这两个信号之和:
在这里插入图片描述
下图为获得的频谱实部和虚部以及将他们求绝对值后的结果,可以看出求出实部虚部的模之后即为两个尖峰,分别对应两个不同的频率:
在这里插入图片描述
下图为经过处理后获得的信号频率,第一个为48.8kHz,第二个为18.3kHz,由于上面说明过在50M的采样率下,只有6.1kHz的精度,所以只能不会完全准确在这里,但是在当前精度下,精确测量出了50kHz和20kHz的信号。(要想提高精度需要提高采样深度或者降低采样率)
在这里插入图片描述

4.完整代码

对于我认为可能比较难理解的地方在上面已做出解释。

module fft_trans 
#(
    SIGNAL_NUM = 2,
    FFT_LEN    = 8192,
    FFT_WIDTH = 32,
    SAMPLE_RATE = 50,
    ADC_WIDTH = 16,
    FFT_CONFIG_WIDTH = 8
)
(
    input  wire clk,//65m clk
    input  wire rst,

    input  wire                       [ADC_WIDTH-1:0]    adc_data ,
    input  wire                                          adc_valid,
    input  wire                                          adc_last ,

    output reg                  [$clog2(FFT_LEN)-1:0]   fft_index[SIGNAL_NUM-1:0],
    output reg                  [ 6:0]  fft_int  [SIGNAL_NUM - 1:0] ,
    output reg                  [ 9:0]  fft_real [SIGNAL_NUM - 1:0] ,
    output reg                  [16:0]  fft_mag  [SIGNAL_NUM - 1:0] ,//!需要根据cordic ip的变化而配置
    output reg                          fft_valid                  ,
    output wire                         fft_slave_ready            ,
    output wire                             freq_valid             ,
    output wire        [$clog2(FFT_LEN)-1:0]freq_index             ,
    output wire        [  16:0]             freq_data                  
);
// region:************parameter************
localparam FFT_SECTION = FFT_WIDTH/2;
// endregion:parameter

// region:************logic define************
//*fft signal
wire                   [$clog2(FFT_LEN)-1:0]x_index                ;
wire              [FFT_CONFIG_WIDTH-1:0]s_axis_config_tdata  = 'd1 ;
wire                                   s_axis_config_tvalid  = 1'b1;
wire                                    s_axis_config_tready       ;
wire                   [FFT_SECTION-1:0]fft_im,fft_re              ;
wire                                    m_axis_data_tvalid         ;
wire                                    m_axis_data_tlast          ;
//*fft end
reg                    [ADC_WIDTH*2-1:0]fft_im_end,fft_re_end      ;
reg                    [ADC_WIDTH*2:0]  fft_end                    ;
reg                                     cordic_valid_reg [1:0]     ;

reg                                     sync_index_en [17:0]       ;
//*detect signal
wire                                    post_fft_valid             ;
wire                   [16:0]           post_fft_freq  [SIGNAL_NUM - 1:0];
wire                   [16:0]           post_fft_mag   [SIGNAL_NUM - 1:0];
wire            [$clog2(FFT_LEN)-1:0] post_fft_index [SIGNAL_NUM - 1:0]  ;

wire                                    cordic_valid               ;
wire                   [  16:0]         cordic_data                ;
wire                   [$clog2(FFT_LEN)-1:0]x_index_sync               ;
// endregion:logic define
// region:************assign************
assign freq_data = cordic_data;   //*freq_data
assign freq_index = x_index_sync;
assign freq_valid = cordic_valid;
assign fft_index[0] =( post_fft_index[0]>post_fft_index[1]) ? post_fft_index[0] : post_fft_index[1];
assign fft_index[1] = (post_fft_index[1]<post_fft_index[0]) ? post_fft_index[1] : post_fft_index[0];
// endregion:assign
always @(posedge clk) begin : re2_im2_end
    if(rst) begin
        fft_im_end <= 'd0;
        fft_re_end <= 'd0;
        fft_end    <= 'd0;
    end
    else if(m_axis_data_tvalid) begin
        fft_im_end <= $signed(fft_im[ADC_WIDTH-1:0])*$signed(fft_im[ADC_WIDTH-1:0]);  //*one
        fft_re_end <= $signed(fft_re[ADC_WIDTH-1:0])*$signed(fft_re[ADC_WIDTH-1:0]);
        fft_end    <= fft_im_end + fft_re_end;          //*two
    end
end
always @(posedge clk) begin:cordic_valid_generate
    if(rst) begin
        for(integer i = 0;i < 2;i++) begin
            cordic_valid_reg[i] <= 'd0;
        end
    end
    else begin
        cordic_valid_reg[1] <= cordic_valid_reg[0];
        cordic_valid_reg[0] <= m_axis_data_tvalid;
    end
end
always @(posedge clk) begin:sync_index
    if(rst) begin
        for(integer i = 0;i < 18;i++) begin
            sync_index_en[i] <= 'd0;
        end
    end
    else begin
        for(integer i = 0;i < 18;i++) begin
            if (i== 0) begin
                sync_index_en[i] <= m_axis_data_tvalid;
            end
            else begin
                sync_index_en[i] <= sync_index_en[i-1];
            end
        end
    end
end
//*out signals
always @(posedge clk) begin
    if(rst) begin
        for(integer i = 0;i < SIGNAL_NUM;i++) begin
            {fft_int[i],fft_real[i]} <= 0;
            fft_mag[i] <= 0;
        end
    end
    else if(post_fft_valid) begin
        for(integer i = 0;i < SIGNAL_NUM;i++) begin
            {fft_int[i],fft_real[i]} <= post_fft_freq[i];
            fft_mag[i] <= post_fft_mag[i];
        end
    end
end
always @(posedge clk) begin
    if(rst) begin
        fft_valid <= 1'b0;
    end
    else begin
        fft_valid <= post_fft_valid;
    end
end


xfft_0 u_xfft_0(
    .aclk                              (clk                       ),
    .aresetn                           (~rst                      ),
    //*fft配置信号
    .s_axis_config_tdata               (s_axis_config_tdata       ),
    .s_axis_config_tvalid              (s_axis_config_tvalid      ),
    .s_axis_config_tready              (s_axis_config_tready      ),
    //*前级adc传入数据
    .s_axis_data_tdata                 ({{{FFT_WIDTH-ADC_WIDTH}{1'b0}},adc_data}),
    .s_axis_data_tvalid                (adc_valid                 ),
    .s_axis_data_tready                (fft_slave_ready           ),
    .s_axis_data_tlast                 (                  ),
    //*out channel
    .m_axis_data_tdata                 ({fft_im,fft_re}           ),
    .m_axis_data_tuser                 (x_index                   ),
    .m_axis_data_tvalid                (m_axis_data_tvalid        ),
    .m_axis_data_tlast                 (m_axis_data_tlast         ),
    //*status channel
    .m_axis_status_tdata               (                          ),
    .m_axis_status_tvalid              (                          ),
    //*event channel
    .event_frame_started               (                          ),
    .event_tlast_unexpected            (                          ),
    .event_tlast_missing               (                          ),
    .event_data_in_channel_halt        (                          ) 
);
//*17 latency
cordic_0 u_cordic (
    .aclk                              (clk                       ),// input wire aclk
    .aresetn                           (~rst                      ),// input wire aresetn
    .s_axis_cartesian_tvalid           (cordic_valid_reg[1]       ),// input wire s_axis_cartesian_tvalid
    .s_axis_cartesian_tdata            (fft_end                   ),// input wire [39 : 0] s_axis_cartesian_tdata

    .m_axis_dout_tvalid                (cordic_valid              ),// output wire m_axis_dout_tvalid
    .m_axis_dout_tdata                 (cordic_data               ) // output wire [23 : 0] m_axis_dout_tdata
);
fifo_generator_0 u_fifo_generator_0(
    .clk                               (clk                       ),
    .srst                              (rst                       ),
    .din                               (x_index                   ),
    .wr_en                             (m_axis_data_tvalid        ),
    .rd_en                             (sync_index_en[17]         ),//!根据cordic ip的变化而配置
    .dout                              (x_index_sync              ),
    .full                              (                          ),
    .empty                             (                          ) 
);

signal_detect
#(
    .FFT_SIZE                          (FFT_LEN                   ),
    .FFT_SIGNAL_NUM                    (SIGNAL_NUM                ),
    .SAMPLE_RATE                       (SAMPLE_RATE               ) 
)
u_signal_detect(
    .clk                               (clk                       ),
    .rst                               (rst                       ),
    .fft_data                          (cordic_data               ),
    .fft_index                         (x_index_sync              ),
    .fft_valid                         (cordic_valid              ),

    .post_fft_index                    (post_fft_index            ),
    .post_fft_valid                    (post_fft_valid            ),
    .post_fft_freq                     (post_fft_freq             ),
    .post_fft_mag                      (post_fft_mag              ) 
);

endmodule //fft_trans


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197

在例化中除了signal_detect均为Xilinx的 ip,其中cordic_0 实现了求根,xfft_0 为fft ip,fifo_generator_0 为一个异步FIFO用于数据对齐,下面给出signal_detect代码

module signal_detect 
#(
    parameter FFT_SIZE = 4096,
    parameter FFT_SIGNAL_NUM = 1,
    parameter integer  SAMPLE_RATE = 'd100 //100MHz,用来计算频率
)
(
    input  wire  clk,
    input  wire  rst,

    input  wire  [16:0] fft_data,//!输入的cordic数据
    input  wire  [$clog2(FFT_SIZE)-1:0] fft_index,
    input  wire        fft_valid,

    output reg  [$clog2(FFT_SIZE)-1:0] post_fft_index [FFT_SIGNAL_NUM],
    output reg  post_fft_valid,
    output reg  [16:0] post_fft_freq [FFT_SIGNAL_NUM-1:0],     //*高16bit为整数,低10bit为小数
    output reg  [16:0] post_fft_mag  [FFT_SIGNAL_NUM-1:0]      //*低位最低,高位最高
);
localparam DETECT_RANGE = FFT_SIZE/2;

reg [$clog2(FFT_SIZE)-1:0] detect_index [FFT_SIGNAL_NUM-1:0]; 
//wire [$clog2(FFT_SIGNAL_NUM):0] detect_cnt;
reg [16:0] detect_data [FFT_SIGNAL_NUM-1:0];
reg [$clog2(DETECT_RANGE):0] cnt;
reg [4:0] state;
reg max_valid;

//*1 state design
always @(posedge clk) begin
    if (rst) begin
        cnt <= {$clog2(DETECT_RANGE){1'b0}};
        state <= 0;
    end
    else begin
        case (state)
            0:  if (fft_valid && (fft_index == 0)) begin//*one clk delay
                    cnt <= 0;
                    state <= 1;
                end
                else begin
                    state <= 0;
                end
            1:  if (fft_valid && (cnt < DETECT_RANGE)) begin
                    cnt <= cnt + 1;
                    state <= 1;
                end
                else if(cnt == DETECT_RANGE)begin
                    state <= 2;
                    cnt <= 0;
                end
            2:  begin
                state <= 0;
                cnt <= 0;
            end
            default: begin
                state <= 0;
                cnt <= 0;
            end
        endcase
    end
end
//*2 output design
generate if(FFT_SIGNAL_NUM == 1) begin
    always @(posedge clk) begin
    if (rst) begin
            detect_data[0] <= 0;
            detect_index[0] <= 0;
            max_valid <= 0;
    end
    else begin
        case (state)
            0:  begin
                    detect_data[0] <= 0;
                    detect_index[0] <= 0;
                    max_valid <= 0;
                end
            1: begin //*只捕获一个信号时
                    if (cnt == DETECT_RANGE-1) begin
                        max_valid <= 1'b1;
                    end
                    else begin
                        max_valid <= 0;
                    end

                    if (fft_data > detect_data[0]) begin
                        detect_data[0] <= fft_data;
                        detect_index[0] <= cnt+1;
                    end
                    
                end
            2:  begin
                max_valid <= 0;
                detect_data[0] <= 0;
                detect_index[0] <= 0;
            end
            default: begin
                max_valid <= 0;
                detect_data[0] <= 0;
                detect_index[0] <= 0;
            end
        endcase
    end
end
end
else begin //*捕获多个信号时
    always @(posedge clk) begin
    if (rst) begin
        max_valid <= 0;
        for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
            detect_data[i] <= 0;
            detect_index[i] <= 0;
        end
    end
    else begin
        case (state)
            0:  begin
                    for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
                        detect_data[i] <= 0;
                        detect_index[i] <= 0;
                    end
                    max_valid <= 0;
                end
            1: begin
                    if( fft_data > detect_data[0] && detect_data[0] <= detect_data[1]) begin
                        detect_data[0] <= fft_data;
                        detect_index[0] <= cnt + 'd1;
                    end
                    else if(fft_data > detect_data[1] && detect_data[1] <= detect_data[0]) begin
                        detect_data[1] <= fft_data;
                        detect_index[1] <= cnt + 'd1;
                    end
                    if (cnt == DETECT_RANGE-1) begin
                        max_valid <= 1'b1;
                    end
                    else begin
                        max_valid <= 0;
                    end
                end
            2:  begin
                max_valid <= 0;
                for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
                    detect_data[i] <= 0;
                    detect_index[i] <= 0;
                end
            end
            default: begin
                max_valid <= 0;
                for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
                    detect_data[i] <= 0;
                    detect_index[i] <= 0;
                end
            end
        endcase
    end
end
end
endgenerate
//*output
always @(posedge clk) begin : result
    if (rst) begin
        for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
            post_fft_freq[i] <= 0;
            post_fft_mag[i] <= 0;
            post_fft_index[i] <= 0;
        end
    end
    else if(max_valid) begin
        for(integer i = 0;i < FFT_SIGNAL_NUM;i++) begin
            post_fft_freq[i]  <= SAMPLE_RATE*detect_index[i]*(1000>>($clog2(FFT_SIZE)-10)); //<<10/1024 //*1000为M转K单位
            post_fft_mag[i]   <= detect_data[i];
            post_fft_index[i] <= detect_index[i];
        end
    end
end
always @(posedge clk) begin : valid
    if (rst) begin
        post_fft_valid <= 0;
    end
    else if(max_valid) begin
        post_fft_valid <= 1;
    end
    else begin
        post_fft_valid <= 0;
    end
end

endmodule //signal_detect
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188

如有疑问或者文章中有错误,请在评论区指出

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/433328
推荐阅读
相关标签