0
0
Fork 0
mirror of https://github.com/MarlinFirmware/Marlin.git synced 2025-01-22 17:52:57 +00:00

🐛 Fix MPC differential tuning (#27274)

This commit is contained in:
tombrazier 2024-08-05 23:44:15 +01:00 committed by GitHub
parent 1662e953fc
commit 851257c44b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 15 deletions

View file

@ -717,6 +717,9 @@
*/
#if ENABLED(MPCTEMP)
#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~6.3K bytes of flash)
#if ENABLED(MPC_AUTOTUNE)
//#define MPC_AUTOTUNE_DEBUG // Enable MPC debug logging (~870 bytes of flash)
#endif
//#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1.3K bytes of flash)
//#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash)

View file

@ -926,8 +926,6 @@ volatile bool Temperature::raw_temps_ready = false;
#define SINGLEFAN 1
#endif
#define DEBUG_MPC_AUTOTUNE 1
millis_t Temperature::MPC_autotuner::curr_time_ms, Temperature::MPC_autotuner::next_report_ms;
celsius_float_t Temperature::MPC_autotuner::temp_samples[16];
@ -983,7 +981,7 @@ volatile bool Temperature::raw_temps_ready = false;
}
wait_for_heatup = false;
#if ENABLED(DEBUG_MPC_AUTOTUNE)
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("MPC_autotuner::measure_ambient_temp() Completed");
SERIAL_ECHOLNPGM("=====");
SERIAL_ECHOLNPGM("ambient_temp ", get_ambient_temp());
@ -1026,16 +1024,15 @@ volatile bool Temperature::raw_temps_ready = false;
// Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative
const float h = MS_TO_SEC_PRECISE(test_interval_ms),
curr_rate = (temp_samples[2] - temp_samples[0]) / 2 * h;
curr_rate = (temp_samples[2] - temp_samples[0]) / 2 / h;
if (curr_rate > rate_fastest) {
// Update fastest values
rate_fastest = curr_rate;
temp_fastest = temp_samples[1];
time_fastest = get_elapsed_heating_time();
time_fastest = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms - h);
}
next_test_time_ms += test_interval_ms;
}
else if (current_temp < 200.0f) {
// Second regime (after 100deg) measure 3 points to determine asymptotic temperature
@ -1052,7 +1049,6 @@ volatile bool Temperature::raw_temps_ready = false;
temp_samples[sample_count++] = current_temp;
next_test_time_ms += test_interval_ms * sample_distance;
}
else {
// Third regime (after 200deg) finished gathering data so finish
@ -1070,7 +1066,7 @@ volatile bool Temperature::raw_temps_ready = false;
if (sample_count == 0) return FAILED;
if (sample_count % 2 == 0) sample_count--;
#if ENABLED(DEBUG_MPC_AUTOTUNE)
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("MPC_autotuner::measure_heatup() Completed");
SERIAL_ECHOLNPGM("=====");
SERIAL_ECHOLNPGM("t1_time ", t1_time);
@ -1140,7 +1136,7 @@ volatile bool Temperature::raw_temps_ready = false;
power_fan0 = total_energy_fan0 / MS_TO_SEC_PRECISE(test_duration);
TERN_(HAS_FAN, power_fan255 = (total_energy_fan255 * 1000) / test_duration);
#if ENABLED(DEBUG_MPC_AUTOTUNE)
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("MPC_autotuner::measure_transfer() Completed");
SERIAL_ECHOLNPGM("=====");
SERIAL_ECHOLNPGM("power_fan0 ", power_fan0);
@ -1219,7 +1215,7 @@ volatile bool Temperature::raw_temps_ready = false;
float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3),
block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval();
#if ENABLED(DEBUG_MPC_AUTOTUNE)
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
#endif
@ -1235,15 +1231,18 @@ volatile bool Temperature::raw_temps_ready = false;
}
// If analytic tuning fails, fall back to differential tuning
if (tuning_type == AUTO) {
if (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0)
if (tuning_type == AUTO && (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0))
tuning_type = FORCE_DIFFERENTIAL;
}
if (tuning_type == FORCE_DIFFERENTIAL) {
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("rate_fastest ", tuner.get_rate_fastest());
SERIAL_ECHOLNPGM("time_fastest ", tuner.get_time_fastest());
SERIAL_ECHOLNPGM("temp_fastest ", tuner.get_temp_fastest());
#endif
// Differential tuning
mpc.block_heat_capacity = mpc.heater_power / tuner.get_rate_fastest();
mpc.sensor_responsiveness = tuner.get_rate_fastest() / (tuner.get_rate_fastest() * tuner.get_time_fastest() + tuner.get_ambient_temp() - tuner.get_time_fastest());
mpc.sensor_responsiveness = tuner.get_rate_fastest() / (tuner.get_rate_fastest() * tuner.get_time_fastest() + tuner.get_ambient_temp() - tuner.get_temp_fastest());
}
hotend.modeled_block_temp = asymp_temp + (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_elapsed_heating_time());
@ -1269,7 +1268,7 @@ volatile bool Temperature::raw_temps_ready = false;
asymp_temp = tuner.get_ambient_temp() + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0;
block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval();
#if ENABLED(DEBUG_MPC_AUTOTUNE)
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("Refining estimates for:");
SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
@ -1279,6 +1278,17 @@ volatile bool Temperature::raw_temps_ready = false;
mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness;
mpc.sensor_responsiveness = block_responsiveness / (1.0f - (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_sample_1_time()) / (t1 - asymp_temp));
// Check again: If analytic tuning fails, fall back to differential tuning
if (tuning_type == AUTO && (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0)) {
#if ENABLED(MPC_AUTOTUNE_DEBUG)
SERIAL_ECHOLNPGM("rate_fastest ", tuner.get_rate_fastest());
SERIAL_ECHOLNPGM("time_fastest ", tuner.get_time_fastest());
SERIAL_ECHOLNPGM("temp_fastest ", tuner.get_temp_fastest());
#endif
tuning_type = FORCE_DIFFERENTIAL;
mpc.block_heat_capacity = mpc.heater_power / tuner.get_rate_fastest();
mpc.sensor_responsiveness = tuner.get_rate_fastest() / (tuner.get_rate_fastest() * tuner.get_time_fastest() + tuner.get_ambient_temp() - tuner.get_temp_fastest());
}
}
SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED);