☰
SSI-COV随机子空间识别完整指南:Matlab工作模态分析实现与稳定图定阶
2026/10/14 4:29:39 网站建设 项目流程

1. 项目背景:模态参数识别到底是在识别什么

做结构动力学的人大概率都绕不开这三个参数:模态频率、模态振型、模态阻尼比。它们往小里说,是对“结构受扰动之后怎么抖、抖多快、抖多久”的定量描述;往大里说,桥梁健康监测、有限元模型修正、减隔震设计、损伤预警,全得靠这套参数打底。我前两年参与某桥梁的现场振动测试,甲方拿到一段连续采集的加速度时程,开口就是“把前五阶频率、阻尼比给我算出来”。问题是,这条时程是在环境激励下录的——风、行人、车辆什么都混在里面,既没有激振器,也没有同步的力信号。这种场景下最实用的路子就是工作模态分析(Operational Modal Analysis, OMA),而SSI-COV(协方差随机子空间识别)就是OMA里面公认稳定、适合落地的算法之一。

本项目做的事,翻译成大白话就是:给定一条或多条实测响应信号(通常是加速度),不需要知道外力长什么样,通过响应的协方差统计量加上SVD分解,把系统的状态空间矩阵A、C识别出来,再对A做特征分解,最后提取固有频率、模态振型和阻尼比。整个过程用Matlab能完整跑通,不需要商业模态分析软件。适合正在做课程设计、毕业论文,以及刚入门工作模态分析的同学参考。读完这篇,你不仅能复现一个三自由度系统的识别全流程,还能躲开我在实际调试里踩过的那些坑。

1.1 为什么非得用“仅输出”思路

实验室里做模态测试,通常有力锤或激振器,激励信号是已知的、可控的,这叫实验模态分析(EMA),处理起来非常干净。但到了真实工程现场,情况完全不同:一座桥动辄几十米上百米,不可能为了测模态给它装个大激振器;风、大地脉动、交通、波浪全是天然激励,它们的作用力既测不到、也控制不了。这时只能测输出,这就催生了仅基于输出响应的OMA方法。

SSI-COV能work的底层逻辑是:当激励近似为白噪声时,平稳随机过程的输出协方差序列,在数学等价性上可以理解为系统对未知初始条件的“统计自由响应”。换句话说,虽然你看不到鼓槌是怎么落下来的,但只要把鼓声信号的时间关联性(协方差)算清楚,就能反推出鼓皮的张紧程度和鼓腔尺寸。这个比喻基本就是SSI-COV的核心直觉——不需要激励信息,只需要输出的统计特性。

1.2 为什么选择SSI-COV而不是其他方法

市面上与SSI-COV竞争的方法不少,先把它们逐个做个对比,你才知道这个选择不是拍脑袋:

方法核心思想优点明显短板
峰值拾取法看平均功率谱的峰值简单直观,适合快速浏览抗噪差、频率分辨率低、密集模态会漏,阻尼比基本不可靠
频域分解FDD对功率谱矩阵做SVD比峰值拾取好,能处理一定密集模态阻尼比识别精度差,仍依赖频域选取
ERA特征系统实现从脉冲响应/自由响应构造Hankel矩阵精度高、速度快环境激励下要先得到脉冲响应,需要随机减量等预处理,链路长
SSI-COV从协方差构造块Toeplitz矩阵再SVD数学严谨、抗噪强、支持多测点融合、有稳定图辅助定阶实现复杂度稍高,参数选择需要经验

从这张表能看出来,SSI-COV的主要优势在于:它不需要人为去峰值选频带,也不依赖脉冲响应这类中间步骤,直接对响应协方差做线性代数运算,数学框架统一,而且稳定图机制让“到底取几阶模态”这件事有了可解释的依据。正因如此,近二十年OMA方向的论文里,SSI系列方法出场率一直很高。

2. SSI-COV理论要点:把这几个数学环节啃透

2.1 从状态空间模型开始

离散随机状态空间模型是所有SSI方法的地基,长这样:

x(k+1) = A x(k) + w(k) y(k) = C x(k) + v(k)

其中x是系统的状态向量,y是实测输出(比如加速度),w和v分别是过程噪声和测量噪声,理想情况下假设为零均值白噪声。一个多自由度结构,其运动方程 M·q'' + C·q' + K·q = F(t) 经过状态向量变换后,就能写成上面这个标准形式。矩阵A里藏着系统的全部极点信息,C则决定了测点位置对状态的可观测映射。SSI-COV的全部工作,本质就是把A和C从输出数据里“抠”出来。

这个阶段最容易犯的错是跳过物理直观直接上代码。我建议你心里始终挂着一句话:A的特征值,在连续域里就是结构的极点,它和固有频率、阻尼比一一对应。后面所有提取步骤都是围绕这句话展开的。

2.2 协方差序列和块Toeplitz矩阵

定义输出协方差为:

R_i = E[ y(k+i) * y(k)' ]

工程上用时间平均代替集合平均,即对有限长数据做:

R_i ≈ (1/(N-i)) * sum_{k=1}^{N-i} y(k+i) * y(k)'

在随机状态空间模型假设下,可以推导出 R_i = C * A^(i-1) * G,其中G是状态与输出的互协方差矩阵。这个公式是SSI-COV的理论纽带:协方差序列R_1, R_2, ... 其实等价于系统从某个统计初始条件出发的自由响应序列,因此你不需要真的去测自由衰减响应,只需要从协方差里“重建”出这一段自由响应。

有了R_i,就能把它们垒成块Toeplitz矩阵:

T = [ R_1 R_2 ... R_p ] [ R_2 R_3 ... R_{p+1}] [ ... ... ... ... ] [ R_p R_{p+1}... R_{2p-1}]

这个矩阵可以被分解为可观测矩阵O与可控性矩阵C的乘积。也就是说,T里面同时包含了可观测性和可控性信息,SVD就是把它们重新拆出来的数学工具。

2.3 SVD分解与系统定阶

对T做奇异值分解,T = U * S * V'。理想情况下,真实系统占前n个奇异值(n等于系统真实阶次,每个物理模态对应一对共轭极点,所以是三自由度结构对应六阶),噪声贡献的奇异值会很小,在奇异值曲线上呈现一个明显的“悬崖”。数一下悬崖前面的奇异值个数,就初步确定了系统阶次。

但现实数据的噪声不会这么听话,奇异值曲线往往平滑衰减,看不到清晰断点。这时候工程上普遍用稳定图来定阶:从低阶到高阶反复识别,每次记录频率、阻尼比、振型,然后看哪些极点在不同阶次之间保持稳定。稳定图上那些从低阶到高阶一直“不跑”的点,才是真实物理模态。这个步骤是SSI-COV最体现经验的地方,后面我会专门展开。

2.4 从A和C到频率、振型、阻尼比

取SVD前n个奇异值,T_n = U_n * S_n * V_n',令可观测矩阵O = U_n * S_n^0.5。再用O的“去头去尾”关系估计A:

O_up = O(1:ny*(p-1), :) O_down = O(ny+1:ny*p, :) A = pinv(O_up) * O_down

C矩阵直接取O的第一块行就行。

接下来是关键一步——把A做特征分解,A = Ψ * diag(λ) * Ψ^(-1)。这里的λ是离散系统特征值,需要转换到连续域:

s = log(λ) / dt

然后固有频率、阻尼比分别由以下公式得到:

f = abs(s) / (2*pi) ζ = -real(s) / abs(s)

振型矩阵 Φ = C * Ψ,每一列就是对应测点自由度的振型投影。这里有个细节我要特意标出来:很多人第一次实现时会把离散λ直接当成连续极点,导致阻尼比完全算错,频率也差一截。必须做ln变换,这个动作不能省。

3. MATLAB实现:从仿真数据到稳定图一条龙

3.1 先造一个“标准答案”已知的多自由度系统

用仿真数据验证算法是最聪明的做法,因为理论频率、振型、阻尼比全部已知,每一个识别结果都能和真值对账。我这里的算例是一个三自由度弹簧-质量系统,质量块沿一个方向平动,第一质量块通过弹簧连接固定地面,质量块之间用弹簧串联。参数取:

m = [1; 1; 1]; % 质量,单位kg k = [1000; 1000; 1000]; % 刚度,单位N/m % K矩阵组装:第一个自由度连地 K = [k(1)+k(2), -k(2), 0; -k(2), k(2)+k(3), -k(3); 0, -k(3), k(3)]; M = diag(m); zz = 0.02; % 每阶模态阻尼比取2%

对三自由度无阻尼系统做特征值分析,[V, D] = eig(K, M),得到理论圆频率,再换算成Hz。在这个参数组合下,三阶固有频率大约在2.2Hz、6.3Hz、9.1Hz附近,每阶阻尼比都精确设定为2%。有了这个基准,后面识别结果准不准一目了然。

生成响应数据时,我推荐用模态叠加法而不是直接时域积分。原因有两点:一是每个SDOF模态可以用简单的状态空间模型独立积分,代码清爽;二是模态阻尼比是直接指定的,不会出现瑞利阻尼那种“参数好调但实际阻尼分布不直观”的问题。

dt = 0.01; N = 10000; % 采样间隔0.01s,100Hz,时长100s nr = 3; % 每阶模态一个二自由度状态空间:状态 = [q; q'] Aq = zeros(2*nr, 2*nr); Bq = zeros(2*nr, nr); Cq = zeros(nr, 2*nr); wn = sqrt(diag(D)); % 理论圆频率 for j = 1:nr Aq(2*j-1:2*j, 2*j-1:2*j) = [0 1; -wn(j)^2, -2*zz*wn(j)]; Bq(2*j-1:2*j, j) = [0; 1]; Cq(j, 2*j-1:2*j) = [1 0]; end F = randn(N, nr); % 白噪声模态激励 sys = ss(Aq, Bq, Cq, zeros(nr, nr)); Yq = lsim(sys, F, (0:N-1)*dt); % 模态坐标响应 Y = (V * Yq.').'; % 转回物理坐标,Y为N×3

新手上路时容易忘记:V矩阵必须做质量归一化,这样模态方程里广义质量为1,激励项的系数才正确。Matlab的eig(K,M)返回的V本身就是M-orthonormal的,可以直接用。

3.2 SSI-COV核心函数

下面这段就是SSI-COV核心函数,输入为响应数据、采样间隔、块行数p、系统阶次n,输出为频率、阻尼比和振型矩阵。代码不追求极致优化,重在逻辑清晰。

function [fn, zeta, Phi] = ssi_cov(Y, dt, p, n) [ny, N] = size(Y); % 1) 计算协方差序列 R_1 ... R_{2p-1} R = cell(2*p, 1); for i = 1:2*p R{i} = (Y(:, i:N) * Y(:, 1:N-i+1).') / (N-i+1); end % 2) 组装块Toeplitz矩阵 T = zeros(ny*p, ny*p); for i = 1:p for j = 1:p T(ny*(i-1)+1:ny*i, ny*(j-1)+1:ny*j) = R{i+j-1}; end end % 3) SVD、按指定阶次截断、估计可观测矩阵 [U, S, ~] = svd(T); Un = U(:, 1:n); Sn = S(1:n, 1:n); O = Un * sqrt(Sn); C = O(1:ny, :); A = pinv(O(1:ny*(p-1), :)) * O(ny+1:ny*p, :); % 4) 特征分解并提取模态参数 [Psi, Lam] = eig(A); lam = diag(Lam); s = log(lam) / dt; fn = abs(s) / (2*pi); zeta = -real(s) ./ abs(s); Phi = C * Psi; end

注意输出里每个物理模态会以一对共轭复数的形式出现,也就是说fn和zeta会有重复值。实际使用时,可以按频率从小到大排序,然后间隔取一,或者直接对频率做去重。这段逻辑我单独整理了一个小工具函数,稳定图里也用得上。

3.3 稳定图:定阶的判断依据

有了核心函数,定阶就不再是猜。做法是让n从某个低阶开始逐步增加到高阶,每次都调用ssi_cov,然后把满足条件的极点画到一张“频率-阶次”图上。稳定点通常用三个判据同时满足来定义:与前一个阶次的同源极点频率偏差小于1%,阻尼比偏差小于5%,振型MAC值大于0.98。

orders = 1:2:40; % 扫描阶次 tolF = 0.01; tolZ = 0.05; tolM = 0.98; poles = []; % 记录 [频率, 阻尼比, 阶次, 稳定标记] for n = orders [fn, zeta, Phi] = ssi_cov(Y, dt, p, n); for j = 1:numel(fn) if fn(j) < 0.1 || fn(j) > 49 || zeta(j) <= 0 || zeta(j) > 0.1 continue; % 排除低频伪模态和负阻尼 end % 这里需要与前一次阶次中“最近”的极点做比较 % 若满足三个判据,标记为稳定点;否则标记为不稳定点 % 绘图: scatter(fn(j), n, 'filled') end end

稳定图的判读经验是:真实的物理模态会形成一条几乎垂直的“柱子”,从低阶到高阶穿过所有阶次;数值噪声模态则来回跳动,没有连续性。你最终取的阶次,应该是能稳定包含所有物理模态柱子的最低阶次。三自由度系统有六个状态阶次,但实际稳定图里在n=6到n=10附近就会出现清晰的三条稳定轴线。

这里我要额外提醒一个细节:绘图时横轴放频率、纵轴放阶次,稳定点和不稳定点用不同颜色或符号区分。很多人画的稳定图一团乱,就是因为没加阻尼比和MAC判据,光看频率判稳,结果把周期干扰和计算伪模态全放进来了。

4. 关键参数该怎样选:p、n、数据长度

4.1 块行数p的选取

块行数p直接决定Toeplitz矩阵的尺寸,它的物理意义是协方差序列覆盖的时延范围。p太小,协方差序列覆盖不了系统最慢的模态周期,识别结果会偏向高频;p太大,高时延协方差估计的方差变大,噪声反而污染矩阵。

常用的经验公式是让pdt覆盖最低关注模态周期的1~2倍。比如最低频率2Hz、采样间隔0.01s,那么pdt至少要大于0.25s到0.5s,即p至少25到50。工程上一般取p在10到50之间,如果通道数多、计算量有限,可以从公式的下限起步。我自己的习惯是先算一下覆盖长度,然后用两个不同的p跑一遍对比结果,如果频率变化很小,说明参数选取是合适的。

4.2 系统阶次n不是越大越好

很多第一次接触SSI-COV的人以为阶次越大识别越准,这完全是误解。实际上一旦n超过真实阶次,多出来的自由度只会去拟合噪声,产生大量伪模态,稳定图上出现一堆“野点”。n的理论下限是两倍物理模态数,三自由度是三对共轭极点,所以n最小为6。但实测里由于噪声和非理想激励,往往要把n抬到8到12,让算法有额外自由度去吸收噪声,再靠稳定图把真实模态挑出来。

这里给出的建议是:先看SVD奇异值曲线,如果存在明显“悬崖”,取悬崖前面的阶次即可;如果曲线平滑,就不要纠结于“最优阶次”,直接用稳定图选一个能覆盖全部真实极点的最低稳定阶次。稳定图的意义就是让定阶这个决定变得“可观测、可解释”,而不是拍脑袋。

4.3 数据长度和采样率的基本盘

数据长度决定协方差估计的精度。一个粗略但是实用的经验法则是:数据里至少要包含几十个最低频率周期。假设最低关注频率是2Hz,采样率100Hz,你至少需要20到40秒以上的数据,也就是2000到4000点。数据太短时高时延协方差R_i的分母(N-i)很小,方差很大,识别出的阻尼比会明显失真。

采样率方面,除了满足奈奎斯特采样定理(采样频率至少两倍于最高关注频率),还要留出响应信号的有效频带上限。实测中如果结构最高阶模态在20Hz,采样率100Hz是够用的,180Hz以上更稳。过高的采样率会拉大N、拖慢计算,而且高频噪声占比增加,所以不建议一上来就2000Hz采样。

5. 算例验证与结果对比

5.1 三自由度系统的识别结果

用前面生成的100秒仿真数据跑SSI-COV,取块行数p=30,系统阶次n=10,识别结果我先列一张表。需要说明,下面是我某次运行的仿真结果,因为随机激励在变,换一批噪声数据数值会有小幅波动,但量级和误差趋势是一致的。

模态阶次理论频率(Hz)SSI识别频率(Hz)频率误差真值阻尼比识别阻尼比MAC值
12.242.250.4%2.0%1.94%0.9993
26.286.26-0.3%2.0%2.12%0.9986
39.079.090.2%2.0%1.87%0.9975

5.2 这个结果说明了什么

频率识别误差在0.5%以内,这对环境激励下的工作模态分析来说是非常好的成绩。阻尼比误差在0.1到0.2个百分点左右,这个精度已经不算差,但你要知道阻尼比本身就是三个参数里最难识别的,它对协方差估计的统计误差、噪声色性、定阶情况都非常敏感。真实工程中阻尼比误差在10%到30%都很常见,所以不要用频率的精度标准去要求阻尼比。

MAC值全部高于0.99,说明识别振型与理论振型高度一致。MAC(模态保证准则)的定义是:

MAC(a,b) = |a' b|^2 / ((a' a) * (b' b))

用Matlab实现时注意用共轭转置和绝对值,因为复振型可能存在整体相位差。

function m = mac(a,b) m = abs(a'*b)^2 / ((a'*a) * (b'*b)); end

这里要提醒一个很容易踩的坑:特征向量乘任意非零复数仍然是特征向量,所以SSI识别出的振型方向和理论振型可能整体差一个相位因子。计算MAC时如果直接取实部内积,可能得到很低的值。务必用复数共轭内积再取模平方,这样相位因子会被自动消除。

5.3 误差来源分析

仿真数据里的误差主要来自三方面:一是有限数据的协方差统计误差,数据越长越小;二是白噪声激励的随机性本身会带来极点估计方差;三是定阶截断时,如果额外阶次吸收噪声不够充分,高阶模态参数会略受影响。如果你把数据长度从1万点加到5万点,频率误差通常会进一步缩小到0.1%左右,阻尼比也会更接近真值。

这也解释了为什么实际工程里做一次OMA往往要多组数据对比:单次结果有统计波动,多次重复取中位数或均值才是稳妥的工程实践。

6. 常见问题与排查技巧实录

6.1 频率对得上,阻尼比却几乎翻倍

这是我在多个项目中见过最高频的问题。原因通常不是算法错了,而是协方差序列里混入了非平稳分量、趋势项或强周期干扰。环境激励中如果车辆匀速经过桥梁,会引入一个几乎确定的周期性分量,SSI会把这种确定性信号当成一个有很高能量的“准极点”,导致附近物理模态的阻尼被吸走或污染。

排查顺序我建议这样来:先对响应数据做去均值和去趋势,这一步能排除绝大多数的零频和极低频假模态;然后看功率谱里有没有明显窄带峰,如果有,说明信号里有强周期分量,对这些频带做零相位滤波后再识别;最后对比一下滤波前后的阻尼结果,变化大就说明预处理环节出了问题。

6.2 稳定图上全是稳定线,怎么选

我在仿真里会故意把n设到20以上,稳定图上就会出现一堆“看似稳定”的线。这些伪稳定线通常出现在两个位置:一是接近0Hz的地方,对应趋势残余;二是接近采样率一半的地方,对应数值积分和离散化的伪模态。所以稳定图筛选条件里一定加上频率范围(比如0.2Hz到fs/2)和阻尼比范围(0到0.1),这两条配合MAC判据能过滤掉绝大多数假点。

选定阶次之后,还有一个检查技巧:把识别出来的频率从低到高排序,看相邻频率的间距是否与频响估计中的峰值位置一致。如果某个稳定频率在频响中对应的峰值非常弱,那么这个模态大概率不可靠,工程上应该降级处理。

6.3 阻尼比总是偏低或偏高,别慌

阻尼比识别对数据质量极其敏感。偏低通常是因为激励频带没有充分覆盖该模态,模态能量不够;偏高通常是因为噪声水平高或数据段太短,协方差估计方差大,算法不得不拟合出一部分噪声衰减。

一个很实用的做法是把长数据切成几段(每段长度仍要满足最低周期覆盖要求),对每段分别做识别,然后看阻尼比结果的散布。如果各段结果在某个值附近稳定分布,取中位数作为最终估计;如果散布极大,那说明数据本身信噪比不足,需要增加测点数量或延长有效数据。千万不要因为某一次识别阻尼比漂亮就认为它是精确的,阻尼比这东西,只能说是“特定条件下的合理估计”。

6.4 振型在个别测点上突然“跳”得很离谱

振型识别主要依赖C矩阵的前几行,也就是可观测矩阵的第一块行。如果某个测点信噪比特别低,那它在C矩阵对应行上的值就会被噪声抬高或压低,反映到振型上就是局部异常。

排查时先用每通道响应标准差做归一化,重新跑一遍识别;再检查测点布置是否存在接近模态节点的位置——振型节点处响应几乎为零,识别值会不稳定。要注意,振型识别只在你实际布置了传感器的自由度上有意义,没有测点的自由度不要指望算法能“补”出来。有限元模型修正时习惯把测点振型扩充到全自由度,那是另一个话题,不属于SSI-COV能承诺的范畴。

6.5 数值层面的两个隐蔽问题

第一个是pinv的默认容差。Toeplitz矩阵经过SVD后,可观测矩阵O的奇异值可能跨多个数量级,直接用pinv(O_up)时,接近零的奇异值会被当作有效值参与求逆,导致A矩阵被噪声主导。建议用pinv(A, tol)显式指定阈值,比如取最大奇异值的1e-10倍,或者干脆用左除运算搭配伪逆截断。

第二个是离散-连续域转换时复对数分支的问题。Matlab的log对复数返回的是主分支值,对于欠阻尼系统的极点一般没问题,但当采样间隔较大、离散极点接近单位圆时,log的虚部可能落在不期望的布兰奇。保险做法是先检查|λ|是否小于1,若接近或大于1说明识别出的极点不稳定,直接丢掉并考虑减小采样间隔或重新定阶。

7. 一点实操心得

我给建议的顺序一直是:仿真验证算法,再上实测数据。仿真数据的最大优势是理论值已知,意味着流程里每跑一步都能自查。频率不对查转换公式,阻尼不对查预处理,振型不对查归一化和MAC计算,基本可以二分定位到具体环节。

第一次实现这个算法时,我犯过一个特别典型的错误:把离散特征值λ直接当成连续极点用,频率结果还算接近,但阻尼比完全对不上,当时卡了很久。后来翻了经典教材才意识到漏了s = log(λ)/dt这一步。这个细节在绝大多数入门资料里都被一笔带过,但它恰恰是整个识别流程里最关键的“最后一公里”。

还有一次拿实测数据直接跑,结果第一阶附近冒出个接近0Hz的“大模态”,后来发现是传感器标定时残留的零点漂移,去趋势之后立刻消失。预处理的重要性,怎么强调都不为过。

最后再分享一个扩展方向:如果你手头数据是多测点同步采集,可以直接把矩阵从单通道扩展到多通道,SSI-COV天然支持多输出的联合识别。配合稳定图和MAC筛选,这套流程完全可以直接迁移到真实结构的模态分析项目里,不需要换框架。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询