mirror of https://github.com/rusefi/bldc.git
Improved flux linkage measurement
This commit is contained in:
parent
ccb2fd3f7f
commit
6f7c40b4e1
|
@ -19,6 +19,7 @@
|
||||||
* Added hall_analyze terminal command.
|
* Added hall_analyze terminal command.
|
||||||
* Motor temperature filtering bug fix.
|
* Motor temperature filtering bug fix.
|
||||||
* Inductance measurement scaling fix.
|
* Inductance measurement scaling fix.
|
||||||
|
* Better flux linkage measurement.
|
||||||
|
|
||||||
=== FW 4.02 ===
|
=== FW 4.02 ===
|
||||||
* Position PID fix (most notable on multiturn encoders).
|
* Position PID fix (most notable on multiturn encoders).
|
||||||
|
|
|
@ -1580,9 +1580,14 @@ static THD_FUNCTION(blocking_thread, arg) {
|
||||||
inductance = buffer_get_float32(data, 1e8, &ind);
|
inductance = buffer_get_float32(data, 1e8, &ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
float linkage;
|
float linkage, linkage_undriven, undriven_samples;
|
||||||
bool res = conf_general_measure_flux_linkage_openloop(current, duty,
|
bool res = conf_general_measure_flux_linkage_openloop(current, duty,
|
||||||
erpm_per_sec, resistance, inductance, &linkage);
|
erpm_per_sec, resistance, inductance,
|
||||||
|
&linkage, &linkage_undriven, &undriven_samples);
|
||||||
|
|
||||||
|
if (undriven_samples > 60) {
|
||||||
|
linkage = linkage_undriven;
|
||||||
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
linkage = 0.0;
|
linkage = 0.0;
|
||||||
|
|
|
@ -789,11 +789,18 @@ uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq
|
||||||
* @param linkage
|
* @param linkage
|
||||||
* The calculated flux linkage.
|
* The calculated flux linkage.
|
||||||
*
|
*
|
||||||
|
* @param linkage_undriven
|
||||||
|
* Flux linkage measured while the motor was undriven.
|
||||||
|
*
|
||||||
|
* @param undriven_samples
|
||||||
|
* Number of flux linkage samples while the motor was undriven.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* True for success, false otherwise.
|
* True for success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
||||||
float erpm_per_sec, float res, float ind, float *linkage) {
|
float erpm_per_sec, float res, float ind, float *linkage,
|
||||||
|
float *linkage_undriven, float *undriven_samples) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
mc_configuration *mcconf = mempools_alloc_mcconf();
|
mc_configuration *mcconf = mempools_alloc_mcconf();
|
||||||
|
@ -901,7 +908,7 @@ bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
||||||
float id_avg = 0.0;
|
float id_avg = 0.0;
|
||||||
float samples2 = 0.0;
|
float samples2 = 0.0;
|
||||||
|
|
||||||
for (int i = 0;i < 30000;i++) {
|
for (int i = 0;i < 10000;i++) {
|
||||||
vq_avg += mcpwm_foc_get_vq();
|
vq_avg += mcpwm_foc_get_vq();
|
||||||
vd_avg += mcpwm_foc_get_vd();
|
vd_avg += mcpwm_foc_get_vd();
|
||||||
iq_avg += mcpwm_foc_get_iq();
|
iq_avg += mcpwm_foc_get_iq();
|
||||||
|
@ -915,14 +922,40 @@ bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
||||||
iq_avg /= samples2;
|
iq_avg /= samples2;
|
||||||
id_avg /= samples2;
|
id_avg /= samples2;
|
||||||
|
|
||||||
(void)ind;
|
float rad_s = rpm_now * ((2.0 * M_PI) / 60.0);
|
||||||
*linkage = (sqrtf(SQ(vq_avg) + SQ(vd_avg)) - res *
|
float v_mag = sqrtf(SQ(vq_avg) + SQ(vd_avg));
|
||||||
sqrtf(SQ(iq_avg) + SQ(id_avg))) / (rpm_now * ((2.0 * M_PI) / 60.0));
|
float i_mag = sqrtf(SQ(iq_avg) + SQ(id_avg));
|
||||||
|
*linkage = (v_mag - (2.0 / 3.0) * res * i_mag) / rad_s - (2.0 / 3.0) * i_mag * ind;
|
||||||
|
|
||||||
// float rad_s = rpm_now * ((2.0 * M_PI) / 60.0);
|
mcconf->foc_motor_r = res;
|
||||||
// float v_mag = sqrtf(SQ(vq_avg) + SQ(vd_avg));
|
mcconf->foc_motor_l = ind;
|
||||||
// float i_mag = sqrtf(SQ(iq_avg) + SQ(id_avg));
|
mcconf->foc_motor_flux_linkage = *linkage;
|
||||||
// *linkage = (v_mag - res * i_mag) / rad_s - i_mag * ind;
|
mcconf->foc_observer_gain = 0.5e3 / SQ(*linkage);
|
||||||
|
mc_interface_set_configuration(mcconf);
|
||||||
|
chThdSleepMilliseconds(500);
|
||||||
|
mcpwm_foc_set_current(0.0);
|
||||||
|
chThdSleepMilliseconds(5);
|
||||||
|
|
||||||
|
float linkage_sum = 0.0;
|
||||||
|
float linkage_samples = 0.0;
|
||||||
|
for (int i = 0;i < 20000;i++) {
|
||||||
|
float rad_s_now = mcpwm_foc_get_rpm_faster() * ((2.0 * M_PI) / 60.0);
|
||||||
|
if (fabsf(mcpwm_foc_get_duty_cycle_now()) < 0.01) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkage_sum += mcpwm_foc_get_vq() / rad_s_now;
|
||||||
|
linkage_samples += 1.0;
|
||||||
|
chThdSleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*undriven_samples = linkage_samples;
|
||||||
|
|
||||||
|
if (linkage_samples > 0) {
|
||||||
|
*linkage_undriven = linkage_sum / linkage_samples;
|
||||||
|
} else {
|
||||||
|
*linkage_undriven = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
@ -1238,13 +1271,23 @@ static void measure_flux_linkage_task(void *arg) {
|
||||||
measure_flux_linkage_arg_t *args = (measure_flux_linkage_arg_t*)arg;
|
measure_flux_linkage_arg_t *args = (measure_flux_linkage_arg_t*)arg;
|
||||||
mc_interface_select_motor_thread(args->motor);
|
mc_interface_select_motor_thread(args->motor);
|
||||||
|
|
||||||
|
float linkage, linkage_undriven, undriven_samples;
|
||||||
|
|
||||||
args->result = conf_general_measure_flux_linkage_openloop(
|
args->result = conf_general_measure_flux_linkage_openloop(
|
||||||
args->current,
|
args->current,
|
||||||
args->duty,
|
args->duty,
|
||||||
args->erpm_per_sec,
|
args->erpm_per_sec,
|
||||||
args->res,
|
args->res,
|
||||||
args->ind,
|
args->ind,
|
||||||
&args->linkage);
|
&linkage,
|
||||||
|
&linkage_undriven,
|
||||||
|
&undriven_samples);
|
||||||
|
|
||||||
|
if (undriven_samples > 60) {
|
||||||
|
args->linkage = linkage_undriven;
|
||||||
|
} else {
|
||||||
|
args->linkage = linkage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -1420,7 +1463,14 @@ int conf_general_detect_apply_all_foc(float max_power_loss,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float lambda = 0.0;
|
float lambda = 0.0;
|
||||||
int res = conf_general_measure_flux_linkage_openloop(i_max / 2.5, 0.3, 1800, r, l, &lambda);
|
float lambda_undriven = 0.0;
|
||||||
|
float lambda_undriven_samples = 0.0;
|
||||||
|
int res = conf_general_measure_flux_linkage_openloop(i_max / 2.5, 0.3, 1800, r, l,
|
||||||
|
&lambda, &lambda_undriven, &lambda_undriven_samples);
|
||||||
|
|
||||||
|
if (lambda_undriven_samples > 60) {
|
||||||
|
lambda = lambda_undriven;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HW_HAS_DUAL_MOTORS
|
#ifdef HW_HAS_DUAL_MOTORS
|
||||||
worker_wait();
|
worker_wait();
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#define FW_VERSION_MAJOR 5
|
#define FW_VERSION_MAJOR 5
|
||||||
#define FW_VERSION_MINOR 00
|
#define FW_VERSION_MINOR 00
|
||||||
// Set to 0 for building a release and iterate during beta test builds
|
// Set to 0 for building a release and iterate during beta test builds
|
||||||
#define FW_TEST_VERSION_NUMBER 3
|
#define FW_TEST_VERSION_NUMBER 4
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@
|
||||||
// Mark3 version of HW60 with power switch and separate NRF UART.
|
// Mark3 version of HW60 with power switch and separate NRF UART.
|
||||||
//#define HW60_IS_MK3
|
//#define HW60_IS_MK3
|
||||||
|
|
||||||
#define HW_SOURCE "hw_60.c"
|
//#define HW_SOURCE "hw_60.c"
|
||||||
#define HW_HEADER "hw_60.h"
|
//#define HW_HEADER "hw_60.h"
|
||||||
|
|
||||||
//#define HW_SOURCE "hw_r2.c"
|
//#define HW_SOURCE "hw_r2.c"
|
||||||
//#define HW_HEADER "hw_r2.h"
|
//#define HW_HEADER "hw_r2.h"
|
||||||
|
@ -121,8 +121,8 @@
|
||||||
//#define HW_SOURCE "hw_binar_v1.c"
|
//#define HW_SOURCE "hw_binar_v1.c"
|
||||||
//#define HW_HEADER "hw_binar_v1.h"
|
//#define HW_HEADER "hw_binar_v1.h"
|
||||||
|
|
||||||
//#define HW_SOURCE "hw_hd.c"
|
#define HW_SOURCE "hw_hd.c"
|
||||||
//#define HW_HEADER "hw_hd.h"
|
#define HW_HEADER "hw_hd.h"
|
||||||
|
|
||||||
//#define HW_SOURCE "hw_a200s_v2.c"
|
//#define HW_SOURCE "hw_a200s_v2.c"
|
||||||
//#define HW_HEADER "hw_a200s_v2.h"
|
//#define HW_HEADER "hw_a200s_v2.h"
|
||||||
|
@ -306,7 +306,8 @@ bool conf_general_measure_flux_linkage(float current, float duty,
|
||||||
float min_erpm, float res, float *linkage);
|
float min_erpm, float res, float *linkage);
|
||||||
uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq);
|
uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq);
|
||||||
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
|
||||||
float erpm_per_sec, float res, float ind, float *linkage);
|
float erpm_per_sec, float res, float ind, float *linkage,
|
||||||
|
float *linkage_undriven, float *undriven_samples);
|
||||||
int conf_general_autodetect_apply_sensors_foc(float current,
|
int conf_general_autodetect_apply_sensors_foc(float current,
|
||||||
bool store_mcconf_on_success, bool send_mcconf_on_success);
|
bool store_mcconf_on_success, bool send_mcconf_on_success);
|
||||||
void conf_general_calc_apply_foc_cc_kp_ki_gain(mc_configuration *mcconf, float tc);
|
void conf_general_calc_apply_foc_cc_kp_ki_gain(mc_configuration *mcconf, float tc);
|
||||||
|
|
19
mcpwm_foc.c
19
mcpwm_foc.c
|
@ -127,6 +127,7 @@ typedef struct {
|
||||||
float m_gamma_now;
|
float m_gamma_now;
|
||||||
bool m_using_encoder;
|
bool m_using_encoder;
|
||||||
float m_speed_est_fast;
|
float m_speed_est_fast;
|
||||||
|
float m_speed_est_faster;
|
||||||
int m_curr_samples;
|
int m_curr_samples;
|
||||||
int m_curr_sum[3];
|
int m_curr_sum[3];
|
||||||
int m_curr_ofs[3];
|
int m_curr_ofs[3];
|
||||||
|
@ -1141,6 +1142,20 @@ float mcpwm_foc_get_rpm(void) {
|
||||||
// return motor_now()->m_speed_est_fast / ((2.0 * M_PI) / 60.0);
|
// return motor_now()->m_speed_est_fast / ((2.0 * M_PI) / 60.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as above, but uses the fast and noisier estimator.
|
||||||
|
*/
|
||||||
|
float mcpwm_foc_get_rpm_fast(void) {
|
||||||
|
return motor_now()->m_speed_est_fast / ((2.0 * M_PI) / 60.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as above, but uses the faster and noisier estimator.
|
||||||
|
*/
|
||||||
|
float mcpwm_foc_get_rpm_faster(void) {
|
||||||
|
return motor_now()->m_speed_est_faster / ((2.0 * M_PI) / 60.0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the motor current. The sign of this value will
|
* Get the motor current. The sign of this value will
|
||||||
* represent whether the motor is drawing (positive) or generating
|
* represent whether the motor is drawing (positive) or generating
|
||||||
|
@ -2686,6 +2701,10 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
|
||||||
|
|
||||||
UTILS_LP_FAST(motor_now->m_speed_est_fast, diff / dt, 0.01);
|
UTILS_LP_FAST(motor_now->m_speed_est_fast, diff / dt, 0.01);
|
||||||
UTILS_NAN_ZERO(motor_now->m_speed_est_fast);
|
UTILS_NAN_ZERO(motor_now->m_speed_est_fast);
|
||||||
|
|
||||||
|
UTILS_LP_FAST(motor_now->m_speed_est_faster, diff / dt, 0.2);
|
||||||
|
UTILS_NAN_ZERO(motor_now->m_speed_est_faster);
|
||||||
|
|
||||||
motor_now->m_phase_before_speed_est = motor_now->m_motor_state.phase;
|
motor_now->m_phase_before_speed_est = motor_now->m_motor_state.phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ float mcpwm_foc_get_pid_pos_now(void);
|
||||||
float mcpwm_foc_get_switching_frequency_now(void);
|
float mcpwm_foc_get_switching_frequency_now(void);
|
||||||
float mcpwm_foc_get_sampling_frequency_now(void);
|
float mcpwm_foc_get_sampling_frequency_now(void);
|
||||||
float mcpwm_foc_get_rpm(void);
|
float mcpwm_foc_get_rpm(void);
|
||||||
|
float mcpwm_foc_get_rpm_fast(void);
|
||||||
|
float mcpwm_foc_get_rpm_faster(void);
|
||||||
float mcpwm_foc_get_tot_current(void);
|
float mcpwm_foc_get_tot_current(void);
|
||||||
float mcpwm_foc_get_tot_current_filtered(void);
|
float mcpwm_foc_get_tot_current_filtered(void);
|
||||||
float mcpwm_foc_get_abs_motor_current(void);
|
float mcpwm_foc_get_abs_motor_current(void);
|
||||||
|
|
12
terminal.c
12
terminal.c
|
@ -469,9 +469,15 @@ void terminal_process_string(char *str) {
|
||||||
|
|
||||||
if (current > 0.0 && current <= mc_interface_get_configuration()->l_current_max &&
|
if (current > 0.0 && current <= mc_interface_get_configuration()->l_current_max &&
|
||||||
erpm_per_sec > 0.0 && duty > 0.02 && res >= 0.0 && ind >= 0.0) {
|
erpm_per_sec > 0.0 && duty > 0.02 && res >= 0.0 && ind >= 0.0) {
|
||||||
float linkage;
|
float linkage, linkage_undriven, undriven_samples;
|
||||||
conf_general_measure_flux_linkage_openloop(current, duty, erpm_per_sec, res, ind, &linkage);
|
commands_printf("Measuring flux linkage...");
|
||||||
commands_printf("Flux linkage: %.7f\n", (double)linkage);
|
conf_general_measure_flux_linkage_openloop(current, duty, erpm_per_sec, res, ind,
|
||||||
|
&linkage, &linkage_undriven, &undriven_samples);
|
||||||
|
commands_printf(
|
||||||
|
"Flux linkage : %.7f\n"
|
||||||
|
"Flux Linkage (undriven) : %.7f\n"
|
||||||
|
"Undriven samples : %.1f\n",
|
||||||
|
(double)linkage, (double)linkage_undriven, (double)undriven_samples);
|
||||||
} else {
|
} else {
|
||||||
commands_printf("Invalid argument(s).\n");
|
commands_printf("Invalid argument(s).\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue