mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 12:47:30 +01:00
659 lines
21 KiB
C++
659 lines
21 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "vehicle/graph/graph_catalog.h"
|
|
#include "vehicle/graph/graph_body.h"
|
|
#include "McZapkie/MOVER.h"
|
|
|
|
#include <cmath>
|
|
|
|
// drive chain: motor -> gear -> axle. the mechanical connections pass the torque forward and the rotational speed back.
|
|
// both are in the frame of the vehicle: positive torque pushes the vehicle towards its front (cab 1), positive speed
|
|
// is the rotation when moving that way. the dir input of the motors is the position of the reverser in the occupied cab,
|
|
// so the motors turn it to the frame of the vehicle with the occupied cab
|
|
namespace vgraph
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
double constexpr two_pi{2.0 * M_PI};
|
|
|
|
TMoverParameters &vehicle(frame const &Frame)
|
|
{
|
|
return *Frame.body->mover;
|
|
}
|
|
|
|
block_type make_type(std::string Id, std::string Name, std::string Description, block_origin Origin)
|
|
{
|
|
block_type type;
|
|
type.id = std::move(Id);
|
|
type.category = "drive";
|
|
type.name = std::move(Name);
|
|
type.description = std::move(Description);
|
|
type.origin = Origin;
|
|
return type;
|
|
}
|
|
|
|
// direction of the drive in the frame of the vehicle: -1, 0 or 1
|
|
int absolute_direction(frame const &Frame, double const Dir)
|
|
{
|
|
auto const dir{Dir > 0.5 ? 1 : Dir < -0.5 ? -1 : 0};
|
|
auto const cab{Frame.body->cab};
|
|
return dir * (cab != 0 ? cab : 1);
|
|
}
|
|
|
|
// generic motor with a torque and power limit; a stand-in for the drives not extracted yet
|
|
class drive_simple final : public block
|
|
{
|
|
public:
|
|
struct port
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
wn,
|
|
demand,
|
|
dir,
|
|
shaft,
|
|
i,
|
|
p
|
|
};
|
|
};
|
|
struct param
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
t_max,
|
|
p_max,
|
|
eff,
|
|
min_voltage
|
|
};
|
|
};
|
|
|
|
explicit drive_simple(block_setup const &Setup)
|
|
: block(Setup), m_supplied(is_connected(Setup, port::wn)), m_tmax(number(Setup, param::t_max)), m_pmax(number(Setup, param::p_max)),
|
|
m_efficiency(std::clamp(number(Setup, param::eff), 0.01, 1.0)), m_minvoltage(number(Setup, param::min_voltage))
|
|
{
|
|
}
|
|
|
|
void update(frame &Frame) override
|
|
{
|
|
auto const voltage{m_supplied ? forward_in(Frame, port::wn) : 0.0};
|
|
auto const powered{false == m_supplied || (voltage > 0.0 && voltage >= m_minvoltage)};
|
|
auto const dir{absolute_direction(Frame, get(Frame, port::dir))};
|
|
auto const demand{std::clamp(get(Frame, port::demand), -1.0, 1.0)};
|
|
auto const speed{back_out(Frame, port::shaft)}; // rad/s
|
|
auto torque{0.0};
|
|
if (powered && dir != 0)
|
|
{
|
|
if (demand >= 0.0)
|
|
{
|
|
// traction, limited by the power above the base speed
|
|
auto const limit{std::abs(speed) > 1e-3 ? std::min(m_tmax, m_pmax / std::abs(speed)) : m_tmax};
|
|
torque = dir * demand * limit;
|
|
}
|
|
else
|
|
{
|
|
// electric brake, against the rotation
|
|
auto const limit{std::abs(speed) > 1e-3 ? std::min(m_tmax, m_pmax / std::abs(speed)) : 0.0};
|
|
torque = (speed >= 0.0 ? -1.0 : 1.0) * (-demand) * limit * std::min(1.0, std::abs(speed));
|
|
}
|
|
}
|
|
auto const mechanical{torque * speed}; // W, positive when driving
|
|
auto const electrical{mechanical >= 0.0 ? mechanical / m_efficiency : mechanical * m_efficiency};
|
|
auto const current{m_supplied && voltage > 1.0 ? electrical / voltage : 0.0};
|
|
if (m_supplied)
|
|
{
|
|
add_back(Frame, port::wn, current);
|
|
}
|
|
set_forward(Frame, port::shaft, torque);
|
|
set(Frame, port::i, current);
|
|
set(Frame, port::p, electrical);
|
|
auto &body{vehicle(Frame)};
|
|
body.Im = current;
|
|
body.EngineVoltage = voltage * dir;
|
|
body.enrot = speed / two_pi;
|
|
}
|
|
|
|
static block_type describe()
|
|
{
|
|
auto type{make_type("drive.simple", "Simple motor",
|
|
"Motor with a torque limit (t_max) and a power limit (p_max): demand 0..1 drives, -1..0 brakes electrically. A stand-in for prototypes.",
|
|
block_origin::native)};
|
|
type.ports = {physical_in("wn", domain::high_voltage, true), signal_in("demand", value_type::real), signal_in("dir", value_type::real),
|
|
physical_out("shaft", domain::mechanical), signal_out("i", value_type::real, "A"), signal_out("p", value_type::real, "W")};
|
|
type.params = {number_param("t_max", 5000.0, "Nm"), number_param("p_max", 500000.0, "W"), number_param("eff", 0.9), number_param("min_voltage", 0.0, "V")};
|
|
type.create = make_block<drive_simple>;
|
|
return type;
|
|
}
|
|
|
|
private:
|
|
bool const m_supplied;
|
|
double const m_tmax;
|
|
double const m_pmax;
|
|
double const m_efficiency;
|
|
double const m_minvoltage;
|
|
};
|
|
|
|
class drive_gear final : public block
|
|
{
|
|
public:
|
|
struct port
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
in,
|
|
out
|
|
};
|
|
};
|
|
|
|
explicit drive_gear(block_setup const &Setup) : block(Setup), m_ratio(number(Setup, 0)), m_efficiency(number(Setup, 1)) {}
|
|
|
|
void update(frame &Frame) override
|
|
{
|
|
set_forward(Frame, port::out, forward_in(Frame, port::in) * m_ratio * m_efficiency);
|
|
add_back(Frame, port::in, back_out(Frame, port::out) * m_ratio);
|
|
}
|
|
|
|
static block_type describe()
|
|
{
|
|
auto type{make_type("drive.gear", "Gear", "Transmission: torque times ratio and efficiency, speed of the input times ratio. ratio = wheel teeth / motor teeth.",
|
|
block_origin::extracted)};
|
|
type.ports = {physical_in("in", domain::mechanical), physical_out("out", domain::mechanical)};
|
|
type.params = {number_param("ratio", 1.0), number_param("eff", 1.0)};
|
|
type.create = make_block<drive_gear>;
|
|
return type;
|
|
}
|
|
|
|
private:
|
|
double const m_ratio;
|
|
double const m_efficiency;
|
|
};
|
|
|
|
// wheelsets driven by one shaft: the torque becomes the tractive force of the vehicle
|
|
class drive_axle final : public block
|
|
{
|
|
public:
|
|
struct port
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
shaft,
|
|
force,
|
|
slip
|
|
};
|
|
};
|
|
|
|
explicit drive_axle(block_setup const &Setup) : block(Setup), m_axles(std::max(0.0, number(Setup, 0))) {}
|
|
|
|
void update(frame &Frame) override
|
|
{
|
|
auto const &body{vehicle(Frame)};
|
|
auto const diameter{body.WheelDiameter > 0.0 ? body.WheelDiameter : 1.0};
|
|
auto const force{forward_in(Frame, port::shaft) * 2.0 / diameter * m_axles};
|
|
Frame.body->tractive_force += force;
|
|
add_back(Frame, port::shaft, Frame.body->wheel_speed * two_pi);
|
|
set(Frame, port::force, force);
|
|
set_bool(Frame, port::slip, Frame.body->slipping);
|
|
}
|
|
|
|
static block_type describe()
|
|
{
|
|
auto type{make_type("drive.axle", "Driven axles",
|
|
"Driven wheelsets: the torque of one shaft (of one motor, after the gear) times powered_axles gives the force at the wheel rim. All axle forces are "
|
|
"summed into the tractive force of the vehicle.",
|
|
block_origin::native)};
|
|
type.ports = {physical_in("shaft", domain::mechanical), signal_out("force", value_type::real, "N"), signal_out("slip", value_type::boolean)};
|
|
type.params = {number_param("powered_axles", 1.0)};
|
|
type.create = make_block<drive_axle>;
|
|
return type;
|
|
}
|
|
|
|
private:
|
|
double const m_axles;
|
|
};
|
|
|
|
// series dc traction motors with resistor starting (TMoverParameters::Current, Momentum)
|
|
class drive_dc_series final : public block
|
|
{
|
|
public:
|
|
struct port
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
wn,
|
|
position,
|
|
shunt,
|
|
dir,
|
|
high,
|
|
reset,
|
|
shaft,
|
|
i,
|
|
u_motor,
|
|
overload
|
|
};
|
|
};
|
|
struct param
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
rlist,
|
|
mpt,
|
|
volt,
|
|
winding_res,
|
|
circuit_res,
|
|
imax_lo,
|
|
imax_hi,
|
|
imin_lo,
|
|
imin_hi,
|
|
trip_delay
|
|
};
|
|
};
|
|
|
|
explicit drive_dc_series(block_setup const &Setup)
|
|
: block(Setup), m_windingres(number(Setup, param::winding_res)), m_circuitres(number(Setup, param::circuit_res)), m_imaxlo(number(Setup, param::imax_lo)),
|
|
m_imaxhi(number(Setup, param::imax_hi)), m_tripdelay(number(Setup, param::trip_delay))
|
|
{
|
|
for (auto const &row : table(Setup, param::rlist))
|
|
{
|
|
// pos, r, bn, mn, auto
|
|
scheme entry;
|
|
entry.r = row[1];
|
|
entry.bn = static_cast<int>(std::lround(row[2]));
|
|
entry.mn = static_cast<int>(std::lround(row[3]));
|
|
m_schemes.push_back(entry);
|
|
}
|
|
for (auto const &row : table(Setup, param::mpt))
|
|
{
|
|
// pos, mfi, mIsat, mfi0, fi, Isat, fi0
|
|
TMotorParameters motor;
|
|
motor.mfi = row[1];
|
|
motor.mIsat = row[2];
|
|
motor.mfi0 = row[3];
|
|
motor.fi = row[4];
|
|
motor.Isat = row[5];
|
|
motor.fi0 = row[6];
|
|
m_motors.push_back(motor);
|
|
}
|
|
if (m_schemes.empty())
|
|
{
|
|
m_schemes.emplace_back();
|
|
}
|
|
if (m_motors.empty())
|
|
{
|
|
m_motors.emplace_back();
|
|
}
|
|
}
|
|
|
|
void update(frame &Frame) override
|
|
{
|
|
auto &body{vehicle(Frame)};
|
|
auto const dir{absolute_direction(Frame, get(Frame, port::dir))};
|
|
auto const voltage{forward_in(Frame, port::wn) * dir};
|
|
auto const position{std::clamp<int>(static_cast<int>(std::lround(get(Frame, port::position))), 0, static_cast<int>(m_schemes.size()) - 1)};
|
|
auto const shunt{std::clamp<int>(static_cast<int>(std::lround(get(Frame, port::shunt))), 0, static_cast<int>(m_motors.size()) - 1)};
|
|
auto const &scheme{m_schemes[position]};
|
|
auto const &motor{m_motors[shunt]};
|
|
auto const revolutions{back_out(Frame, port::shaft) / two_pi}; // rev/s
|
|
|
|
if (get_bool(Frame, port::reset))
|
|
{
|
|
m_overload = false;
|
|
}
|
|
auto current{0.0};
|
|
if (scheme.bn != 0 && std::abs(voltage) > 1.0 && false == m_overload)
|
|
{
|
|
auto const resistance{scheme.r + m_circuitres};
|
|
current = series_motor_current(voltage, revolutions, scheme.mn, scheme.mn * m_windingres + resistance, motor);
|
|
}
|
|
// overload relay, as in TractionForce: trips when the current stays above the limit
|
|
auto const imax{get_bool(Frame, port::high) ? m_imaxhi : m_imaxlo};
|
|
if (imax > 0.0 && std::abs(current) > imax)
|
|
{
|
|
m_overtime += Frame.dt;
|
|
if (m_overtime > m_tripdelay)
|
|
{
|
|
m_overload = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_overtime = 0.0;
|
|
}
|
|
auto const torque{series_motor_momentum(current, motor)};
|
|
auto const linecurrent{current * scheme.bn};
|
|
add_back(Frame, port::wn, std::abs(linecurrent));
|
|
set_forward(Frame, port::shaft, torque);
|
|
set(Frame, port::i, current);
|
|
set(Frame, port::u_motor, scheme.mn > 0 ? (std::abs(voltage) - std::abs(current) * (scheme.r + m_circuitres)) / scheme.mn : 0.0);
|
|
set_bool(Frame, port::overload, m_overload);
|
|
body.Im = current;
|
|
body.EngineVoltage = voltage;
|
|
body.enrot = revolutions;
|
|
body.MainCtrlActualPos = position;
|
|
}
|
|
|
|
std::size_t state_count() const override
|
|
{
|
|
return 1;
|
|
}
|
|
char const *state_name(std::size_t) const override
|
|
{
|
|
return "overload";
|
|
}
|
|
double state_value(std::size_t) const override
|
|
{
|
|
return m_overload ? 1.0 : 0.0;
|
|
}
|
|
|
|
static block_type describe()
|
|
{
|
|
auto type{make_type("drive.dc_series", "Series DC motors",
|
|
"Series wound DC traction motors with resistor starting, computed as for the .fiz vehicles. position selects the row of rlist (resistance, "
|
|
"branches, motors in series), shunt the row of mpt (motor characteristics). The shaft carries the torque of one motor. high selects imax_hi "
|
|
"for the overload relay; reset clears it.",
|
|
block_origin::extracted)};
|
|
type.ports = {physical_in("wn", domain::high_voltage),
|
|
signal_in("position", value_type::integer),
|
|
signal_in("shunt", value_type::integer, 0.0, "", true),
|
|
signal_in("dir", value_type::real),
|
|
signal_in("high", value_type::boolean, 0.0, "", true),
|
|
signal_in("reset", value_type::boolean, 0.0, "", true),
|
|
physical_out("shaft", domain::mechanical),
|
|
signal_out("i", value_type::real, "A"),
|
|
signal_out("u_motor", value_type::real, "V"),
|
|
signal_out("overload", value_type::boolean)};
|
|
type.params = {table_param("rlist", {"pos", "r", "bn", "mn", "auto"}),
|
|
table_param("mpt", {"pos", "mfi", "misat", "mfi0", "fi", "isat", "fi0"}),
|
|
number_param("volt", 1500.0, "V"),
|
|
number_param("winding_res", 0.0, "ohm"),
|
|
number_param("circuit_res", 0.0, "ohm"),
|
|
number_param("imax_lo", 0.0, "A"),
|
|
number_param("imax_hi", 0.0, "A"),
|
|
number_param("imin_lo", 0.0, "A"),
|
|
number_param("imin_hi", 0.0, "A"),
|
|
number_param("trip_delay", 0.05, "s")};
|
|
type.create = make_block<drive_dc_series>;
|
|
return type;
|
|
}
|
|
|
|
private:
|
|
struct scheme
|
|
{
|
|
double r{0.0};
|
|
int bn{0};
|
|
int mn{0};
|
|
};
|
|
|
|
double const m_windingres;
|
|
double const m_circuitres;
|
|
double const m_imaxlo;
|
|
double const m_imaxhi;
|
|
double const m_tripdelay;
|
|
std::vector<scheme> m_schemes;
|
|
std::vector<TMotorParameters> m_motors;
|
|
double m_overtime{0.0};
|
|
bool m_overload{false};
|
|
};
|
|
|
|
// induction motors fed by inverters (the ElectricInductionMotor drive of TMoverParameters::TractionForce)
|
|
class drive_async final : public block
|
|
{
|
|
public:
|
|
struct port
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
wn,
|
|
demand,
|
|
dir,
|
|
shaft,
|
|
i,
|
|
f,
|
|
ed_active,
|
|
ed
|
|
};
|
|
};
|
|
// in the order of the eimc constants they're copied to
|
|
struct param
|
|
{
|
|
enum : std::size_t
|
|
{
|
|
dfic,
|
|
dfmax,
|
|
p,
|
|
cfu,
|
|
cim,
|
|
icif,
|
|
uzmax,
|
|
uzh,
|
|
du,
|
|
i0,
|
|
fcfu,
|
|
fcfuh,
|
|
f0,
|
|
a1,
|
|
pmax,
|
|
fh,
|
|
ph,
|
|
vh0,
|
|
vh1,
|
|
imax,
|
|
abed,
|
|
edep,
|
|
flat,
|
|
motors,
|
|
ratio,
|
|
eff,
|
|
log_force
|
|
};
|
|
};
|
|
|
|
explicit drive_async(block_setup const &Setup)
|
|
: block(Setup), m_flat(boolean(Setup, param::flat)), m_motors(static_cast<int>(std::lround(number(Setup, param::motors)))), m_ratio(number(Setup, param::ratio)),
|
|
m_efficiency(number(Setup, param::eff)), m_logforce(boolean(Setup, param::log_force))
|
|
{
|
|
std::fill(std::begin(m_eimc), std::end(m_eimc), 0.0);
|
|
std::fill(std::begin(m_eimv), std::end(m_eimv), 0.0);
|
|
m_eimc[eimc_s_dfic] = number(Setup, param::dfic);
|
|
m_eimc[eimc_s_dfmax] = number(Setup, param::dfmax);
|
|
m_eimc[eimc_s_p] = number(Setup, param::p);
|
|
m_eimc[eimc_s_cfu] = number(Setup, param::cfu);
|
|
m_eimc[eimc_s_cim] = number(Setup, param::cim);
|
|
m_eimc[eimc_s_icif] = number(Setup, param::icif);
|
|
m_eimc[eimc_f_Uzmax] = number(Setup, param::uzmax);
|
|
m_eimc[eimc_f_Uzh] = number(Setup, param::uzh);
|
|
m_eimc[eimc_f_DU] = number(Setup, param::du);
|
|
m_eimc[eimc_f_I0] = number(Setup, param::i0);
|
|
m_eimc[eimc_f_cfu] = number(Setup, param::fcfu);
|
|
// as in LoadFIZ_Engine: fcfuH defaults to fcfu
|
|
m_eimc[eimc_f_cfuH] = number(Setup, param::fcfuh) > 0.0 ? number(Setup, param::fcfuh) : m_eimc[eimc_f_cfu];
|
|
m_eimc[eimc_p_F0] = number(Setup, param::f0);
|
|
m_eimc[eimc_p_a1] = number(Setup, param::a1);
|
|
m_eimc[eimc_p_Pmax] = number(Setup, param::pmax);
|
|
m_eimc[eimc_p_Fh] = number(Setup, param::fh);
|
|
m_eimc[eimc_p_Ph] = number(Setup, param::ph);
|
|
m_eimc[eimc_p_Vh0] = number(Setup, param::vh0);
|
|
m_eimc[eimc_p_Vh1] = number(Setup, param::vh1);
|
|
m_eimc[eimc_p_Imax] = number(Setup, param::imax);
|
|
m_eimc[eimc_p_abed] = number(Setup, param::abed);
|
|
m_eimc[eimc_p_eped] = number(Setup, param::edep);
|
|
}
|
|
|
|
void update(frame &Frame) override
|
|
{
|
|
auto &body{vehicle(Frame)};
|
|
auto const voltage{forward_in(Frame, port::wn)};
|
|
auto const dir{absolute_direction(Frame, get(Frame, port::dir))};
|
|
auto const enrot{back_out(Frame, port::shaft) / two_pi};
|
|
auto const demand{std::clamp(get(Frame, port::demand), -1.0, 1.0)};
|
|
if (voltage < 1.0 || dir == 0)
|
|
{
|
|
// without supply the inverters stop, as for the vehicles without the main circuit (Mains)
|
|
std::fill(std::begin(m_eimv), std::end(m_eimv), 0.0);
|
|
m_eimvpr = 0.0;
|
|
m_dynamicbrake = false;
|
|
add_back(Frame, port::wn, 0.0);
|
|
publish(Frame, body, 0.0, 0.0, 0.0, voltage * dir, enrot);
|
|
return;
|
|
}
|
|
auto const vel{body.Vel};
|
|
// set value of the force and the rate of its ramp, as in TractionForce
|
|
double posratio;
|
|
double rate;
|
|
if (demand < -0.001)
|
|
{
|
|
m_dynamicbrake = true;
|
|
auto const vhramp{std::clamp((vel - m_eimc[eimc_p_Vh0]) / std::max(0.001, m_eimc[eimc_p_Vh1] - m_eimc[eimc_p_Vh0]), 0.0, 1.0)};
|
|
posratio = demand * vhramp;
|
|
rate = 5.0;
|
|
}
|
|
else
|
|
{
|
|
m_dynamicbrake = false;
|
|
posratio = std::max(demand, 0.0);
|
|
if (m_flat && m_eimc[eimc_p_F0] * m_eimv[eimv_Fful] > 0)
|
|
{
|
|
posratio = std::min(posratio * m_eimc[eimc_p_F0] / m_eimv[eimv_Fful], 1.0);
|
|
}
|
|
rate = 4.0;
|
|
}
|
|
if (body.SlippingWheels)
|
|
{
|
|
// anti-slip: the set value drops quickly
|
|
posratio = 0.0;
|
|
rate = 10.0;
|
|
}
|
|
induction_motor_inputs input;
|
|
input.demand = posratio;
|
|
input.rate = rate;
|
|
input.dynamic_brake = m_dynamicbrake;
|
|
input.engine_voltage = voltage;
|
|
input.enrot = enrot;
|
|
input.vel = vel;
|
|
input.v = body.V;
|
|
input.dir_absolute = dir;
|
|
input.dir_active = dir;
|
|
input.powered_axles = m_motors;
|
|
input.inverters_ratio = 1.0;
|
|
input.ratio = m_ratio;
|
|
input.efficiency = m_efficiency;
|
|
input.wheel_diameter = body.WheelDiameter > 0.0 ? body.WheelDiameter : 1.0;
|
|
input.log_force = m_logforce;
|
|
input.max_voltage = body.EnginePowerSource.CollectorParameters.MaxV;
|
|
input.dt = Frame.dt;
|
|
induction_motor_outputs output;
|
|
induction_motor_update(input, m_eimc, m_eimv, m_eimvpr, m_vadd, output);
|
|
|
|
add_back(Frame, port::wn, output.Itot);
|
|
// share of the requested braking force the motors deliver, for the blending with the pneumatic brake
|
|
auto edshare{0.0};
|
|
if (m_dynamicbrake && m_eimc[eimc_p_Fh] > 0.0 && demand < -0.001)
|
|
{
|
|
edshare = std::clamp(std::abs(m_eimv[eimv_Fr]) / (m_eimc[eimc_p_Fh] * -demand), 0.0, 1.0);
|
|
}
|
|
publish(Frame, body, output.Mm, output.Im, edshare, voltage, enrot);
|
|
}
|
|
|
|
std::size_t state_count() const override
|
|
{
|
|
return 2;
|
|
}
|
|
char const *state_name(std::size_t Index) const override
|
|
{
|
|
return Index == 0 ? "set_value" : "force_kn";
|
|
}
|
|
double state_value(std::size_t Index) const override
|
|
{
|
|
return Index == 0 ? m_eimvpr : m_eimv[eimv_Fr];
|
|
}
|
|
|
|
static block_type describe()
|
|
{
|
|
auto type{make_type("drive.async", "Induction motors with inverters",
|
|
"Induction traction motors fed by inverters, computed as for the .fiz vehicles (Engine: ElectricInductionMotor). demand 0..1 drives, -1..0 brakes "
|
|
"electrically (faded out between vh1 and vh0). The shaft carries the torque of one motor; ratio and eff have to match the gear, and motors the "
|
|
"driven axles. ed is the share of the requested braking force the motors deliver, for the ed input of the distributor.",
|
|
block_origin::extracted)};
|
|
type.ports = {physical_in("wn", domain::high_voltage), signal_in("demand", value_type::real), signal_in("dir", value_type::real),
|
|
physical_out("shaft", domain::mechanical), signal_out("i", value_type::real, "A"), signal_out("f", value_type::real, "Hz"),
|
|
signal_out("ed_active", value_type::boolean), signal_out("ed", value_type::real)};
|
|
type.params = {number_param("dfic", 0.0),
|
|
number_param("dfmax", 0.0),
|
|
number_param("p", 2.0),
|
|
number_param("cfu", 0.0),
|
|
number_param("cim", 0.0),
|
|
number_param("icif", 0.0),
|
|
number_param("uzmax", 0.0, "V"),
|
|
number_param("uzh", 0.0, "V"),
|
|
number_param("du", 0.0, "V"),
|
|
number_param("i0", 0.0, "A"),
|
|
number_param("fcfu", 0.0),
|
|
number_param("fcfuh", 0.0),
|
|
number_param("f0", 0.0, "kN"),
|
|
number_param("a1", 0.0),
|
|
number_param("pmax", 0.0, "kW"),
|
|
number_param("fh", 0.0, "kN"),
|
|
number_param("ph", 0.0, "kW"),
|
|
number_param("vh0", 0.0, "km/h"),
|
|
number_param("vh1", 0.0, "km/h"),
|
|
number_param("imax", 0.0, "A"),
|
|
number_param("abed", 1.0),
|
|
number_param("edep", 1.5),
|
|
boolean_param("flat", false),
|
|
number_param("motors", 4.0),
|
|
number_param("ratio", 1.0),
|
|
number_param("eff", 1.0),
|
|
boolean_param("log_force", false)};
|
|
type.create = make_block<drive_async>;
|
|
return type;
|
|
}
|
|
|
|
private:
|
|
void publish(frame &Frame, TMoverParameters &Body, double const Torque, double const Current, double const Edshare, double const Voltage, double const Revolutions)
|
|
{
|
|
set_forward(Frame, port::shaft, Torque);
|
|
set(Frame, port::i, Current);
|
|
set(Frame, port::f, std::abs(m_eimv[eimv_fp]));
|
|
set_bool(Frame, port::ed_active, m_dynamicbrake);
|
|
set(Frame, port::ed, Edshare);
|
|
Body.Im = Current;
|
|
Body.EngineVoltage = Voltage;
|
|
Body.enrot = Revolutions;
|
|
Body.DynamicBrakeFlag = m_dynamicbrake;
|
|
Body.InverterFrequency = std::abs(m_eimv[eimv_fp]);
|
|
std::copy(std::begin(m_eimv), std::end(m_eimv), Body.eimv);
|
|
}
|
|
|
|
bool const m_flat;
|
|
int const m_motors;
|
|
double const m_ratio;
|
|
double const m_efficiency;
|
|
bool const m_logforce;
|
|
double m_eimc[26];
|
|
double m_eimv[21];
|
|
double m_eimvpr{0.0};
|
|
double m_vadd{0.0};
|
|
bool m_dynamicbrake{false};
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void register_drive_blocks(catalog &Catalog)
|
|
{
|
|
Catalog.add(drive_simple::describe());
|
|
Catalog.add(drive_dc_series::describe());
|
|
Catalog.add(drive_async::describe());
|
|
Catalog.add(drive_gear::describe());
|
|
Catalog.add(drive_axle::describe());
|
|
}
|
|
|
|
} // namespace vgraph
|