第二章 辨识数据采集:激励信号设计、采样率选择与数据预处理

大家好,我是老张。今天咱们聊聊辨识数据采集这个环节。说实话,很多工程师把精力都放在算法上,却忽略了数据质量。我见过太多案例——算法调得再好,数据一塌糊涂,结果全是白费功夫。

数据采集,说白了就是给系统做一次“体检”。你得设计合适的“体检项目”,选对“测量仪器”,最后还得把“体检报告”整理干净。这一章,我就把这三个环节掰开揉碎了讲。

核心观点:辨识数据的质量,直接决定了模型精度的天花板。数据不好,再牛的算法也救不了。

2.1 激励信号设计

为什么要设计激励信号?你想想看,系统就像一个人,你问它“你还好吗?”,它可能回你“嗯”。但如果你给它来点刺激,它才会真正“开口说话”。激励信号就是用来“刺激”系统的,让它把动态特性全抖出来。

我个人习惯,最常用的两种信号是PRBS和扫频信号。它们各有各的脾气。

2.1.1 PRBS信号

PRBS,全称是伪随机二进制序列。说白了,它就是在两个值之间来回跳的信号。为什么叫“伪随机”?因为它看起来随机,其实是有规律的。

PRBS的核心参数:

  • 阶数n:决定了序列长度,长度 = 2^n - 1。n越大,信号越“随机”。
  • 时钟周期T_clk:信号保持一个值的最小时间。这决定了信号的带宽。
  • 幅值:一般取系统正常工作范围的5%~20%。

我在项目中遇到过一件事。有一次给一个温度系统做辨识,我用了PRBS信号,结果模型死活不准。后来发现,温度系统响应太慢,PRBS跳变太快,系统根本来不及反应。嗯,这里要注意——PRBS的时钟周期必须大于系统的上升时间。

经验之谈:PRBS的时钟周期T_clk,我一般取系统时间常数的1/5到1/10。这样既能激励出高频特性,又不至于让系统“跟不上”。

PRBS的生成代码(Python):

import numpy as np

def generate_prbs(n, T_clk, num_periods=1):
    """
    生成PRBS信号
    n: 阶数
    T_clk: 时钟周期(采样点数)
    num_periods: 周期数
    """
    # 线性反馈移位寄存器
    reg = np.ones(n, dtype=int)
    seq_len = 2**n - 1
    seq = np.zeros(seq_len)
    
    for i in range(seq_len):
        seq[i] = reg[-1]
        # 反馈多项式:x^n + x^(n-1) + 1(常用)
        feedback = reg[-1] ^ reg[-2]
        reg = np.roll(reg, 1)
        reg[0] = feedback
    
    # 扩展到时钟周期
    signal = np.repeat(seq, T_clk)
    # 映射到[-1, 1]
    signal = 2 * signal - 1
    
    return np.tile(signal, num_periods)

2.1.2 扫频信号

扫频信号,就是频率从低到高慢慢扫过去。它特别适合用来摸清系统的“频率响应”。我个人觉得,扫频信号比PRBS更直观——你一看频谱图,就知道系统在哪个频率段“兴奋”,哪个频率段“萎了”。

扫频信号的参数:

  • 起始频率f_start:一般取系统最低工作频率的1/10。
  • 终止频率f_end:一般取系统最高工作频率的10倍。
  • 扫频时间T_sweep:决定了频率变化的速度。太短了,系统来不及响应;太长了,浪费时间。
  • 幅值:同PRBS,取5%~20%。

注意:扫频信号有一个坑——如果扫频速度太快,系统会出现“瞬态响应”和“稳态响应”混在一起的情况。我曾经吃过这个亏,扫频结果乱七八糟,后来把扫频时间延长了3倍才搞定。

扫频信号的生成代码:

def generate_chirp(f_start, f_end, T_sweep, fs):
    """
    生成线性扫频信号
    f_start: 起始频率 (Hz)
    f_end: 终止频率 (Hz)
    T_sweep: 扫频时间 (s)
    fs: 采样率 (Hz)
    """
    t = np.linspace(0, T_sweep, int(T_sweep * fs))
    # 瞬时频率线性变化
    inst_freq = f_start + (f_end - f_start) * t / T_sweep
    # 相位是频率的积分
    phase = 2 * np.pi * np.cumsum(inst_freq) / fs
    signal = np.sin(phase)
    return t, signal

2.1.3 PRBS vs 扫频信号:怎么选?

特性 PRBS 扫频信号
频谱特性 宽频带,能量均匀 窄频带,能量集中
对非线性敏感度 低 高
实现难度 简单(数字电路直接生成) 中等(需要D/A转换)
适用场景 线性系统、弱非线性系统 强非线性系统、需要频率响应分析

我个人习惯:如果系统比较“规矩”(线性度好),我首选PRBS。如果系统有强非线性,或者我想仔细看看频率响应,那就用扫频信号。

2.2 采样率选择

采样率选多少?这个问题看似简单,其实坑很多。

基本原则:采样率必须满足奈奎斯特采样定理——采样率 ≥ 2 × 系统最高频率。但实际工程中,我一般取5~10倍。

为什么?你想想看,奈奎斯特定理只是保证“不混叠”,但没保证“辨识精度”。采样率太低,高频信息丢失;采样率太高,数据量爆炸,计算也慢。

我的经验公式:

  • 对于慢系统(温度、液位):采样率 = 10~20倍系统带宽
  • 对于中速系统(电机转速):采样率 = 5~10倍系统带宽
  • 对于快速系统(振动、电流):采样率 = 3~5倍系统带宽

我曾经在一个电机辨识项目里,采样率设得太高(100kHz),结果数据量巨大,跑一次辨识要半小时。后来降到10kHz,精度几乎没变,速度却快了10倍。嗯,这里要提醒大家——采样率不是越高越好,够用就行。

2.3 数据预处理

数据采回来了,但别急着用。原始数据里有很多“脏东西”——趋势项、噪声、异常值。不处理干净,模型就会学歪。

2.3.1 去趋势

什么是趋势项?就是数据中缓慢变化的成分。比如温度系统,环境温度在慢慢上升,这个趋势不是系统本身的动态特性,必须去掉。

去趋势的方法:

  • 均值移除:最简单,减去数据的均值。适用于趋势是常数的情况。
  • 线性去趋势:拟合一条直线,然后减去。适用于趋势是线性变化的情况。
  • 高通滤波:用高通滤波器滤掉低频趋势。适用于趋势频率已知的情况。

代码示例:

from scipy import signal

def detrend_signal(data, method='linear'):
    """
    去趋势
    method: 'constant'(均值移除), 'linear'(线性去趋势)
    """
    if method == 'constant':
        return data - np.mean(data)
    elif method == 'linear':
        # 使用scipy的detrend函数
        return signal.detrend(data, type='linear')
    else:
        raise ValueError("不支持的方法")

2.3.2 滤波

滤波是为了去掉高频噪声。但要注意——滤波也会改变信号的相位和幅值。搞不好,你会把有用的信息也滤掉。

我常用的滤波器:

  • 低通滤波器:最常用。截止频率取系统带宽的2~3倍。
  • 中值滤波器:对付“野点”(异常值)特别好用。
  • 零相位滤波:用filtfilt函数,可以避免相位偏移。我个人强烈推荐。

避坑指南:我曾经用普通低通滤波器处理数据,结果模型辨识出来总是有延迟。后来才发现,普通滤波器会引入相位滞后。改用零相位滤波后,问题就解决了。

零相位滤波代码:

from scipy.signal import butter, filtfilt

def zero_phase_lowpass(data, cutoff, fs, order=4):
    """
    零相位低通滤波
    cutoff: 截止频率 (Hz)
    fs: 采样率 (Hz)
    """
    nyquist = 0.5 * fs
    normal_cutoff = cutoff / nyquist
    b, a = butter(order, normal_cutoff, btype='low')
    # 使用filtfilt实现零相位
    filtered = filtfilt(b, a, data)
    return filtered

2.3.3 数据预处理流程总结

我一般按这个顺序处理数据:

  1. 检查数据完整性:有没有缺失值?有没有明显异常?
  2. 去趋势:先去掉缓慢变化的趋势项。
  3. 滤波:用零相位低通滤波器去掉高频噪声。
  4. 归一化:把数据缩放到[-1, 1]或[0, 1]区间,方便后续计算。
  5. 分段:把数据分成训练集和验证集。

小技巧:预处理完成后,一定要看一眼处理前后的对比图。如果滤波后的信号“太光滑”,说明截止频率设得太低了,丢失了信息。如果还是“毛刺很多”,说明截止频率太高了,噪声没滤干净。

本章知识体系

下面这张图,是我自己总结的数据采集全流程。你可以把它当作一个检查清单。

辨识数据采集全流程 激励信号设计 PRBS / 扫频信号 幅值、频率范围 采样率选择 奈奎斯特准则 5~10倍系统带宽 数据采集 实时采集 存储原始数据 数据预处理 去趋势 → 滤波 → 归一化 检查完整性 → 分段 数据验证 频谱分析 / 相关性检查 确认数据可用 每一步都直接影响最终模型的质量,不可跳过

好了,这一章的内容就到这里。数据采集是辨识工作的“地基”,地基不牢,房子再漂亮也白搭。下一章我们会讲怎么用这些数据来辨识模型参数,到时候见。

可可精品资料库