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:
parent
1662e953fc
commit
851257c44b
2 changed files with 28 additions and 15 deletions
|
@ -717,6 +717,9 @@
|
||||||
*/
|
*/
|
||||||
#if ENABLED(MPCTEMP)
|
#if ENABLED(MPCTEMP)
|
||||||
#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~6.3K bytes of flash)
|
#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_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)
|
//#define MPC_AUTOTUNE_MENU // Add MPC auto-tuning to the "Advanced Settings" menu. (~350 bytes of flash)
|
||||||
|
|
||||||
|
|
|
@ -926,8 +926,6 @@ volatile bool Temperature::raw_temps_ready = false;
|
||||||
#define SINGLEFAN 1
|
#define SINGLEFAN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG_MPC_AUTOTUNE 1
|
|
||||||
|
|
||||||
millis_t Temperature::MPC_autotuner::curr_time_ms, Temperature::MPC_autotuner::next_report_ms;
|
millis_t Temperature::MPC_autotuner::curr_time_ms, Temperature::MPC_autotuner::next_report_ms;
|
||||||
|
|
||||||
celsius_float_t Temperature::MPC_autotuner::temp_samples[16];
|
celsius_float_t Temperature::MPC_autotuner::temp_samples[16];
|
||||||
|
@ -983,7 +981,7 @@ volatile bool Temperature::raw_temps_ready = false;
|
||||||
}
|
}
|
||||||
wait_for_heatup = 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("MPC_autotuner::measure_ambient_temp() Completed");
|
||||||
SERIAL_ECHOLNPGM("=====");
|
SERIAL_ECHOLNPGM("=====");
|
||||||
SERIAL_ECHOLNPGM("ambient_temp ", get_ambient_temp());
|
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
|
// Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative
|
||||||
const float h = MS_TO_SEC_PRECISE(test_interval_ms),
|
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) {
|
if (curr_rate > rate_fastest) {
|
||||||
// Update fastest values
|
// Update fastest values
|
||||||
rate_fastest = curr_rate;
|
rate_fastest = curr_rate;
|
||||||
temp_fastest = temp_samples[1];
|
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;
|
next_test_time_ms += test_interval_ms;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (current_temp < 200.0f) {
|
else if (current_temp < 200.0f) {
|
||||||
// Second regime (after 100deg) measure 3 points to determine asymptotic temperature
|
// 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;
|
temp_samples[sample_count++] = current_temp;
|
||||||
|
|
||||||
next_test_time_ms += test_interval_ms * sample_distance;
|
next_test_time_ms += test_interval_ms * sample_distance;
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Third regime (after 200deg) finished gathering data so finish
|
// 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 == 0) return FAILED;
|
||||||
if (sample_count % 2 == 0) sample_count--;
|
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("MPC_autotuner::measure_heatup() Completed");
|
||||||
SERIAL_ECHOLNPGM("=====");
|
SERIAL_ECHOLNPGM("=====");
|
||||||
SERIAL_ECHOLNPGM("t1_time ", t1_time);
|
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);
|
power_fan0 = total_energy_fan0 / MS_TO_SEC_PRECISE(test_duration);
|
||||||
TERN_(HAS_FAN, power_fan255 = (total_energy_fan255 * 1000) / 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("MPC_autotuner::measure_transfer() Completed");
|
||||||
SERIAL_ECHOLNPGM("=====");
|
SERIAL_ECHOLNPGM("=====");
|
||||||
SERIAL_ECHOLNPGM("power_fan0 ", power_fan0);
|
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),
|
float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3),
|
||||||
block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval();
|
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("asymp_temp ", asymp_temp);
|
||||||
SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
|
SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
|
||||||
#endif
|
#endif
|
||||||
|
@ -1235,15 +1231,18 @@ volatile bool Temperature::raw_temps_ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If analytic tuning fails, fall back to differential tuning
|
// If analytic tuning fails, fall back to differential tuning
|
||||||
if (tuning_type == AUTO) {
|
if (tuning_type == AUTO && (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0))
|
||||||
if (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0)
|
|
||||||
tuning_type = FORCE_DIFFERENTIAL;
|
tuning_type = FORCE_DIFFERENTIAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (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
|
// Differential tuning
|
||||||
mpc.block_heat_capacity = mpc.heater_power / tuner.get_rate_fastest();
|
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());
|
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;
|
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();
|
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("Refining estimates for:");
|
||||||
SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
|
SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp);
|
||||||
SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4));
|
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.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));
|
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);
|
SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED);
|
||||||
|
|
Loading…
Reference in a new issue