一、回顾欧拉公式

1.1 欧拉公式

欧拉公式为:

e^{i\theta}=\cos\theta+i\sin\theta

它表示单位圆上的一个点。随着 θ 变大,这个复数就在平面上旋转。

例如:

e^{i\omega t}

如果取实部:

\operatorname{Re}\left(e^{i\omega t}\right)=\cos \omega t

如果取虚部:

\operatorname{Im}\left(e^{i\omega t}\right)=\sin \omega t

二、傅里叶变换就是频率探针

2.1 案例

假设我们的源信号是:

x(t)=\sin(2\pi\cdot 50t)+0.5\sin(2\pi\cdot 120t)

其含义是:

x(t) = 50Hz 正弦波 + 120Hz 正弦波

其中成分为:

  • 50Hz 分量幅值 = 1
  • 120Hz 分量幅值为 = 0.5

2.2 使用积分计算函数成分

2.2.1 频率探针

可以把傅里叶分析理解成:拿不同频率的波,一个个去和原信号对暗号。

2.2.1 50Hz 积分探针

首先用 50Hz 的波去测试,让它与原信号相乘 (相当于重合的面积相乘),然后在一段时间内积分:

\int_{0}^{T} x(t)\sin(2\pi\cdot 50t)\,dt

因为 x(t) 原本就有50Hz信号,所以平方永远不小于零,所以会不断累加,结果比较大。

2.2.2 120Hz 积分探针

同样的,我们对 120Hz 也求积分,求他们重合的面积:

\int_{0}^{T} x(t)\sin(2\pi\cdot 120t)\,dt

2.2.3 计算结果

在下列案例中,引入了实部和虚部的概念。

这是因为我们的案例波形 t=0 时刻开始周期,所以实部统计不到为 0。

为了避免复杂,这里不举例 t=x 时刻开始周期的 f=(t) 函数了。

#include <stdio.h> // 标准输入输出函数
#include <math.h>  // sin、cos、sqrt 数学函数

#define PI 3.14159265358979323846
#define N 100000 // 数值积分分段数量
#define T 1.0    // 信号观察时间,单位:s

// 生成包含 50 Hz 和 120 Hz 的测试信号
double signal(double t)
{
    return sin(2.0 * PI * 50.0 * t) + 0.5 * sin(2.0 * PI * 120.0 * t);
}

// 计算信号在指定频率 f 下的傅里叶积分
void calculate_fourier(double f)
{
    double dt = T / N; // 每个积分小区间的时间宽度
    double real = 0.0; // 傅里叶变换的实部
    double imag = 0.0; // 傅里叶变换的虚部

    // 用矩形面积累加的方式近似计算连续积分
    for (int n = 0; n < N; n++)
    {
        double t = n * dt;               // 当前时刻
        double x = signal(t);            // 当前时刻的信号值
        double angle = 2.0 * PI * f * t; // 检测频率对应的相位角

        real += x * cos(angle) * dt; // 计算实部积分
        imag -= x * sin(angle) * dt; // 计算虚部积分
    }

    // 根据实部和虚部计算复数模长
    double magnitude = sqrt(real * real + imag * imag);

    // 将傅里叶积分模长还原为单边正弦波幅值
    double amplitude = 2.0 * magnitude / T;

    // 输出当前检测频率的计算结果
    printf("检测频率:%6.1f Hz\n", f);
    printf("实部 Re: % .6f\n", real);
    printf("虚部 Im: % .6f\n", imag);
    printf("模长:     %.6f\n", magnitude);
    printf("幅值:     %.6f\n\n", amplitude);
}

int main(void)
{
    // 分别检测 50 Hz、120 Hz 和 80 Hz
    calculate_fourier(50.0);
    calculate_fourier(120.0);
    calculate_fourier(80.0);

    return 0;
}

2.3 引入真正的傅里叶公式

X(f)=\int_{0}^{T}x(t)e^{-j2\pi ft}\,dt

其含义是原信号乘反向旋转频率,然后积分累加。

其中:

e^{-j2\pi ft}

就是用来检测频率 f=x(t) 的反向旋转探针。

将 公式展开后得到:

e^{-j2\pi ft}=\cos(2\pi ft)-j\sin(2\pi ft)

积分后也就是:

X(f) = \int_{0}^{T} x(t) \left[ \cos(2\pi ft)-j\sin(2\pi ft) \right] \,dt

将实部分虚部分离可得:

X(f) = \int_{0}^{T}x(t)\cos(2\pi ft)\,dt - j\int_{0}^{T}x(t)\sin(2\pi ft)\,dt

2.4 离散化的 C 代码

离散化代码如下:

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

#define N 1000                    // 定义采样点数,也就是信号长度为 1000 个点
#define FS 1000.0                 // 定义采样频率,单位为 Hz,这里表示每秒采样 1000 次
#define PI 3.14159265358979323846 // 定义圆周率常量,用于角度计算

int main(void)
{                // 主函数函数体开始
    double x[N]; // 定义长度为 N 的数组,用来保存测试信号的采样值

    // 构造一个测试信号:由 50Hz 正弦波和 120Hz 正弦波叠加而成
    for (int n = 0; n < N; n++)
    {                           
        double t = n / FS;      // 根据采样点序号计算当前时间,单位为秒

        // 给第 n 个采样点赋值生成 50Hz、幅值为 1 的正弦信号叠加 120Hz、幅值为 0.5 的正弦信号
        x[n] = sin(2.0 * PI * 50.0 * t) + 0.5 * sin(2.0 * PI * 120.0 * t);
    } 
    // 对信号 x 进行离散傅里叶变换 DFT,计算频谱
    for (int k = 0; k < N / 2; k++) // 遍历频率下标,只计算前半部分频谱
    {                               // 外层 for 循环函数体开始
        double real = 0.0;          // 保存 DFT 结果的实部,初始值为 0
        double imag = 0.0;          // 保存 DFT 结果的虚部,初始值为 0

        for (int n = 0; n < N; n++)              // 遍历所有采样点,用于计算当前频率 k 的 DFT
        {                                        // 内层 for 循环函数体开始
            double angle = 2.0 * PI * k * n / N; // 计算 DFT 公式中的旋转角度

            real += x[n] * cos(angle); // 累加当前频率分量的实部
            imag -= x[n] * sin(angle); // 累加当前频率分量的虚部,负号来自 DFT 定义
        }

        // 根据实部和虚部计算当前频率分量的幅值
        double amplitude = 2.0 / N * sqrt(real * real + imag * imag); // 计算单边频谱幅值

        // 根据频率下标 k 计算对应的实际频率
        double freq = k * FS / N; // 当前频率点对应的频率,单位为 Hz

        // 只打印幅值比较明显的频率成分
        if (amplitude > 0.1)                                                // 如果当前频率分量的幅值大于 0.1,就认为它比较明显
        {                                                                   // if 语句函数体开始
            printf("freq = %7.2f Hz, amplitude = %.3f\n", freq, amplitude); // 输出频率和幅值
        }
    } 

    return 0;
} 

三、 漏水水桶案例

3.1 漏水水桶案例引入

假设我们有一个漏水的水桶,水量是:

x(t)

假设规律是:

\frac{dx}{dt}=-2x\ (L/min)

  • x = 剩余水量

水量的导数是 -2x。

意味着,任意时刻,水量的瞬时减少速率 (每分钟流量),等于当前水量的 2 倍。

假设当前桶中有 1L 水,在不考虑微分的情况,1 分钟后会流出 2L 水。

写成自然常数的形式就是:

x(t) = x_{0}e^{-2t}

  • x0 = 初始水量

3.2 变量分离的微分形式计算

我们假设桶里目前水量为 5L,试求 1 分钟后的桶中水量。

已知水量变化的微分方程为:

\frac{dx}{dt}=-2x\ (L/min)

把 xxx 和 ttt 分到两边:

\frac{1}{x}\,dx=-2\,dt

按照初始 t=0,x=5 (5L 水) 计算 t = 1 (1 分钟),两边做定积分:

\int_{5}^{x_1}\frac{1}{x}\,dx = -2\int_{0}^{1}dt

所以:

x_1\approx0.6767\text{ L}

3.3 自然指数 e 形式计算

5e^{-2}

四、赫维塞斯算子

4.1 得到算子

首先定义微分算子 (赫维塞斯算子):

p=\frac{d}{dt}

那么 px 的意思是:

px=\frac{dx}{dt}

所以在水桶案例中,可以将原来的导数形式:

\frac{dx}{dt}=-2x

写成:

px=-2x

提取可得:

(p+2)x=0

最后得到:

p=-2

4.2 使用算子

我们知道指数函数满足:

\frac{d}{dt}e^{at}=ae^{at}

把我们的赫维塞斯算子代入:

\frac{d}{dt}e^{-2t}=-2e^{2t}

因此水量函数一定具有下面的形式:

x(t)=Ce^{-2t}

将我们的初始水量 5L 带入公式,得到:

x(t)=5e^{-2t}

4.3 总结

这个例子中,把微分直接转化成 p:

\frac{d}{dt}\rightarrow p

于是:

\frac{dx}{dt}=-2x

直接变成:

px=-2x

微分方程就像普通代数一样处理了。

五、拉普拉斯变换

5.1 拉普拉斯变换公式

\mathcal{L}\left\{\frac{dx(t)}{dt}\right\} = sX(s)-x(0)

  • x(t) = 时间有关的函数
  • t = 时间
  • \frac{dx(t)}{dt} = 瞬时变化速度
  • \mathcal{L} = 拉普拉斯变换符号
  • s = 拉普拉斯域的自变量
  • X(s) = 拉普拉斯域的函数
  • x(0) = 时间的初始值

可以理解为:

导数的拉普拉斯变换 = s乘原函数的变换结果 − 初始值

5.2 使用拉普拉斯变换计算水桶案例

5.2.1 两侧拉普拉斯变换

水桶案例的原微分方程是:

\frac{dx(t)}{dt}=-2x(t)

两边同时进行拉普拉斯变换:

\mathcal{L} \left\{ \frac{dx(t)}{dt} \right\} = \mathcal{L} \{-2x(t)\}

得到:

sX(s)-x(0) = -2X(s)

5.2.2 求 X(s)

提取 X(s):

sX(s)+2X(s)=x_{0}

X(s)(s+2)=x_{0}

两侧相除得到水量在 s 域的表达式:

X(s)=x_{0}\frac{1}{s+2}

5.2.3 拉普拉斯反变换查表

现在我们需要把拉普拉斯域反变换,目前已有公式:

\mathcal{L}\{e^{-at}\} = \frac{1}{s+a}

\mathcal{L}^{-1} \left\{ \frac{1}{s+a} \right\} = e^{-at}

我们直接将 X(s) 根据公式转换得到:

x(t)=x_{0}e^{-2t}

我们的初始水量是 5L 时间是 1 分钟,代入得到:

x(1)=5e^{-2}

x(1)=577mL

5.3 拉普拉斯变换和傅里叶变换的关系

5.3.1 两个公式

傅里叶变换的公式是:

X(j\omega) = \int_{-\infty}^{+\infty} x(t)e^{-j\omega t}dt

而拉普拉斯变换的公式多了一个 s:

X(s) = \int_0^{+\infty} x(t)e^{-st}dt

5.3.2 s 的定义

s=\sigma +j\omega

e^{-st}=e^{\sigma t}e^{-j\omega t}

  • e^{-j\omega t} = 频率旋转
  • e^{\sigma t} = 指数增长/衰减

5.3.3 两者关系总结

拉普拉斯变换 = 傅里叶变换 + 指数衰减 / 增长因子

在傅里叶分析中,我们只能分析不衰减的波形:

\sin (\omega t)\rightarrow e^{-j\omega t}

拉普拉斯变换则可以分析增长信号和衰减信号:

e^{\sigma t}e^{-j\omega t}

这样就是衰减了:

e^{- \sigma t}

拉普拉斯变换把探针升级了,也就是说,不仅可以分析波形的频率成分,还可以分析衰减状态。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐