1一开始#100; rst_n 1;首先等待100拍之后复位信号拉高系统开始运行。因为还没输入数据经过FFT模块FFT模块输出m_axis_data_tuser为0存储UW的FFT的ROM在黄线时钟上升沿的时刻检测到rst_n还在低电平下一时钟上升沿时刻检测到rst_n拉高开始工作检测到m_axis_data_tuser为0douta上挂靠第0个数据。2之后s_axis_config_tready从低电平跳变为高电平。这表示 FFT IP 核已经完成了内部初始化准备好接收配置数据s_axis_config_tvalid一开始复位信号处于低电平的时候就是高电平。二者在这一时钟里同时为高配置完成握手配置指令s_axis_config_tdata8b1已经送入FFT模块(表示做FFT)。之后在下一时钟上升沿将s_axis_config_tvalid拉低之后送入的配置都是无效的。s_axis_data_tready(数据通道准备就绪)这是 FFT IP 核告诉你的上游模块“我现在可以接收时域数据了”。rsta_busy(复位忙状态)从高电平跳变为低电平。这个信号通常来自BRAM (ROM)模块。当rst_n刚释放时存储器需要几个时钟周期来处理内部复位此时rsta_busy为 1表示 ROM 还不能被读取。当它变低时说明你的本地导频 ROMrom_uw_fft已经可以正常工作了。3数据开始输入输入数据开始送入data_in_valid拉高处于发送UW阶段uw_data_valid拉高。但在此刻时钟上升沿检测到uw_data_valid还是0uw_dot_cnt还是0没有增加下一时钟上升沿加1。4第一个1024点的128点发送完在黄线的时钟上升沿检测到uw_data_valid还是1uw_dot_cnt加1达到127。与此同时assign s_axis_data_tlast (uw_dot_cnt 127) uw_data_valid;s_axis_data_tlast为1表示这是128 个点的最后一个点。在下一时钟上升沿检测到uw_data_valid还是1.但是uw_dot_cnt 127给uw_dot_cnt赋值为0并且已经发送128点数据uw_data_valid置0.5FFT开始吐出频域数据FFT 输出启动 (fft_out_valid拉高)信号跳变在光标位置fft_out_valid从低电平变为高电平。含义经过了 FFT 内部的流水线延迟第一组频域数据fft_out_i和fft_out_q正式出现在总线上。索引同步注意m_axis_data_tuser也变为了00。这表示当前输出的是这 128 个子载波中的第 0 号点即 DC 直流分量如果是中心对齐则是最左侧频点。ROM 地址寻址与延迟对齐ROM 响应m_axis_data_tuser值为 00作为地址传给rom_uw_fft。1 拍延迟在光标后的下一个上升沿ram_uw_fft_q/i出现了有效数据如000764等。这证实了我们之前的判断ROM 有 1 个时钟周期的读取延迟。打拍对齐 (fft_out_i_d1)观察下方的fft_out_i_d1信号。它在光标后的第二个上升沿才更新为 FFT 输出的第一个值010207。fft_out_valid_d1有效标识也在此刻才拉高关键点这说明你的代码中对 FFT 数据做了 1 拍的延迟处理使得fft_out_i_d1正好与ram_uw_fft_i在同一个时钟沿对齐。计算就绪这种对齐是 LS 计算复数乘法正确进行的前提。6复数乘法器输出cmpy_out_valid变为 1在黄色光标处有效信号拉高。这说明从 FFT 吐出数据并经过 1 拍对齐进入乘法器后再经过乘法器自身的流水线延迟约 6 拍第一组 LS 估计结果正式产生。全精度计算你可以看到cmpy_out_q和cmpy_out_i显示的是非常长的十六进制数例如0000005af7000。这正是我们之前讨论的49位符合字节对齐后在总线上显示为 50位全精度乘法结果。定点小数点位置这些数的高位包含了符号信息而低位包含 27 位小数。ls_channel_estimate_i/q(截位后的中间变量)就在cmpy_out下方你可以看到截位后的数值数值对应红圈内的14e2和0b5e是从那一长串全精度数据中按照你的逻辑[29:15]截取出来的 16 位结果。物理意义这就是在该子载波上计算出的信道频域响应{H}(k)。csi_out_i/q与csi_data_valid(最终输出)这是你模块的最外层端口信号也是 Testbench 写入文件的信号。同步跳变可以看到在红圈右侧csi_data_valid紧随其后变高csi_out出现了与截位变量一致的14e2和0b5e。对齐验证这证明了你最后修改的always块逻辑是正确的——数据被成功打拍并与有效信号严格对齐输出。7ifft输出processing_active is_processing || (ifft_out_tvalid (count_1024 10d0));如果寄存器已经在处理中 (is_processing)或者 刚刚收到首个有效数据它都会立刻为 1。(以防IFFT输出数据会和pad_out有偏差)IFFT IP核开始输出数据ifft_out_tvalid拉高表示输出数据有效pad_out_i (processing_active count_1024 10d11) ? ifft_out_i : 24d0;根据当前状态以及发送过来的数据的数量来判定输出前11个数据还是0.在下一时刻上升沿检测到processing_active为1is_processing才升为1.注意重点数学世界中以及MATLAB中IFFT的公式是带有一个1/N的但是FPGAXilinx IP里的 Unscaled IFFT在硬件里做除法是非常消耗资源的。Xilinx 的工程师在设计 FFT/IFFT IP 核时为了保证最大化的计算精度和最小的硬件消耗当配置为Unscaled不缩放模式时它直接把公式里的 1/N扔掉了FFT 在底层是由一级一级的加法器和乘法器组成的。每过一级就是把两个数相加或相减。在二进制中两个 n 位的数相加结果必然需要 n1位来防止溢出。128 点的 IFFT 内部需要 log_2(128) 7级蝶形运算。经历了 7 次纯粹的加减法累加数据的整数位不可避免地长胖了 7 圈增加了 7 bit。所以在硬件的 Unscaled 模式下IFFT 根本没有任何“缩小”数据的动作它就像一个贪吃蛇把 128 个频域点的数据疯狂加在一起导致总幅度扩大了 128 倍。(相当于左移了7位)而FPGA 算出来的 FFT 结果和 MATLAB 算出来的 FFT 结果在绝对幅度上是天然一模一样的8FFT输出FFT开始输出第一个数据csi_out_tvalid拉高