[实战] CIC滤波器设计与实现

在原有的博客基础上,我们补充了内插CIC滤波器的实现与验证。新增的"3.4 内插CIC滤波器实现与验证"一节包含结构说明、Python类实现以及测试示例。最终博客全文如下(包含新内容)。


CIC滤波器设计与实现:从数学原理到Python实战

在数字信号处理领域,特别是在软件无线电和数字下变频应用中,我们经常需要处理采样率的巨大变化。当降采样倍数高达几十甚至几百倍时,传统的FIR滤波器会变得异常臃肿,因为它的抽头数量与降采样倍数成正比。级联积分梳状滤波器 应运而生,它以一种极其经济的方式解决了这个问题------不需要任何乘法器,只需加法和延迟

1. CIC滤波器的数学原理

1.1 从滑动平均说起

要理解CIC滤波器,最直观的切入点是滑动平均滤波器。一个长度为 DDD 的滑动平均滤波器的差分方程为:

y[n]=1D∑k=0D−1x[n−k] y[n] = \frac{1}{D} \sum_{k=0}^{D-1} x[n-k] y[n]=D1k=0∑D−1x[n−k]

将其变换到Z域,传递函数为:

HMA(z)=1D1−z−D1−z−1 H_{MA}(z) = \frac{1}{D} \frac{1-z^{-D}}{1-z^{-1}} HMA(z)=D11−z−11−z−D

这个形式隐藏着一个秘密:它由一个积分器 1/(1−z−1)1/(1-z^{-1})1/(1−z−1) 和一个梳状滤波器 1−z−D1-z^{-D}1−z−D 级联而成。

1.2 CIC滤波器的传递函数

CIC滤波器正是利用了这一分解。单级CIC滤波器的传递函数为:

H(z)=1−z−RMRM(1−z−1)=1RM⋅积分器⋅梳状滤波器 H(z) = \frac{1 - z^{-RM}}{RM(1 - z^{-1})} = \frac{1}{RM} \cdot \text{积分器} \cdot \text{梳状滤波器} H(z)=RM(1−z−1)1−z−RM=RM1⋅积分器⋅梳状滤波器

其中,RRR 为抽取或内插因子,MMM 为差分延迟(通常取1或2),RMRMRM 决定了滤波器的长度。

将 z=ejωz = e^{j\omega}z=ejω 代入,得到频率响应

∣H(ejω)∣=∣sin⁡(ωRM/2)RMsin⁡(ω/2)∣ |H(e^{j\omega})| = \left|\frac{\sin(\omega RM/2)}{RM \sin(\omega/2)}\right| ∣H(ejω)∣= RMsin(ω/2)sin(ωRM/2)

当 ω\omegaω 较小时,sin⁡(ω/2)≈ω/2\sin(\omega/2) \approx \omega/2sin(ω/2)≈ω/2,上式近似为:

∣H(ejω)∣≈∣sin⁡(ωRM/2)ωRM/2∣=∣sinc(ωRM/2)∣ |H(e^{j\omega})| \approx \left|\frac{\sin(\omega RM/2)}{\omega RM/2}\right| = |\text{sinc}(\omega RM/2)| ∣H(ejω)∣≈ ωRM/2sin(ωRM/2) =∣sinc(ωRM/2)∣

这正是sinc函数的形态------CIC滤波器本质上是一个sinc滤波器

1.3 多级级联的考量

单级CIC滤波器的旁瓣电平仅比主瓣低约13.46dB,阻带衰减远不能满足实际需求。解决方案是采用多级级联 。若级联 NNN 级,则阻带衰减变为 N×13.46dBN \times 13.46\text{dB}N×13.46dB。例如,5级CIC滤波器可提供约67dB的阻带衰减,相当可观。

但代价是通带衰减也随着级数增加而恶化。级联 NNN 级后的传递函数为:

HN(z)=(1−z−RMRM(1−z−1))N H_N(z) = \left(\frac{1 - z^{-RM}}{RM(1 - z^{-1})}\right)^N HN(z)=(RM(1−z−1)1−z−RM)N

2. CIC滤波器的实现结构

2.1 直接型结构与硬件友好性

如果按照传递函数直接实现,CIC滤波器在结构上非常清晰:积分器在前,抽取/内插在中,梳状在后(对于抽取CIC)。图1展示了N级抽取CIC滤波器的整体实现架构。

复制代码
x[n]  (高采样率 f_s)
  │
  ▼
┌─────────────┐
│ 积分器 1    │   y1[n] = y1[n-1] + x[n]
└─────────────┘
  │
  ▼
┌─────────────┐
│ 积分器 2    │   y2[n] = y2[n-1] + y1[n]
└─────────────┘
  │
  ▼
     ⋮
  │
  ▼
┌─────────────┐
│ 积分器 N    │   yN[n] = yN[n-1] + y(N-1)[n]
└─────────────┘
  │
  ▼
   [ ↓R ]      <── 抽取器 (每R个点保留一个)
  │
  ▼
┌─────────────┐
│ 梳状 1      │   c1[m] = u[m] - u[m-M]   (u为抽取后的序列)
└─────────────┘
  │
  ▼
┌─────────────┐
│ 梳状 2      │   c2[m] = c1[m] - c1[m-M]
└─────────────┘
  │
  ▼
     ⋮
  │
  ▼
┌─────────────┐
│ 梳状 N      │   cN[m] = c(N-1)[m] - c(N-1)[m-M]
└─────────────┘
  │
  ▼
y[m] (低采样率 f_s/R)

图1:N级抽取CIC滤波器结构框图

所有积分器工作在原始高采样率 fsf_sfs 下,每个积分器是一个累加器:y[n]=y[n−1]+x[n]y[n] = y[n-1] + x[n]y[n]=y[n−1]+x[n]。抽取器 ↓R\downarrow R↓R 将采样率降低为 fs/Rf_s/Rfs/R。梳状部分工作在降低后的采样率 fs/Rf_s/Rfs/R 下,每个梳状单元是一个差分器:y[m]=x[m]−x[m−RM]y[m] = x[m] - x[m-RM]y[m]=x[m]−x[m−RM](其中 MMM 通常取1或2)。

这种结构完全由加法和延迟单元构成,没有任何乘法运算,在FPGA或ASIC实现中极为高效。图2给出了积分器和梳状滤波器的基本单元内部结构。

积分器单元:

复制代码
x[n] ──→⊕──→ y[n]
       ↑   │
       │   │ z⁻¹
       └───┘

图2a:CIC积分器结构

传递函数:HI(z)=11−z−1H_I(z) = \frac{1}{1-z^{-1}}HI(z)=1−z−11

梳状滤波器单元:

复制代码
x[m] ──→⊕──→ y[m]
       ↑   │
       │   │ z^{-RM}
       └───┘

图2a:CIC梳状滤波器结构

传递函数:HC(z)=1−z−RMH_C(z) = 1 - z^{-RM}HC(z)=1−z−RM

2.2 Hogenauer结构与位宽增长

经典的Hogenauer结构正是图1所示的布局,它将积分器全部置于抽取之前,梳状全部置于抽取之后。这种安排使得大部分运算(积分)在高速时钟下进行,而梳状运算在低速时钟下进行,功耗更优。

一个关键问题是位宽增长 。由于积分器是累加器,数据位宽会不断增长。在N级CIC滤波器中,为避免溢出,输出位宽 LLL 需满足:

L=输入位宽+⌈Nlog⁡2(RM)⌉ L = \text{输入位宽} + \lceil N \log_2(RM) \rceil L=输入位宽+⌈Nlog2(RM)⌉

例如,输入位宽16位,R=64R=64R=64,M=1M=1M=1,N=5N=5N=5,则输出位宽需达到 16+⌈5log⁡2(64)⌉=16+30=4616 + \lceil 5 \log_2(64) \rceil = 16 + 30 = 4616+⌈5log2(64)⌉=16+30=46 位。

2.3 补偿滤波器的必要性

从sinc频率响应可以看出,CIC滤波器的通带并不平坦,随着频率增加有明显衰减。在许多应用中,需要在CIC后级联一个补偿滤波器(通常是FIR),其频率响应为CIC响应的倒数:

Hcomp(f)≈∣πMfsin⁡(πMf)∣N H_{comp}(f) \approx \left|\frac{\pi M f}{\sin(\pi M f)}\right|^N Hcomp(f)≈ sin(πMf)πMf N

以此使通带恢复平坦。

3. Python实现与验证

理论讲再多,不如代码跑一跑。下面我们通过Python实现CIC抽取和内插滤波器,并验证其功能。

3.1 面向对象的CIC抽取滤波器实现

我们首先设计一个CIC抽取滤波器类,包含积分和梳状两个主要过程。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import freqz

class CICDecimator:
    """
    级联积分梳状抽取滤波器 (CIC Decimator)
    
    参数:
        num_stages (int): 级联级数 N
        decimation_factor (int): 抽取因子 R
        differential_delay (int): 差分延迟 M (通常为1或2)
    """
    def __init__(self, num_stages, decimation_factor, differential_delay=1):
        self.N = num_stages
        self.R = decimation_factor
        self.M = differential_delay
        
        # 积分器状态 (每个积分级保存上一个输出)
        self.integrator_state = [0] * self.N
        
        # 梳状部分延迟线: 每个梳状级需要保存 M 个历史样本
        self.comb_delay_line = np.zeros((self.N, self.M))
    
    def reset(self):
        """重置滤波器状态"""
        self.integrator_state = [0] * self.N
        self.comb_delay_line = np.zeros((self.N, self.M))
    
    def process(self, x):
        """
        处理输入信号 (抽取模式: 积分在前, 抽取在中, 梳状在后)
        
        参数:
            x: 输入信号 (numpy数组)
        返回:
            y: 抽取后的输出信号
        """
        # 积分器 (高采样率)
        integrator_out = np.zeros(len(x))
        for i, sample in enumerate(x):
            self.integrator_state[0] += sample
            current = self.integrator_state[0]
            for stage in range(1, self.N):
                self.integrator_state[stage] += current
                current = self.integrator_state[stage]
            integrator_out[i] = current
        
        # 抽取
        decimated = integrator_out[::self.R]
        
        # 梳状滤波 (低采样率)
        y = np.zeros(len(decimated))
        for i, sample in enumerate(decimated):
            current = sample
            for stage in range(self.N-1, -1, -1):
                diff = current - self.comb_delay_line[stage][0]
                self.comb_delay_line[stage] = np.roll(self.comb_delay_line[stage], -1)
                self.comb_delay_line[stage][-1] = current
                current = diff
            y[i] = current
        
        return y

3.2 抽取滤波器验证

我们生成一个包含多频分量的测试信号,通过CIC抽取滤波器后观察其频谱。

python 复制代码
# 参数设置
Fs = 1e6  # 采样率 1MHz
R = 64    # 抽取因子
M = 1     # 差分延迟
N = 5     # 级联级数

# 生成测试信号: 5kHz + 20kHz + 100kHz 的混合
t = np.arange(0, 0.01, 1/Fs)
x = (np.sin(2*np.pi*5000*t) + 
     0.5*np.sin(2*np.pi*20000*t) + 
     0.3*np.sin(2*np.pi*100000*t))

# 创建CIC抽取滤波器
cic_dec = CICDecimator(num_stages=N, decimation_factor=R, differential_delay=M)

# 处理信号
y = cic_dec.process(x)

# 绘制时域波形对比
plt.figure(figsize=(12, 8))

plt.subplot(3, 1, 1)
plt.plot(t[:500], x[:500])
plt.title('原始信号 (时域片段)')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')

plt.subplot(3, 1, 2)
t_dec = t[::R][:len(y)]
plt.plot(t_dec[:min(500, len(y))], y[:min(500, len(y))])
plt.title(f'CIC抽取后信号 (R={R}, N={N})')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')

# 频谱分析
plt.subplot(3, 1, 3)
freq = np.fft.fftfreq(len(x), 1/Fs)[:len(x)//2]
X_fft = np.abs(np.fft.fft(x))[:len(x)//2]
X_fft = X_fft / np.max(X_fft)

y_fs_new = Fs / R
freq_y = np.fft.fftfreq(len(y), 1/y_fs_new)[:len(y)//2]
Y_fft = np.abs(np.fft.fft(y))[:len(y)//2]
Y_fft = Y_fft / np.max(Y_fft)

plt.plot(freq/1000, 20*np.log10(X_fft+1e-10), label='原始信号频谱', alpha=0.7)
plt.plot(freq_y/1000, 20*np.log10(Y_fft+1e-10), label='CIC输出频谱', linewidth=2)
plt.title('频谱对比')
plt.xlabel('频率 (kHz)')
plt.ylabel('归一化幅度 (dB)')
plt.legend()
plt.grid(True)
plt.ylim(-100, 5)
plt.xlim(0, 100)

plt.tight_layout()
plt.show()

滤波器效果如下图所示。

3.3 理论响应验证

绘制CIC滤波器的理论频率响应,与实际滤波效果对照。

python 复制代码
w, h = freqz(np.ones(R*M), 1, worN=2048, fs=Fs)
h_N = h ** N

plt.figure(figsize=(10, 6))
plt.plot(w/1000, 20*np.log10(np.abs(h_N) + 1e-10), label=f'理论响应 (N={N}, R={R})')
plt.axvline(x=Fs/(2*R)/1000, color='r', linestyle='--', label=f'抽取后奈奎斯特频率 ({Fs/(2*R)/1000:.1f} kHz)')
plt.title('CIC抽取滤波器频率响应 (抽取前)')
plt.xlabel('频率 (kHz)')
plt.ylabel('幅度 (dB)')
plt.grid(True)
plt.legend()
plt.ylim(-150, 5)
plt.xlim(0, Fs/2/1000)
plt.show()

从图中可以清晰看到sinc函数的形状,以及在抽取后奈奎斯特频率处的混叠抑制能力。

3.4 内插CIC滤波器实现与验证

对于采样率升高的内插应用,CIC滤波器的结构恰好对称:梳状滤波器在内插之前(低采样率侧),内插器在中间,积分器在内插之后(高采样率侧)。图3展示了N级内插CIC滤波器的结构。

复制代码
x[m] (低采样率 f_s)
  │
  ▼
┌─────────────┐
│ 梳状 1      │   c1[m] = x[m] - x[m-M]
└─────────────┘
  │
  ▼
┌─────────────┐
│ 梳状 2      │   c2[m] = c1[m] - c1[m-M]
└─────────────┘
  │
  ▼
     ⋮
  │
  ▼
┌─────────────┐
│ 梳状 N      │   cN[m] = c(N-1)[m] - c(N-1)[m-M]
└─────────────┘
  │
  ▼
   [ ↑R ]      <── 内插器 (每两个样本间插入R-1个零)
  │
  ▼
┌─────────────┐
│ 积分器 1    │   y1[n] = y1[n-1] + u[n]
└─────────────┘
  │
  ▼
┌─────────────┐
│ 积分器 2    │   y2[n] = y2[n-1] + y1[n]
└─────────────┘
  │
  ▼
     ⋮
  │
  ▼
┌─────────────┐
│ 积分器 N    │   yN[n] = yN[n-1] + y(N-1)[n]
└─────────────┘
  │
  ▼
y[n] (高采样率 f_s * R)

图3:N级内插CIC滤波器结构框图

内插CIC的工作原理是:首先在低采样率下对输入信号进行梳状滤波(差分运算),然后通过内插器(插入零值样本)将采样率提高R倍,最后在高采样率下通过积分器链(累加器)得到最终输出。这种结构同样只有加法和延迟,非常适合硬件实现。

下面我们实现内插CIC滤波器类,并进行验证。

python 复制代码
class CICInterpolator:
    """
    级联积分梳状内插滤波器 (CIC Interpolator)
    
    参数:
        num_stages (int): 级联级数 N
        interpolation_factor (int): 内插因子 R
        differential_delay (int): 差分延迟 M (通常为1或2)
    """
    def __init__(self, num_stages, interpolation_factor, differential_delay=1):
        self.N = num_stages
        self.R = interpolation_factor
        self.M = differential_delay
        
        # 梳状部分状态 (在低采样率下)
        self.comb_state = [0] * self.N      # 当前输出
        self.comb_delay_line = np.zeros((self.N, self.M))  # 历史样本
        
        # 积分器状态 (在高采样率下)
        self.integrator_state = [0] * self.N
    
    def reset(self):
        """重置滤波器状态"""
        self.comb_state = [0] * self.N
        self.comb_delay_line = np.zeros((self.N, self.M))
        self.integrator_state = [0] * self.N
    
    def process(self, x):
        """
        处理输入信号 (内插模式: 梳状在前, 内插在中, 积分在后)
        
        参数:
            x: 输入信号 (低采样率数组)
        返回:
            y: 内插后的高采样率信号
        """
        # 1. 梳状滤波 (低采样率)
        comb_out = np.zeros(len(x))
        for i, sample in enumerate(x):
            current = sample
            for stage in range(self.N):
                diff = current - self.comb_delay_line[stage][0]
                self.comb_delay_line[stage] = np.roll(self.comb_delay_line[stage], -1)
                self.comb_delay_line[stage][-1] = current
                current = diff
                self.comb_state[stage] = current
            comb_out[i] = current
        
        # 2. 内插 (零值插入)
        # 在每两个梳状输出之间插入 R-1 个零
        upsampled = np.zeros(len(comb_out) * self.R)
        upsampled[::self.R] = comb_out  # 零填充
        
        # 3. 积分滤波 (高采样率)
        y = np.zeros(len(upsampled))
        for i, sample in enumerate(upsampled):
            self.integrator_state[0] += sample
            current = self.integrator_state[0]
            for stage in range(1, self.N):
                self.integrator_state[stage] += current
                current = self.integrator_state[stage]
            y[i] = current
        
        # 注意: 此处未进行增益归一化,实际应用需缩放
        return y

为了验证内插CIC的性能,我们生成一个低频正弦信号,通过内插CIC将采样率提高,并观察其频谱中镜像频率的抑制情况。

python 复制代码
# 内插参数
Fs_low = 10000      # 低采样率 10 kHz
R = 8               # 内插因子
M = 1               # 差分延迟
N = 5               # 级联级数
F_signal = 1000     # 信号频率 1 kHz

# 生成低采样率信号 (1 kHz正弦波)
t_low = np.arange(0, 0.01, 1/Fs_low)  # 10 ms
x_low = np.sin(2*np.pi*F_signal * t_low)

# 创建内插CIC滤波器
cic_int = CICInterpolator(num_stages=N, interpolation_factor=R, differential_delay=M)

# 处理信号
y_high = cic_int.process(x_low)

# 高采样率对应的时间轴
Fs_high = Fs_low * R
t_high = np.arange(0, len(y_high)) / Fs_high

# 绘制时域波形
plt.figure(figsize=(12, 10))

plt.subplot(3, 1, 1)
plt.stem(t_low[:20], x_low[:20], basefmt=" ", linefmt='r-', markerfmt='ro', label='低采样率输入')
plt.title('内插前信号 (低采样率)')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.legend()

plt.subplot(3, 1, 2)
plt.plot(t_high[:20*R], y_high[:20*R], 'b-o', markersize=3, label='内插后输出')
plt.title(f'内插后信号 (R={R}, N={N})')
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.legend()

# 频谱分析
plt.subplot(3, 1, 3)
# 低采样率信号频谱
freq_low = np.fft.fftfreq(len(x_low), 1/Fs_low)[:len(x_low)//2]
X_low = np.abs(np.fft.fft(x_low))[:len(x_low)//2]
X_low = X_low / np.max(X_low)

# 高采样率信号频谱
freq_high = np.fft.fftfreq(len(y_high), 1/Fs_high)[:len(y_high)//2]
Y_high = np.abs(np.fft.fft(y_high))[:len(y_high)//2]
Y_high = Y_high / np.max(Y_high)

plt.plot(freq_low/1000, 20*np.log10(X_low+1e-10), label='低采样率信号频谱', alpha=0.7)
plt.plot(freq_high/1000, 20*np.log10(Y_high+1e-10), label='内插后信号频谱', linewidth=2)
plt.axvline(x=Fs_low/2/1000, color='r', linestyle='--', label='原始奈奎斯特频率')
plt.title('频谱对比 (镜像抑制)')
plt.xlabel('频率 (kHz)')
plt.ylabel('归一化幅度 (dB)')
plt.legend()
plt.grid(True)
plt.ylim(-100, 5)
plt.xlim(0, Fs_high/2/1000)

plt.tight_layout()
plt.show()

运行上述代码,可以看到内插后的信号时域上变得更平滑(因为插入了更多采样点),频谱中除了原始信号频率外,还在原始采样率的整数倍附近出现了镜像频率,但由于CIC滤波器的sinc响应,这些镜像被有效抑制。验证了内插CIC的镜像抑制能力。

4. 设计要点与工程考虑

4.1 参数选择指南

  • 级数N:通常取3~5。N=1时阻带衰减不足;N>5时通带衰减过大且硬件位宽急剧增长。
  • 差分延迟M:通常取1或2。M增大虽能改善混叠/镜像抑制,但会进一步压缩通带。
  • 抽取/内插因子R:CIC擅长处理大幅率变换(如R>10)。对于小幅变换,FIR可能更经济。

4.2 溢出处理与增益控制

CIC滤波器具有固定的增益 G=(RM)NG = (RM)^NG=(RM)N。在定点实现中,必须为中间结果预留足够的位宽,或在输出级进行缩放。常用的方法是输出右移操作:

yfinal=yCIC2S y_{\text{final}} = \frac{y_{\text{CIC}}}{2^S} yfinal=2SyCIC

其中 S=⌈log⁡2(G)⌉S = \lceil \log_2(G) \rceilS=⌈log2(G)⌉,也可根据信噪比要求适当选择截位位数。

4.3 补偿滤波器设计

若需平坦的通带响应,可在CIC后级联补偿滤波器。补偿滤波器通常为低阶FIR,其系数可通过如下方法生成:

python 复制代码
from scipy.signal import firwin2

def design_cic_compensator(R, M, N, cutoff, numtaps=100):
    """
    设计CIC补偿滤波器
    """
    # 补偿响应 = 1 / H_cic(f) 在通带内
    freq_points = np.linspace(0, cutoff, 50)
    cic_resp = np.sinc(freq_points * M * R) ** N  # 近似
    comp_resp = 1 / (cic_resp + 1e-10)
    
    # 构造完整的频率响应数组 (包括阻带)
    freqs = np.concatenate((freq_points / cutoff * cutoff, [cutoff, 0.5]))
    gains = np.concatenate((comp_resp, [comp_resp[-1], 0]))
    
    # 归一化
    gains = gains / gains[0]
    
    # 设计FIR
    taps = firwin2(numtaps, freqs, gains, fs=1.0)
    return taps

结语

CIC滤波器以其无乘法器的简洁结构,在多速率信号处理领域占据着不可替代的地位。本文从数学原理出发,通过Python实现了抽取和内插两种模式的CIC滤波器,并辅以清晰的实现框图和验证示例。在实际工程中,无论是FPGA实现还是ASIC设计,CIC滤波器都是处理大幅采样率转换的首选方案。

希望本文能帮助您理解CIC滤波器的核心思想,并在您的项目中灵活运用。欢迎动手运行代码,调整参数,感受sinc滤波器的魅力。


参考文献

1\] Hogenauer, E. B. "An Economical Class of Digital Filters for Decimation and Interpolation." IEEE Transactions on Acoustics, Speech and Signal Processing, 1981. \[2\] Harris, F. J. "Multirate Signal Processing for Communication Systems." Prentice Hall, 2004. *** ** * ** *** **研究学习不易,点赞易。 工作生活不易,收藏易,点收藏不迷茫 :)** *** ** * ** ***

相关推荐
Rorsion2 小时前
循环神经网络(RNN)
人工智能·rnn·深度学习
Sakinol#2 小时前
Leetcode Hot 100 ——多维动态规划
算法·leetcode·动态规划
李可以量化2 小时前
QMT之如何判断因子好坏(下)
大数据·机器学习·qmt·量化 qmt ptrade·因子
网管NO.12 小时前
OpenClaw 多模型配置完整教程(WSL2 + Ubuntu)
运维·网络·人工智能·ubuntu
XZXZZX2 小时前
ATCODER ABC 450 C题解
c++·算法·ccf csp
东离与糖宝2 小时前
不用Python!Java+Spring AI 3.x本地RAG系统搭建实战
java·人工智能
堕2742 小时前
JavaEE初阶——《多线程--. 多线程带来的的⻛险-线程安全 (重点)》
java·算法·java-ee
像素猎人2 小时前
差分数组【自用笔记】【c++】
c++·笔记·算法
找了一圈尾巴2 小时前
OpenClaw 技术架构解析-网关层(下)
人工智能·架构