相关运算及实现

news2024/11/25 4:40:11

本文介绍相关运算及实现。

相关运算在相关检测及数字锁相放大中经常用到,其与卷积运算又有一定的联系,本文简要介绍其基本运算及与卷积运算的联系,并给出实现。

1.定义

这里以长度为N的离散时间序列x(n),y(n)为例,相关运算定义如下:

1)R_{xy}(n)

x(n)保持不动,y(n)相对于x(n)向左移动

R_{xy}(n)=\sum_{m=0}^{N-1}x(m)y(m+n)=\sum_{m=0}^{N-1}x(m-n)y(m)

最后面的式子是等效情况下,y(n)不动,x(n)相对于y(n)向右移动

2)R_{yx}(n)

y(n)保持不动,x(n)相对于y(n)向左移动

R_{yx}(n)=\sum_{m=0}^{N-1}y(m)x(m+n)=\sum_{m=0}^{N-1}y(m-n)x(m)

最后面的式子是等效情况下,x(n)不动,y(n)相对于x(n)向右移动

注意:

1)R_{xy}(n)R_{yx}(n)的定义是不一样的,R_{xy}(n)=R_{yx}(-n)

2)n的取值范围为[-(N-1),N-1]

3)相关运算结果长度为2*N-1(2个序列长度和减1)

对比卷积公式:

z(n)=x(n)\ast y(n)=\sum_{m=0}^{N-1}x(m)y(n-m)=\sum_{m=0}^{N-1}y(m)x(n-m)

注意:

1)n的取值范围为[0,2*N-2]

2)卷积运算结果长度为2*N-1(2个序列长度和减1)

3)后面2个等式成立使用的是卷积交换律

对比卷积公式和相关运算公式,可以知道,无论是R_{xy}(n)还是R_{yx}(n),它们与卷积运算差别仅在运算时x(n)或y(n)是否需要折叠(转换成x(-n)或y(-n))。因此,在做相关运算时可以将输入x(n)或y(n)先折叠,再经过卷积运算即可求出相关运算结果。

这里用Matlab作下验证,在Matlab命令行下输入:

x=[1,2,3];
y=[3,2,1];

z1=xcorr(x,y);
z2=conv(x, flip(y));

其中flip(y)即对y进行折叠(反转序列),得到的结果是z1和z2是相等的。

2.实现

这里基于C语言来实现。参考代码如下:

static void correlate(float *pSrcA, uint32_t srcALen, float *pSrcB, uint32_t srcBLen, float *pDst);


static void correlate(float *pSrcA, uint32_t srcALen, float *pSrcB, uint32_t srcBLen, float *pDst)
{
    float *pIn1 = pSrcA;                       /* inputA pointer */
    float *pIn2 = pSrcB + (srcBLen - 1U);      /* inputB pointer */
    float sum = 0;                             /* Accumulator */
    uint32_t i = 0U;                           /* loop counter */
    uint32_t j = 0U;                           /* loop counter */
    uint32_t inv = 0U;                         /* Reverse order flag */
    uint32_t tot = 0U;                         /* Length */

    if ((pSrcA == NULL) || (srcALen == 0) || (pSrcB == NULL) || (srcBLen == 0) || (pDst == NULL))
    {
        return ;
    }

    /* The algorithm implementation is based on the lengths of the inputs. */
    /* srcB is always made to slide across srcA. */
    /* So srcBLen is always considered as shorter or equal to srcALen */
    /* But CORR(x, y) is reverse of CORR(y, x) */
    /* So, when srcBLen > srcALen, output pointer is made to point to the end of the output buffer */
    /* and a varaible, inv is set to 1 */
    /* If lengths are not equal then zero pad has to be done to  make the two
     * inputs of same length. But to improve the performance, we assume zeroes
     * in the output instead of zero padding either of the the inputs*/
    /* If srcALen > srcBLen, (srcALen - srcBLen) zeroes has to included in the
     * starting of the output buffer */
    /* If srcALen < srcBLen, (srcALen - srcBLen) zeroes has to included in the
     * ending of the output buffer */
    /* Once the zero padding is done the remaining of the output is calcualted
     * using convolution but with the shorter signal time shifted. */

    /* Calculate the length of the remaining sequence */
    tot = ((srcALen + srcBLen) - 2U);

    if (srcALen > srcBLen)
    {
      /* Calculating the number of zeros to be padded to the output */
      j = srcALen - srcBLen;

      /* Initialise the pointer after zero padding */
      pDst += j;
    }
    else if (srcALen < srcBLen)
    {
      /* Initialization to inputB pointer */
      pIn1 = pSrcB;

      /* Initialization to the end of inputA pointer */
      pIn2 = pSrcA + (srcALen - 1U);

      /* Initialisation of the pointer after zero padding */
      pDst = pDst + tot;

      /* Swapping the lengths */
      j = srcALen;
      srcALen = srcBLen;
      srcBLen = j;

      /* Setting the reverse flag */
      inv = 1;
    }

    /* Loop to calculate convolution for output length number of times */
    for (i = 0U; i <= tot; i++)
    {
      /* Initialize sum with zero to carry on MAC operations */
      sum = 0.0f;

      /* Loop to perform MAC operations according to convolution equation */
      for (j = 0U; j <= i; j++)
      {
        /* Check the array limitations */
        if ((((i - j) < srcBLen) && (j < srcALen)))
        {
          /* z[i] += x[i-j] * y[j] */
          sum += pIn1[j] * pIn2[-((int32_t)i - (int32_t)j)];
        }
      }
      /* Store the output in the destination buffer */
      if (inv == 1)
      {
        *pDst-- = sum;
      }
      else
      {
        *pDst++ = sum;
      }
    }
}

main函数:

int main()
{
    float x[] = {1, 2, 3, 4};
    float y[] = {4, 3, 2, 1};
    float z[7] = {0};
    uint32_t i = 0;

    correlate(x, 4, y, 4, z);

    for (i = 0; i < sizeof(z) / sizeof(z[0]); i++)
    {
        printf("%f ", z[i]);
    }

    printf("\r\n");

    return 0;
}

输出结果:

作为对比,在Matlab命令行下输入:

x=[1,2,3,4];
y=[4,3,2,1];
z=xcorr(x,y);

查看结果和用C语言实现的是一致的。

3.应用

通过相关运算,我们得到了相关序列,为了方便后续数据处理,需要对得到的相关序列进行归一化处理,对于2个互相关序列,有如下2种归一化方法:

1)有偏估计

\hat{R_{xy,biased}(m)}=\frac{1}{N}\hat{R_{xy}(m)}

2)无偏估计

\hat{R_{xy,unbiased}(m)}=\frac{1}{N-\left | m \right |}\hat{R_{xy}(m)}

为了查看这2者之间差异,在Matlab命令行下,输入如下命令:

fm=1000;
fs=100000;
N=fs/fm;
k=0:1:1000;
theta=pi/8;
x=sin(2*k*pi/N + theta);%原始信号
xn=awgn(x,20,0);%原始信号加噪声
subplot(5,1,1);
plot(k,x);
title('x');
subplot(5,1,2);
plot(k,xn);
title('xn');
[r,lags]=xcorr(xn,x,500);%未缩放的互相关
subplot(5,1,3);
plot(k,r);
title('corr none');
[rb,lags]=xcorr(xn,x,500,'biased');%互相关的有偏估计
subplot(5,1,4);
plot(k,rb);
title('corr biased');
[rub,lags]=xcorr(xn,x,500,'unbiased');%互相关的无偏估计
subplot(5,1,5);
plot(k,rub);
title('corr unbiased');

输出结果:

由图可知:

1)“未缩放的互相关运算”仅是相关运算计算出的序列,在2个互相关信号重叠(相位差为0)时值最大

2)“互相关的有偏估计”在2个互相关信号重叠(相位差为0)时值最大,且为原始信号幅值的一半

3)“互相关的无偏估计”则有如下特点:

a)与原始信号频率相同

b)输出为cos信号,且起始相位为2个互相关信号相位之差(0)

c)信号幅值为原信号幅值的一半

这其实和相敏检波(PSD)运算效果是一致的(未加LPF)。

总结,本文介绍了相关运算及实现。

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

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

相关文章

2024 年 6 款最佳高清屏幕录像机,用于录制和共享

为了获得令人惊叹和详细的视频&#xff0c;一个优秀的高清屏幕 录像机是必不可少的。高清录像机广泛用于录制研讨会、会议、培训课程&#xff0c;甚至视频游戏。顶屏摄像头通常包含视频编辑、动画和 4K 录制等尖端功能和高端效果。 市场上有大量适用于 Windows 和 Mac 的屏幕录…

冯喜运:4.29黄金原油多空争夺,今日操作建议走势分析

【黄金消息面分析】&#xff1a;周一&#xff08;4月29日&#xff09;亚市早盘&#xff0c;现货黄金窄幅震荡&#xff0c;目前交投于2328美元/盎司。金价上周五反弹受阻&#xff0c;收报2337.36美元/盎司&#xff0c;此前数据显示美国物价升幅符合预期&#xff1b;随着中东危机…

认识及创建线程(Thread)

1 概念 1.1线程是什么 线程是CPU调度的基本单位&#xff0c;它是在进程内部运行的执行流&#xff0c;线程比进程粒度更细&#xff0c;调度成本更低 一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行着多…

git 命令怎么回退到指定的某个提交 commit hash 并推送远程分支?

问题 如下图&#xff0c;我要回退到 【002】Babel 的编译流程 这一次提交 解决 1、先执行下面命令&#xff0c;输出日志&#xff0c;主要就是拿到提交 commit 的 hash&#xff0c;上图红框即可 git log或者 vscode 里面直接右击&#xff0c;copy sha 2、执行下面命令回退 g…

AOMEI Partition Assistant傲梅分区助手技术员版:专业级的硬盘分区利器

在数字化时代&#xff0c;数据存储和管理变得愈发重要。对于电脑技术员而言&#xff0c;一款功能强大、操作简便的分区工具无疑是提高工作效率的得力助手。而傲梅分区助手技术员版&#xff08;AOMEI Partition Assistant&#xff09;正是这样一款备受赞誉的专业级硬盘分区软件。…

9种单片机常用的软件架构

长文预警&#xff0c;加代码5000多字&#xff0c;写了4个多小时&#xff0c;盘软件架构&#xff0c;这篇文章就够了! 可能很多工程师&#xff0c;工作了很多年&#xff0c;都不会有软件架构的概念。 因为我在做研发工程师的第6年&#xff0c;才开始意识到这个东西&#xff0c;在…

【Linux】对信号产生的内核级理解

一、键盘产生信号 键盘产生信号这里就要涉及一个重要的概念了&#xff0c;叫硬件中断。我这里会粗粒度地说一下键盘产生信号&#xff0c;以及信号被上层软件读到的过程&#xff0c;只是说一下我自己的理解。 1.1、硬件中断 硬件中断是计算机中的一种机制&#xff0c;它允许硬件…

Python 自定义日志输出

Python 有着内置的日志输出模块&#xff1a;logging 使用也很方便&#xff0c;但我们今天不说这个&#xff0c;我们用文件读写模块&#xff0c;实现自己的日志输出模块&#xff1b;这样在项目中&#xff0c;可以存在更高的自由度及更高的扩展性&#xff1b; 先来看看日志输出…

道路积水检查与报警

文章目录 模型训练积水图像数据集yolo训练流程 图像采集图像预处理模型训练参数设置积水检测与分类数据存储界面制作 模型训练 积水图像数据集 收集积水图像&#xff0c;制作数据集。每张图像对应的标注信息&#xff0c;通常包括目标的类别、边界框坐标等。标注数据可以通过标…

SAP的生成式AI

这是一篇openSAP中关于SAP生成式AI课程的笔记&#xff0c;原地址https://open.sap.com/courses/genai1/ 文章目录 Unit 1: Approaches to artificial intelligence概念三种范式监督学习非监督学习强化学习 Unit 2: Introduction to generative AI生成式AI基础模型关系基础模型有…

软件物料清单(SBOM)生成指南 .pdf

如今软件安全攻击技术手段不断升级&#xff0c;攻击数量显著增长。尤其是针对软件供应链的安全攻击&#xff0c;具有高隐秘性、追溯难的特点&#xff0c;对企业软件安全威胁极大。 同时&#xff0c;软件本身也在不断地更新迭代&#xff0c;软件内部成分安全性在持续变化浮动。…

报错:测试报错postman(测试接口)

报错如下 c.e.exception.GlobalExceptionHandler : 异常信息&#xff1a; Content type multipart/form-data;boundary--------------------------952399813172082093419475;charsetUTF-8 not supported 解决&#xff1a; 异常信息 Content type multipart/form-data;boundary…

STM32使用PWM控制舵机

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. 舵机简介 2. 硬件连接 3. 代码实现 3.1 PWM.c 3.2 PWM.h 3.3 Servo.c 3.4 Servo.h 3.5 main.c 3.6 完整工程文件 PWM和OC输出详解&#xff1a; STM32定时器的OC比较和PWM​​​​​​​ 1. …

树莓派学习笔记--树莓派终端基本操作与系统备份(全卡备份,压缩备份)

树莓派终端基本操作 sudo su #切换为超级用户身份 su lyh #切换回普通用户lyh&#xff08;用户名&#xff09;#目录切换命令 pwd #显示当前所在目录 cd ~ #切换到主目录&#xff08;/home/用户名&#xff09;,~也可省略不写 cd dir …

python程序设计语言超详细知识总结

Python 首先 python 并不是简单&#xff0c;什么语言都有基础和高级之分&#xff0c;要想掌握一门语言&#xff0c;必须把高级部分掌握才行。 HelloWorld helloWorld.py print(hello, world)数据类型与变量 变量的数据类型数据类型描述变量的定义方式整数型 (int)整数&…

OpenVINO安装教程 Docker版

从 Docker 映像安装IntelDistribution OpenVINO™ 工具套件 本指南介绍了如何使用预构建的 Docker 镜像/手动创建镜像来安装 OpenVINO™ Runtime。 Docker Base 映像支持的主机操作系统&#xff1a; Linux操作系统 Windows (WSL2) macOS(仅限 CPU exectuion) 您可以使用预…

微软最新季度业绩结果充分说明了云和AI的增长、谷歌和AWS的竞争

微软最新的季度业绩超出了华尔街的各种预期&#xff0c;但对其服务合作伙伴来说&#xff0c;最重要的是这家科技巨头的预期&#xff1a;人工智能不仅能够增长&#xff0c;而且其云产品尚未达到稳定状态——人工智能是云的潜在增长加速器。 周五的一份分析师报告称&#xff0c;…

实现堆的各种基本运算的算法(数据结构)

以小堆为例&#xff0c;大堆就举一反三了。 堆的物理结构就是普通的数组&#xff0c;但是逻辑结构看成了一颗完全二叉树。 小堆&#xff0c;就是树的每一个父节点都小于他的孩子节点。如图中第一排的a与b。大堆&#xff0c;就是树的每一个父节点都大于他的孩子节点。如图中第…

Mysql基础(三)DDL之create table语句

一 create table 创表 说明&#xff1a; create table相关语句从功能上进行讲解补充&#xff1a; 前面已经讲解过相关的约束,已进行相关的铺垫声明&#xff1a; 参考价值较少,了解即可 ① 基本语法 思考&#xff1a; 约束加在哪里? ② 创建新表 强调&#xff1a;使…

node环境创建Vue项目

node环境创建Vue项目 目录 node环境创建Vue项目安装node.js安装Vue创建Vue项目 安装node.js 【1】.官网下载 【2】.选择路径 【3】配置环境变量 后面就是一路next完成安装 【4】测试 cmd输入node指令&#xff0c;显示版本号证明安装成功 安装Vue 【1】安装cnpm 这是由淘宝…