最近视频号有个清华老哥天天站黑板面前讲信号处理:

(我一看这不就是科普版,这真实干活不瞎眼了),赶紧在路上怒写一个完整版的 SINC 函数奉献给社会!!!希望大家看开心~

从数学角度看 sinc 函数

两种常用定义

数学定义

信号处理常用的“归一化 sinc”

归一化的好处:零点刚好落在整数点 ,非常适合“在整数点做插值”的场景(比如  那一类)。

实线:

虚线:,整体形状一样,只是沿 x 轴拉伸/压缩了一点。

基本形状与性质

中间有一个“主瓣”,在  处取值 1;往两边衰减,并出现正负交替的“旁瓣”。在未归一化定义下,零点在 ;在归一化定义下,零点刚好在 

数学性质:

极限存在且为 1(用洛必达法则)

所以我们定义 sinc(0)=1 是连续的。

偶函数

因为 ,分子分母都变号。

振荡衰减当  始终在 [-1,1] 内,而分母  变大:

所以尾巴按  衰减。

积分与能量

这是很多傅里叶积分里经常出现的结果。 对于归一化 sinc,

这像一个“单位面积核”,在建模里很有用(卷积核、插值核)。

从“信号与系统”的视角看 sinc

理想低通滤波器:矩形频响 ↔ sinc 冲激响应

在经典连续时间傅里叶变换的约定下,矩形频域 ↔ sinc 时域 是一对标准变换对:

频域:理想低通滤波器

时域:冲激响应(我用归一化 sinc 写得好看一点)

下张图看到的就是一个以 t=0 对称、像 sinc 的脉冲:中间最高,往两边有无限长的振荡尾巴。

任何一个 LTI 系统都可以用“冲激响应 h(t)”来描述;理想低通的冲激响应恰好是 sinc,所以 “用理想低通滤波信号 = 用 sinc 和信号做卷积”。

重要现实问题:这个 sinc 冲激响应 无限长(从  到 );而且左右对称,非因果(t<0 也有响应);这意味着理想低通滤波器物理上不可实现,我们只能在数学上把它当作极限模型,现实里必须用“有限长度 & 近似”的滤波器来逼近它(FIR 窗函数设计就是这么来的)。

采样定理:sinc 是“完美插值核”

香农采样定理讲的是:

若连续时间信号  带宽有限(带限到  Hz),且以采样频率  采样,则原信号可以用无限长 sinc 插值精确重构。

最经典的公式(用归一化 sinc):

其中 ,且

翻译成人话:每一个采样点  在连续时间上对应一个以  为中心的 sinc“脉冲”;所有这些 sinc 叠加在一起,刚好把原信号拼出来;

在采样点处 

由于  当  是非零整数,且 ,所以只有  这一项保留下来,完美“插值通过采样点”。(也就是示波器的时域波形的插值由来,我记忆是之前写过的)

蓝色实线:原本连续信号(两路低频正弦叠加)。

圆点:按一定采样频率取的离散点。

虚线:用 sinc 插值公式重构出来的连续曲线。

由于我选的是“确实带限且采样频率足够高”的例子,重构曲线和原曲线是重合的(几乎看不出两条线)。

这就是 sinc 在信号与系统里最经典、最核心的角色:理想插值核 和 理想低通滤波核 是同一个东西,只是换了一个场景。

从数学建模角度怎么用 sinc?

可以把 sinc 看成是一种“核函数(kernel)”,类似于高斯核、三角核,只是形状不同。几个典型的建模思路:

连续信号/场的插值与重构

给定一串样本值 ,我们希望构造一个连续函数 

这就是“基函数展开”:每个样本点乘一个“基函数”再加起来。

当  时,这个展开在带限信号假设下是严格无失真的;其它常见选择还有 B 样条、高斯、Lanczos(其实就是多项 sinc 的组合)等,往往是“牺牲一点精度,换取局部性和更好数值特性”。

从建模角度看:sinc 模型对应的是“带限 + 无噪声 + 无限长度核”这一理想假设,这提供了一个基准;现实系统达不到,就设计各种近似核去逼近这个理想。

有限长度 sinc 与窗函数(FIR 滤波器设计)

理想低通的冲激响应是 sinc,但它太长,不可实现;常用操作:截断 + 加窗

从无限长的 sinc 中截出一个长为  的对称窗口:

乘上一个窗函数 (Hamming, Blackman 等):

这样我们得到一个有限长 FIR 滤波器,其频响逼近矩形低通,但有一点通带波纹、阻带衰减有限;从最原始的观点来看,这整个设计流程就是:

拿 sinc 当“原型”,再做有限化和修饰

在很多 “矩形开口”/“有限长度窗” 的问题里,sinc 都会蹦出来:时域里,对信号乘上一个有限时长的矩形窗(只观察一小段时间),其频域多了一个 sinc 形状的卷积核 → 这就是频谱泄漏的根源;总之谁有矩形谁就有 sinc,不是在时域就是在频域/空间频域。

(恭喜读者可以看到这里,在信号与系统的功力已经有鄙人的百分之五了,hhhh)

上面的文章已经把 SINC 这个函数的本体说差不多了,但是最终我们还是要应用的,在之前 FFT 的窗的文章已经写过了,但是无妨,基础知识常写常新,以及 SINC 的故事还没有结束。

好,那我们就接着刚才的 sinc,从“窗函数 + 时宽带宽积 ≈ 常数”这条线,把信号与系统和数学建模串起来。

你刚看到的几组图分别是:

  1. 连续时间:矩形窗 w(t) 和它的频率响应 |W(f)|(典型 sinc)
  2. 离散时间:Rect / Hann / Blackman 三种窗在时域、频域的对比
  3. 用窗函数加权截断 sinc 设计 FIR 低通滤波器的幅频响应

下面我分三块讲:

窗函数的本质:时域乘窗 = 频域卷积

离散时间场景里,设原信号/理想冲激响应为 ,窗函数为 ,则

其 DTFT(离散时间傅里叶变换)满足:

也就是:

时域相乘 → 频域卷积

在 FIR 设计里:

:通常是理想低通的 sinc 冲激响应(无限长)

:我们选定的窗函数(有限支持 N 点)。

:真正实现的 FIR 系统冲激响应。

:就是我们得到的近似低通滤波器的频率响应。

在时域,用窗函数“剪掉”了 sinc 的两端(截断+平滑);在频域,把理想的矩形频响  跟窗函数频响  做卷积:所以矩形不再是完美的直上直下了,边缘被抹圆,带来了过渡带旁瓣

矩形窗:最简单的窗函数,让“时宽带宽积”直观可见

连续时间:矩形 ↔ sinc

我们定义一个宽度为  的矩形窗:

它的傅里叶变换是(采用 f 作为频率):

图里看到的时域是扁扁的一块,频域是一个以 0 为中心的 sinc 形状。

零点位置:

第一对零点在 ;主瓣宽度(从负第一零点到正第一零点)约为 

于是我们可以很自然地定义:

时间宽度:

频率主瓣宽度:

那么:

如果你一个定义(比如半宽度、0.5 幅值点等)常数会稍微变一下,但都体现同一个现象:

在时间上截得越短(T 越小),频域主瓣越宽;在时间上留得越长(T 越大),频域越集中。 时宽 × 带宽 ≈ 常数,这就是“时宽带宽积”/不确定性原理的直观版本。

归一化与“积为一”的说法

如果想写得“刚好等于 1”,可以通过简单的归一化来做到。

例如,把变量换成无量纲形式:令 ,则矩形窗写成 ,支持区间长度为 1:;对应的频域变量用 ,则频响应是 ,其主瓣宽度约 。如果再把“带宽定义的一半”或者使用某个对称定义(比如取 ),就可以人为地把“时宽 × 带宽”调整成 1。这就是很多教材里说的那种“合适定义下的时宽带宽积为 1”的感觉,本质是尺度归一化的问题。

从建模角度我们更关注的是: 无论你怎样缩放,只要你压缩了时间,就必然拉宽频谱;整体面积保持不变;这个可以用连续时间傅里叶变换的缩放性质来精确表达。

缩放性质 + 数学建模:为什么“越短越宽,越长越窄”

假设  与其傅里叶变换  是一对变换对:

对任意非零实数 ,有缩放性质:

若 :时间轴压缩(信号变化更快),频谱拉宽;

若 :时间轴拉长(信号变化更慢),频谱收窄。

把矩形窗看成 ,即 ,可以把 ,那么

本质结论是:

“时宽带宽积为常数”是傅里叶缩放性质的直接体现,矩形窗 + sinc 刚好是非常直观的一对例子。

离散时间窗函数频谱:Rect / Hann / Blackman 对比

三种窗的数学定义(长度 N)

设  为窗长,

矩形窗(Rect)

汉宁窗(Hann)

Blackman 窗

对应的 DTFT:

在代码里我用

W = exp(-1j * outer(w_axis, k)) @ w

直接算出了连续频率轴上的频响。

时域形状 vs 频域特性

从频域图你能看到:

Rect 窗:主瓣最窄(过渡带最陡),但旁瓣最高(频谱泄漏严重,约 -13dB)。

Hann 窗:主瓣稍宽一点,旁瓣大幅降低(约 -31dB)。

Blackman 窗:主瓣更宽,但旁瓣压得更低(约 -58dB)。

这就是窗函数设计的核心 trade-off

想要频域旁瓣低,就要让时域窗“边缘更平滑”(更“宽”); 想要频域主瓣窄,就要让时域窗“更集中、更接近矩形”。 换句话说,就是把“有限长度的时宽”如何分配给“主瓣宽度”和“旁瓣高度”的问题。

用窗函数修饰 sinc 设计 FIR 低通:一个完整建模思路

刚才的最后一组图就是这一块:sinc + 窗

理想低通的离散冲激响应

在离散时间域,目标是一个理想低通滤波器,频率响应:

其理想(无限长)冲激响应(采样的 sinc)是:

我在代码里用归一化 sinc 写成:

wc = 0.4 * np.pi
M = (N - 1) // 2
m = np.arange(-M, M+1)
h_ideal = (wc/np.pi) * sinc_norm((wc/np.pi) * m)

其中 sinc_norm(x) = sin(pi x)/(pi x)

有限长度约束:乘以窗函数

由于实际 FIR 必须是有限长 N(这里 N=51),我们只能取:

在图里看到:用 Rect 窗:时间上是“截断的 sinc”,频域有明显旁瓣。

用 Hann/Blackman:时间上头尾逐渐收敛到 0,频域旁瓣压下去,但主瓣拓宽(过渡带变宽)。

数学建模:优化意义

如果严肃一点看,可以把 FIR 设计写成一个优化问题:

决策变量:冲激响应 (或者窗权系数 )。

目标:尽量逼近理想频响 ,例如最小化平方误差:

约束:

支持长度有限: for n outside ;或者要求线性相位、对称性  等;甚至可以添加“时宽-带宽积”的约束,如控制过渡带宽度、旁瓣级别等。

窗函数法实际上是一个非常工程化、简化版的解法:先写出“满足频率形状”的无约束解 (无限长 sinc);再用一个选好的窗  把它截断成有限长,使其满足实现约束;窗的形状、长度 N 就隐含地决定了“带宽(主瓣宽度)”和“旁瓣抑制”之间的权衡—实际上就是在“时宽带宽积 ~ 常数”的约束下,调节频谱的分布。

Python 仿真源码

import numpy as np
import matplotlib.pyplot as plt

# ============================================
# 1. 连续时间:矩形窗 <-> sinc 频响
# ============================================

# 时域矩形窗
T = 1.0  # 窗宽
t = np.linspace(-1.5, 1.5, 2000)
rect_t = np.where(np.abs(t) <= T/2, 1.0, 0.0)

# 频域响应:W(f) = T * sinc_norm(f T)
def sinc_norm(x):
    y = np.ones_like(x)
    nz = x != 0
    y[nz] = np.sin(np.pi * x[nz]) / (np.pi * x[nz])
    return y

f = np.linspace(-10, 10, 4000)
Wf = T * sinc_norm(f * T)

plt.figure(figsize=(6,4))
震惊,怼老板高速怒写六千字!直接解剖 SINC 函数(非常通俗版)
plt.plot(t, rect_t)
plt.title('连续时间矩形窗 w(t)')
plt.xlabel('t')
plt.ylabel('w(t)')
plt.grid(True)
plt.tight_layout()
plt.show()

plt.figure(figsize=(6,4))
plt.plot(f, np.abs(Wf))
plt.title('矩形窗的幅频响应 |W(f)|(sinc 形状)')
plt.xlabel('频率 f')
plt.ylabel('|W(f)|')
plt.grid(True)
plt.tight_layout()
plt.show()

# ============================================
# 2. 离散时间:不同窗函数的频谱(长度 N)
# ============================================

N = 51
n = np.arange(N)

# 三种窗函数
w_rect = np.ones(N)
w_hann = 0.5 - 0.5 * np.cos(2*np.pi*n/(N-1))
w_blackman = 0.42 - 0.5*np.cos(2*np.pi*n/(N-1)) + 0.08*np.cos(4*np.pi*n/(N-1))

# 频率轴(归一化 rad/samp)
w_axis = np.linspace(-np.pi, np.pi, 4096)

def dtft(w):
    # 计算离散时间傅里叶变换(零相位对齐)
    k = np.arange(len(w))
    W = np.exp(-1j * np.outer(w_axis, k)) @ w
    return W

W_rect = dtft(w_rect)
W_hann = dtft(w_hann)
W_blackman = dtft(w_blackman)

plt.figure(figsize=(6,4))
plt.plot(n, w_rect, label='Rect')
plt.plot(n, w_hann, label='Hann')
plt.plot(n, w_blackman, label='Blackman')
plt.title('三种长度 N=51 的窗函数(时域)')
plt.xlabel('n')
plt.ylabel('w[n]')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

plt.figure(figsize=(6,4))
plt.plot(w_axis, 20*np.log10(np.abs(W_rect)/np.max(np.abs(W_rect)) + 1e-12), label='Rect')
plt.plot(w_axis, 20*np.log10(np.abs(W_hann)/np.max(np.abs(W_hann)) + 1e-12), label='Hann')
plt.plot(w_axis, 20*np.log10(np.abs(W_blackman)/np.max(np.abs(W_blackman)) + 1e-12), label='Blackman')
plt.title('三种窗函数的归一化幅频响应 (dB)')
plt.xlabel('归一化角频率 ω')
plt.ylabel('幅度 (dB)')
plt.ylim(-120, 5)
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

# ============================================
# 3. 用窗函数设计 FIR 低通:sinc * window
# ============================================

# 目标:理想低通截止频率 wc(归一化 rad/samp)
wc = 0.4 * np.pi
M = (N - 1) // 2
m = np.arange(-M, M+1)

# 理想低通冲激响应(截断 sinc)
h_ideal = (wc/np.pi) * sinc_norm((wc/np.pi) * m)

# 用三种窗加权
h_rect = h_ideal * w_rect
h_hann = h_ideal * w_hann
h_blackman = h_ideal * w_blackman

def freq_response(h):
    k = np.arange(len(h))
    H = np.exp(-1j * np.outer(w_axis, k)) @ h
    return H

H_rect = freq_response(h_rect)
H_hann = freq_response(h_hann)
H_blackman = freq_response(h_blackman)

plt.figure(figsize=(6,4))
plt.stem(m, h_ideal, basefmt=" ")
plt.title('理想低通冲激响应(截断 sinc)')
plt.xlabel('n')
plt.ylabel('h_ideal[n]')
plt.grid(True)
plt.tight_layout()
plt.show()

plt.figure(figsize=(6,4))
plt.plot(w_axis, 20*np.log10(np.abs(H_rect) / np.max(np.abs(H_rect)) + 1e-12), label='Rect 窗')
plt.plot(w_axis, 20*np.log10(np.abs(H_hann) / np.max(np.abs(H_hann)) + 1e-12), label='Hann 窗')
plt.plot(w_axis, 20*np.log10(np.abs(H_blackman) / np.max(np.abs(H_blackman)) + 1e-12), label='Blackman 窗')
plt.axvline(wc, linestyle='--')
plt.axvline(-wc, linestyle='--')
plt.title('用窗设计的 FIR 低通滤波器幅频响应 (N=51)')
plt.xlabel('归一化角频率 ω')
plt.ylabel('幅度 (dB)')
plt.ylim(-120, 5)
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
import numpy as np
import matplotlib.pyplot as plt

# 1. Basic sinc vs normalized sinc
x = np.linspace(-10, 10, 2000)

def sinc_math(x):
    y = np.ones_like(x)
    nz = x != 0
    y[nz] = np.sin(x[nz]) / x[nz]
    return y

def sinc_norm(x):
    y = np.ones_like(x)
    nz = x != 0
    y[nz] = np.sin(np.pi * x[nz]) / (np.pi * x[nz])
    return y

y1 = sinc_math(x)
y2 = sinc_norm(x)

plt.figure(figsize=(6,4))
plt.plot(x, y1, label='sinc(x) = sin(x)/x')
plt.plot(x, y2, linestyle='--', label='sinc_norm(x) = sin(πx)/(πx)')
plt.axhline(0, linewidth=0.8)
plt.axvline(0, linewidth=0.8)
plt.xlim(-10, 10)
plt.ylim(-0.3, 1.2)
plt.legend()
plt.title('数学 sinc 与 归一化 sinc 对比')
plt.xlabel('x')
plt.ylabel('幅度')
plt.grid(True)
plt.tight_layout()
plt.show()

# 2. Ideal low-pass filter: rectangular in freq -> sinc in time
t = np.linspace(-1, 1, 2000)
B = 5  # Hz
# 连续时间理想低通冲激响应: h(t) = 2B * sinc(2Bt)
arg = 2 * B * t
h = np.ones_like(t) * 2 * B
nz = arg != 0
h[nz] = 2 * B * np.sin(np.pi * arg[nz]) / (np.pi * arg[nz])

plt.figure(figsize=(6,4))
plt.plot(t, h)
plt.axhline(0, linewidth=0.8)
plt.axvline(0, linewidth=0.8)
plt.title('理想低通滤波器冲激响应 = sinc 形状')
plt.xlabel('时间 t (s)')
plt.ylabel('h(t)')
plt.grid(True)
plt.tight_layout()
plt.show()

# 3. Sampling and sinc reconstruction demo
fs = 20.0  # 采样频率
T = 1/fs
t_cont = np.linspace(0, 1, 2000)
# 带限信号:两个正弦叠加,频率都在 Nyquist 以下
x_cont = np.sin(2*np.pi*3*t_cont) + 0.6*np.sin(2*np.pi*5*t_cont)

# 采样
n = np.arange(0, int(1/T))
t_samp = n * T
x_samp = np.sin(2*np.pi*3*t_samp) + 0.6*np.sin(2*np.pi*5*t_samp)

# 用 sinc 插值重构:
# x_rec(t) = sum x[n] sinc((t/T) - n)
x_rec = np.zeros_like(t_cont)
for k, xk in zip(n, x_samp):
    x_rec += xk * sinc_norm(t_cont / T - k)

plt.figure(figsize=(6,4))
plt.plot(t_cont, x_cont, label='原连续信号')
plt.scatter(t_samp, x_samp, marker='o', label='采样点')
plt.plot(t_cont, x_rec, linestyle='--', label='sinc 重构信号')
plt.xlabel('时间 t (s)')
plt.ylabel('幅度')
plt.title('采样与 sinc 插值重构示意')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()


文末是蹲一个角落里面写的,hhhh