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.
Conception/drake-master/systems/primitives/sine.cc

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)