侧边栏壁纸
  • 累计撰写 35 篇文章
  • 累计创建 9 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

数字信号处理-离散线性卷积

Hollies
2023-11-30 / 0 评论 / 0 点赞 / 15 阅读 / 6233 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-06-08,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 要求

计算两个正弦序列的线性卷积和。

数字信号处理_离散线性卷积_图1.png

2. 基本原理

数字信号处理_离散线性卷积_图2.png

将第一个序列的第一个数与第二个序列的每个数相乘;

将第一个序列的第二个数与第二个序列的每个数想乘,且横坐标整体向右移1;

执行第二步直到第一个序列的数全部使用一遍;

将相同横坐标上的值相加。

与课上从右往左的思维相反,这里使用从左往右;不必担心会有区别,原来我们使用从右往左的乘法计算是为了方便进位计算,这里不涉及进位,使用从左往右的思维能够使代码层面容易实现。

3. 程序实现

C语言

代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 需要手动输入数据请把下面取消注释
// #define MANUAL 1

#define L_MAX 720 // 序列最大长度
#define PI 3.1415926

void linearConvolution();
void sinGen(float s[], float U, int n);

// 变量定义
float s1[L_MAX], s2[L_MAX], s3[2 * L_MAX - 1]; // 定义两个输入序列和一个输出序列
int l1, l2;                                    // 两个输入序列长度
// 主函数
int main()
{
    system("CHCP 65001");
#ifdef MANUAL
    printf("请输入第一个序列的长度:");
    scanf("%d", &l1);
    printf("请输入第一个序列:");
    if (l1 <= L_MAX)
    {
        for (int i = 0; i < l1; i++)
        {
            scanf("%f", &s1[i]);
        }
    }
    else
    {
        printf("输入长度超出最大长度!\n");
        return 0;
    }

    printf("请输入第二个序列的长度:");
    scanf("%d", &l2);
    printf("请输入第二个序列:");
    if (l2 <= L_MAX)
    {
        for (int i = 0; i < l2; i++)
        {
            scanf("%f", &s2[i]);
        }
    }
    else
    {
        printf("输入长度超出最大长度!\n");
        return 0;
    }
#endif

#ifndef MANUAL
    l1 = l2 = L_MAX;
    // 生成正弦信号
    sinGen(s1, 1, -18);
    sinGen(s2, 1, 0);
#endif

    linearConvolution();
    // 创建并打开数据文件
    FILE *sf1 = fopen("sf1.txt", "w");
    FILE *sf2 = fopen("sf2.txt", "w");
    FILE *sf3 = fopen("sf3.txt", "w");
    // 将数据写入文件
    for (int i = 0; i < l1; i++)
    {
        fprintf(sf1, "%f\n", s1[i]);
    }
    for (int i = 0; i < l2; i++)
    {
        fprintf(sf2, "%f\n", s2[i]);
    }
    for (int i = 0; i < l1 + l2 - 1; i++)
    {
        fprintf(sf3, "%f\n", s3[i]);
    }
    // 关闭文件
    fclose(sf1);
    fclose(sf2);
    fclose(sf3);
    return 0;
}
/**
 * @brief   线性卷积
 */
void linearConvolution()
{
    for (int i = 0; i < l1; i++)
    {
        for (int j = 0; j < l2; j++)
        {
            s3[i + j] += s1[i] * s2[j];
        }
    }
}
/**
 * @brief 产生正弦序列
 * @param   U:幅值
 * @param   n:相移,默认一周期360点
 * @return
 */
void sinGen(float s[], float U, int n)
{
    for (int i = 0; i < L_MAX; i++)
    {
        s[i] = U * sin((i + n) * PI / 180);
    }
}

sin函数以及文件使用参考:

PLL锁相环-SOGI变换-GiftHub - 致力分享学习中的好东西-GiftHub学习

结果

使用matlab导入数据(需要把工作目录转到数据文件的文件夹)

close all;
clear;
%数据导入
load('sf1.txt');
load('sf2.txt');
load('sf3.txt');
%设定要画的点数
pointNum = 720;
%设置输入序列和输出序列的横坐标
x1 = 0:1:pointNum-1;
x2 = 0:1:(pointNum * 2 - 2);
%从文件导出数据
s1 = sf1(1:pointNum,1);
s2 = sf2(1:pointNum,1);
s3 = sf3(1:(pointNum * 2 - 1),1);
%绘制
subplot(1,3,1);
stem(x1,s1);
subplot(1,3,2);
stem(x1,s2);
subplot(1,3,3);
stem(x2,s3);

运行之后可以看到图形,符合卷积定义

数字信号处理_离散线性卷积_图3.png

Matlab

代码

close all;
clear;
%输入序列和输出序列的横坐标
pointNum = 360;
x1 = 0:1:pointNum-1;
x2 = 0:1:pointNum*2-2;
%生成两个正弦序列
f1 = sin(x1/180*pi);
f2 = sin(x1/180*pi-0.1*pi);
%卷积
f3 = linearConv(f1, f2);
%绘制
subplot(1,3,1);
stem(x1,f1);
subplot(1,3,2);
stem(x1,f2);
subplot(1,3,3);
stem(x2,f3);

%线性卷积函数
function [f3] = linearConv(f1, f2)
l1 = length(f1);
l2 = length(f2);
f3 = zeros(1,l1+l2-1);
for i=1:1:l1
    for j=1:1:l2
        f3(i+j-1)=f3(i+j-1)+f1(i)*f2(j);
    end
end
end

结果

数字信号处理_离散线性卷积_图4.png

可以看到与C程序参数相同的时候结果一样,都符合卷积和效果。

附件

C语言卷积文件

LinearConvolution.c

C语言验证文件

verify_c.m

Matlab文件

LinearConvolution.m

参考

Linear Convolution using C and MATLAB - GeeksforGeeks

0

评论区