15#include <csvd/csvd.hpp>
42 template<
class T =
double>
45 Eigen::Vector<T, Eigen::Dynamic> omegas_;
46 Eigen::Vector<std::complex<T>, Eigen::Dynamic> values_;
56 Bode(
const Eigen::Vector<T, Eigen::Dynamic>& freqs_rad,
const Eigen::Vector<std::complex<T>, Eigen::Dynamic>&
values)
61 assert(this->omegas_.size() == this->values_.size());
64 for(
size_t i = 0; i < static_cast<size_t>(omegas_.size()); ++i){
65 assert(omegas_(i) >= T(0));
69 for(
size_t i = 1; i < static_cast<size_t>(omegas_.size()); ++i){
70 assert(omegas_(i) > omegas_(i-1));
74 Bode(Eigen::Vector<T, Eigen::Dynamic>&& freqs_rad, Eigen::Vector<std::complex<T>, Eigen::Dynamic>&&
values)
75 : omegas_(std::move(freqs_rad))
76 , values_(std::move(
values))
79 assert(this->omegas_.size() == this->values_.size());
82 for(
size_t i = 0; i < static_cast<size_t>(omegas_.size()); ++i){
83 assert(omegas_(i) >= T(0));
87 for(
size_t i = 1; i < static_cast<size_t>(omegas_.size()); ++i){
88 assert(omegas_(i) > omegas_(i-1));
92 Bode(
const Eigen::Vector<T, Eigen::Dynamic>& freqs_rad, Eigen::Vector<std::complex<T>, Eigen::Dynamic>&&
values)
94 , values_(std::move(
values))
97 assert(this->omegas_.size() == this->values_.size());
100 for(
size_t i = 0; i < static_cast<size_t>(omegas_.size()); ++i){
101 assert(omegas_(i) >= T(0));
105 for(
size_t i = 1; i < static_cast<size_t>(omegas_.size()); ++i){
106 assert(omegas_(i) > omegas_(i-1));
110 Bode(Eigen::Vector<T, Eigen::Dynamic>&& freqs_rad,
const Eigen::Vector<std::complex<T>, Eigen::Dynamic>&
values)
111 : omegas_(std::move(freqs_rad))
115 assert(this->omegas_.size() == this->values_.size());
118 for(
size_t i = 0; i < static_cast<size_t>(omegas_.size()); ++i){
119 assert(omegas_(i) >= T(0));
123 for(
size_t i = 1; i < static_cast<size_t>(omegas_.size()); ++i){
124 assert(omegas_(i) > omegas_(i-1));
134 return this->omegas_;
143 return this->omegas_;
152 return this->omegas_(n);
161 return this->omegas_(n);
268 const Eigen::Vector<std::complex<T>, Eigen::Dynamic>&
values()
const {
269 return this->values_;
276 Eigen::Vector<std::complex<T>, Eigen::Dynamic>&
values() {
277 return this->values_;
285 const std::complex<T>&
value(std::size_t n)
const {
286 return this->values_(n);
294 std::complex<T>&
value(std::size_t n) {
295 return this->values_(n);
298 size_t size()
const {
return this->omegas_.size();}
317 if(result.has_value()){
319 const T* low = result.value().first;
320 const T* high = result.value().second;
323 const size_t i_low = low - this->omegas_.data();
324 const size_t i_high = high - this->omegas_.data();
327 const T f_low = *low;
328 const T f_high = *high;
329 const std::complex<T> v_low = this->values_(i_low);
330 const std::complex<T> v_high = this->values_(i_high);
333 const T p = (
frequency - f_low) / (f_high - f_low);
336 const T mag_interp = std::abs(v_low) * (
static_cast<T
>(1) - p) + (p) * std::abs(v_high);
339 const T phase_interp = std::arg(v_low) * (
static_cast<T
>(1) - p) + (p) * std::arg(v_high);
342 const std::complex<T> result = std::polar(mag_interp, phase_interp);
347 return this->values_(0);
349 return this->values_(this->values_.size()-1);
409 const T mag_dB =
static_cast<T>(20) * std::log10(
mag);
477 return bode.frequencies() * std::numbers::inv_pi_v<T> / 2;
492 return bode.values().real();
507 return bode.values().imag();
522 return bode.values();
539 return bode.values().array().abs();
556 return static_cast<T
>(20) *
bode.values().array().abs().log10();
573 Eigen::Vector<T, Eigen::Dynamic> result =
bode.values().array().arg();
592 Eigen::Vector<T, Eigen::Dynamic> result =
bode.values().array().arg() *
static_cast<T
>(180) / std::numbers::pi_v<T>;
615 assert(
bode.empty() ==
false);
616 assert(simulation_time > T(0));
617 assert(time_step > T(0));
619 const T pi = std::numbers::pi_v<T>;
620 const std::complex<T> j(0, 1);
622 const T start_time = 0.0;
623 const size_t number_of_samples =
static_cast<size_t>(simulation_time / time_step + T(0.5));
624 Eigen::Vector<T, Eigen::Dynamic> times = Eigen::Vector<T, Eigen::Dynamic>::LinSpaced(number_of_samples, start_time, simulation_time);
625 Eigen::Vector<T, Eigen::Dynamic>
values(number_of_samples);
628 const auto f1 =
bode.frequencies().head(
bode.frequencies().size() - 1);
629 const auto f2 =
bode.frequencies().tail(
bode.frequencies().size() - 1);
631 Eigen::Vector<T, Eigen::Dynamic> delta_f = f2.array() - f1.array();
632 T df_max = delta_f.maxCoeff();
634 const auto X1 =
bode.values().head(
bode.values().size() - 1);
635 const auto X2 =
bode.values().tail(
bode.values().size() - 1);
638 const T t_switch = 0.001 / (2 * pi * df_max);
641 Eigen::Vector<std::complex<T>, Eigen::Dynamic> e_j_2_pi_f_ti(
bode.frequencies().size());
642 e_j_2_pi_f_ti.setOnes();
645 Eigen::Vector<std::complex<T>, Eigen::Dynamic> e_j_2_pi_f_t1 = (j * T(2) * pi * time_step *
bode.frequencies().array()).exp();
647 const bool includes_dc =
bode.frequencies()[0] == 0;
648 const std::complex<T> dc_gain =
bode.values()[0];
649 const T delta_f_dc =
bode.frequencies()[0];
652 std::complex<T> v0_one_sided = 0;
655 v0_one_sided = ((X1.array() + X2.array()) * delta_f.array()).sum() * T(0.5);
658 if(includes_dc ==
false){
659 v0_one_sided += ((dc_gain + X1(0)) * delta_f_dc) * T(0.5);
662 values(0) = std::real(v0_one_sided) * 2;
668 std::complex<T> LinF = j * (pi/T(3)) * (delta_f.array() * (X1.array() * (T(2) * f1.array() + f2.array()) + X2.array() * (T(2) * f2.array() + f1.array()))).sum();
671 if(includes_dc ==
false){
672 LinF += j * (pi/T(3)) * (delta_f_dc * (dc_gain * f1(0) + X1(0) * (T(2) * f1(0))));
675 for(; (t_itr < static_cast<size_t>(number_of_samples)) && (times(t_itr) <= t_switch); ++ t_itr){
676 const T t = times(t_itr);
677 std::complex<T> v = v0_one_sided + LinF * t;
678 values(t_itr) = std::real(v) * 2;
679 e_j_2_pi_f_ti.array() *= e_j_2_pi_f_t1.array();
683 for(; t_itr < static_cast<size_t>(number_of_samples); ++ t_itr){
684 const T t = times(t_itr);
685 const T w = 2 * pi * t;
687 e_j_2_pi_f_ti.array() *= e_j_2_pi_f_t1.array();
689 const auto E_f1 = e_j_2_pi_f_ti.head(e_j_2_pi_f_ti.size()-1);
690 const auto E_f2 = e_j_2_pi_f_ti.tail(e_j_2_pi_f_ti.size()-1);
692 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> Ia = E_f1.array() * (T(1) + j * w * delta_f.array()) - E_f2.array();
693 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> Ib = E_f2.array() * (T(1) - j * w * delta_f.array()) - E_f1.array();
694 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> I = (X1.array() * Ia.array() + X2.array() * Ib.array()) / delta_f.array();
696 std::complex<T> sum = I.sum();
699 if(includes_dc ==
false){
700 const std::complex<T> Ia_ = (T(1) + j * w * delta_f_dc) - E_f1(0);
701 const std::complex<T> Ib_ = E_f1(0) * (T(1) - j * w * delta_f_dc) - T(1);
702 const std::complex<T> I = (dc_gain * Ia_ + X1(0) * Ib_) / delta_f_dc;
706 const std::complex<T> v = sum / (w * w);
708 values(t_itr) = std::real(v) * 2;
740 const T max_freq =
bode.frequencies()[
bode.frequencies().size()-1];
741 const T min_freq =
bode.frequencies()[0];
743 const T time_step =
static_cast<T
>(1) / (T(2 * 4) * max_freq);
744 const T total_time =
static_cast<T
>(1) / (T(4) * min_freq);
766 T prev_value = in.
values(0);
770 for(
size_t i = 1; i < in.
size(); ++i){
772 const T sum_i = (in.
values(i) + prev_value) * (in.
times(i) - in.
times(i-1)) * T(0.5);
773 prev_value = in.
values(i);
812 integrate<T>(imp, imp);
830 integrate<T>(imp, imp);
849 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() + r.
values().array();
862 template<
class T, std::convertible_to<T> T2>
864 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() +
static_cast<std::complex<T>
>(l)(r);
877 template<
class T, std::convertible_to<T> T2>
879 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result =
static_cast<std::complex<T>
>(l) + r.
values().array();
892 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = +b.
values().array();
907 template<
class T,
int NumOrder,
int DenOrder>
910 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() + r_mags.array();
925 template<
class T,
int NumOrder,
int DenOrder>
928 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l_mags.array() + l.values().array();
939 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() - r.
values().array();
943 template<
class T, std::convertible_to<T> T2>
945 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() -
static_cast<std::complex<T>
>(r);
949 template<
class T, std::convertible_to<T> T2>
951 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result =
static_cast<std::complex<T>
>(l) - r.
values().array();
957 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = -b.
values().array();
961 template<
class T,
int NumOrder,
int DenOrder>
964 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() - r_mags.array();
968 template<
class T,
int NumOrder,
int DenOrder>
971 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l_mags.array() - l.values().array();
982 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() * r.
values().array();
986 template<
class T, std::convertible_to<T> T2>
988 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() *
static_cast<std::complex<T>
>(r);
992 template<
class T, std::convertible_to<T> T2>
994 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result =
static_cast<std::complex<T>
>(l) * r.
values().array();
998 template<
class T,
int NumOrder,
int DenOrder>
1001 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() * r_mags.array();
1005 template<
class T,
int NumOrder,
int DenOrder>
1008 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l_mags.array() * r.
values().array();
1029 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() / r.
values().array();
1033 template<
class T, std::convertible_to<T> T2>
1035 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() / std::complex<T>(r);
1039 template<
class T, std::convertible_to<T> T2>
1041 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = std::complex<T>(l) / r.
values().array();
1045 template<
class T,
int NumOrder,
int DenOrder>
1048 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> result = l.
values().array() / r_mags.array();
1052 template<
class T,
int NumOrder,
int DenOrder>
1070 template<
class T,
int NumOrder,
int DenOrder>
1073 const Eigen::Vector<T, Eigen::Dynamic>& freqs
1075 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> complex_magnitudes = tf.
eval_frequencies(freqs);
1076 const Bode<T> result(freqs, complex_magnitudes);
1083 template<
class T,
int NumOrder,
int DenOrder>
1086 Eigen::Vector<T, Eigen::Dynamic>&& freqs
1088 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> complex_magnitudes = tf.
eval_frequencies(freqs);
1089 const Bode<T> result(std::move(freqs), complex_magnitudes);
1105 template<
class T,
int NumOrder,
int DenOrder>
1108 const Eigen::Vector<T, Eigen::Dynamic>& freqs_Hz
1110 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> complex_magnitudes = tf.
eval_frequencies_hz(freqs_Hz);
1111 Eigen::Vector<T, Eigen::Dynamic> freqs_rad = freqs_Hz.array() * 2 * std::numbers::pi_v<T>;
1112 const Bode<T> result(std::move(freqs_rad), complex_magnitudes);
1119 template<
class T,
int NumOrder,
int DenOrder>
1122 Eigen::Vector<T, Eigen::Dynamic>&& freqs_Hz
1124 const Eigen::Vector<std::complex<T>, Eigen::Dynamic> complex_magnitudes = tf.
eval_frequencies_hz(freqs_Hz);
1125 freqs_Hz *= 2 * std::numbers::pi_v<T>;
1126 const Bode<T> result(std::move(freqs_Hz), complex_magnitudes);
1140 template<
class T,
int NumOrder,
int DenOrder, std::convertible_to<T> T1, std::convertible_to<T> T2>
1143 const T1& slowest_freq_Hz,
1144 const T2& fastest_freq_Hz,
1145 const int samples_per_decade=100
1147 const T decades = std::log10(
static_cast<T
>(fastest_freq_Hz)) - std::log10(
static_cast<T
>(slowest_freq_Hz));
1148 const T samples = samples_per_decade * decades;
1149 const Eigen::Vector<T, Eigen::Dynamic> freqs_Hz = Eigen::Vector<T, Eigen::Dynamic>::LinSpaced(samples, std::log(slowest_freq_Hz), std::log(fastest_freq_Hz)).array().exp();
1150 return bode_hz<T, NumOrder, DenOrder>(tf, freqs_Hz);
1163 template<
class T,
int NumOrder,
int DenOrder, std::convertible_to<T> T1, std::convertible_to<T> T2>
1166 const T1& slowest_freq_rad,
1167 const T2& fastest_freq_rad,
1168 const int samples_per_decade=100
1170 const T decades = std::log10(
static_cast<T
>(fastest_freq_rad)) - std::log10(
static_cast<T
>(slowest_freq_rad));
1171 const T samples = samples_per_decade * decades;
1173 const Eigen::Vector<T, Eigen::Dynamic> freqs_rad = Eigen::Vector<T, Eigen::Dynamic>::LinSpaced(samples, std::log(slowest_freq_rad), std::log(fastest_freq_rad)).array().exp();
1174 return bode<T, NumOrder, DenOrder>(tf, freqs_rad);
1189 template<
class T,
int NumOrder,
int DenOrder>
1192 const int samples_per_decade=100
1195 const T frequency_from_Hz = slowest_freq_rad / (
static_cast<T
>(10 * 2) * std::numbers::pi_v<T>);
1196 const T frequency_to_Hz = fastest_freq_rad *
static_cast<T
>(10 / 2) / std::numbers::pi_v<T>;
1197 return bode_hz(tf, frequency_from_Hz, frequency_to_Hz, samples_per_decade);
1212 template<
class T,
int NumOrder,
int DenOrder>
1215 const int samples_per_decade=100
1218 const T frequency_from_rad = slowest_freq_rad /
static_cast<T
>(10);
1219 const T frequency_to_rad = fastest_freq_rad *
static_cast<T
>(10);
1220 return bode(tf, frequency_from_rad, frequency_to_rad, samples_per_decade);
1232 stream <<
"Frequencies (Hz), Magnitudes (dB), Phases (deg), Real, Imag" << std::endl;
1234 const int n =
bode.size();
1235 for(
int i = 0; i < n; ++i){
1236 const T omega =
bode.frequency(i);
1237 const T f =
to_hz(omega);
1239 const std::complex<T> value =
bode.value(i);
1240 const T mag =
to_dB(std::abs(value));
1241 const T phase =
to_deg(std::arg(value));
1242 const T
real = std::real(value);
1243 const T
imag = std::imag(value);
1245 stream << f <<
", " << mag <<
", " << phase <<
", " <<
real <<
", " <<
imag;
1246 if(i < n-1) stream <<
"\n";
1322 std::variant<EBodeCsvReadError, csvd::ReadError>>
1324 std::istream& stream,
1325 const csvd::Settings& csv_settings = csvd::Settings(),
General algorithms that are used in multiple places in the library.
Frequency response data.
Definition Bode.hpp:43
const T & frequency(std::size_t n) const
Returns a reference to the frequency in rad at the index n.
Definition Bode.hpp:160
bool empty() const
Definition Bode.hpp:300
Eigen::Vector< T, Eigen::Dynamic > & frequencies()
Returns a reference to the frequency vector in rad.
Definition Bode.hpp:142
T phase_at(const T &frequency) const
Returns the phase at the passed frequency.
Definition Bode.hpp:365
size_t size() const
Definition Bode.hpp:298
void prewarp_tustin(const T &Ts)
Applies tustin pre-warping to the frequency axis.
Definition Bode.hpp:243
void unwarp_tustin(const T &Ts)
Unwarps the pre-warping. Or calculates how system frequencies will shift after tustin discretisation.
Definition Bode.hpp:260
const Eigen::Vector< T, Eigen::Dynamic > & frequencies() const
Returns a const-reference to the frequency vector in rad.
Definition Bode.hpp:133
Bode(const Eigen::Vector< T, Eigen::Dynamic > &freqs_rad, const Eigen::Vector< std::complex< T >, Eigen::Dynamic > &values)
Constructs a bode from frequencies and complex magnitudes.
Definition Bode.hpp:56
std::complex< T > & value(std::size_t n)
Returns a reference to the complex magnitue at the n-th position.
Definition Bode.hpp:294
std::complex< T > value_at(const T &frequency) const
returns the complex value at the given frequency using interpolation
Definition Bode.hpp:315
const std::complex< T > & value(std::size_t n) const
Returns a reference to the complex magnitue at the n-th position.
Definition Bode.hpp:285
T magnitude_dB_at(const T &frequency) const
Returns the magnitude at the passed frequency.
Definition Bode.hpp:407
Bode(Eigen::Vector< T, Eigen::Dynamic > &&freqs_rad, const Eigen::Vector< std::complex< T >, Eigen::Dynamic > &values)
Definition Bode.hpp:110
Bode(Eigen::Vector< T, Eigen::Dynamic > &&freqs_rad, Eigen::Vector< std::complex< T >, Eigen::Dynamic > &&values)
Definition Bode.hpp:74
const Eigen::Vector< std::complex< T >, Eigen::Dynamic > & values() const
Returns a const-reference to the complex magnitued vector.
Definition Bode.hpp:268
T phase_deg_at(const T &frequency) const
return the phase at the given frequency in degree
Definition Bode.hpp:381
T & frequency(std::size_t n)
Returns a reference to the frequency in rad at the index n.
Definition Bode.hpp:151
Eigen::Vector< std::complex< T >, Eigen::Dynamic > & values()
Returns a reference to the complex magnitued vector.
Definition Bode.hpp:276
Bode(const Eigen::Vector< T, Eigen::Dynamic > &freqs_rad, Eigen::Vector< std::complex< T >, Eigen::Dynamic > &&values)
Definition Bode.hpp:92
T magnitude_at(const T &frequency) const
Returns the magnitude at the passed frequency.
Definition Bode.hpp:394
Continuous transfer functions in the s lapace plain.
Definition ContinuousTransferFunction.hpp:28
Eigen::Vector< std::complex< T >, M > eval_frequencies_hz(const Eigen::Vector< T, M > &frequencies) const
Evaluates the transfer function (Hz) at the given frequencies.
Definition ContinuousTransferFunction.hpp:142
Eigen::Vector< std::complex< T >, M > eval_frequencies(const Eigen::Vector< T, M > &frequencies) const
Evaluates the transfer function (rad/s) at the given frequencies.
Definition ContinuousTransferFunction.hpp:132
Contiains time and values pairs.
Definition TimeSeries.hpp:26
Eigen::Vector< T, Eigen::Dynamic > & times()
Definition TimeSeries.hpp:79
void resize(int n)
Definition TimeSeries.hpp:100
size_t size() const
Definition TimeSeries.hpp:105
Eigen::Vector< T, Eigen::Dynamic > & values()
Definition TimeSeries.hpp:85
void integrate(TimeSeries< T > &out, const TimeSeries< T > &in, const T &v0=T(0))
Integrates the time series and writes it to out.
Definition Bode.hpp:765
const Eigen::Vector< T, Eigen::Dynamic > & values(const Bode< T > &bode)
Returns the complex values of the bode data.
Definition Bode.hpp:521
const Eigen::Vector< T, Eigen::Dynamic > & frequencies(const Bode< T > &bode)
Converts and returns the frequency vector in rad.
Definition Bode.hpp:461
TimeSeries< T > impulse(const Bode< T > &bode, const T &time_step, const T &simulation_time)
Calculates the impulse-response of frequency data.
Definition Bode.hpp:614
Eigen::Vector< T, Eigen::Dynamic > phases(const Bode< T > &bode)
Creates a vector of phases in rad.
Definition Bode.hpp:572
Bode< T > operator+(const Bode< T > &l, const Bode< T > &r)
Adds two bode plots together.
Definition Bode.hpp:846
Eigen::Vector< T, Eigen::Dynamic > frequencies_hz(const Bode< T > &bode)
Converts and returns the frequency vector in Hz.
Definition Bode.hpp:476
Eigen::Vector< T, Eigen::Dynamic > magnitudes_dB(const Bode< T > &bode)
Creates a vector of magnitudes in dB.
Definition Bode.hpp:555
Eigen::Vector< T, Eigen::Dynamic > phases_deg(const Bode< T > &bode)
Creates a vector of phases in degree.
Definition Bode.hpp:591
Eigen::Vector< T, Eigen::Dynamic > magnitudes(const Bode< T > &bode)
Creates a vector containing the absolute magnitudes.
Definition Bode.hpp:538
Eigen::Vector< T, Eigen::Dynamic > imag(const Bode< T > &bode)
Converts and returns the frequency vector in rad/s.
Definition Bode.hpp:506
Bode< T > prewarp_tustin(const Bode< T > &bode, const T &Ts)
Prewarps the frequency axis of a bode plot for tustin discretisation.
Definition Bode.hpp:427
Bode< T > unwarp_tustin(const Bode< T > &bode, const T &Ts)
Unwarps the frequency axis of a bode plot for tustin discretisation.
Definition Bode.hpp:445
Eigen::Vector< T, Eigen::Dynamic > real(const Bode< T > &bode)
Converts and returns the frequency vector in rad/s.
Definition Bode.hpp:491
The main namespace for the Control++ library.
Definition Bode.cpp:3
EPhaseInterpretation
Enum that determines how phase data will be interpreted when reading CSV data.
Definition Bode.hpp:1282
@ ForceDeg
Forces the magnitude data to be interpreted in deg regardless of the header name.
@ AutoDeg
Automatically infers the unit from the header or interprets the data as deg if no unit is found in th...
EBodeCsvReadError
Error cases for reading/parsing bode data from CSV formated data.
Definition Bode.hpp:1253
@ CouldNotFindFrequencyVector
Could not find the frequency axis in the csv data. Searched for a header that starts with "f" (case-i...
@ CouldNotFindAmplitudeVectors
Could not find the amplitude data. Needed either: 1) Two columns that start with "re" and "im" (case-...
std::ostream & operator<<(std::ostream &stream, EBodeCsvReadError val)
Definition Bode.cpp:5
Bode< T > bode_hz(const ContinuousTransferFunction< T, NumOrder, DenOrder > &tf, const Eigen::Vector< T, Eigen::Dynamic > &freqs_Hz)
Calculates the bode response for a pre defined frequency (Hz) vector.
Definition Bode.hpp:1106
T to_hz(const T &radps)
Converts a number from radiants per second to herz.
Definition conversion.hpp:16
void write_csv(std::ostream &stream, const Bode< T > &bode)
Prints a bode plot to an output stream as a .csv file.
Definition Bode.hpp:1231
Eigen::Vector< T, N > unwrap_deg(const Eigen::Vector< T, N > &phases)
Unwinds phase jumps of in degrees.
Definition math.hpp:93
Bode< T > bode(const ContinuousTransferFunction< T, NumOrder, DenOrder > &tf, const Eigen::Vector< T, Eigen::Dynamic > &freqs)
Calculates the bode response for a pre defined frequency (rad/s) vector.
Definition Bode.hpp:1071
std::optional< std::pair< Itr, Itr > > find_enclosing(Itr first, Itr last, const T &v)
Finds elements in a range that enclose v.
Definition algorithm.hpp:29
Bode< T > operator-(const Bode< T > &l, const Bode< T > &r)
Definition Bode.hpp:936
Bode< T > operator*(const Bode< T > &l, const Bode< T > &r)
Definition Bode.hpp:979
TimeSeries< T > step(const DiscreteStateSpace< T, NStates, 1, 1 > &dss, double Ts, double simulation_time)
calculates the step response of a system
Definition analysis.hpp:34
EFrequencyInterpretation
Enum that determines how frequency data will be interpreted when reading CSV data.
Definition Bode.hpp:1263
@ ForceHz
When reading frequency data the data is always interpreted in Hz regardless of the header name.
@ AutoHz
Automatically infers the unit from the header or interprets the data in Hz if no unit is found in the...
@ AutoRad
Automatically infers the unit from the header or interprets the data in rad if no unit is found in th...
@ ForceRad
When reading frequency data the data is always interpreted in rad regardless of the header name.
std::tuple< T, T > slowest_fastest_frequencies(const ContinuousTransferFunction< T, NumOrder, DenOrder > &tf, T alternative=static_cast< T >(1))
Calculates the slowest (lowest) and fastest (highest) frequencies of a continuous transfer function.
Definition analysis.hpp:66
EMagnitudeInterpretation
Enum that determines how frequency data will be interpreted when reading CSV data.
Definition Bode.hpp:1273
@ Auto
Automatically infers the unit from the header and interprets as deci-Bell if "dB" has been found or i...
@ ForceAbs
Forces the magnitude data to be interpreted in absolute values regardless of the header name.
@ ForceDB
Forces the magnitude data to be interpreted in dB regardless of the header name.
T to_dB(const T &value)
Definition conversion.hpp:70
Bode< T > operator/(const Bode< T > &l, const Bode< T > &r)
TODO: make it also work for bode that have different frequency vectors.
Definition Bode.hpp:1026
tl::expected< Bode< double >, std::variant< EBodeCsvReadError, csvd::ReadError > > read_bode_from_csv(std::istream &stream, const csvd::Settings &csv_settings, EFrequencyInterpretation freq_interp, EMagnitudeInterpretation mag_interp, EPhaseInterpretation phase_interp)
Loads bode data from csv data.
Definition Bode.cpp:61
T to_deg(const T &rad)
Definition conversion.hpp:46
Eigen::Vector< T, N > unwrap_rad(const Eigen::Vector< T, N > &phases)
Unwinds phase jumps of in radiants.
Definition math.hpp:80