forked from pz4kybsvg/Conception
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
5.4 KiB
167 lines
5.4 KiB
#include "drake/systems/primitives/sine.h"
|
|
|
|
#include "drake/common/drake_throw.h"
|
|
#include "drake/common/fmt_eigen.h"
|
|
|
|
namespace drake {
|
|
namespace systems {
|
|
|
|
template <typename T>
|
|
Sine<T>::Sine(double amplitude, double frequency, double phase, int size,
|
|
bool is_time_based)
|
|
: Sine(Eigen::VectorXd::Ones(size) * amplitude,
|
|
Eigen::VectorXd::Ones(size) * frequency,
|
|
Eigen::VectorXd::Ones(size) * phase, is_time_based) {}
|
|
|
|
template <typename T>
|
|
Sine<T>::Sine(const Eigen::VectorXd& amplitudes,
|
|
const Eigen::VectorXd& frequencies,
|
|
const Eigen::VectorXd& phases,
|
|
bool is_time_based)
|
|
: LeafSystem<T>(SystemTypeTag<Sine>{}),
|
|
amplitude_(amplitudes), frequency_(frequencies), phase_(phases),
|
|
is_time_based_(is_time_based) {
|
|
// Ensure the incoming vectors are all the same size
|
|
DRAKE_THROW_UNLESS(amplitudes.size() == frequencies.size());
|
|
DRAKE_THROW_UNLESS(amplitudes.size() == phases.size());
|
|
|
|
// Check each of the incoming vectors. For each vector, set a flag if every
|
|
// element in that vector is the same.
|
|
is_const_amplitude_ = amplitude_.isConstant(amplitude_[0]);
|
|
is_const_frequency_ = frequency_.isConstant(frequency_[0]);
|
|
is_const_phase_ = phase_.isConstant(phase_[0]);
|
|
|
|
// If the Sine system is system time based, do not create an input port.
|
|
// System time is used as the time variable in this case. If the Sine system
|
|
// is not system time based, create an input port that contains the signal to
|
|
// be used as the time variable.
|
|
if (!is_time_based) {
|
|
this->DeclareInputPort(kUseDefaultName, kVectorValued, amplitudes.size());
|
|
}
|
|
value_output_port_index_ =
|
|
this->DeclareVectorOutputPort(kUseDefaultName, amplitudes.size(),
|
|
&Sine::CalcValueOutput)
|
|
.get_index();
|
|
first_derivative_output_port_index_ =
|
|
this->DeclareVectorOutputPort(kUseDefaultName, amplitudes.size(),
|
|
&Sine::CalcFirstDerivativeOutput)
|
|
.get_index();
|
|
second_derivative_output_port_index_ =
|
|
this->DeclareVectorOutputPort(kUseDefaultName, amplitudes.size(),
|
|
&Sine::CalcSecondDerivativeOutput)
|
|
.get_index();
|
|
}
|
|
|
|
template <typename T>
|
|
template <typename U>
|
|
Sine<T>::Sine(const Sine<U>& other)
|
|
: Sine<T>(other.amplitude_vector(), other.frequency_vector(),
|
|
other.phase_vector(), other.is_time_based()) {}
|
|
|
|
template <typename T>
|
|
double Sine<T>::amplitude() const {
|
|
if (!is_const_amplitude_) {
|
|
throw std::logic_error(fmt::format(
|
|
"The amplitude vector, [{}], cannot be represented as a scalar value. "
|
|
"Please use drake::systems::Sine::amplitude_vector() instead.",
|
|
fmt_eigen(amplitude_)));
|
|
}
|
|
return amplitude_[0];
|
|
}
|
|
|
|
template <typename T>
|
|
double Sine<T>::frequency() const {
|
|
if (!is_const_frequency_) {
|
|
throw std::logic_error(fmt::format(
|
|
"The frequency vector, [{}], cannot be represented as a scalar value. "
|
|
"Please use drake::systems::Sine::frequency_vector() instead.",
|
|
fmt_eigen(frequency_)));
|
|
}
|
|
return frequency_[0];
|
|
}
|
|
|
|
template <typename T>
|
|
double Sine<T>::phase() const {
|
|
if (!is_const_phase_) {
|
|
throw std::logic_error(fmt::format(
|
|
"The phase vector, [{}], cannot be represented as a scalar value. "
|
|
"Please use drake::systems::Sine::phase_vector() instead.",
|
|
fmt_eigen(phase_)));
|
|
}
|
|
return phase_[0];
|
|
}
|
|
|
|
template <typename T>
|
|
bool Sine<T>::is_time_based() const {
|
|
return is_time_based_;
|
|
}
|
|
|
|
template <typename T>
|
|
const Eigen::VectorXd& Sine<T>::amplitude_vector() const {
|
|
return amplitude_;
|
|
}
|
|
|
|
template <typename T>
|
|
const Eigen::VectorXd& Sine<T>::frequency_vector() const {
|
|
return frequency_;
|
|
}
|
|
|
|
template <typename T>
|
|
const Eigen::VectorXd& Sine<T>::phase_vector() const {
|
|
return phase_;
|
|
}
|
|
|
|
template <typename T>
|
|
void Sine<T>::CalcValueOutput(const Context<T>& context,
|
|
BasicVector<T>* output) const {
|
|
VectorX<T> sine_arg;
|
|
Sine::CalcArg(context, &sine_arg);
|
|
|
|
Eigen::VectorBlock<VectorX<T>> output_block = output->get_mutable_value();
|
|
output_block = amplitude_.array() * sine_arg.array().sin();
|
|
}
|
|
|
|
template <typename T>
|
|
void Sine<T>::CalcFirstDerivativeOutput(
|
|
const Context<T>& context, BasicVector<T>* output) const {
|
|
|
|
VectorX<T> cos_arg;
|
|
Sine::CalcArg(context, &cos_arg);
|
|
|
|
Eigen::VectorBlock<VectorX<T>> output_block = output->get_mutable_value();
|
|
output_block =
|
|
amplitude_.array() * frequency_.array() * cos_arg.array().cos();
|
|
}
|
|
|
|
template <typename T>
|
|
void Sine<T>::CalcSecondDerivativeOutput(
|
|
const Context<T>& context, BasicVector<T>* output) const {
|
|
|
|
VectorX<T> sine_arg;
|
|
Sine::CalcArg(context, &sine_arg);
|
|
|
|
Eigen::VectorBlock<VectorX<T>> output_block = output->get_mutable_value();
|
|
output_block =
|
|
- amplitude_.array() * frequency_.array().pow(2) * sine_arg.array().sin();
|
|
}
|
|
|
|
template <typename T>
|
|
void Sine<T>::CalcArg(
|
|
const Context<T>& context, VectorX<T>* arg) const {
|
|
|
|
if (is_time_based_) {
|
|
VectorX<T> time_vec(amplitude_.size());
|
|
time_vec.fill(context.get_time());
|
|
*arg = frequency_.array() * time_vec.array() + phase_.array();
|
|
} else {
|
|
const VectorX<T>& input = this->get_input_port(0).Eval(context);
|
|
*arg = frequency_.array() * input.array() + phase_.array();
|
|
}
|
|
}
|
|
|
|
} // namespace systems
|
|
} // namespace drake
|
|
|
|
DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS(
|
|
class ::drake::systems::Sine)
|