Skip to content

Commit

Permalink
Support Basic Induction Machine C-Simulation. The IM has high magneti…
Browse files Browse the repository at this point in the history
…zing inductance so the desired bandwidth should be low or else the current loop regulation would fail and you cannot even get large high frequency ripples in your M-axis current.
  • Loading branch information
horychen committed Dec 21, 2020
1 parent 11304b0 commit aabb7ed
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 247 deletions.
72 changes: 35 additions & 37 deletions emachinery/acmsimcv5/c/ACMConfig.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
#ifndef ACMCONFIG_H
#define ACMCONFIG_H

// #define sm im
// 电机类型
#define INDUCTION_MACHINE_CLASSIC_MODEL 1
#define INDUCTION_MACHINE_FLUX_ONLY_MODEL 11
#define PM_SYNCHRONOUS_MACHINE 2
#define MACHINE_TYPE 11
#define IM_STAOTR_RESISTANCE 3.04
#define IM_ROTOR_RESISTANCE 1.6
#define IM_TOTAL_LEAKAGE_INDUCTANCE 0.0249
#define IM_MAGNETIZING_INDUCTANCE 0.448
#define IM_FLUX_COMMAND_DC_PART 0.7105842093440861
#define IM_FLUX_COMMAND_SINE_PART 0.0
#define MOTOR_NUMBER_OF_POLE_PAIRS 2
#define MOTOR_RATED_CURRENT_RMS 8.8
#define MOTOR_RATED_POWER_WATT 4000
#define MOTOR_RATED_SPEED_RPM 1440
#define MOTOR_SHAFT_INERTIA 0.063

// 指令类型
#define EXCITATION_VELOCITY 0
#define EXCITATION_POSITION 1
#define EXCITATION_POSITION 0
#define EXCITATION_VELOCITY 1
#define EXCITATION_SWEEP_FREQUENCY 2
#define EXCITATION_TYPE (2)

#define NULL_D_AXIS_CURRENT_CONTROL -1
#define MTPA -2 // not supported
#define CONTROL_STRATEGY NULL_D_AXIS_CURRENT_CONTROL
#define EXCITATION_TYPE (1)

// 控制策略
#define INDIRECT_FOC 1
#define CONTROL_STRATEGY INDIRECT_FOC
#define NUMBER_OF_STEPS 160000
#define DOWN_SAMPLE 1
#define SENSORLESS_CONTROL FALSE
Expand All @@ -33,20 +47,6 @@
#define POW2AMPL (0.816496581) // = 1/sqrt(1.5) power-invariant to aplitude-invariant (the dqn vector becomes shorter to have the same length as the abc vector)
#define AMPL2POW (1.22474487)

#define INDUCTION_MACHINE_CLASSIC_MODEL 1
#define INDUCTION_MACHINE_FLUX_ONLY_MODEL 11
#define PM_SYNCHRONOUS_MACHINE 2
#define MACHINE_TYPE 2
#define PMSM_RESISTANCE 0.152
#define PMSM_D_AXIS_INDUCTANCE 0.00046600000000000005
#define PMSM_Q_AXIS_INDUCTANCE 0.00046600000000000005
#define PMSM_PERMANENT_MAGNET_FLUX_LINKAGE 0.011724639454177425
#define MOTOR_NUMBER_OF_POLE_PAIRS 4
#define MOTOR_RATED_CURRENT_RMS 12.8
#define MOTOR_RATED_POWER_WATT 400
#define MOTOR_RATED_SPEED_RPM 3000
#define MOTOR_SHAFT_INERTIA 1.6000000000000003e-05

#define LOAD_INERTIA 0.16
#define LOAD_TORQUE 0.0
#define VISCOUS_COEFF 7e-05
Expand All @@ -56,20 +56,13 @@
#define MOTOR_BACK_EMF_CONSTANT ( MOTOR_TORQUE_CONSTANT / 1.5 / MOTOR_NUMBER_OF_POLE_PAIRS )
#define MOTOR_BACK_EMF_CONSTANT_mV_PER_RPM ( MOTOR_BACK_EMF_CONSTANT * 1e3 / (1.0/MOTOR_NUMBER_OF_POLE_PAIRS/2/3.1415926*60) )

#define CURRENT_KP (1.47784)
#define CURRENT_KI (326.18)
#define CURRENT_KP (610.52)
#define CURRENT_KI (6.42842)
#define CURRENT_KI_CODE (CURRENT_KI*CURRENT_KP*CL_TS)
#define SPEED_KP (0.0321806)
#define SPEED_KI (75.061)
#define SPEED_KP (3.40446)
#define SPEED_KI (30.5565)
#define SPEED_KI_CODE (SPEED_KI*SPEED_KP*VL_TS)

#define SWEEP_FREQ_MAX_FREQ 200
#define SWEEP_FREQ_INIT_FREQ 2
#define SWEEP_FREQ_VELOCITY_AMPL 500
#define SWEEP_FREQ_CURRENT_AMPL 1
#define SWEEP_FREQ_C2V FALSE
#define SWEEP_FREQ_C2C FALSE

#define SPEED_LOOP_PID_PROPORTIONAL_GAIN 0.00121797
#define SPEED_LOOP_PID_INTEGRAL_TIME_CONSTANT (1/312.3)
#define SPEED_LOOP_PID_DIREVATIVE_TIME_CONSTANT 0
Expand All @@ -79,13 +72,18 @@
#define CURRENT_LOOP_PID_PROPORTIONAL_GAIN 9.2363 // (CL_TS_INVERSE*0.1*PMSM_D_AXIS_INDUCTANCE) // 9.2363
#define CURRENT_LOOP_PID_INTEGRAL_TIME_CONSTANT (1/352.143)
#define CURRENT_LOOP_PID_DIREVATIVE_TIME_CONSTANT 0
#define CURRENT_LOOP_LIMIT_VOLTS 48
#define DATA_FILE_NAME "../dat/Closed/PMSM_SweepFreq-V2V-@200Hz-505-1000-276-173.dat"
#define CURRENT_LOOP_LIMIT_VOLTS (600)
#define DATA_FILE_NAME "../dat/PMSM_SweepFreq-205-1000-7-2624.dat"
#define PC_SIMULATION TRUE



#define MACHINE_TS (CL_TS*TS_UPSAMPLING_FREQ_EXE) //1.25e-4
#define MACHINE_TS_INVERSE (CL_TS_INVERSE*TS_UPSAMPLING_FREQ_EXE_INVERSE) // 8000

#define SWEEP_FREQ_MAX_FREQ 200
#define SWEEP_FREQ_INIT_FREQ 2
#define SWEEP_FREQ_VELOCITY_AMPL 500
#define SWEEP_FREQ_CURRENT_AMPL 1
#define SWEEP_FREQ_C2V FALSE
#define SWEEP_FREQ_C2C FALSE

#endif
95 changes: 48 additions & 47 deletions emachinery/acmsimcv5/c/im_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void CTRL_init(){
// PID调谐
ACMSIMC_PIDTuner();
printf("Speed PID: Kp=%g, Ki=%g, limit=%g Nm\n", pid1_spd.Kp, pid1_spd.Ki/CL_TS, pid1_spd.OutLimit);
printf("Current PID: Kp=%g, Ki=%g, limit=%g V\n", pid1_id.Kp, pid1_id.Ki/CL_TS, pid1_id.OutLimit);
printf("Current PID: Kp=%g, Ki=%g, limit=%g V\n", pid1_iM.Kp, pid1_iM.Ki/CL_TS, pid1_iM.OutLimit);
}

// 定义特定的测试指令,如快速反转等
Expand Down Expand Up @@ -248,24 +248,24 @@ void controller(){
// 帕克变换
#define THE_FIELD_IS_KNOWN FALSE
#if THE_FIELD_IS_KNOWN
ob.theta_M = atan2(IM.x[3], IM.x[2]);
ob.cosT = cos(ob.theta_M);
ob.sinT = sin(ob.theta_M);
CTRL.theta_M = atan2(IM.x[3], IM.x[2]);
CTRL.cosT = cos(CTRL.theta_M);
CTRL.sinT = sin(CTRL.theta_M);
#else
// 间接磁场定向第一部分
ob.theta_M += TS * CTRL.omega_syn;
ob.cosT = cos(ob.theta_M);
ob.sinT = sin(ob.theta_M);
if(ob.theta_M > M_PI){
ob.theta_M -= 2*M_PI;
}else if(ob.theta_M < -M_PI){
ob.theta_M += 2*M_PI; // 反转!
CTRL.theta_M += CL_TS * CTRL.omega_syn;
CTRL.cosT = cos(CTRL.theta_M);
CTRL.sinT = sin(CTRL.theta_M);
if(CTRL.theta_M > M_PI){
CTRL.theta_M -= 2*M_PI;
}else if(CTRL.theta_M < -M_PI){
CTRL.theta_M += 2*M_PI; // 反转!
}
#endif
CTRL.iMs = AB2M(IS_C(0), IS_C(1), ob.cosT, ob.sinT);
CTRL.iTs = AB2T(IS_C(0), IS_C(1), ob.cosT, ob.sinT);
pid1_id.Fdb = CTRL.iMs;
pid1_iq.Fdb = CTRL.iTs;
CTRL.iMs = AB2M(IS_C(0), IS_C(1), CTRL.cosT, CTRL.sinT);
CTRL.iTs = AB2T(IS_C(0), IS_C(1), CTRL.cosT, CTRL.sinT);
pid1_iM.Fbk = CTRL.iMs;
pid1_iT.Fbk = CTRL.iTs;


// 转速环
Expand All @@ -274,57 +274,58 @@ void controller(){
vc_count = 0;

pid1_spd.Ref = rpm_speed_command*RPM_2_RAD_PER_SEC;
pid1_spd.Fdb = CTRL.omg__fb;
pid1_spd.Fbk = CTRL.omg__fb;
pid1_spd.calc(&pid1_spd);
pid1_iq.Ref = pid1_spd.Out;

pid1_iT.Ref = pid1_spd.Out*0;
CTRL.iTs_cmd = pid1_iT.Ref;
}
CTRL.iTs_cmd = pid1_spd.Out;
// 磁链环
// double the_dc_part = TAAO_FLUX_COMMAND_VALUE;
ob.taao_flux_cmd = 1.0; //TAAO_FluxModulusCommand();
if(ob.taao_flux_cmd_on){
CTRL.iMs_cmd = the_dc_part * CTRL.Lmu_inv \
+ ( M1*OMG1*cos(OMG1*ob.timebase) )/ CTRL.rreq; /////////////////////////////////
}else{
CTRL.iMs_cmd = ob.taao_flux_cmd * CTRL.Lmu_inv + (deriv_fluxModCmd)/ CTRL.rreq;
// CTRL.iMs_cmd = ob.taao_flux_cmd * CTRL.Lmu_inv;
}
pid1_iq.Ref = CTRL.iMs_cmd;
CTRL.torque_cmd = CLARKE_TRANS_TORQUE_GAIN * im.npp * CTRL.iTs_cmd * (ob.taao_flux_cmd);
// if(ob.taao_flux_cmd_on){
// CTRL.iMs_cmd = IM_FLUX_COMMAND_DC_PART * CTRL.Lmu_inv \
// + ( M1*OMG1*cos(OMG1*ob.timebase) )/ CTRL.rreq; /////////////////////////////////
// }else{
// CTRL.iMs_cmd = * CTRL.Lmu_inv + (deriv_fluxModCmd)/ CTRL.rreq;
CTRL.rotor_flux_cmd = IM_FLUX_COMMAND_DC_PART;
CTRL.iMs_cmd = CTRL.rotor_flux_cmd * CTRL.Lmu_inv;
// }
pid1_iM.Ref = CTRL.iMs_cmd;
// 计算转矩
CTRL.torque_cmd = CLARKE_TRANS_TORQUE_GAIN * im.npp * CTRL.iTs_cmd * (CTRL.rotor_flux_cmd);
// 间接磁场定向第二部分
CTRL.omega_sl = CTRL.rreq*CTRL.iTs_cmd/(ob.taao_flux_cmd);
CTRL.omega_sl = CTRL.rreq*CTRL.iTs_cmd/(CTRL.rotor_flux_cmd);
CTRL.omega_syn = CTRL.omg__fb + CTRL.omega_sl;

// 扫频将覆盖上面产生的励磁、转矩电流指令
#if SWEEP_FREQ_C2V == TRUE
pid1_iq.Ref = amp_current_command;
#endif
#if SWEEP_FREQ_C2C == TRUE
pid1_iq.Ref = 0.0;
pid1_id.Ref = amp_current_command;
#else
pid1_id.Ref = 0.0;
// 扫频将覆盖上面产生的励磁、转矩电流指令
#if EXCITATION_TYPE == EXCITATION_SWEEP_FREQUENCY
#if SWEEP_FREQ_C2V == TRUE
pid1_iT.Ref = amp_current_command;
#endif
#if SWEEP_FREQ_C2C == TRUE
pid1_iT.Ref = 0.0;
pid1_iM.Ref = amp_current_command;
#else
pid1_iM.Ref = 0.0;
#endif
#endif




// 电流环
pid1_id.calc(&pid1_id);
pid1_iq.calc(&pid1_iq);
REAL decoupled_d_axis_voltage=0.0, decoupled_q_axis_voltage=0.0;
pid1_iM.calc(&pid1_iM);
pid1_iT.calc(&pid1_iT);
{ // Steady state dynamics based decoupling circuits for current regulation
#if VOLTAGE_CURRENT_DECOUPLING_CIRCUIT == TRUE
// decoupled_d_axis_voltage = vM + (CTRL.rs+CTRL.rreq)*CTRL.iMs + CTRL.Lsigma*(-CTRL.omega_syn*CTRL.iTs) - CTRL.alpha*CTRL.psimod_fb; // Jadot09
// decoupled_q_axis_voltage = vT + (CTRL.rs+CTRL.rreq)*CTRL.iTs + CTRL.Lsigma*( CTRL.omega_syn*CTRL.iMs) + CTRL.omg_fb*CTRL.psimod_fb;

decoupled_d_axis_voltage = pid1_id.Out + (CTRL.Lsigma) * (-CTRL.omega_syn*CTRL.iTs); // Telford03/04
decoupled_d_axis_voltage = pid1_iM.Out + (CTRL.Lsigma) * (-CTRL.omega_syn*CTRL.iTs); // Telford03/04
// decoupled_q_axis_voltage = vT + CTRL.omega_syn*(ob.taao_flux_cmd + im.Lsigma*CTRL.iMs); // 这个行,但是无速度运行时,会导致M轴电流在转速暂态高频震荡。
// decoupled_q_axis_voltage = vT + CTRL.omega_syn*(CTRL.Lsigma+CTRL.Lmu)*CTRL.iMs; // 这个就不行,说明:CTRL.Lmu*iMs != ob.taao_flux_cmd,而是会因iMs的波动在T轴控制上引入波动和不稳定
decoupled_q_axis_voltage = pid1_iq.Out;
decoupled_q_axis_voltage = pid1_iT.Out;
#else
decoupled_d_axis_voltage = pid1_id.Out;
decoupled_q_axis_voltage = pid1_iq.Out;
decoupled_d_axis_voltage = pid1_iM.Out;
decoupled_q_axis_voltage = pid1_iT.Out;
#endif
}

Expand Down
2 changes: 2 additions & 0 deletions emachinery/acmsimcv5/c/im_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ struct ControllerForExperiment {
double psibe_fb;
double psimod_fb;
double psimod_fb_inv;

double rotor_flux_cmd;
double deriv_fluxModSim;

double rs;
Expand Down
12 changes: 10 additions & 2 deletions emachinery/acmsimcv5/c/induction_motor.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,17 @@ int machine_simulation(){
ACM.iqs = ACM.x[1];
#elif MACHINE_TYPE == INDUCTION_MACHINE_FLUX_ONLY_MODEL
collectCurrents(ACM.x);

ACM.ial = ACM.ids;
ACM.ibe = ACM.iqs;

ACM.theta_M = atan2(ACM.x[3], ACM.x[2]);
ACM.cosT = cos(ACM.theta_M);
ACM.sinT = sin(ACM.theta_M);

ACM.iMs = AB2M(ACM.ial, ACM.ibe, ACM.cosT, ACM.sinT);
ACM.iTs = AB2T(ACM.ial, ACM.ibe, ACM.cosT, ACM.sinT);
#endif
ACM.ial = ACM.ids;
ACM.ibe = ACM.iqs;

// 电机转速接口
ACM.omg_elec = ACM.x[4]; // 电气转速 [elec. rad/s]
Expand Down
6 changes: 6 additions & 0 deletions emachinery/acmsimcv5/c/induction_motor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ struct InductionMachineSimulated{
double Tload;
double Tem;

double theta_M;
double cosT; // cosine for Park Transform
double sinT; // sine for Park Transform

double omg_elec;

double Lsigma;
Expand Down Expand Up @@ -57,6 +61,8 @@ struct InductionMachineSimulated{
double iqs; // q-axis is aligned with beta-axis
double idr;
double iqr;
double iMs; // rotor field oritented M-axis current
double iTs; // rotor field oritented T-axis current

double ual;
double ube;
Expand Down
20 changes: 10 additions & 10 deletions emachinery/acmsimcv5/c/pid_regulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

// 声明控制器结构体变量
struct ControllerForExperiment CTRL;
PID_REG pid1_id = PID_REG_DEFAULTS;
PID_REG pid1_iq = PID_REG_DEFAULTS;
PID_REG pid1_iM = PID_REG_DEFAULTS;
PID_REG pid1_iT = PID_REG_DEFAULTS;
PID_REG pid1_pos = PID_REG_DEFAULTS;
PID_REG pid1_spd = PID_REG_DEFAULTS;
PID_REG pid1_ia = PID_REG_DEFAULTS;
Expand All @@ -14,7 +14,7 @@ PID_REG pid1_ic = PID_REG_DEFAULTS;
#if INCREMENTAL_PID
void PID_calc(PID_Reg *r){

r->Err = r->Ref - r->Fdb;
r->Err = r->Ref - r->Fbk;
r->Out = r->OutPrev \
+ r->Kp * ( r->Err - r->ErrPrev ) + r->Ki * r->Err;

Expand All @@ -31,7 +31,7 @@ void PID_calc(PID_REG *r){
#define DYNAMIC_CLAPMING TRUE

// 误差
r->Err = r->Ref - r->Fdb;
r->Err = r->Ref - r->Fbk;

// 比例
r->P_Term = r->Err * r->Kp;
Expand Down Expand Up @@ -77,14 +77,14 @@ void PID_calc(PID_REG *r){
// 初始化函数
void ACMSIMC_PIDTuner(){

pid1_id.Kp = CURRENT_KP;
pid1_iq.Kp = CURRENT_KP;
pid1_iM.Kp = CURRENT_KP;
pid1_iT.Kp = CURRENT_KP;
pid1_ia.Kp = CURRENT_KP;
pid1_ib.Kp = CURRENT_KP;
pid1_ic.Kp = CURRENT_KP;

pid1_id.Ki = CURRENT_KI_CODE;
pid1_iq.Ki = CURRENT_KI_CODE;
pid1_iM.Ki = CURRENT_KI_CODE;
pid1_iT.Ki = CURRENT_KI_CODE;
pid1_ia.Ki = CURRENT_KI_CODE;
pid1_ib.Ki = CURRENT_KI_CODE;
pid1_ic.Ki = CURRENT_KI_CODE;
Expand All @@ -93,8 +93,8 @@ void ACMSIMC_PIDTuner(){
pid1_spd.Ki = SPEED_KI_CODE;

pid1_spd.OutLimit = SPEED_LOOP_LIMIT_AMPERE;
pid1_id.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_iq.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_iM.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_iT.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_ia.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_ib.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
pid1_ic.OutLimit = CURRENT_LOOP_LIMIT_VOLTS;
Expand Down
6 changes: 3 additions & 3 deletions emachinery/acmsimcv5/c/pid_regulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

typedef struct {
float32 Ref;
float32 Fdb;
float32 Fbk;
float32 Err;
float32 ErrPrev;
float32 P_Term;
Expand Down Expand Up @@ -39,8 +39,8 @@ void PID_calc(PID_REG_handle);
/*Difference between Non-Saturated Output and Saturated Output*/ 0.0, \
(void (*)(Uint32)) PID_calc \
}
extern PID_REG pid1_id;
extern PID_REG pid1_iq;
extern PID_REG pid1_iM;
extern PID_REG pid1_iT;
extern PID_REG pid1_pos;
extern PID_REG pid1_spd;
extern PID_REG pid1_ia;
Expand Down
Loading

0 comments on commit aabb7ed

Please sign in to comment.