165 lines
6.4 KiB
C++
165 lines
6.4 KiB
C++
|
/*
|
||
|
* BLDC.cpp
|
||
|
*
|
||
|
* Created on: 26.06.2018
|
||
|
* Author: eyck
|
||
|
*/
|
||
|
|
||
|
#include "sysc/top/BLDC.h"
|
||
|
|
||
|
// implementation according to Modeling of BLDC Motor with Ideal Back-EMF for Automotive Applications
|
||
|
// Proceedings of the World Congress on Engineering 2011 Vol II WCE 2011, July 6 - 8, 2011, London, U.K.
|
||
|
BLDC::BLDC(const Config config)
|
||
|
: config(config)
|
||
|
, stateVector({{0.0, 0.0, 0.0, 0.0, 0.0}})
|
||
|
, state(stateVector)
|
||
|
, vin({{0.0, 0.0, 0.0}})
|
||
|
, voltages({{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}})
|
||
|
{
|
||
|
state.init();
|
||
|
}
|
||
|
|
||
|
BLDC::~BLDC() {
|
||
|
|
||
|
}
|
||
|
|
||
|
double BLDC::calc_bemf_factor(const State& x, double theta){
|
||
|
if(theta>=0 && theta < 2./3.*M_PI){
|
||
|
return 1;
|
||
|
} else if(theta>=2./3.*M_PI && theta < M_PI){
|
||
|
return 1-6/M_PI*(theta-2./3.*M_PI);
|
||
|
} else if(theta>=M_PI && theta < 5./3. * M_PI){
|
||
|
return -1;
|
||
|
} else if(theta>=5./3. * M_PI && theta < 2. * M_PI){
|
||
|
return -1+6/M_PI*(theta-5./3.*M_PI);
|
||
|
} else {
|
||
|
fprintf(stderr, "ERROR: angle out of bounds can not calculate bemf %f\n", theta);
|
||
|
throw std::runtime_error("angle out of bounds can not calculate bemf");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BLDC::calc_back_emf(const State& state, double theta_e) {
|
||
|
double max_bemf = config.Ke * state.omega;
|
||
|
voltages[EA] = max_bemf*calc_bemf_factor(state, norm_angle(theta_e));
|
||
|
voltages[EB] = max_bemf*calc_bemf_factor(state, norm_angle(theta_e + M_PI * (2. / 3.)));
|
||
|
voltages[EC] = max_bemf*calc_bemf_factor(state, norm_angle(theta_e + M_PI * (4. / 3.)));
|
||
|
}
|
||
|
|
||
|
|
||
|
void BLDC::calc_voltages(){
|
||
|
const double NaN = nan("");
|
||
|
/* Check which phases are excited. */
|
||
|
bool pa = isnan(vin[0])?false:true;
|
||
|
bool pb = isnan(vin[1])?false:true;
|
||
|
bool pc = isnan(vin[2])?false:true;
|
||
|
|
||
|
if (pa && pb && pc) {
|
||
|
voltages[VA] = vin[0];
|
||
|
voltages[VB] = vin[1];
|
||
|
voltages[VC] = vin[2];
|
||
|
voltages[VCENTER] = (voltages[VA] + voltages[VB] + voltages[VC] - voltages[EA] - voltages[EB] - voltages[EC]) / 3.;
|
||
|
} else if (pa && pb) {
|
||
|
voltages[VA] = vin[0];
|
||
|
voltages[VB] = vin[1];
|
||
|
voltages[VCENTER] = (voltages[VA] + voltages[VB] - voltages[EA] - voltages[EB]) / 2.;
|
||
|
voltages[VC] = voltages[EC] + voltages[VCENTER];
|
||
|
} else if (pa && pc) {
|
||
|
voltages[VA] = vin[0];
|
||
|
voltages[VC] = vin[2];
|
||
|
voltages[VCENTER] = (voltages[VA] + voltages[VC] - voltages[EA] - voltages[EC]) / 2.;
|
||
|
voltages[VB] = voltages[EB] + voltages[VCENTER];
|
||
|
} else if (pb && pc) {
|
||
|
voltages[VB] = vin[1];
|
||
|
voltages[VC] = vin[2];
|
||
|
voltages[VCENTER] = (voltages[VB] + voltages[VC] - voltages[EB] - voltages[EC]) / 2.;
|
||
|
voltages[VA] = voltages[EA] + voltages[VCENTER];
|
||
|
} else if (pa) {
|
||
|
voltages[VA] = vin[0];
|
||
|
voltages[VCENTER] = (voltages[VA] - voltages[EA]);
|
||
|
voltages[VB] = voltages[EB] + voltages[VCENTER];
|
||
|
voltages[VC] = voltages[EC] + voltages[VCENTER];
|
||
|
} else if (pb) {
|
||
|
voltages[VB] = vin[1];
|
||
|
voltages[VCENTER] = (voltages[VB] - voltages[EB]);
|
||
|
voltages[VA] = voltages[EA] + voltages[VCENTER];
|
||
|
voltages[VC] = voltages[EC] + voltages[VCENTER];
|
||
|
} else if (pc) {
|
||
|
voltages[VC] = vin[0];
|
||
|
voltages[VCENTER] = (voltages[VC] - voltages[EC]);
|
||
|
voltages[VA] = voltages[EA] + voltages[VCENTER];
|
||
|
voltages[VB] = voltages[EB] + voltages[VCENTER];
|
||
|
} else {
|
||
|
voltages[VA] = voltages[EA];
|
||
|
voltages[VB] = voltages[EB];
|
||
|
voltages[VC] = voltages[EC];
|
||
|
voltages[VCENTER] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BLDC::printToStream(std::ostream& os) const {
|
||
|
os<<state.omega<<";"<<state.theta<<";"
|
||
|
<<state.ia<<";"<<state.ib<<";"<<state.ic<<";"
|
||
|
<<voltages[VA]<<";"<<voltages[VB]<<";"<<voltages[VC]<<";"
|
||
|
<<voltages[EA]<<";"<<voltages[EB]<<";"<<voltages[EC]<<";"<<voltages[VCENTER]<<";"
|
||
|
<<vin[0]<<";"<<vin[1]<<";"<<vin[2]<<";"<<etorque;
|
||
|
}
|
||
|
|
||
|
void BLDC::rotor_dyn(const StateVector& x_, StateVector& dxdt_, const double t) {
|
||
|
const State x(const_cast<StateVector&>(x_));
|
||
|
State dxdt(dxdt_);
|
||
|
double theta_e = state.theta * (config.NbPoles / 2.);
|
||
|
/* Calculate backemf voltages. */
|
||
|
calc_back_emf(x, theta_e);
|
||
|
/* Calculate voltages. */
|
||
|
calc_voltages();
|
||
|
/* Electromagnetic torque. */
|
||
|
// if (x.omega == 0) {
|
||
|
// printf("ERROR: input state vector omega equals 0!!!\n");
|
||
|
// throw std::runtime_error("input state vector omega equals 0");
|
||
|
// }
|
||
|
/* electrical torque */
|
||
|
//etorque = ((voltages[EA] * x.ia) + (voltages[EB] * x.ib) + (voltages[EC] * x.ic)) / x.omega;
|
||
|
// which is equivalent to:
|
||
|
etorque = config.Ke*(
|
||
|
x.ia * (calc_bemf_factor(state, norm_angle(theta_e))) +
|
||
|
x.ib * (calc_bemf_factor(state, norm_angle(theta_e + M_PI * (2. / 3.)))) +
|
||
|
x.ic * (calc_bemf_factor(state, norm_angle(theta_e + M_PI * (4. / 3.))))
|
||
|
);
|
||
|
/* Mechanical torque. */
|
||
|
mtorque = ((etorque * (config.NbPoles / 2)) - (config.damping * x.omega) - torque_load);
|
||
|
|
||
|
if ((mtorque > 0) && (mtorque <= config.static_friction)) {
|
||
|
mtorque = 0;
|
||
|
} else if (mtorque > config.static_friction) {
|
||
|
mtorque -= config.static_friction;
|
||
|
} else if ((mtorque < 0) && (mtorque >= -(config.static_friction))) {
|
||
|
mtorque = 0;
|
||
|
} else if (mtorque < -(config.static_friction)) {
|
||
|
mtorque += config.static_friction;
|
||
|
}
|
||
|
/* Position of the rotor */
|
||
|
dxdt.theta = x.omega;
|
||
|
/* Acceleration of the rotor. (omega_dot) */
|
||
|
// a=M/J with M->torque, J->Inertia, a->angular acceleration
|
||
|
dxdt.omega = mtorque / config.inertia;
|
||
|
/* Calculate dot currents. */
|
||
|
dxdt.ia = (voltages[VA] - (config.R * x.ia) - voltages[EA] - voltages[VCENTER]) / (config.L - config.M);
|
||
|
dxdt.ib = (voltages[VB] - (config.R * x.ib) - voltages[EB] - voltages[VCENTER]) / (config.L - config.M);
|
||
|
dxdt.ic = (voltages[VC] - (config.R * x.ic) - voltages[EC] - voltages[VCENTER]) / (config.L - config.M);
|
||
|
}
|
||
|
|
||
|
void BLDC::run(double incr) {
|
||
|
if(dt>incr) throw std::runtime_error("incr needs to be larger than dt");
|
||
|
double next_time = current_time+incr;
|
||
|
odeint::integrate_adaptive(make_controlled( 1.0e-10 , 1.0e-6 , stepper_type() ),
|
||
|
[this]( const StateVector &x , StateVector &dxdt , double t ) {this->rotor_dyn(x, dxdt,t);},
|
||
|
stateVector, current_time, next_time, dt);
|
||
|
current_time=next_time;
|
||
|
state.theta=norm_angle(state.theta);
|
||
|
}
|
||
|
|
||
|
std::ostream& operator <<(std::ostream& os, const BLDC& bldc) {
|
||
|
bldc.printToStream(os);
|
||
|
return os;
|
||
|
}
|