suanPan
response_spectrum.h
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (C) 2017-2023 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 
37 template<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 
81 public:
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 
121 template<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(0llu, 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  {
128  spectrum.col(I)(0) = spectrum.col(I)(1) = T(0);
129  spectrum.col(I)(2) = std::max(std::abs(motion.max()), std::abs(motion.min()));
130  }
131  });
132 
133  arma::inplace_trans(spectrum);
134 
135  return arma::join_rows(period, spectrum);
136 }
137 
146 template<sp_d T> Mat<T> sdof_response(const T damping_ratio, const T interval, const T freq, const Col<T>& motion) {
147  Oscillator system(freq * datum::tau, damping_ratio);
148 
149  return arma::join_rows(interval * arma::regspace<Col<T>>(T(0), static_cast<double>(motion.n_elem) - T(1)), system.compute_response(interval, motion));
150 }
151 
152 #endif
Definition: response_spectrum.h:37
Col< T > compute_maximum_response(const T interval, const Col< T > &motion)
Definition: response_spectrum.h:99
Oscillator(const T O, const T Z)
Definition: response_spectrum.h:82
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:146
Mat< T > compute_response(const T interval, const Col< T > &motion)
Definition: response_spectrum.h:86
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
void suanpan_for(const IT start, const IT end, F &&FN)
Definition: utility.h:27