diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index dc04fd2a0e..461101368e 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -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) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 1b8ebeea69..f617d8391a 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -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);