top of page

Modal Analysis -- Ritz vs Eigen?

  • Writer: Adisorn O.
    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]);


bottom of page