Modal Analysis -- Ritz vs Eigen?
- Adisorn O.
- Apr 12
- 3 min read
Updated: 6 days ago
Eigen: "You're searching the entire modal domain, including irrelevant modes — torsion, out-of-plane wiggles, garbage local oscillations.I don't care about those. I'm a building engineer."
🔺 Ritz: "You focus on what I care about — lateral modes, where buildings actually shake in earthquakes.You reduce the problem, skip useless modes, and get to the point."
Here is a MATLAB script to study how Ritz analysis performs
clc; clear; close all;
%% === STEP 1: DEFINE STRUCTURE ===
% 3-story shear building
k = 10000; % Stiffness of each story (N/m)
m = [1000; 1000; 1000]; % Mass per floor (kg)
h = [3; 6; 9]; % Elevations of floors (m)
% Mass matrix (lumped masses)
M = diag(m);
% Stiffness matrix for shear-type building
K = [ k -k 0;
-k 2*k -k;
0 -k k];
%% === STEP 2: SOLVE FULL EIGENVALUE PROBLEM ===
% This is the "truth" — what ETABS does with all DOFs
[phi_full, lambda_full] = eig(K, M);
omega_full = sqrt(diag(lambda_full)); % Natural frequencies (rad/s)
% Normalize each eigenvector by its max value for easier comparison
phi_full = phi_full ./ max(abs(phi_full), [], 1);
%% === STEP 3: DEFINE LOAD PATTERNS FOR RITZ VECTORS ===
% These are static loads we use to generate Ritz basis (like ETABS)
F1 = m .* h; % Load ∝ m * z → Mode 1 like
F2 = [1; 1; 1]; % Uniform lateral load
F3 = [0; 0; 1]; % Top floor load only
%% === STEP 4: GENERATE RITZ VECTORS BY STATIC ANALYSIS ===
% For each load, compute displacement: u = K⁻¹ F
U1 = K \ F1;
U2 = K \ F2;
U3 = K \ F3;
% Stack the displacement vectors to form a Ritz basis
R_raw = [U1, U2, U3];
% Orthonormalize using QR (like Gram-Schmidt)
[Q, ~] = qr(R_raw, 0); % Q: Ritz basis, orthonormalized
%% === STEP 5: TRANSFORM SYSTEM INTO RITZ SPACE ===
% Reduced stiffness and mass matrices:
K_r = Q' * K * Q; % Reduced stiffness
M_r = Q' * M * Q; % Reduced mass
%% === STEP 6: SOLVE REDUCED EIGENPROBLEM ===
[phi_r, lambda_r] = eig(K_r, M_r);
omega_r = sqrt(diag(lambda_r));
% Map reduced eigenvectors back to full DOF space:
phi_ritz = Q * phi_r;
% Normalize for comparison
phi_ritz = phi_ritz ./ max(abs(phi_ritz), [], 1);
%% === STEP 7: PLOT AND COMPARE MODE SHAPES ===
% Include ground level (0 displacement)
Y = [0; h(:)];
figure; hold on; grid on; axis equal;
title('Ritz vs Full Eigenvectors (3-Story Building)');
xlabel('Normalized Displacement');
ylabel('Height (m)');
plot([0 0], [0 h(end)], 'k--');
styles = {'-o','--s','-.^'};
for i = 1:3
full_mode = [0; phi_full(:,i)];
ritz_mode = [0; phi_ritz(:,i)];
plot(full_mode, Y, styles{i}, 'LineWidth', 2, 'DisplayName', ['Full Mode ' num2str(i)]);
plot(ritz_mode, Y, styles{i}, 'LineWidth', 2, 'DisplayName', ['Ritz Mode ' num2str(i)]);
end
legend('Location','northeast');
xlim([-1.2 1.2]);
ylim([0 h(end)+1]);
%% === STEP 2: SOLVE FULL EIGENVALUE PROBLEM ===
% This is the "truth" — what ETABS does with all DOFs
[phi_full, lambda_full] = eig(K, M);
omega_full = sqrt(diag(lambda_full)); % Natural frequencies (rad/s)
% Normalize each eigenvector by its max value for easier comparison
phi_full = phi_full ./ max(abs(phi_full), [], 1);
%% === STEP 3: DEFINE LOAD PATTERNS FOR RITZ VECTORS ===
% These are static loads we use to generate Ritz basis (like ETABS)
F1 = m .* h; % Load ∝ m * z → Mode 1 like
F2 = [1; 1; 1]; % Uniform lateral load
F3 = [0; 0; 1]; % Top fl
%% === STEP 4: GENERATE RITZ VECTORS BY STATIC ANALYSIS ===
% For each load, compute displacement: u = K⁻¹ F
U1 = K \ F1;
U2 = K \ F2;
U3 = K \ F3;
% Stack the displacement vectors to form a Ritz basis
R_raw = [U1, U2, U3];
% Orthonormalize using QR (like Gram-Schmidt)
[Q, ~] = qr(R_raw, 0); % Q: Ritz basis, orthonormalized
%% === STEP 5: TRANSFORM SYSTEM INTO RITZ SPACE ===
% Reduced stiffness and mass matrices:
K_r = Q' * K * Q; % Reduced stiffness
M_r = Q' * M * Q; % Reduced mass
%% === STEP 6: SOLVE REDUCED EIGENPROBLEM ===
[phi_r, lambda_r] = eig(K_r, M_r);
omega_r = sqrt(diag(lambda_r));
% Map reduced eigenvectors back to full DOF space:
phi_ritz = Q * phi_r;
% Normalize for comparison
phi_ritz = phi_ritz ./ max(abs(phi_ritz), [], 1);
%% === STEP 7: PLOT AND COMPARE MODE SHAPES ===
% Include ground level (0 displacement)
Y = [0; h(:)];
figure; hold on; grid on; axis equal;
title('Ritz vs Full Eigenvectors (3-Story Building)');
xlabel('Normalized Displacement');
ylabel('Height (m)');
plot([0 0], [0 h(end)], 'k--');
styles = {'-o','--s','-.^'};
for i = 1:3
full_mode = [0; phi_full(:,i)];
ritz_mode = [0; phi_ritz(:,i)];
plot(full_mode, Y, styles{i}, 'LineWidth', 2, 'DisplayName', ['Full Mode ' num2str(i)]);
plot(ritz_mode, Y, styles{i}, 'LineWidth', 2, 'DisplayName', ['Ritz Mode ' num2str(i)]);
end
legend('Location','northeast');
xlim([-1.2 1.2]);
ylim([0 h(end)+1]);