suanPan
response_spectrum.h
Go to the documentation of this file.
1/*******************************************************************************
2 * Copyright (C) 2017-2024 Theodore Chang
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
32#ifndef RESPONSE_SPECTRUM_H
33#define RESPONSE_SPECTRUM_H
34
35#include <Toolbox/utility.h>
36
37template<sp_d T> class Oscillator {
38 const T omega; // natural angular frequency
39 const T zeta; // damping ratio
40
41 const T alpha = omega * zeta;
42 const T beta = omega * std::sqrt(1. - zeta * zeta);
43
44 T gamma{0.};
45 T a{0.}, b{0.}, c{0.};
46
47 T amplitude(const Col<T>& data) { return std::max(std::abs(data.max()), std::abs(data.min())); }
48
49 void compute_parameter(const T interval) {
50 const auto exp_term = std::exp(-alpha * interval);
51
52 a = exp_term * std::sin(beta * interval) / beta;
53 b = 2. * exp_term * std::cos(beta * interval);
54 c = exp_term * exp_term;
55
56 gamma = (1. - b + c) / a / interval / omega / omega;
57 }
58
59 std::tuple<Col<T>, Col<T>, Col<T>> populate_response(const T interval, const Col<T>& motion) {
60 this->compute_parameter(interval);
61
62 Col<T> displacement(motion.n_elem, fill::none);
63 displacement(0) = T(0);
64 displacement(1) = b * displacement(0) - motion(0);
65
66 for(auto I = 2llu, J = 1llu, K = 0llu; I < motion.n_elem; ++I, ++J, ++K) displacement(I) = b * displacement(J) - c * displacement(K) - motion(J);
67
68 const auto n_elem = motion.n_elem - 1llu;
69
70 Col<T> velocity(motion.n_elem, fill::none);
71 velocity(0) = T(0);
72 velocity.tail(n_elem) = arma::diff(displacement);
73
74 Col<T> acceleration(motion.n_elem, fill::none);
75 acceleration(0) = T(0);
76 acceleration.tail(n_elem) = arma::diff(velocity);
77
78 return std::make_tuple(displacement, velocity, acceleration);
79 }
80
81public:
82 Oscillator(const T O, const T Z)
83 : omega(O)
84 , zeta(Z) {}
85
86 Mat<T> compute_response(const T interval, const Col<T>& motion) {
87 Col<T> displacement, velocity, acceleration;
88 std::tie(displacement, velocity, acceleration) = this->populate_response(interval, motion);
89
90 const auto factor = gamma * a;
91
92 displacement *= factor * interval;
93 velocity *= factor;
94 acceleration *= factor / interval;
95
96 return arma::join_rows(displacement, velocity, acceleration);
97 }
98
99 Col<T> compute_maximum_response(const T interval, const Col<T>& motion) {
100 Col<T> displacement, velocity, acceleration;
101 std::tie(displacement, velocity, acceleration) = this->populate_response(interval, motion);
102
103 const auto factor = gamma * a;
104
105 const auto max_u = this->amplitude(displacement) * factor * interval;
106 const auto max_v = this->amplitude(velocity) * factor;
107 const auto max_a = this->amplitude(acceleration * factor / interval + motion);
108
109 return {max_u, max_v, max_a};
110 }
111};
112
121template<sp_d T> Mat<T> response_spectrum(const T damping_ratio, const T interval, const Col<T>& motion, const Col<T>& period) {
122 Mat<T> spectrum(3, period.n_elem, fill::none);
123
124 suanpan::for_each(period.n_elem, [&](const uword I) {
125 if(!suanpan::approx_equal(period(I), T(0), 10000)) [[likely]] spectrum.col(I) = Oscillator(datum::tau / period(I), damping_ratio).compute_maximum_response(interval, motion);
126 else [[unlikely]] {
127 spectrum.col(I)(0) = spectrum.col(I)(1) = T(0);
128 spectrum.col(I)(2) = std::max(std::abs(motion.max()), std::abs(motion.min()));
129 }
130 });
131
132 arma::inplace_trans(spectrum);
133
134 return arma::join_rows(period, spectrum);
135}
136
145template<sp_d T> Mat<T> sdof_response(const T damping_ratio, const T interval, const T freq, const Col<T>& motion) {
146 Oscillator system(freq * datum::tau, damping_ratio);
147
148 return arma::join_rows(interval * arma::regspace<Col<T>>(T(0), static_cast<double>(motion.n_elem) - T(1)), system.compute_response(interval, motion));
149}
150
151#endif
Definition: response_spectrum.h:37
Mat< T > sdof_response(const T damping_ratio, const T interval, const T freq, const Col< T > &motion)
compute response of a linear SDOF system
Definition: response_spectrum.h:145
Oscillator(const T O, const T Z)
Definition: response_spectrum.h:82
Mat< T > response_spectrum(const T damping_ratio, const T interval, const Col< T > &motion, const Col< T > &period)
compute response spectrum of the given ground motion
Definition: response_spectrum.h:121
Mat< T > compute_response(const T interval, const Col< T > &motion)
Definition: response_spectrum.h:86
Col< T > compute_maximum_response(const T interval, const Col< T > &motion)
Definition: response_spectrum.h:99
void for_each(const IT start, const IT end, F &&FN)
Definition: utility.h:28