前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GNU Radio之Schmidl & Cox OFDM synch.底层C++实现

GNU Radio之Schmidl & Cox OFDM synch.底层C++实现

作者头像
Gnep@97
发布2024-04-27 08:47:28
3171
发布2024-04-27 08:47:28
举报
文章被收录于专栏:Gnep's_Technology_Blog

前言

在 GNU Radio OFDM 系统中,一个非常重要的环节是在接收端准确地同步和检测发送端发出的信号。这就是 Schmidl & Cox 同步算法发挥作用的地方。Schmidl & Cox 算法是一种用于 OFDM 信号的时间同步的技术。本文对其底层 C++ 源码进行学习记录。

一、Schmidl & Cox 同步模块

在 GNU Radio 中,Schmidl & Cox 同步模块如下图所示,其接受三个参数,分别是:FFT 长度、循环前缀长度、检测阈值。

在这里插入图片描述
在这里插入图片描述

Schmidl & Cox 算法利用特殊设计的训练序列或前导符号(preamble),这些前导符号包含两个连续的相同部分,通常记为 A 和 A。这种结构使得接收端能够通过比较这两部分来估计开始接收数据的最佳时刻。

  • 相关性计算:通过计算连续两个 A 部分的相关性,可以检测到信号的起始点。如果两个部分完全一致,相关性达到最大值,这表明接收到的是预期的训练序列的开始部分。
  • 频偏估计:Schmidl & Cox 方法还可以用来估计和校正频率偏移。算法通过分析两个 A 部分的相位差异来估计频偏。

这里的训练序列或前导符号指的是同步字,在 ofdm grc 例程中用的是两个符号的同步字

在这里插入图片描述
在这里插入图片描述
  • 同步字 1 的内容为:[0., 0., 0., 0., 0., 0., 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., -1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., -1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 1.41421356, 0., 0., 0., 0., 0., 0.]
    • 通过在偶数频率上传输伪噪声(PN)序列,使训练符号的两半(按时间顺序)相同,而在奇数频率上使用零。
  • 同步字 2 的内容为:[0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 0, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 0, 0, 0, 0, 0]
    • 第二个训练符号包含奇数频率上的 PN 序列来测量这些子信道,以及偶数频率上的另一个 PN 序列来帮助确定频率偏移。

GNU Radio 的 Schmidl & Cox OFDM Sync 模块具有以下两个输出端:

  • 1、Correlation (或称为 Peak Detector) 输出:
    • 这个输出指示 OFDM 帧的起始位置。这个端口输出一个数字信号,用来明确指示第一个 OFDM 符号的开始。在这个信号中,当检测到一个 OFDM 帧的开始时,输出值为 1;在其他所有时间,输出值为 0。这种机制对于正确解码接收到的 OFDM 信号至关重要,因为它标定了 OFDM 符号的精确起点。
    • 通过使用特殊的训练序列来实现这种同步,这个训练序列在实际数据传输开始之前发送。该训练序列特别设计为两个连续的相同 OFDM 符号。这种设计允许算法在接收端通过比较这两个符号来实现同步:
      • ①、检测同步:
        • 互相关:算法计算两个连续训练符号之间的互相关。由于两个符号是相同的,它们之间的互相关应该在同一OFDM符号的起始位置达到最大值。
        • 能量比:算法还会计算两个训练符号的能量比率。这有助于确认互相关峰值是否真的表示一个符号的开始,还是仅仅因为噪声或其他信号干扰。
      • ②、标记开始:
        • 当算法确定了一个符号的开始位置后,它会在“detect”输出端口生成一个脉冲(值为1),表示第一个OFDM符号(即实际数据传输符号)的起始位置。在其他所有时间点,该端口的值为0。
  • 2、Frequency Offset (或称为 Fine Frequency Offset) 输出:
    • 这个输出提供了接收到的信号与发送信号之间的频率偏移估计。在 OFDM 系统中,由于发射机和接收机之间的本地振荡器可能不完全同步,频率偏移的估计和补偿是必要的。该输出提供了一个估计值,通常以一种可以直接用于频率校正模块的格式输出。
    • 该输出值表示归一化的频率偏移,计算方式如下:
      Frequency Offset = \frac{2.0*output}{fft\_len}
      • 这里的 output0 是模块输出的原始频率偏移估计值,fft_len 是 FFT 的长度,归一化的频率偏移是指偏移量除以 FFT 长度的一半,原因是 FFT 的输出范围通常解释为从负一半到正一半(即 -0.5 到 0.5)的频率范围。
      • 归一化频率偏移的值告诉我们信号的载波频率与接收机本地振荡器之间的偏差,相对于总采样率的一半。
        • 当归一化频率偏移接近 0 时,表示频率偏移很小,信号质量好。
        • 当偏移值较大时,可能需要进行频率补偿以确保数据正确解码。

官方对其其输出也做了相应的解释:

在这里插入图片描述
在这里插入图片描述

其意思就是说:粗略频率偏移的评估不在该块中完成。此外,此处不计算初始均衡器抽头。 如果时序度量是

M(d)=\frac{|P(d)|^2}{(R(d))^2}

,那么归一化计算为

R(d)=\frac{1}{2}\sum_{k=0}^{N-1}|r_{k+d}|^2

,(N = fft_len),这就意味着此模块估计两个半符号的能量,这可以避免在突发结束时能量水平突然下降时出现虚假检测。

他这里的理论参考的是 Robust Frequency and Timing Synchronization for OFDM. Timothy M. Schmidl and Donald C. Cox, Fellow, IEEE 的论文内容。

论文中指出:

  • 符号时序恢复依赖于在时域内搜索具有两个完全相同的训练符号,这两个训练符号在通过信道后将保持相同,只是它们之间会由于载波频率偏移而产生相位差。通过在偶数频率上传输伪噪声(PN)序列,使训练符号的两半(按时间顺序)相同,而在奇数频率上使用零。
  • 第二个训练符号包含奇数频率上的 PN 序列来测量这些子信道,以及偶数频率上的另一个 PN 序列来帮助确定频率偏移。
  • 设在第一个训练符号(不包括循环前缀)的一半中有 L 个复样本,并设乘积对的和为:
    P(d)=\sum_{m=0}^{L-1}r_{d+m}^{*}r_{d+m+L}^{*}
    R(d)=\sum_{m=0}^{L-1}|r_{d+m+L}|^2
    M(d)=\frac{|P(d)|^2}{(R(d))^2}
    在这里插入图片描述
    在这里插入图片描述

其实也就是说论文中使用的是估计半个符号的能量,而在 Schmidl & Cox 同步模块中,使用的是估计两个半符号(即一个完整的 OFDM 符号)的能量。

二、C++ 源码分析

代码语言:javascript
复制
ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl(int fft_len,				// FFT(快速傅立叶变换)的长度 
                                             int cp_len,				// 循环前缀的长度
                                             bool use_even_carriers,	// 一个布尔值,指示是否使用偶数承载波
                                             float threshold)			// 用于检测峰值的阈值
    : hier_block2("ofdm_sync_sc_cfb",
                  io_signature::make(1, 1, sizeof(gr_complex)),
#ifndef SYNC_ADD_DEBUG_OUTPUT
                  io_signature::make2(2, 2, sizeof(float), sizeof(unsigned char)))
#else
                  io_signature::make3(
                      3, 3, sizeof(float), sizeof(unsigned char), sizeof(float)))
#endif
{
// 处理组件   ,代码创建了多个处理块,并且将这些块相互连接,形成数据处理的流程
    std::vector<float> ma_taps(fft_len / 2, 1.0);	// 被用作一个移动平均(Moving Average, MA)滤波器的系数
    gr::blocks::delay::sptr delay(	// 接收输入信号并将其延迟 fft_len / 2个样本。这用于创建与原始信号相比有一定时间偏移的信号
        gr::blocks::delay::make(sizeof(gr_complex), fft_len / 2));	
    gr::blocks::conjugate_cc::sptr delay_conjugate(gr::blocks::conjugate_cc::make());	// 取延迟信号的共轭,这在信号处理中用于某些相关计算
    gr::blocks::multiply_cc::sptr delay_corr(gr::blocks::multiply_cc::make());	// 将原始信号与延迟并共轭处理后的信号相乘,用于计算相关性,这是同步算法的一部分
    gr::filter::fir_filter_ccf::sptr delay_ma(gr::filter::fir_filter_ccf::make(	// 对上述乘积的结果应用滑动平均滤波器,滤波器的系数根据use_even_carriers确定为1或-1
        1, std::vector<float>(fft_len / 2, use_even_carriers ? 1.0 : -1.0)));
    gr::blocks::complex_to_mag_squared::sptr delay_magsquare(	// 计算滤波后信号的幅度的平方,这有助于后续的峰值检测
        gr::blocks::complex_to_mag_squared::make());
    gr::blocks::divide_ff::sptr delay_normalize(gr::blocks::divide_ff::make());	// 将上述幅度平方与一个标准化信号相除,以调整不同条件下的信号级别

    gr::blocks::complex_to_mag_squared::sptr normalizer_magsquare(	// 用于计算复数输入信号的幅度的平方
        gr::blocks::complex_to_mag_squared::make());
    gr::filter::fir_filter_fff::sptr normalizer_ma(		// 创建一个FIR滤波器实例,它的滤波器系数是一个大小为 fft_len 的向量,每个元素值为
        gr::filter::fir_filter_fff::make(1, std::vector<float>(fft_len, 0.5)));
    gr::blocks::multiply_ff::sptr normalizer_square(gr::blocks::multiply_ff::make());	// 该乘法块用于将两个浮点数输入信号逐点相乘

// 同步和频率估计
    gr::blocks::complex_to_arg::sptr peak_to_angle(gr::blocks::complex_to_arg::make());	// 将复数信号转换为其相角,用于频率误差的估计
    gr::blocks::sample_and_hold_ff::sptr sample_and_hold(	// 在检测到峰值时,保持当前的频率估计值,直到下一个峰值被检测到
        gr::blocks::sample_and_hold_ff::make());
// 峰值检测
    gr::blocks::plateau_detector_fb::sptr plateau_detector(	// 根据设置的阈值来检测峰值,这是确定信号同步点的关键步骤。
        gr::blocks::plateau_detector_fb::make(cp_len, threshold));

    // store plateau detector for use in callback setting threshold
    d_plateau_detector = plateau_detector;

// 连接组件,将所有这些组件按照处理逻辑连接起来。这包括将信号从一个块传输到另一个块,确保信号流能够按照设计的路径正确流动。
    // Delay Path
    connect(self(), 0, delay, 0);				// 连接源自身到延迟块
    connect(delay, 0, delay_conjugate, 0);		// 连接延迟块到共轭块
    connect(delay_conjugate, 0, delay_corr, 1);	// 连接共轭块到乘法块的第二个输入
    connect(self(), 0, delay_corr, 0);			// 连接源自身到乘法块的第一个输入
    connect(delay_corr, 0, delay_ma, 0);		// 连接乘法块到移动平均滤波器块
    connect(delay_ma, 0, delay_magsquare, 0);	// 连接移动平均滤波器块到幅度平方块
    connect(delay_magsquare, 0, delay_normalize, 0);	// 连接幅度平方块到归一化块
    // Energy Path
    connect(self(), 0, normalizer_magsquare, 0);	// 从源自身到能量平方块
    connect(normalizer_magsquare, 0, normalizer_ma, 0);	// 从能量平方块到移动平均滤波器
    connect(normalizer_ma, 0, normalizer_square, 0);	// 从移动平均滤波器到乘法块(第一个输入)
    connect(normalizer_ma, 0, normalizer_square, 1);	// 从移动平均滤波器到乘法块(第二个输入)
    connect(normalizer_square, 0, delay_normalize, 1);	// 从乘法块到归一化块
    // Fine frequency estimate (output 0)
    connect(delay_ma, 0, peak_to_angle, 0);	// 将delay_ma(移动平均滤波器)的输出连接到peak_to_angle块的输入
    connect(peak_to_angle, 0, sample_and_hold, 0);	// 从相位转换块到采样保持块
    connect(sample_and_hold, 0, self(), 0);		// 从采样保持块到层次块的输出
    // Peak detect (output 1)
    connect(delay_normalize, 0, plateau_detector, 0);	// 从归一化块到平台检测器
    connect(plateau_detector, 0, sample_and_hold, 1);	// 从平台检测器到采样保持块(第二输入)
    connect(plateau_detector, 0, self(), 1);	// 从平台检测器到层次块的第二输出
#ifdef SYNC_ADD_DEBUG_OUTPUT
    // Debugging: timing metric (output 2)
    connect(delay_normalize, 0, self(), 2);	// 将delay_normalize块的输出连接到层次块的第三个输出端口
#endif
}
  • ①、std::vector<float> ma_taps(fft_len / 2, 1.0);
    • 在 C++ 中用于创建一个类型为 float 的向量(vector),名称为 ma_taps。向量的大小是 fft_len / 2,其中每个元素的初始值都设置为 1.0。
    • 在信号处理中,这个向量 ma_taps 通常用作滤波器的系数。在给定的代码上下文中,这个向量被用作一个移动平均(Moving Average, MA)滤波器的系数。移动平均滤波器是一种常用的数字滤波器,主要用于平滑数据,减少噪声,从而提取有用的信号。
    • 移动平均滤波器的工作原理:
      • 系数设定:在这个案例中,所有系数都设为 1.0。这意味着每个输入样本对于输出的影响是均等的。
      • 滤波操作:移动平均滤波器通过对输入信号的连续样本进行平均来工作。具体来说,它计算当前和之前的 fft_len / 2 个样本的平均值来产生每一个输出样本。例如,如果 fft_len 是 1024,那么滤波器会计算最近 512 个样本的平均值。
    • 在 OFDM 同步中的应用:
      • 在 Schmidl & Cox OFDM 同步算法中,移动平均滤波器用于处理相关性输出。相关性计算是通过将接收到的信号与其延迟的共轭版本相乘来完成的。这种乘积输出含有频谱的峰值,这些峰值可以揭示原始信号的起始位置。
    • 使用移动平均滤波器来平滑这种乘积输出有助于:
      • 减少随机噪声:帮助稳定峰值检测,减少因噪声引起的错误检测。
      • 提升峰值的可识别性:通过平滑处理,使真正的峰值更加突出,而忽略较小的波动。
    • 因此,这个向量 ma_taps 虽然简单,但在整个 OFDM 同步过程中起着至关重要的作用,帮助算法准确地定位信号的起始点和同步帧。
  • ②、 gr::blocks::delay::sptr delay( gr::blocks::delay::make(sizeof(gr_complex), fft_len / 2));
    • 代码解析:
      • gr::blocks::delay::sptr delay:这部分定义了一个名为 delay 的智能指针(sptr,即shared pointer),指向 GNU Radio 中的一个延迟块。GNU Radio 通常使用智能指针来管理块的内存,这有助于自动处理块的生命周期和内存回收。
      • gr::blocks::delay::make(sizeof(gr_complex), fft_len / 2):这是一个静态工厂方法,用于创建延迟块的实例。它接收两个参数:
        • sizeof(gr_complex):这个参数指定了输入样本的大小,gr_complex表示复数类型的数据,sizeof(gr_complex)计算一个复数样本占用的字节数。这对于GNU Radio内部正确处理流中的数据非常重要。
        • fft_len / 2:这个参数指定延迟块应该引入的延迟量,以样本数为单位。在这里,它设置为FFT长度的一半。例如,如果FFT长度为1024,则延迟为512个样本。
    • 功能和用途
      • 在信号处理和尤其是OFDM系统中,延迟块有多种用途。在Schmidl & Cox OFDM同步算法的上下文中,延迟块的主要功能是为了创建一个与原始信号相比有时间偏移的信号版本。这种时间偏移的信号用于以下目的:
        • 相关计算:延迟块输出的信号会与原始信号的共轭相乘(通常在另一个处理块中完成)。这种乘积是计算信号自相关的一部分,自相关用于检测信号中的周期性模式,这对于确定OFDM符号的起始点非常关键。
        • 同步检测:通过比较原始信号和其延迟版本,可以检测到信号中的特定结构,如OFDM的循环前缀。这种检测是实现精确时间同步的基础。
  • ③、gr::blocks::divide_ff::sptr delay_normalize(gr::blocks::divide_ff::make());
    • 在Schmidl & Cox OFDM同步算法的上下文中,delay_normalize块用于以下具体步骤:
      • 归一化自相关结果:在计算信号的自相关后,通常得到的是原始幅度的平方,这些值可以非常大。通过将这些值除以信号的平均能量或某个参考值,可以将结果归一化,使其更加适合于后续的阈值检测和峰值检测。
      • 处理幅度平方信号:在OFDM同步中,除法块可能用于将由前面块(如complex_to_mag_squared)生成的幅度平方信号进行归一化,确保信号在不同接收条件下具有可比性。
  • ④、 connect(self(), 0, delay, 0); // 连接源自身到延迟块 connect(delay, 0, delay_conjugate, 0); // 连接延迟块到共轭块 connect(delay_conjugate, 0, delay_corr, 1); // 连接共轭块到乘法块的第二个输入 connect(self(), 0, delay_corr, 0); // 连接源自身到乘法块的第一个输入 connect(delay_corr, 0, delay_ma, 0); // 连接乘法块到移动平均滤波器块 connect(delay_ma, 0, delay_magsquare, 0); // 连接移动平均滤波器块到幅度平方块 connect(delay_magsquare, 0, delay_normalize, 0); // 连接幅度平方块到归一化块
    • 从接收信号开始,经过延迟、共轭、乘法处理、移动平均滤波,再到幅度平方和归一化处理。这个处理流程是为了实现精确的同步和信号特性提取,特别是在OFDM系统中,这些步骤对于准确地确定信号的起始点和进行频率估计是必需的。
  • ⑤、 connect(self(), 0, normalizer_magsquare, 0); // 从源自身到能量平方块 connect(normalizer_magsquare, 0, normalizer_ma, 0); // 从能量平方块到移动平均滤波器 connect(normalizer_ma, 0, normalizer_square, 0); // 从移动平均滤波器到乘法块(第一个输入) connect(normalizer_ma, 0, normalizer_square, 1); // 从移动平均滤波器到乘法块(第二个输入) connect(normalizer_square, 0, delay_normalize, 1); // 从乘法块到归一化块
    • 整个信号处理流程涉及信号能量的计算、平滑、再次加工(自乘)和用于最终归一化的准备。这些步骤共同构成了信号的能量路径,其目的是为信号的特性分析和同步处理提供稳定、可靠的能量信息
  • ⑥、connect(delay_ma, 0, peak_to_angle, 0); // 将delay_ma(移动平均滤波器)的输出连接到peak_to_angle块的输入 connect(peak_to_angle, 0, sample_and_hold, 0); // 从相位转换块到采样保持块 connect(sample_and_hold, 0, self(), 0); // 从采样保持块到层次块的输出
    • 整个流程是一个频率估计的实现,它从对信号的基本处理开始,通过提取相位信息,并在特定条件下锁定这些信息,最终提供一个稳定的频率估计输出。
  • ⑦、connect(delay_normalize, 0, plateau_detector, 0); // 从归一化块到平台检测器 connect(plateau_detector, 0, sample_and_hold, 1); // 从平台检测器到采样保持块(第二输入) connect(plateau_detector, 0, self(), 1); // 从平台检测器到层次块的第二输出
    • 配置了OFDM同步过程中的关键功能:峰值检测,这对于准确同步接收的OFDM信号至关重要。通过检测信号的峰值来确定关键时刻(如OFDM符号的开始),并通过采样保持和输出确保这些信息能够被系统正确地利用。

三、处理流程

流程图如下:

在这里插入图片描述
在这里插入图片描述

处理流程包括多个信号处理块的创建和连接,涉及信号的延迟处理、能量分析、频率估计和峰值检测。下面将详细解释各个部分的功能和它们之间的关系。

1、延迟路径(Delay Path)

  • self()delay 块:
    • connect(self(), 0, delay, 0);
      • 这是信号处理流的开始,信号从层次化块的第一个输出端口流入 delay 块。delay 块用于对信号进行时间延迟,这是许多同步和信号处理算法的基本需求。
  • delaydelay_conjugate 块:
    • connect(delay, 0, delay_conjugate, 0); 延迟后的信号进入 delay_conjugate 块,该块计算输入信号的复共轭。在信号处理中,复共轭常用于相关性计算和频谱分析。
  • delay_conjugatedelay_corr 块:
    • connect(delay_conjugate, 0, delay_corr, 1);
    • connect(self(), 0, delay_corr, 0);
      • 这里 delay_corr(一个复数乘法块)接收两个输入:直接来自 self() 的原始信号和来自 delay_conjugate 的延迟共轭信号。delay_corr 计算这两个信号的乘积,用于后续的相关性分析。
  • delay_corrdelay_ma 块:
    • connect(delay_corr, 0, delay_ma, 0);
      • 乘积输出进入 delay_ma(一个移动平均滤波器),用于平滑信号并减少噪声,这对于信号的稳定性和检测效果非常重要。
  • delay_madelay_magsquare 块:
    • connect(delay_ma, 0, delay_magsquare, 0);
      • 此块计算移动平均后信号的幅度平方,通常用于能量分析和信号强度评估。
  • delay_magsquaredelay_normalize 块:
    • connect(delay_magsquare, 0, delay_normalize, 0);
      • 最后,幅度平方信号被用来归一化,确保信号的幅度在一个标准化的范围内,为后续处理做好准备。

2、能量路径(Energy Path)

  • self()normalizer_magsquare 块:
    • connect(self(), 0, normalizer_magsquare, 0);
      • 直接将原始信号用于另一种能量分析,计算其幅度平方。
  • normalizer_magsquarenormalizer_ma 块:
    • connect(normalizer_magsquare, 0, normalizer_ma, 0);
      • 幅度平方信号进一步经过移动平均滤波处理,平滑信号。
  • normalizer_manormalizer_square 块:
    • connect(normalizer_ma, 0, normalizer_square, 0); connect(normalizer_ma, 0, normalizer_square, 1);
      • 这一步是将同一个平滑信号分两次输入到乘法块(normalizer_square),实际上是在计算信号的平方,进一步调整信号的动态范围。
  • normalizer_squaredelay_normalize 块:
    • connect(normalizer_square, 0, delay_normalize, 1);
      • 将处理后的能量信号与之前的延迟路径输出共同输入到归一化块,完成最终的信号归一化。

3、频率估计(Fine Frequency Estimate)

  • delay_mapeak_to_angle 块:
    • connect(delay_ma, 0, peak_to_angle, 0);
      • 将移动平均后的信号传输到相位转换块,用于提取信号的相位信息,这对于频率估计非常关键。
  • peak_to_anglesample_and_hold 块:
    • connect(peak_to_angle, 0, sample_and_hold, 0);
      • 相位信息被用于样本保持,确保频率估计在适当的时刻被锁定。
  • sample_and_holdself()
    • connect(sample_and_hold, 0, self(), 0);
      • 最终的频率估计结果被输出到层次化块的第一个输出端口。

4、峰值检测(Peak Detect)

  • delay_normalizeplateau_detector 块:
    • connect(delay_normalize, 0, plateau_detector, 0);
      • 归一化后的信号用于检测平台或峰值,这在同步信号时非常重要。
  • plateau_detectorsample_and_holdself()
    • connect(plateau_detector, 0, sample_and_hold, 1); connect(plateau_detector, 0, self(), 1);
      • 峰值检测结果用于第二个样本保持路径,并输出到层次化块的第二个输出端口。 调试输出(Debugging: timing metric)

5、调试选项

  • delay_normalizeself()(如果启用调试):
    • connect(delay_normalize, 0, self(), 2);
      • 提供额外的调试信息输出,用于分析和调试信号处理流程。 这段代码展示了一个复杂的信号处理框架,涉及多个处理阶段和功能块,其目的是实现精确的信号同步和特征提取,适用于高度动态的通信系统。

四、频率校正原理

这里将下图红框内的流程进行讲解梳理:

在这里插入图片描述
在这里插入图片描述

在这个GNU Radio流程图中,Schmidl & Cox OFDM synch 模块输出的频率偏移被送到了一个 Frequency Mod(频率调制)模块,然后此输出与延迟后的 OFDM 信号相乘。这是一种常见的频率校正方法,目的是要对接收到的 OFDM 信号进行补偿,以便修正由于接收机和发射机之间的频率偏差造成的效应。

流程说明:

  • 频率偏移检测:
    • Schmidl & Cox OFDM synch 模块的一个功能是估计接收信号的频率偏移量。该模块将频率偏移输出到 Frequency Mod 模块。
  • 频率调制:
    • Frequency Mod 模块根据输入的频率偏移量生成一个连续的复指数信号(相当于一个旋转向量),其频率与估计的偏移相对应。
  • 信号乘法(频率补偿):
    • 这个旋转向量与原始接收信号(通过 Delay 模块延迟一定时间以保持时序对齐)相乘,这实际上是将接收信号“旋转回去”以抵消频率偏移。换言之,如果接收信号的频率稍微高了一些,通过与一个频率稍微低的信号相乘,可以使得结果的频率与预期的 OFDM 子载波频率对齐。

为什么需要延迟?

  • 原始信号通过延迟模块的原因是为了使其与通过 Frequency Mod 模块生成的信号保持时序上的对齐。如果没有这个延迟,由于 Schmidl & Cox OFDM synch 模块和 Frequency Mod 模块本身的处理延迟,直接乘以原始信号将不会正确补偿频率偏移。

Robust Frequency and Timing Synchronization for OFDM 文献部分阅读笔记

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、Schmidl & Cox 同步模块
  • 二、C++ 源码分析
  • 三、处理流程
    • 1、延迟路径(Delay Path)
      • 2、能量路径(Energy Path)
        • 3、频率估计(Fine Frequency Estimate)
          • 4、峰值检测(Peak Detect)
            • 5、调试选项
            • 四、频率校正原理
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档