qualia_core_db/specialized_libs/engineering_analysis/
vibration.rs1use super::*;
2
3pub struct VibrationAnalysis {
5 free_vibration: FreeVibration,
6 forced_vibration: ForcedVibration,
7 random_vibration: RandomVibration,
8}
9
10#[derive(Debug, Clone)]
12pub struct FreeVibration {
13 pub natural_frequencies: Vec<f64>,
14 pub mode_shapes: Vec<ModeShape>,
15 pub damping_ratios: Vec<f64>,
16}
17
18#[derive(Debug, Clone)]
20pub struct ForcedVibration {
21 pub excitation_frequencies: Vec<f64>,
22 pub response_amplitudes: Vec<f64>,
23 pub phase_angles: Vec<f64>,
24}
25
26#[derive(Debug, Clone)]
28pub struct RandomVibration {
29 pub power_spectral_density: Vec<f64>,
30 pub rms_response: f64,
31 pub fatigue_damage: f64,
32}
33impl VibrationAnalysis {
34 pub fn new() -> Self {
35 Self {
36 free_vibration: FreeVibration::new(),
37 forced_vibration: ForcedVibration::new(),
38 random_vibration: RandomVibration::new(),
39 }
40 }
41
42 pub fn initialize(&mut self) -> Result<(), EngineeringError> {
43 Ok(())
44 }
45
46 pub fn free_vibration(&self) -> &FreeVibration {
48 &self.free_vibration
49 }
50
51 pub fn free_vibration_mut(&mut self) -> &mut FreeVibration {
53 &mut self.free_vibration
54 }
55
56 pub fn forced_vibration(&self) -> &ForcedVibration {
58 &self.forced_vibration
59 }
60
61 pub fn forced_vibration_mut(&mut self) -> &mut ForcedVibration {
63 &mut self.forced_vibration
64 }
65
66 pub fn random_vibration(&self) -> &RandomVibration {
68 &self.random_vibration
69 }
70
71 pub fn random_vibration_mut(&mut self) -> &mut RandomVibration {
73 &mut self.random_vibration
74 }
75
76 pub fn analyze_free(
84 &mut self,
85 stiffness: &[f64],
86 mass_diag: &[f64],
87 num_dofs: usize,
88 ) -> Result<FreeVibration, EngineeringError> {
89 let modes = solve_modal_eigen(stiffness, mass_diag, num_dofs)?;
90 let mut natural_frequencies = Vec::with_capacity(modes.len());
91 let mut mode_shapes = Vec::with_capacity(modes.len());
92 for (i, (omega, phi)) in modes.into_iter().enumerate() {
93 natural_frequencies.push(omega);
94 mode_shapes.push(ModeShape {
95 mode_number: (i + 1) as u32,
96 natural_frequency: omega,
97 damping_ratio: 0.0,
98 mode_shape_vector: phi,
99 });
100 }
101 let damping_ratios = vec![0.0; natural_frequencies.len()];
102 let fv = FreeVibration {
103 natural_frequencies,
104 mode_shapes,
105 damping_ratios,
106 };
107 self.free_vibration = fv.clone();
108 Ok(fv)
109 }
110
111 pub fn natural_frequency_sdof(
113 &self,
114 stiffness: f64,
115 mass: f64,
116 ) -> Result<f64, EngineeringError> {
117 if mass <= 0.0 {
118 return Err(EngineeringError::ValidationError(
119 "mass must be positive".to_string(),
120 ));
121 }
122 if stiffness < 0.0 {
123 return Err(EngineeringError::ValidationError(
124 "stiffness must be non-negative".to_string(),
125 ));
126 }
127 Ok((stiffness / mass).sqrt())
128 }
129
130 pub fn analyze_harmonic_sdof(
137 &mut self,
138 mass: f64,
139 damping: f64,
140 stiffness: f64,
141 force_amplitude: f64,
142 excitation_freqs: &[f64],
143 ) -> Result<ForcedVibration, EngineeringError> {
144 if mass <= 0.0 {
145 return Err(EngineeringError::ValidationError(
146 "mass must be positive".to_string(),
147 ));
148 }
149 if damping < 0.0 || stiffness < 0.0 {
150 return Err(EngineeringError::ValidationError(
151 "damping and stiffness must be non-negative".to_string(),
152 ));
153 }
154 if excitation_freqs.is_empty() {
155 return Err(EngineeringError::InsufficientData(
156 "no excitation frequencies supplied".to_string(),
157 ));
158 }
159 let mut response_amplitudes = Vec::with_capacity(excitation_freqs.len());
160 let mut phase_angles = Vec::with_capacity(excitation_freqs.len());
161 for &w in excitation_freqs {
162 let re = stiffness - mass * w * w;
163 let im = damping * w;
164 let denom = (re * re + im * im).sqrt();
165 let amp = if denom > 0.0 {
166 force_amplitude / denom
167 } else {
168 f64::INFINITY
169 };
170 response_amplitudes.push(amp);
171 phase_angles.push(im.atan2(re));
172 }
173 let fv = ForcedVibration {
174 excitation_frequencies: excitation_freqs.to_vec(),
175 response_amplitudes,
176 phase_angles,
177 };
178 self.forced_vibration = fv.clone();
179 Ok(fv)
180 }
181}
182
183impl FreeVibration {
184 pub fn new() -> Self {
185 Self {
186 natural_frequencies: Vec::new(),
187 mode_shapes: Vec::new(),
188 damping_ratios: Vec::new(),
189 }
190 }
191}
192
193impl ForcedVibration {
194 pub fn new() -> Self {
195 Self {
196 excitation_frequencies: Vec::new(),
197 response_amplitudes: Vec::new(),
198 phase_angles: Vec::new(),
199 }
200 }
201}
202
203impl RandomVibration {
204 pub fn new() -> Self {
205 Self {
206 power_spectral_density: Vec::new(),
207 rms_response: 0.0,
208 fatigue_damage: 0.0,
209 }
210 }
211}