📜  使用 C 和 MATLAB 进行线性卷积

📅  最后修改于: 2022-05-13 01:54:30.034000             🧑  作者: Mango

使用 C 和 MATLAB 进行线性卷积

经常向从事电子工程的人介绍的一个关键概念是线性卷积。这是数字信号处理和信号与系统的重要组成部分。考虑到普遍兴趣和学术影响,本文介绍了这一概念及其应用,并使用 C 和 MATLAB 实现了它。

卷积:纯粹从数学上讲,卷积是计算两个图重叠的过程。事实上,卷积也被解释为两个图随时间共享的区域。比喻地说,它是两种功能之间的一种混合,一种通过另一个功能。因此,给定两个函数 F(n) 和 G(n),两者的卷积由以下数学表达式表示和给出:

线性卷积

因此,看起来很直观,我们必须考虑 TIME。卷积涉及随时间融合的函数。这是在使用时移的表达式中引入的,即 g(tu) 是 g(t) 右移“u”次)。此外,我们如何描述这个时间也很重要。在继续之前,让我们编译所涉及的先决条件:

  • 函数:在数学上,我们查看函数或图形。但是,重要的是要注意,这里的实际等效项是信号。我们处理2个信号的卷积。
  • LTI 系统:线性时不变系统是产生线性和时不变输出的系统或过程,即输出满足线性(叠加规则)并且不随时间变化。卷积是 LTI 系统的输入和输出之间的关系。
  • 脉冲响应:如果所考虑的系统受到短时时域信号的影响,通常会得到脉冲响应。不同的 LTI 系统具有不同的脉冲响应。
  • 时间系统:我们可以使用连续时间信号或离散时间信号。假设读者知道并理解差异。可以为 CT 和 DT 信号定义卷积。

线性卷积:线性卷积是一种在给定系统脉冲响应的情况下将 LTI 系统的输出和输入联系起来的方法。显然,需要将输入信号与系统的脉冲响应进行卷积。使用前面的表达式,可以形成以下等式 -

之所以对表达式进行无限次求和,只是为了确保两个函数重叠的概率为1。脉冲响应是无限时移的,因此在一段时间内,两个函数肯定会重叠。代表程序员运行无限循环似乎是粗心的——只要两个函数不重叠,代码就可以继续执行。

解决方案在于使用 LTI 系统。由于函数不会随着时间的推移而改变它们的值/形状(时不变),它们可以简单地相互靠近。请记住,只需要输出,而“何时”收到输出并不重要。所有手动计算也依赖于相同的想法。

说明:这是计算输出时可能使用的一种技术:

  • 将输入信号和脉冲响应作为两个单独的单行矩阵。
  • 脉冲响应的第一个元素与输入信号的每个元素相乘。该结果被存储。
  • 脉冲响应的第二个元素与输入信号的每个元素相乘。结果右移一级并存储。
  • 以上两步是针对脉冲响应中的其余元素完成的。
  • 将所有元素相乘后,将所有结果相互对齐。请参考下图。
  • 垂直地,添加每列中的所有元素。
  • 生成的单行矩阵是卷积输出。

线性卷积的解释



方法:

  • 获取输入信号和脉冲响应作为两个不同的数组。
  • 获取时间索引序列。时间索引序列是 MATLAB 获知我们的函数何时启动的一种方式。它默认从 0 开始,即 [0 1 2 3 ……..]。然而,第二个序列或脉冲响应不必同时开始。可以选择推迟或提前开始。如果它提前一秒引入,那么它的时间索引序列应该输入为[-1 0 1 2 …….]。
  • 使用用户定义的函数。函数findconv()定义了如何计算输出的长度。将“ ny ”定义为输出中 x 轴的长度。它早先被定义为从“ nybegin ”开始并延伸到“ nyend ”的数组。函数calconv()findconv被引用()和通过取k和n的不同的值依次计算的实际输出,使用2个不同的for循环。
  • 对于 n 的每个值,通过在每次迭代中取不同的 X(k) 值来计算输出的总和。
  • 这个结果存储在一个数组 – y(n) 中。
  • 绘制结果。由于输入本质上是离散的,因此在绘图时使用了函数stem()。如果要绘制连续时间输出,则使用 stem() 没有任何意义,因为它会使输出看起来像是被采样的。建议在绘制连续值时使用plot(x_axis, y_axis)
  • 注意:不要改变时间索引序列和第一和第二序列的长度。 stem()返回一个错误,表明它无法在输出中建立 x 轴的长度。

下面是实现上述方法的 Matlab 程序:

Matlab
% Matlab program to implement
% the above approach
clc;
x = input('Enter the 1st sequence: ');
nx = input('Enter the Time Index sequence: ');
h = input('Enter the second sequence: ');
nh = input('Enter the Time Index sequence: ');
  
% Sending parameters to a separate function
[y, ny] = findconv(x, nx, h, nh);
  
figure;
stem(ny, y);
xlabel('Time');
ylabel('Amplitude');
title('Linear Convolution');
disp(y);
disp(ny);
  
% Function to find the length of our output
function [y, ny] = findconv(x, nx, h, nh)
    nybegin = nx(1) + nh(1);
    nyend = nx(length(nx)) + nh(length(nh));
    ny = nybegin : nyend;
      
    % Calling a function within a function
    y = calconv(x, h);
end
  
% Here is where the summation is calculated
function [y] = calconv(x, h)
    l1 = length(x);
    l2 = length(h);
    N = l1 + l2 - 1;
    for n = 1 : 1 : N
        y(n) = 0;
        for k = 1 : 1 : l1
            if(n - k + 1 >= 1 & n - k + 1 <= l2)
                y(n) = y(n) + x(k) * h(n - k + 1);
            end
        end
    end
end


C
// C program for the above approach
#include 
#include 
  
void calc_conv(int*, int*);
  
// Chose any length. They must
// all be equal though.
int x[10], h[10], y[10];
  
int l1, l2 = 0;
  
// Driver code
void main()
{
    printf("Enter the length of "
           "the first sequence: ");
    scanf("%d", &l1);
    printf("Enter the length of the"
           " second sequence: ");
    scanf("%d", &l2);
  
    // Delegating calculation to a
    // separate function.
    calc_conv(l1, l2);
}
  
void calc_conv(int* len1, int* len2)
{
    int l = (*len1) + (*len2) - 1;
    int i, j, n, k = 0;
  
    // Getting values of 1st sequence
    for (i = 0; i < *len1; i++) {
        scanf("%d", &x[i]);
    }
  
    // Getting values of 2nd sequence
    for (j = 0; j < *len2; j++) {
        scanf("%d", &h[i]);
    }
  
    for (n = 0; n < l; n++) {
        y[n] = 0;
        for (k = 0; k < len1; k++) {
  
            // To right shift the impulse
            if ((n - k) >= 0
                && (n - k) < *len2) {
  
                // Main calculation
                y[n] = y[n] + x[k] * h[n - k];
            }
            printf("%d\t", y[n]);
        }
    }
}


输入(任意一组数字):

>> Enter the 1st Sequence: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]
>> Enter the Time Index sequence: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
>> Enter the second sequence: [1 2 2 1 4 5 2 2 1 1 4 5 2 2 1 2 2]
>> Enter the Time Index sequence: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]

输出:

>> Columns 1 through 17
    1     4     9    15    25    40    57    76    96   117   142   172   204   238   273   310   349

>> Columns 18 through 33

   370   372   372   388   349   288   276   262   264   265   211   135   108    79    66    34

第一和第二序列

这些是输入序列。请注意,它们是离散时间序列。

线性卷积

输出。这在时间上也是离散的。

注意:鼓励读者使用连续时间信号尝试相同的方法。在这些情况下,输入被视为预定义的连续信号,例如 y = sin x。此外,使用 plot(x_axis, y_axis) 而不是 stem(x_axis, y_axis)。

下面是实现上述方法的 C 程序:

C

// C program for the above approach
#include 
#include 
  
void calc_conv(int*, int*);
  
// Chose any length. They must
// all be equal though.
int x[10], h[10], y[10];
  
int l1, l2 = 0;
  
// Driver code
void main()
{
    printf("Enter the length of "
           "the first sequence: ");
    scanf("%d", &l1);
    printf("Enter the length of the"
           " second sequence: ");
    scanf("%d", &l2);
  
    // Delegating calculation to a
    // separate function.
    calc_conv(l1, l2);
}
  
void calc_conv(int* len1, int* len2)
{
    int l = (*len1) + (*len2) - 1;
    int i, j, n, k = 0;
  
    // Getting values of 1st sequence
    for (i = 0; i < *len1; i++) {
        scanf("%d", &x[i]);
    }
  
    // Getting values of 2nd sequence
    for (j = 0; j < *len2; j++) {
        scanf("%d", &h[i]);
    }
  
    for (n = 0; n < l; n++) {
        y[n] = 0;
        for (k = 0; k < len1; k++) {
  
            // To right shift the impulse
            if ((n - k) >= 0
                && (n - k) < *len2) {
  
                // Main calculation
                y[n] = y[n] + x[k] * h[n - k];
            }
            printf("%d\t", y[n]);
        }
    }
}

输入:

Enter the length of the first sequence: 4
Enter the length of the second sequence: 4
Enter x[0]: 1
Enter x[1]: 2
Enter x[2]: 3
Enter x[3]: 4
Enter h[0]: 1
Enter h[1]: 2
Enter h[2]: 2
Enter h[3]: 1

输出:

1    4    9    15    16    11    4

输出

想要从精选的视频和练习题中学习,请查看C 基础到高级C 基础课程