【微科普】压缩感知(CS):违反了奈奎斯特采样定理?不先采集也能还原信号?大白话讲透稀疏采样、L1重建与OMP,一文吃透附代码

文章目录

    • [1. 从"先采样后压缩"到"采样即压缩"](#1. 从“先采样后压缩”到“采样即压缩”)
      • [1.1 奈奎斯特采样定理的负担:为什么传统思路在工程上越来越吃力](#1.1 奈奎斯特采样定理的负担:为什么传统思路在工程上越来越吃力)
      • [1.2 最大误区:压缩感知不是"不采样",而是采样与压缩同时发生](#1.2 最大误区:压缩感知不是“不采样”,而是采样与压缩同时发生)
    • [2. 压缩感知能工作的两个数学前提](#2. 压缩感知能工作的两个数学前提)
      • [2.1 稀疏性:一张照片为什么能在傅里叶域用少量系数表达](#2.1 稀疏性:一张照片为什么能在傅里叶域用少量系数表达)
      • [2.2 测量矩阵与稀疏基不相干:随机测量为什么能捕获全局特征](#2.2 测量矩阵与稀疏基不相干:随机测量为什么能捕获全局特征)
    • [3. 从少量测量值恢复信号:L1凸优化与OMP怎么选](#3. 从少量测量值恢复信号:L1凸优化与OMP怎么选)
      • [3.1 欠定方程组:测量值远少于未知数,为什么还能求唯一解](#3.1 欠定方程组:测量值远少于未知数,为什么还能求唯一解)
      • [3.2 Basis Pursuit 与 OMP 的工程选型:精度、速度与内存对比](#3.2 Basis Pursuit 与 OMP 的工程选型:精度、速度与内存对比)
      • [3.3 一段能跑的 OMP 重建代码:Python 实现与逐行解释](#3.3 一段能跑的 OMP 重建代码:Python 实现与逐行解释)
    • [4. 压缩感知典型应用与工程避坑](#4. 压缩感知典型应用与工程避坑)
      • [4.1 医学MRI少采K空间数据:缩短扫描时间的稀疏重建逻辑](#4.1 医学MRI少采K空间数据:缩短扫描时间的稀疏重建逻辑)
      • [4.2 单像素相机与雷达通信:单探测器成像与降低功耗的工程收益](#4.2 单像素相机与雷达通信:单探测器成像与降低功耗的工程收益)
      • [4.3 落地避坑:稀疏基选错、随机测量矩阵不当、重建参数漂移](#4.3 落地避坑:稀疏基选错、随机测量矩阵不当、重建参数漂移)

压缩感知(Compressed Sensing,CS)名字里带"压缩",但它真正颠覆的不是文件压缩,而是采样方式本身 。传统信号处理告诉我们:要无失真恢复一个模拟信号,采样率至少是最高频率的两倍,这就是奈奎斯特采样定理。压缩感知却说:如果信号在某个变换域足够稀疏,用远低于奈奎斯特要求的测量数量,也能高概率恢复原信号。

下面我们先把"采样即压缩"这件事讲清楚,再落到数学建模、重建算法和工程指南,最后给出一段可以直接运行的 OMP 重建代码。


1. 从"先采样后压缩"到"采样即压缩"

1.1 奈奎斯特采样定理的负担:为什么传统思路在工程上越来越吃力

传统数字信号处理流程非常固定:模拟信号先经过抗混叠滤波器,再由高速 ADC 按照奈奎斯特频率采样,得到大量数字样本,然后为了存储或传输再做压缩。以图像为例,相机传感器先采集几千万像素,再通过 JPEG 丢弃大量高频 DCT 系数,最后只保留一小部分数据。

这个流程里存在一个明显浪费:先花很大代价把数据全部采回来,压缩时又把大部分数据丢掉。对于音频、普通照片,这种浪费还能接受;但在雷达、医学成像、超宽带通信等领域,信号带宽很高,ADC 采样率、存储器吞吐、传输带宽都会变得非常昂贵,甚至硬件上根本做不到。压缩感知的出发点就是:既然最终只保留少数重要信息,能不能一开始只采集那些"不会被丢掉"的信息?

难点在于,传统采样前并不知道哪些系数重要。压缩感知用随机线性测量绕开了这个难点。

1.2 最大误区:压缩感知不是"不采样",而是采样与压缩同时发生

很多人听到"压缩感知"会误以为它完全不需要采样。实际上,CS 仍然要做测量,只是每个测量值不再是单个时间点的采样值,而是原始信号与一个测量向量做内积得到的线性组合

设原始信号为 x ∈ R N x\in\mathbb{R}^N x∈RN,传统点采样得到的是 x x x 的某个分量;压缩感知的第 j j j 个测量值则写成:

y j = ⟨ x , ϕ j ⟩ y_j=\langle x,\phi_j\rangle yj=⟨x,ϕj⟩

一次测量同时包含多个原始样本的加权和。因此当测量次数 M M M 远小于信号长度 N N N 时,仍然可能保留足够多信息。传统思路是"先完整扫描、后压缩成小尺寸",压缩感知则是"直接用少量随机笔画勾勒关键特征,再通过算法还原全貌"。

这个区别在硬件上的意义很大:在采集端就把压缩做了,采样率、存储量和传输量同时下降。后面要讨论的两个数学前提,保证了这种"少量线性组合"不会丢掉稀疏信号的主要信息。


2. 压缩感知能工作的两个数学前提

2.1 稀疏性:一张照片为什么能在傅里叶域用少量系数表达

稀疏性 是压缩感知成立的第一前提。一个信号 x x x 本身可能不稀疏,但在某个变换域可以写成:

x = Ψ s x=\Psi s x=Ψs

其中 s s s 只有 K K K 个非零系数,且 K ≪ N K\ll N K≪N,就称 x x x 在基 Ψ \Psi Ψ 下是 K K K 稀疏的。比如一段音频波形在时域几乎每个时刻都有值,但做傅里叶变换后,只有少数频点幅度大,其余接近零;一张自然照片在 DCT 或小波域里,大部分系数也很小,JPEG 压缩利用的就是这个特性。

工程上很多信号并不是严格稀疏,而是可压缩 :变换系数按幂律衰减,保留前 K K K 个大系数就能以很小误差逼近原信号。因此压缩感知并不要求信号精确只有 K K K 个非零值,只要近似稀疏 ,算法同样能工作。实际项目中,稀疏基选得好不好,直接决定恢复质量。这一点在第 4 章还会展开。

2.2 测量矩阵与稀疏基不相干:随机测量为什么能捕获全局特征

如果只有稀疏性还不够。设想一个极端情况:信号在某个基下只有一个重要系数,但测量方式恰好只在另一个局部区域采样,就可能完全漏掉这个重要系数。因此 CS 要求测量矩阵 Φ \Phi Φ 与稀疏基 Ψ \Psi Ψ 不相干

直观理解是:测量向量不能和稀疏基的列"太对齐"。随机高斯矩阵、随机伯努利矩阵与任何固定稀疏基都高度不相干,因为随机向量不会偏向某一个特定基方向。它的每个测量值都会均匀地混入来自所有稀疏位置的少量信息,少量随机测量就能捕获全局特征。

更严谨的理论保证是有限等距性质 RIP:等效测量矩阵 Θ = Φ Ψ \Theta=\Phi\Psi Θ=ΦΨ 在稀疏向量上近似保持长度。满足 RIP 时,从 y = Θ s y=\Theta s y=Θs 恢复稀疏 s s s 是稳定的。实际工程中,随机高斯矩阵理论性质好,但硬件难实现;部分傅里叶矩阵在 MRI 中更常见,因为它天然对应 K 空间欠采样。

传统 MRI 必须要按奈奎斯特采样要求填满整个 K 空间。如果要得到一张 256×256的图像,就需要采集 256条 K

空间线,每条线包含256个频域样本。

问题在于,MRI 采集每条线都需要时间。对于某些序列,每条 K

空间线的采集时间从几十毫秒到几百毫秒不等。一次完整扫描下来,患者需要躺几分钟到几十分钟。扫描期间患者必须保持不动,否则运动伪影会破坏图像质量。

更麻烦的是动态成像。比如心脏 MRI,需要在一次屏气内完成扫描,传统方法根本采不完完整 K 空间。这就是 MRI

迫切需要"少采数据但还能重建出清晰图像"的根本原因。压缩感知恰好提供了这个可能。


3. 从少量测量值恢复信号:L1凸优化与OMP怎么选

3.1 欠定方程组:测量值远少于未知数,为什么还能求唯一解

压缩感知的测量模型可以统一写成:

y = Φ x = Φ Ψ s = Θ s y=\Phi x=\Phi \Psi s=\Theta s y=Φx=ΦΨs=Θs

这里 y y y 是 M M M 维测量值, s s s 是 N N N 维稀疏系数,通常 M < N M<N M<N。从线性代数看,这是一个欠定方程组,一般有无穷多解。但加上" s s s 尽量稀疏"的约束后,解空间被大幅缩小。

最直接的数学表达是求 L 0 L_0 L0 范数最小化:

min ⁡ ∥ s ∥ 0 s . t . y = Θ s \min \|s\|_0 \quad \mathrm{s.t.} \quad y=\Theta s min∥s∥0s.t.y=Θs

其中 ∥ s ∥ 0 \|s\|_0 ∥s∥0 表示 s s s 中非零元素的个数。这个优化问题能精确给出最稀疏解,但它是组合优化,NP 难,工程上不可行。压缩感知理论给出的替代方案是 L 1 L_1 L1 凸优化:

min ⁡ ∥ s ∥ 1 s . t . y = Θ s \min \|s\|_1 \quad \mathrm{s.t.} \quad y=\Theta s min∥s∥1s.t.y=Θs

在测量矩阵满足一定条件、测量数量足够时, L 1 L_1 L1 最小化与 L 0 L_0 L0 最小化等价。为什么 L 1 L_1 L1 能促进稀疏?可以从几何上理解: L 2 L_2 L2 约束的可行区域是圆滑的球,最优切点往往不落在坐标轴;而 L 1 L_1 L1 约束区域是菱形,在坐标轴上有尖锐顶点,最优解更容易落在坐标轴上,从而得到稀疏解。

3.2 Basis Pursuit 与 OMP 的工程选型:精度、速度与内存对比

重建算法主要分两大类:凸优化算法和贪婪算法。

Basis Pursuit(BP)就是求解上面 L 1 L_1 L1 最小化问题的凸优化方法。它的优点是重建质量高、理论保证强 ,在测量矩阵合适时恢复成功率接近最优;缺点是计算量大,一般复杂度在 O ( N 3 ) O(N^3) O(N3) 量级,对大规模问题内存和时间都吃紧。带噪声场景下通常使用基追踪降噪 BPDN:

min ⁡ ∥ s ∥ 1 s . t . ∥ y − Θ s ∥ 2 ≤ ϵ \min \|s\|_1 \quad \mathrm{s.t.} \quad \|y-\Theta s\|_2\le \epsilon min∥s∥1s.t.∥y−Θs∥2≤ϵ

其中 ϵ \epsilon ϵ 用来容纳噪声能量。

OMP(Orthogonal Matching Pursuit,正交匹配追踪)是贪婪算法中的代表。它每次迭代选择和当前残差最相关的一列,加入支持集,再用最小二乘更新系数,迭代 K K K 次。OMP 的优点是速度快、实现简单,在工程中应用广泛;缺点是恢复成功率对测量矩阵和稀疏度更敏感,信噪比低时容易选错原子,且错误一旦发生会累积。

工程选型建议很直接:小规模、高精度、离线重建场景优先用 BP 或 BPDN;大规模、实时性要求高、稀疏度已知的场景优先用 OMP 或 CoSaMP 等贪婪变体 。医学 MRI 重建通常用非线性共轭梯度求解 L 1 L_1 L1 问题,雷达实时处理则更偏向 OMP 系列。

3.3 一段能跑的 OMP 重建代码:Python 实现与逐行解释

下面给出一段可直接运行的 Python 代码。它生成一个在 DCT 基下稀疏的信号,用随机高斯矩阵做测量,再通过 OMP 从少量测量值中恢复原信号。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

# 设置中文和负号正常显示
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

np.random.seed(42)

N = 256      # 原始信号长度
M = 64       # 测量值数量
K = 8        # 稀疏度

def dct_matrix(N):
    """构造 N x N 的 DCT 正交基矩阵"""
    Psi = np.zeros((N, N))
    for k in range(N):
        for n in range(N):
            if k == 0:
                Psi[k, n] = np.sqrt(1.0 / N)
            else:
                Psi[k, n] = np.sqrt(2.0 / N) * np.cos(
                    np.pi * k * (2 * n + 1) / (2 * N)
                )
    return Psi

Psi = dct_matrix(N)

# 生成稀疏系数 s:随机 K 个非零位置
s = np.zeros(N)
nonzero_pos = np.random.choice(N, K, replace=False)
s[nonzero_pos] = np.random.randn(K) * 5

# 原始信号:在 DCT 基下稀疏
x = Psi @ s

# 随机高斯测量矩阵,按列归一化
Phi = np.random.randn(M, N) / np.sqrt(M)

# 等效测量矩阵
Theta = Phi @ Psi

# 压缩测量值
y = Theta @ s

def omp(Theta, y, K, tol=1e-8):
    """
    正交匹配追踪 OMP
    Theta: 等效测量矩阵,形状 M x N
    y: 测量向量,形状 M
    K: 稀疏度
    tol: 残差停止容差
    """
    N = Theta.shape[1]
    residual = y.copy()
    support = []
    residual_norms = [np.linalg.norm(residual)] # 用于记录残差变化

    for _ in range(K):
        # 计算每列与残差的相关性,选择绝对值最大的列
        corr = Theta.T @ residual
        idx = int(np.argmax(np.abs(corr)))
        if idx in support:
            break
        support.append(idx)

        # 用当前支持集做最小二乘,更新残差
        Theta_t = Theta[:, support]
        s_t, _, _, _ = np.linalg.lstsq(Theta_t, y, rcond=None)
        residual = y - Theta_t @ s_t
        
        residual_norms.append(np.linalg.norm(residual))

        if np.linalg.norm(residual) < tol:
            break

    # 最终最小二乘估计
    s_hat = np.zeros(N)
    if support:
        Theta_t = Theta[:, support]
        s_t, _, _, _ = np.linalg.lstsq(Theta_t, y, rcond=None)
        s_hat[support] = s_t

    return s_hat, support, residual_norms

s_hat, support, residual_norms = omp(Theta, y, K)
x_hat = Psi @ s_hat
y_hat = Theta @ s_hat # 重建测量值

print("真实非零位置:", np.sort(nonzero_pos))
print("OMP恢复位置:", np.sort(support))
print("重建相对误差:", np.linalg.norm(x - x_hat) / np.linalg.norm(x))

# ================= 丰富的可视化部分 =================
fig = plt.figure(figsize=(14, 10))

# 子图 1: 原始信号 vs 恢复信号
ax1 = fig.add_subplot(2, 2, 1)
ax1.plot(x, label='原始信号 x', color='royalblue', linewidth=1.5)
ax1.plot(x_hat, label='OMP重建信号 x_hat', color='darkorange', linestyle='--', linewidth=1.5)
ax1.set_title('1. 原始信号与 OMP 重建信号对比', fontsize=12, fontweight='bold')
ax1.set_xlabel('索引 (n)')
ax1.set_ylabel('幅值')
ax1.legend(loc='upper right')
ax1.grid(True, linestyle=':', alpha=0.6)

# 子图 2: 稀疏系数对比
ax2 = fig.add_subplot(2, 2, 2)
ax2.stem(s, linefmt='royalblue', markerfmt='bo', basefmt='k-', label='真实稀疏系数 s')
ax2.stem(s_hat, linefmt='darkorange', markerfmt='r^', basefmt='k-', label='估计稀疏系数 s_hat')
ax2.set_title('2. 变换域稀疏系数对比 (DCT域)', fontsize=12, fontweight='bold')
ax2.set_xlabel('索引 (k)')
ax2.set_ylabel('幅值')
ax2.legend(loc='upper right')
ax2.grid(True, linestyle=':', alpha=0.6)

# 子图 3: OMP 残差收敛曲线
ax3 = fig.add_subplot(2, 2, 3)
ax3.plot(range(len(residual_norms)), residual_norms, marker='o', color='forestgreen', linewidth=2)
ax3.set_title('3. OMP 迭代残差收敛曲线 ($\ell_2$ 范数)', fontsize=12, fontweight='bold')
ax3.set_xlabel('迭代次数')
ax3.set_ylabel('残差范数 ||y - Theta_t * s_t||')
ax3.grid(True, linestyle=':', alpha=0.6)

# 子图 4: 压缩测量值对比
ax4 = fig.add_subplot(2, 2, 4)
ax4.plot(y, label='实际测量值 y', color='purple', marker='o', markersize=4, linestyle='-')
ax4.plot(y_hat, label='重建测量值 y_hat', color='crimson', marker='x', markersize=4, linestyle='--')
ax4.set_title('4. 测量空间对比 (y vs y_hat)', fontsize=12, fontweight='bold')
ax4.set_xlabel('测量索引 (m)')
ax4.set_ylabel('幅值')
ax4.legend(loc='upper right')
ax4.grid(True, linestyle=':', alpha=0.6)

plt.tight_layout()
plt.show()

真实非零位置: 6 79 117 167 185 206 228 242

OMP恢复位置: 6 79 117 167 185 206 228 242

重建相对误差: 2.0138947317550645e-15

这段代码的核心流程是:构造 DCT 基 Ψ \Psi Ψ,生成稀疏系数 s s s,得到原始信号 x = Ψ s x=\Psi s x=Ψs;再用随机高斯矩阵 Φ \Phi Φ 得到测量值 y = Φ x y=\Phi x y=Φx。OMP 每次选择与残差最相关的一列,最小二乘更新后继续,直到达到稀疏度 K K K 或残差足够小。运行后重建相对误差通常能到 10 − 14 10^{-14} 10−14 量级。

注意,示例中若某个原子被重复选中,代码会直接跳出。实际工程中还可以加入更稳健的防重复机制、噪声容差和最大迭代次数。


4. 压缩感知典型应用与工程避坑

4.1 医学MRI少采K空间数据:缩短扫描时间的稀疏重建逻辑

压缩感知在医学影像中最经典的应用是核磁共振成像 MRI 。MRI 采集的是傅里叶域数据 ,也叫 K 空间数据。传统方式必须按奈奎斯特要求扫描足够多的 K 空间线,扫描时间动辄几十分钟。CS 允许随机欠采样 K 空间,然后用重建算法恢复图像。

医学图像在小波域或总变差 TV 域是近似稀疏的,重建目标通常写成:

min ⁡ ∥ Ψ x ∥ 1 + λ ∥ ∇ x ∥ 1 s . t . ∥ F u x − y ∥ 2 ≤ ϵ \min \|\Psi x\|_1+\lambda \|\nabla x\|_1 \quad \mathrm{s.t.} \quad \|F_u x-y\|_2\le \epsilon min∥Ψx∥1+λ∥∇x∥1s.t.∥Fux−y∥2≤ϵ

其中 F u F_u Fu 是欠采样傅里叶算子, y y y 是采集到的少量 K 空间数据。这里同时加入 L 1 L_1 L1 稀疏项和 TV 项,是为了保留图像边缘。

需要特别注意:K 空间欠采样如果采用均匀间隔采样,会产生规则的混叠伪影;采用随机或类随机欠采样后,伪影会变成类似噪声的分布,重建算法更容易去除。这一条是 MRI-CS 落地的细节,但也经常被初学者忽略。

4.2 单像素相机与雷达通信:单探测器成像与降低功耗的工程收益

单像素相机是压缩感知的另一个典型应用。传统面阵相机需要数百万个探测单元,而单像素相机只用一个点探测器,配合数字微镜阵列 DMD 产生一系列随机光斑图案,每次测量的是场景经过随机图案调制后的总光强。重复 M M M 次得到测量向量 y y y,再用算法重建图像。

它的价值不在消费摄影,而在一些面阵探测器很贵的波段,比如红外、太赫兹。用单探测器替代面阵可以显著降低成本,同时降低制冷和功耗需求。雷达领域也类似:传统 SAR 需要大量脉冲积累,CS 可以减少脉冲发射次数,缩短成像时间,对机动平台尤其重要。通信领域里,稀疏信道估计、频谱感知同样能利用少量导频恢复信道信息。

这些应用有一个共同点:降低采集端的硬件成本、功耗或时间成本,把复杂度转移到后端计算。这也是压缩感知最吸引工程团队的地方。

4.3 落地避坑:稀疏基选错、随机测量矩阵不当、重建参数漂移

第一个坑是稀疏基选得不合适。如果信号在选定基下并不稀疏,或只有变换系数衰减很慢,CS 重建效果会很差。动手前应先用实际数据做变换域系数分析,观察保留前 K K K 个系数的能量占比。自然图像可选小波、DCT 或学习字典;如果单一基不够,可以联合 TV 正则。

第二个坑是测量矩阵设计不当。随机高斯矩阵理论性质好,但很多硬件无法直接实现。实际系统通常使用部分傅里叶矩阵、结构随机矩阵或确定性矩阵。无论选哪种,都要保证测量数量满足经验公式:

M ≥ c K log ⁡ ( N / K ) M \ge cK \log(N/K) M≥cKlog(N/K)

其中 c c c 是与测量矩阵和稀疏基不相干程度有关的常数。 M M M 太少,恢复失败; M M M 太多,采集端的节省效果就弱了。

第三个坑是忽略噪声和量化误差。纯 L 1 L_1 L1 等式约束只适用于无噪模型。实际系统必须使用 BPDN 或带噪声容差的 OMP,否则算法会为了拟合噪声产生大量虚假小系数。正则化参数 ϵ \epsilon ϵ 或 λ \lambda λ 要根据噪声水平调节,不能照搬无噪仿真值。

第四个坑是重建参数漂移。同一套参数在仿真数据上效果很好,换一批真实数据可能明显变差。工程上建议用交叉验证或自适应策略,根据残差能量动态调整迭代停止条件。图像重建中还可以先做小尺寸试验,确认稀疏基和测量矩阵组合后再扩展到全尺寸。

压缩感知不是万能工具,只有信号确实稀疏、测量方式确实不相干、重建参数确实匹配噪声水平时,它才能带来实际收益。


你在压缩感知工程实现中,遇到过因为测量矩阵不合适导致恢复失败,或者稀疏基选错导致重建质量差的问题吗?欢迎留言交流。

相关推荐
88号技师1 小时前
2026年SCI-分数牛顿衍生优化算法Fractional Newton-derived optimizer-附Matlab免费代码
开发语言·算法·数学建模·matlab·优化算法
承渊政道1 小时前
【Python编程—从入门到实践】(Python操作列表深度教程:循环、切片、元组与代码风格)
开发语言·python·pycharm·列表·元组·切片
guwentian1 小时前
一文搞懂 AI Agent 安全护栏:用 Python 手写工具网关,把越权挡在执行层
人工智能·python·安全
布值倒区什么name1 小时前
Pycharm2026找不到编译器 点击运行运行不了
开发语言·python·pycharm
Python私教1 小时前
软件开发报价为什么能差 3 倍:需求范围、验收标准和变更成本怎么算
后端·python·架构
水獭比特1 小时前
Pydantic AI 2.33.0 遇上 Anthropic SDK 1.0:别让 httpx2 在运行时才暴雷
人工智能·python
张哈大1 小时前
完整版:对话 Agent 全链路架构详解:从 RAG 召回、Prompt 构建到 ReAct 交互落地指南
人工智能·python
夏玉林的学习之路1 小时前
算法7.链式栈
算法
今天AI了吗1 小时前
AI 数据安全治理框架:模型能力与数据权限的边界在哪里
java·linux·开发语言·人工智能·python·深度学习·机器学习