From b02eb11e158272ab26327e4918d2c1fed6d016fc Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Thu, 9 Mar 2023 21:12:00 +0000 Subject: [PATCH 01/43] Added variable to control how often to test temperature during ambient temperature detection --- Marlin/src/module/temperature.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index b5726902561b..a90f90e796d2 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1006,7 +1006,8 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; + const millis_t ambient_test_interval_ms = 10000UL; + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + ambient_test_interval_ms; celsius_float_t current_temp = degHotend(e), ambient_temp = current_temp; @@ -1020,7 +1021,7 @@ volatile bool Temperature::raw_temps_ready = false; break; } ambient_temp = current_temp; - next_test_ms += 10000UL; + next_test_ms += ambient_test_interval_ms; } } wait_for_heatup = false; From f9ed41a832a094ed2749e6d06c2ec74c1c12cc91 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Thu, 9 Mar 2023 21:12:41 +0000 Subject: [PATCH 02/43] Added a varliable to control how quickly the temperature is checked during heating --- Marlin/src/module/temperature.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index a90f90e796d2..5d5a8cbb44df 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1037,6 +1037,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); hotend.target = 200.0f; // So M105 looks nice hotend.soft_pwm_amount = (MPC_MAX) >> 1; + const millis_t heat_test_tick_interval_ms = 1000UL; const millis_t heat_start_time = next_test_ms = ms; celsius_float_t temp_samples[16]; uint8_t sample_count = 0; @@ -1058,13 +1059,13 @@ volatile bool Temperature::raw_temps_ready = false; sample_distance *= 2; } - if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; + if (sample_count == 0) t1_time = float(ms - heat_start_time) / heat_test_tick_interval_ms; temp_samples[sample_count++] = current_temp; } if (current_temp >= 200.0f) break; - next_test_ms += 1000UL * sample_distance; + next_test_ms += heat_test_tick_interval_ms * sample_distance; } } wait_for_heatup = false; @@ -1076,8 +1077,9 @@ volatile bool Temperature::raw_temps_ready = false; const float t1 = temp_samples[0], t2 = temp_samples[(sample_count - 1) >> 1], t3 = temp_samples[sample_count - 1]; + const float heat_test_tick_interval_sec = heat_test_tick_interval_ms * 1000.0f; float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval_sec * (sample_count >> 1)); mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); mpc.fan255_adjustment = 0.0f; @@ -1147,7 +1149,7 @@ volatile bool Temperature::raw_temps_ready = false; // Calculate a new and better asymptotic temperature and re-evaluate the other constants asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval_sec * (sample_count >> 1)); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); From 2b33f1ff66a07a9ffeda806ceaab89255d7ca991 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Thu, 9 Mar 2023 21:19:38 +0000 Subject: [PATCH 03/43] Fixed previous commit --- Marlin/src/module/temperature.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 5d5a8cbb44df..4bb42a3f0bd1 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1037,7 +1037,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); hotend.target = 200.0f; // So M105 looks nice hotend.soft_pwm_amount = (MPC_MAX) >> 1; - const millis_t heat_test_tick_interval_ms = 1000UL; + const float heat_test_tick_interval = 1.0f; // Time (secs) between tests of temperature const millis_t heat_start_time = next_test_ms = ms; celsius_float_t temp_samples[16]; uint8_t sample_count = 0; @@ -1059,13 +1059,14 @@ volatile bool Temperature::raw_temps_ready = false; sample_distance *= 2; } - if (sample_count == 0) t1_time = float(ms - heat_start_time) / heat_test_tick_interval_ms; + if (sample_count == 0) + t1_time = float(ms - heat_start_time) / (heat_test_tick_interval * 1000UL); temp_samples[sample_count++] = current_temp; } if (current_temp >= 200.0f) break; - next_test_ms += heat_test_tick_interval_ms * sample_distance; + next_test_ms += heat_test_tick_interval * sample_distance; } } wait_for_heatup = false; @@ -1077,9 +1078,8 @@ volatile bool Temperature::raw_temps_ready = false; const float t1 = temp_samples[0], t2 = temp_samples[(sample_count - 1) >> 1], t3 = temp_samples[sample_count - 1]; - const float heat_test_tick_interval_sec = heat_test_tick_interval_ms * 1000.0f; float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval_sec * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval * (sample_count >> 1)); mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); mpc.fan255_adjustment = 0.0f; From eef587ab2e5a08080225e25fd21d7e0dbe83ee9d Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Thu, 9 Mar 2023 21:25:25 +0000 Subject: [PATCH 04/43] Renamed sample_distance to ticks_per_sample --- Marlin/src/module/temperature.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 4bb42a3f0bd1..2712b38e702b 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1041,7 +1041,7 @@ volatile bool Temperature::raw_temps_ready = false; const millis_t heat_start_time = next_test_ms = ms; celsius_float_t temp_samples[16]; uint8_t sample_count = 0; - uint16_t sample_distance = 1; + uint16_t ticks_per_sample = 1; float t1_time = 0; wait_for_heatup = true; @@ -1056,7 +1056,7 @@ volatile bool Temperature::raw_temps_ready = false; for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) temp_samples[i] = temp_samples[i*2]; sample_count /= 2; - sample_distance *= 2; + ticks_per_sample *= 2; } if (sample_count == 0) @@ -1066,7 +1066,7 @@ volatile bool Temperature::raw_temps_ready = false; if (current_temp >= 200.0f) break; - next_test_ms += heat_test_tick_interval * sample_distance; + next_test_ms += heat_test_tick_interval * ticks_per_sample; } } wait_for_heatup = false; @@ -1079,7 +1079,7 @@ volatile bool Temperature::raw_temps_ready = false; t2 = temp_samples[(sample_count - 1) >> 1], t3 = temp_samples[sample_count - 1]; float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval * (sample_count >> 1)); mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); mpc.fan255_adjustment = 0.0f; @@ -1149,7 +1149,7 @@ volatile bool Temperature::raw_temps_ready = false; // Calculate a new and better asymptotic temperature and re-evaluate the other constants asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * heat_test_tick_interval_sec * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval_sec * (sample_count >> 1)); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); @@ -1160,7 +1160,7 @@ volatile bool Temperature::raw_temps_ready = false; #if 0 SERIAL_ECHOLNPGM("t1_time ", t1_time); SERIAL_ECHOLNPGM("sample_count ", sample_count); - SERIAL_ECHOLNPGM("sample_distance ", sample_distance); + SERIAL_ECHOLNPGM("ticks_per_sample ", ticks_per_sample); for (uint8_t i = 0; i < sample_count; i++) SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); From c7215f645a34163bc5c013f1cc16eed147f43a38 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Thu, 9 Mar 2023 21:29:50 +0000 Subject: [PATCH 05/43] Clarified the logic for making sample_count odd --- Marlin/src/module/temperature.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 2712b38e702b..15f11db6c674 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1074,7 +1074,8 @@ volatile bool Temperature::raw_temps_ready = false; hotend.soft_pwm_amount = 0; // Calculate physical constants from three equally-spaced samples - sample_count = (sample_count + 1) / 2 * 2 - 1; + // Sample count must be odd to ensure we have an exact "middle" sample between t1 and t3 + if (sample_count%2 == 0) sample_count--; const float t1 = temp_samples[0], t2 = temp_samples[(sample_count - 1) >> 1], t3 = temp_samples[sample_count - 1]; From 32b8196348b728c7ed361db833b29fb25ea4e932 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 9 Mar 2023 18:05:07 -0600 Subject: [PATCH 06/43] fix heat_test_tick_interval --- Marlin/src/module/temperature.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 15f11db6c674..291182024f64 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1037,7 +1037,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); hotend.target = 200.0f; // So M105 looks nice hotend.soft_pwm_amount = (MPC_MAX) >> 1; - const float heat_test_tick_interval = 1.0f; // Time (secs) between tests of temperature + constexpr float heat_test_interval_s = 1.0f; // Time (secs) between tests of temperature const millis_t heat_start_time = next_test_ms = ms; celsius_float_t temp_samples[16]; uint8_t sample_count = 0; @@ -1060,27 +1060,29 @@ volatile bool Temperature::raw_temps_ready = false; } if (sample_count == 0) - t1_time = float(ms - heat_start_time) / (heat_test_tick_interval * 1000UL); + t1_time = float(ms - heat_start_time) / (heat_test_interval_s * 1000UL); temp_samples[sample_count++] = current_temp; } if (current_temp >= 200.0f) break; - next_test_ms += heat_test_tick_interval * ticks_per_sample; + next_test_ms += heat_test_interval_s * ticks_per_sample; } } wait_for_heatup = false; hotend.soft_pwm_amount = 0; + //if (sample_count < 2) return; + // Calculate physical constants from three equally-spaced samples // Sample count must be odd to ensure we have an exact "middle" sample between t1 and t3 - if (sample_count%2 == 0) sample_count--; + if (!(sample_count & 0x01)) sample_count--; const float t1 = temp_samples[0], t2 = temp_samples[(sample_count - 1) >> 1], t3 = temp_samples[sample_count - 1]; float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_interval_s * (sample_count >> 1)); mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); mpc.fan255_adjustment = 0.0f; @@ -1150,7 +1152,7 @@ volatile bool Temperature::raw_temps_ready = false; // Calculate a new and better asymptotic temperature and re-evaluate the other constants asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval_sec * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_interval_s * (sample_count >> 1)); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); From 84d98a8cf2c767d5de7a9b9dc46ee54491b04fde Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Fri, 10 Mar 2023 08:34:39 +0000 Subject: [PATCH 07/43] Fixed previous commit --- Marlin/src/module/temperature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 15f11db6c674..1d209db8b495 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1150,7 +1150,7 @@ volatile bool Temperature::raw_temps_ready = false; // Calculate a new and better asymptotic temperature and re-evaluate the other constants asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval_sec * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (ticks_per_sample * heat_test_tick_interval * (sample_count >> 1)); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); From b6dca2bccd38ac176ca9143db463c480515d46f8 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Sat, 11 Mar 2023 17:03:49 +0000 Subject: [PATCH 08/43] Moving tuning logic into utility class --- Marlin/src/module/temperature.cpp | 58 ++++++++++++++++--------------- Marlin/src/module/temperature.h | 11 ++++++ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index b5726902561b..912c70d98e66 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -931,8 +931,29 @@ volatile bool Temperature::raw_temps_ready = false; #define SINGLEFAN 1 #endif - void Temperature::MPC_autotune(const uint8_t e) { - auto housekeeping = [] (millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms) { + Temperature::MPC_autotuner::MPC_autotuner(const uint8_t extruderIdx) : e(extruderIdx) + { + TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); + } + + Temperature::MPC_autotuner::~MPC_autotuner() { + wait_for_heatup = false; + + ui.reset_status(); + + temp_hotend[e].target = 0.0f; + temp_hotend[e].soft_pwm_amount = 0; + #if HAS_FAN + set_fan_speed(TERN(SINGLEFAN, 0, e), 0); + planner.sync_fan_speeds(fan_speed); + #endif + + do_z_clearance(MPC_TUNING_END_Z); + + TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); + } + + bool Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms) { ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready @@ -960,34 +981,15 @@ volatile bool Temperature::raw_temps_ready = false; return false; }; - struct OnExit { - uint8_t e; - OnExit(const uint8_t _e) { this->e = _e; } - ~OnExit() { - wait_for_heatup = false; - - ui.reset_status(); - - temp_hotend[e].target = 0.0f; - temp_hotend[e].soft_pwm_amount = 0; - #if HAS_FAN - set_fan_speed(TERN(SINGLEFAN, 0, e), 0); - planner.sync_fan_speeds(fan_speed); - #endif - - do_z_clearance(MPC_TUNING_END_Z); - - TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); - } - } on_exit(e); - + void Temperature::MPC_autotune(const uint8_t e) { SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); + + MPC_autotuner autotuner(e); + MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; - TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); - // Move to center of bed, just above bed height and cool with max fan gcode.home_all_axes(true); disable_all_heaters(); @@ -1012,7 +1014,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; + if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; if (ELAPSED(ms, next_test_ms)) { if (current_temp >= ambient_temp) { @@ -1044,7 +1046,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; + if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; if (ELAPSED(ms, next_test_ms)) { // Record samples between 100C and 200C @@ -1103,7 +1105,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; + if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; if (ELAPSED(ms, next_test_ms)) { hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index b7f388cbb6e4..680ff7094405 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1195,6 +1195,17 @@ class Temperature { #endif #if ENABLED(MPCTEMP) + // Utility class that contains the business logic for auto tuning MPCTEMP + class MPC_autotuner{ + public: + MPC_autotuner(const uint8_t extruderIdx); + ~MPC_autotuner(); + // TODO: This can be protected once the bulk of logic is in this class + bool housekeeping(millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms); + private: + uint8_t e; + }; + void MPC_autotune(const uint8_t e); #endif From a66684712a5dd64c697b51b9ce2233ba3a1b0268 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Sat, 11 Mar 2023 18:09:32 +0000 Subject: [PATCH 09/43] Extracted Ambient and Heatup measurement --- Marlin/src/module/temperature.cpp | 165 +++++++++++++++++------------- Marlin/src/module/temperature.h | 23 ++++- 2 files changed, 117 insertions(+), 71 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 912c70d98e66..0a2ed2846102 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -953,7 +953,80 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); } - bool Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms) { + bool Temperature::MPC_autotuner::determineAmbientTemperature() { + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; + ambient_temp = current_temp; + + current_temp = degHotend(e); + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, next_report_ms)) return false; + + if (ELAPSED(ms, next_test_ms)) { + if (current_temp >= ambient_temp) { + ambient_temp = (ambient_temp + current_temp) / 2.0f; + break; + } + ambient_temp = current_temp; + next_test_ms += 10000UL; + } + } + wait_for_heatup = false; + + return true; + } + + bool Temperature::MPC_autotuner::measureHeatup() { + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 1000UL; + MPCHeaterInfo &hotend = temp_hotend[e]; + + current_temp = degHotend(e); + millis_t heat_start_time = ms; + sample_count = 0; + sample_distance = 1; + t1_time = 0; + + hotend.target = 200.0f; // So M105 looks nice + hotend.soft_pwm_amount = (MPC_MAX) >> 1; + + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, next_report_ms)) return false; + + if (ELAPSED(ms, next_test_ms)) { + // Record samples between 100C and 200C + if (current_temp >= 100.0f) { + // If there are too many samples, space them more widely + if (sample_count == COUNT(temp_samples)) { + for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) + temp_samples[i] = temp_samples[i*2]; + sample_count /= 2; + sample_distance *= 2; + } + + if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; + temp_samples[sample_count++] = current_temp; + } + + if (current_temp >= 200.0f) break; + + next_test_ms += 1000UL * sample_distance; + } + } + wait_for_heatup = false; + + hotend.soft_pwm_amount = 0; + + elapsed_heating_time = float(ms - heat_start_time) / 1000.0f; + + // Ensure sample count is odd so that we have 3 equally spaced samples + if (sample_count%2 == 0) + sample_count--; + + return true; + } + + bool Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready @@ -1000,6 +1073,7 @@ volatile bool Temperature::raw_temps_ready = false; #endif do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS)); + // Determine ambient temperature. SERIAL_ECHOLNPGM(STR_MPC_COOLING_TO_AMBIENT); #if ENABLED(DWIN_LCD_PROUI) DWIN_MPCTuning(MPCTEMP_START); @@ -1008,91 +1082,42 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; - celsius_float_t current_temp = degHotend(e), - ambient_temp = current_temp; - - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - if (current_temp >= ambient_temp) { - ambient_temp = (ambient_temp + current_temp) / 2.0f; - break; - } - ambient_temp = current_temp; - next_test_ms += 10000UL; - } - } - wait_for_heatup = false; + if (!autotuner.determineAmbientTemperature()) return; + hotend.modeled_ambient_temp = autotuner.get_ambient_temp(); #if HAS_FAN set_fan_speed(TERN(SINGLEFAN, 0, e), 0); planner.sync_fan_speeds(fan_speed); #endif - hotend.modeled_ambient_temp = ambient_temp; - + // Heat to 200 degrees SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); - hotend.target = 200.0f; // So M105 looks nice - hotend.soft_pwm_amount = (MPC_MAX) >> 1; - const millis_t heat_start_time = next_test_ms = ms; - celsius_float_t temp_samples[16]; - uint8_t sample_count = 0; - uint16_t sample_distance = 1; - float t1_time = 0; - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - // Record samples between 100C and 200C - if (current_temp >= 100.0f) { - // If there are too many samples, space them more widely - if (sample_count == COUNT(temp_samples)) { - for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) - temp_samples[i] = temp_samples[i*2]; - sample_count /= 2; - sample_distance *= 2; - } - - if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; - temp_samples[sample_count++] = current_temp; - } - - if (current_temp >= 200.0f) break; - - next_test_ms += 1000UL * sample_distance; - } - } - wait_for_heatup = false; - - hotend.soft_pwm_amount = 0; + if (!autotuner.measureHeatup()) return; // Calculate physical constants from three equally-spaced samples - sample_count = (sample_count + 1) / 2 * 2 - 1; - const float t1 = temp_samples[0], - t2 = temp_samples[(sample_count - 1) >> 1], - t3 = temp_samples[sample_count - 1]; + const float t1 = autotuner.sample_1_temp(), + t2 = autotuner.sample_2_temp(), + t3 = autotuner.sample_3_temp(); float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / autotuner.sample_interval(); - mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); + mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - autotuner.get_ambient_temp()); mpc.fan255_adjustment = 0.0f; mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.sample_1_time()) / (t1 - asymp_temp)); - hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); - hotend.modeled_sensor_temp = current_temp; + hotend.modeled_block_temp = asymp_temp + (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.get_elapsed_heating_time()); + hotend.modeled_sensor_temp = autotuner.last_sampled_temp(); // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_MEASURING_AMBIENT), LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT)); + +// extract this fn! + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + MPC_dT * 1000; hotend.target = hotend.modeled_block_temp; - next_test_ms = ms + MPC_dT * 1000; constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; millis_t settle_end_ms = ms + settle_time, test_end_ms = settle_end_ms + test_duration; @@ -1138,19 +1163,19 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = false; const float power_fan0 = total_energy_fan0 * 1000 / test_duration; - mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); + mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - autotuner.get_ambient_temp()); #if HAS_FAN const float power_fan255 = total_energy_fan255 * 1000 / test_duration, - ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); + ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - autotuner.get_ambient_temp()); mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); #endif // Calculate a new and better asymptotic temperature and re-evaluate the other constants - asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + asymp_temp = autotuner.get_ambient_temp() + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / autotuner.sample_interval(); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.sample_1_time()) / (t1 - asymp_temp)); SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 680ff7094405..ac0b584e95fc 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1200,10 +1200,31 @@ class Temperature { public: MPC_autotuner(const uint8_t extruderIdx); ~MPC_autotuner(); + bool determineAmbientTemperature(); + bool measureHeatup(); // TODO: This can be protected once the bulk of logic is in this class - bool housekeeping(millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms); + bool housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); + + celsius_float_t get_ambient_temp() { return ambient_temp; } + celsius_float_t last_sampled_temp() { return current_temp; } + + float get_elapsed_heating_time() { return elapsed_heating_time; } + float sample_1_time() { return t1_time; } + float sample_1_temp() { return temp_samples[0]; } + float sample_2_temp() { return temp_samples[(sample_count - 1) >> 1]; } + float sample_3_temp() { return temp_samples[sample_count - 1]; } + float sample_interval() { return sample_distance * (sample_count >> 1); } + private: uint8_t e; + + float elapsed_heating_time; + celsius_float_t ambient_temp; + celsius_float_t current_temp; + celsius_float_t temp_samples[16]; + uint8_t sample_count; + uint16_t sample_distance; + float t1_time; }; void MPC_autotune(const uint8_t e); From e02836837d8a9a812eade722b28524a9e20c4e6e Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 09:15:04 +0000 Subject: [PATCH 10/43] renamed variable --- Marlin/src/module/temperature.cpp | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 0a2ed2846102..54f79d2bbf89 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1058,7 +1058,7 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); - MPC_autotuner autotuner(e); + MPC_autotuner tuner(e); MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; @@ -1082,8 +1082,8 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - if (!autotuner.determineAmbientTemperature()) return; - hotend.modeled_ambient_temp = autotuner.get_ambient_temp(); + if (!tuner.determineAmbientTemperature()) return; + hotend.modeled_ambient_temp = tuner.get_ambient_temp(); #if HAS_FAN set_fan_speed(TERN(SINGLEFAN, 0, e), 0); @@ -1094,22 +1094,22 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); - if (!autotuner.measureHeatup()) return; + if (!tuner.measureHeatup()) return; // Calculate physical constants from three equally-spaced samples - const float t1 = autotuner.sample_1_temp(), - t2 = autotuner.sample_2_temp(), - t3 = autotuner.sample_3_temp(); + const float t1 = tuner.sample_1_temp(), + t2 = tuner.sample_2_temp(), + t3 = tuner.sample_3_temp(); float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / autotuner.sample_interval(); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.sample_interval(); - mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - autotuner.get_ambient_temp()); + mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - tuner.get_ambient_temp()); mpc.fan255_adjustment = 0.0f; mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.sample_1_time()) / (t1 - asymp_temp)); + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.sample_1_time()) / (t1 - asymp_temp)); - hotend.modeled_block_temp = asymp_temp + (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.get_elapsed_heating_time()); - hotend.modeled_sensor_temp = autotuner.last_sampled_temp(); + hotend.modeled_block_temp = asymp_temp + (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_elapsed_heating_time()); + hotend.modeled_sensor_temp = tuner.last_sampled_temp(); // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); @@ -1130,7 +1130,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (autotuner.housekeeping(ms, e, current_temp, next_report_ms)) return; + if (tuner.housekeeping(ms, e, current_temp, next_report_ms)) return; if (ELAPSED(ms, next_test_ms)) { hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; @@ -1163,19 +1163,19 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = false; const float power_fan0 = total_energy_fan0 * 1000 / test_duration; - mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - autotuner.get_ambient_temp()); + mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - tuner.get_ambient_temp()); #if HAS_FAN const float power_fan255 = total_energy_fan255 * 1000 / test_duration, - ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - autotuner.get_ambient_temp()); + ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - tuner.get_ambient_temp()); mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); #endif // Calculate a new and better asymptotic temperature and re-evaluate the other constants - asymp_temp = autotuner.get_ambient_temp() + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / autotuner.sample_interval(); + 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.sample_interval(); mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (autotuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * autotuner.sample_1_time()) / (t1 - asymp_temp)); + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.sample_1_time()) / (t1 - asymp_temp)); SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); From 1b6be8856ce07c7a763a9947b595bde5e8a6a851 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 09:17:09 +0000 Subject: [PATCH 11/43] renamed function --- Marlin/src/module/temperature.cpp | 4 ++-- Marlin/src/module/temperature.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 54f79d2bbf89..53e3a0555dc0 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -953,7 +953,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); } - bool Temperature::MPC_autotuner::determineAmbientTemperature() { + bool Temperature::MPC_autotuner::measureAmbientTemperature() { millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; ambient_temp = current_temp; @@ -1082,7 +1082,7 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - if (!tuner.determineAmbientTemperature()) return; + if (!tuner.measureAmbientTemperature()) return; hotend.modeled_ambient_temp = tuner.get_ambient_temp(); #if HAS_FAN diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index ac0b584e95fc..068770be635a 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1200,7 +1200,7 @@ class Temperature { public: MPC_autotuner(const uint8_t extruderIdx); ~MPC_autotuner(); - bool determineAmbientTemperature(); + bool measureAmbientTemperature(); bool measureHeatup(); // TODO: This can be protected once the bulk of logic is in this class bool housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); From 9158f3afc7d44998618364c5c8850f0b2b207b8c Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 09:27:10 +0000 Subject: [PATCH 12/43] Added return enum to self-document result --- Marlin/src/module/temperature.cpp | 22 +++++++++++----------- Marlin/src/module/temperature.h | 10 +++++++--- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 53e3a0555dc0..4df49bbc9d90 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -953,14 +953,14 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); } - bool Temperature::MPC_autotuner::measureAmbientTemperature() { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measureAmbientTemperature() { millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; ambient_temp = current_temp; current_temp = degHotend(e); wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms)) return false; + if (housekeeping(ms, e, next_report_ms)) return MeasurementState::CANCELLED; if (ELAPSED(ms, next_test_ms)) { if (current_temp >= ambient_temp) { @@ -973,10 +973,10 @@ volatile bool Temperature::raw_temps_ready = false; } wait_for_heatup = false; - return true; + return MeasurementState::SUCCESS; } - bool Temperature::MPC_autotuner::measureHeatup() { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measureHeatup() { millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 1000UL; MPCHeaterInfo &hotend = temp_hotend[e]; @@ -991,7 +991,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms)) return false; + if (housekeeping(ms, e, next_report_ms)) return MeasurementState::CANCELLED; if (ELAPSED(ms, next_test_ms)) { // Record samples between 100C and 200C @@ -1023,10 +1023,10 @@ volatile bool Temperature::raw_temps_ready = false; if (sample_count%2 == 0) sample_count--; - return true; + return MeasurementState::SUCCESS; } - bool Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready @@ -1048,10 +1048,10 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_INTERRUPTED); TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_INTERRUPTED)); - return true; + return MeasurementState::CANCELLED; } - return false; + return MeasurementState::SUCCESS; }; void Temperature::MPC_autotune(const uint8_t e) { @@ -1082,7 +1082,7 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - if (!tuner.measureAmbientTemperature()) return; + if (tuner.measureAmbientTemperature() != MPC_autotuner::MeasurementState::SUCCESS) return; hotend.modeled_ambient_temp = tuner.get_ambient_temp(); #if HAS_FAN @@ -1094,7 +1094,7 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); - if (!tuner.measureHeatup()) return; + if (tuner.measureHeatup() != MPC_autotuner::MeasurementState::SUCCESS) return; // Calculate physical constants from three equally-spaced samples const float t1 = tuner.sample_1_temp(), diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 068770be635a..b8424741600d 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1198,12 +1198,16 @@ class Temperature { // Utility class that contains the business logic for auto tuning MPCTEMP class MPC_autotuner{ public: + enum MeasurementState { + CANCELLED, + SUCCESS + }; MPC_autotuner(const uint8_t extruderIdx); ~MPC_autotuner(); - bool measureAmbientTemperature(); - bool measureHeatup(); + MeasurementState measureAmbientTemperature(); + MeasurementState measureHeatup(); // TODO: This can be protected once the bulk of logic is in this class - bool housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); + MeasurementState housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); celsius_float_t get_ambient_temp() { return ambient_temp; } celsius_float_t last_sampled_temp() { return current_temp; } From 0ef902d83115934469c44b5a0ab114e25451f247 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 09:56:51 +0000 Subject: [PATCH 13/43] Updated return value checks --- Marlin/src/module/temperature.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 4df49bbc9d90..95fbc4350088 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -960,7 +960,7 @@ volatile bool Temperature::raw_temps_ready = false; current_temp = degHotend(e); wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms)) return MeasurementState::CANCELLED; + if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { if (current_temp >= ambient_temp) { @@ -973,7 +973,7 @@ volatile bool Temperature::raw_temps_ready = false; } wait_for_heatup = false; - return MeasurementState::SUCCESS; + return SUCCESS; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measureHeatup() { @@ -991,7 +991,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms)) return MeasurementState::CANCELLED; + if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { // Record samples between 100C and 200C @@ -1023,7 +1023,7 @@ volatile bool Temperature::raw_temps_ready = false; if (sample_count%2 == 0) sample_count--; - return MeasurementState::SUCCESS; + return SUCCESS; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { From 4bfaaf7756fad592e8c61724dee922477cfaaf6b Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:06:43 +0000 Subject: [PATCH 14/43] Implemented heat transfer coefficient calcs --- Marlin/src/module/temperature.cpp | 112 +++++++++++++++++------------- Marlin/src/module/temperature.h | 11 +++ 2 files changed, 74 insertions(+), 49 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 95fbc4350088..a73d1c34a3d0 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1026,6 +1026,65 @@ volatile bool Temperature::raw_temps_ready = false; return SUCCESS; } + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + MPC_dT * 1000; + MPCHeaterInfo &hotend = temp_hotend[e]; + MPC_t &mpc = hotend.mpc; + + constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; + millis_t settle_end_ms = ms + settle_time, + test_end_ms = settle_end_ms + test_duration; + float total_energy_fan0 = 0.0f; + #if HAS_FAN + bool fan0_done = false; + float total_energy_fan255 = 0.0f; + #endif + float last_temp = current_temp; + + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; + + if (ELAPSED(ms, next_test_ms)) { + hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; + + if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) + total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; + #if HAS_FAN + else if (ELAPSED(ms, test_end_ms) && !fan0_done) { + set_fan_speed(TERN(SINGLEFAN, 0, e), 255); + planner.sync_fan_speeds(fan_speed); + settle_end_ms = ms + settle_time; + test_end_ms = settle_end_ms + test_duration; + fan0_done = true; + } + else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) + total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; + #endif + else if (ELAPSED(ms, test_end_ms)) break; + + last_temp = current_temp; + next_test_ms += MPC_dT * 1000; + } + + // Ensure we don't drift too far from the window between the last sampled temp and the target temperature + if (!WITHIN(current_temp, sample_3_temp() - 15.0f, hotend.target + 15.0f)) { + SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); + TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); + wait_for_heatup = false; + return CANCELLED; + } + } + wait_for_heatup = false; + + power_fan0 = total_energy_fan0 * 1000 / test_duration; + #if HAS_FAN + power_fan255 = total_energy_fan255 * 1000 / test_duration; + #endif + + return SUCCESS; + } + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { ms = millis(); @@ -1115,59 +1174,14 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_MEASURING_AMBIENT), LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT)); -// extract this fn! - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + MPC_dT * 1000; + // Use the estimated overshoot of the temperature as the target to achieve. hotend.target = hotend.modeled_block_temp; - constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; - millis_t settle_end_ms = ms + settle_time, - test_end_ms = settle_end_ms + test_duration; - float total_energy_fan0 = 0.0f; - #if HAS_FAN - bool fan0_done = false; - float total_energy_fan255 = 0.0f; - #endif - float last_temp = current_temp; - - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (tuner.housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; - - if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) - total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; - #if HAS_FAN - else if (ELAPSED(ms, test_end_ms) && !fan0_done) { - set_fan_speed(TERN(SINGLEFAN, 0, e), 255); - planner.sync_fan_speeds(fan_speed); - settle_end_ms = ms + settle_time; - test_end_ms = settle_end_ms + test_duration; - fan0_done = true; - } - else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) - total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; - #endif - else if (ELAPSED(ms, test_end_ms)) break; - - last_temp = current_temp; - next_test_ms += MPC_dT * 1000; - } - - if (!WITHIN(current_temp, t3 - 15.0f, hotend.target + 15.0f)) { - SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); - TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); - break; - } - } - wait_for_heatup = false; + if (tuner.measure_transfer() != MPC_autotuner::MeasurementState::SUCCESS) return; - const float power_fan0 = total_energy_fan0 * 1000 / test_duration; - mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - tuner.get_ambient_temp()); + mpc.ambient_xfer_coeff_fan0 = tuner.get_power_fan0() / (hotend.target - tuner.get_ambient_temp()); #if HAS_FAN - const float power_fan255 = total_energy_fan255 * 1000 / test_duration, - ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - tuner.get_ambient_temp()); + const float ambient_xfer_coeff_fan255 = tuner.get_power_fan255() / (hotend.target - tuner.get_ambient_temp()); mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); #endif diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index b8424741600d..822c7f6fbf39 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1206,6 +1206,7 @@ class Temperature { ~MPC_autotuner(); MeasurementState measureAmbientTemperature(); MeasurementState measureHeatup(); + MeasurementState measure_transfer(); // TODO: This can be protected once the bulk of logic is in this class MeasurementState housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); @@ -1219,6 +1220,11 @@ class Temperature { float sample_3_temp() { return temp_samples[sample_count - 1]; } float sample_interval() { return sample_distance * (sample_count >> 1); } + float get_power_fan0() { return power_fan0; } + #if HAS_FAN + float get_power_fan255() { return power_fan255; } + #endif + private: uint8_t e; @@ -1229,6 +1235,11 @@ class Temperature { uint8_t sample_count; uint16_t sample_distance; float t1_time; + + float power_fan0; + #if HAS_FAN + float power_fan255; + #endif }; void MPC_autotune(const uint8_t e); From b3b093c3c89f5bef61eb3a8051d71d96a5ca646c Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:10:03 +0000 Subject: [PATCH 15/43] Renamed functions --- Marlin/src/module/temperature.cpp | 13 +++++++------ Marlin/src/module/temperature.h | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index a73d1c34a3d0..2eb1c9f08a75 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -953,7 +953,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); } - Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measureAmbientTemperature() { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_ambient_temp() { millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; ambient_temp = current_temp; @@ -976,7 +976,7 @@ volatile bool Temperature::raw_temps_ready = false; return SUCCESS; } - Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measureHeatup() { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 1000UL; MPCHeaterInfo &hotend = temp_hotend[e]; @@ -1020,6 +1020,8 @@ volatile bool Temperature::raw_temps_ready = false; elapsed_heating_time = float(ms - heat_start_time) / 1000.0f; // Ensure sample count is odd so that we have 3 equally spaced samples + if (sample_count == 0) + return FAILED; if (sample_count%2 == 0) sample_count--; @@ -1072,7 +1074,7 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); wait_for_heatup = false; - return CANCELLED; + return FAILED; } } wait_for_heatup = false; @@ -1141,7 +1143,7 @@ volatile bool Temperature::raw_temps_ready = false; LCD_MESSAGE(MSG_COOLING); #endif - if (tuner.measureAmbientTemperature() != MPC_autotuner::MeasurementState::SUCCESS) return; + if (tuner.measure_ambient_temp() != MPC_autotuner::MeasurementState::SUCCESS) return; hotend.modeled_ambient_temp = tuner.get_ambient_temp(); #if HAS_FAN @@ -1153,7 +1155,7 @@ volatile bool Temperature::raw_temps_ready = false; SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); - if (tuner.measureHeatup() != MPC_autotuner::MeasurementState::SUCCESS) return; + if (tuner.measure_heatup() != MPC_autotuner::MeasurementState::SUCCESS) return; // Calculate physical constants from three equally-spaced samples const float t1 = tuner.sample_1_temp(), @@ -1179,7 +1181,6 @@ volatile bool Temperature::raw_temps_ready = false; if (tuner.measure_transfer() != MPC_autotuner::MeasurementState::SUCCESS) return; mpc.ambient_xfer_coeff_fan0 = tuner.get_power_fan0() / (hotend.target - tuner.get_ambient_temp()); - #if HAS_FAN const float ambient_xfer_coeff_fan255 = tuner.get_power_fan255() / (hotend.target - tuner.get_ambient_temp()); mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 822c7f6fbf39..62876fbd4d95 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1200,12 +1200,13 @@ class Temperature { public: enum MeasurementState { CANCELLED, + FAILED, SUCCESS }; MPC_autotuner(const uint8_t extruderIdx); ~MPC_autotuner(); - MeasurementState measureAmbientTemperature(); - MeasurementState measureHeatup(); + MeasurementState measure_ambient_temp(); + MeasurementState measure_heatup(); MeasurementState measure_transfer(); // TODO: This can be protected once the bulk of logic is in this class MeasurementState housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); From a86bc3bd2da5e1fd4e952084c9d0d528d922e428 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:11:51 +0000 Subject: [PATCH 16/43] Updated functon names --- Marlin/src/module/temperature.cpp | 18 +++++++++--------- Marlin/src/module/temperature.h | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 2eb1c9f08a75..3b742107221e 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1070,7 +1070,7 @@ volatile bool Temperature::raw_temps_ready = false; } // Ensure we don't drift too far from the window between the last sampled temp and the target temperature - if (!WITHIN(current_temp, sample_3_temp() - 15.0f, hotend.target + 15.0f)) { + if (!WITHIN(current_temp, get_sample_3_temp() - 15.0f, hotend.target + 15.0f)) { SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); wait_for_heatup = false; @@ -1158,19 +1158,19 @@ volatile bool Temperature::raw_temps_ready = false; if (tuner.measure_heatup() != MPC_autotuner::MeasurementState::SUCCESS) return; // Calculate physical constants from three equally-spaced samples - const float t1 = tuner.sample_1_temp(), - t2 = tuner.sample_2_temp(), - t3 = tuner.sample_3_temp(); + const float t1 = tuner.get_sample_1_temp(), + t2 = tuner.get_sample_2_temp(), + t3 = tuner.get_sample_3_temp(); float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.sample_interval(); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval(); mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - tuner.get_ambient_temp()); mpc.fan255_adjustment = 0.0f; 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.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)); hotend.modeled_block_temp = asymp_temp + (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_elapsed_heating_time()); - hotend.modeled_sensor_temp = tuner.last_sampled_temp(); + hotend.modeled_sensor_temp = tuner.get_last_sampled_temp(); // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); @@ -1188,9 +1188,9 @@ volatile bool Temperature::raw_temps_ready = false; // Calculate a new and better asymptotic temperature and re-evaluate the other constants 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.sample_interval(); + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval(); 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.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)); SERIAL_ECHOPGM(STR_MPC_AUTOTUNE); SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 62876fbd4d95..eb52bf20ab2d 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1212,14 +1212,14 @@ class Temperature { MeasurementState housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); celsius_float_t get_ambient_temp() { return ambient_temp; } - celsius_float_t last_sampled_temp() { return current_temp; } + celsius_float_t get_last_measured_temp() { return current_temp; } float get_elapsed_heating_time() { return elapsed_heating_time; } - float sample_1_time() { return t1_time; } - float sample_1_temp() { return temp_samples[0]; } - float sample_2_temp() { return temp_samples[(sample_count - 1) >> 1]; } - float sample_3_temp() { return temp_samples[sample_count - 1]; } - float sample_interval() { return sample_distance * (sample_count >> 1); } + float get_sample_1_time() { return t1_time; } + float get_sample_1_temp() { return temp_samples[0]; } + float get_sample_2_temp() { return temp_samples[(sample_count - 1) >> 1]; } + float get_sample_3_temp() { return temp_samples[sample_count - 1]; } + float get_sample_interval() { return sample_distance * (sample_count >> 1); } float get_power_fan0() { return power_fan0; } #if HAS_FAN From 8ea7a07c06730843aaf082e0b48c9a18daee98c8 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:14:59 +0000 Subject: [PATCH 17/43] Fixed last commit --- Marlin/src/module/temperature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 3b742107221e..064b00599971 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1170,7 +1170,7 @@ volatile bool Temperature::raw_temps_ready = false; mpc.sensor_responsiveness = block_responsiveness / (1.0f - (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_sample_1_time()) / (t1 - asymp_temp)); hotend.modeled_block_temp = asymp_temp + (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_elapsed_heating_time()); - hotend.modeled_sensor_temp = tuner.get_last_sampled_temp(); + hotend.modeled_sensor_temp = tuner.get_last_measured_temp(); // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); From cb8dca7e241ba307ebe54cae91a5d9eec31878d6 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:15:18 +0000 Subject: [PATCH 18/43] Removed unneeded param from housekeeping function --- Marlin/src/module/temperature.cpp | 8 ++++---- Marlin/src/module/temperature.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 064b00599971..b6be59bbe73a 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -960,7 +960,7 @@ volatile bool Temperature::raw_temps_ready = false; current_temp = degHotend(e); wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { if (current_temp >= ambient_temp) { @@ -991,7 +991,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { // Record samples between 100C and 200C @@ -1045,7 +1045,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; @@ -1087,7 +1087,7 @@ volatile bool Temperature::raw_temps_ready = false; return SUCCESS; } - Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms) { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, millis_t &next_report_ms) { ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index eb52bf20ab2d..5da34b6b9fec 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1208,8 +1208,6 @@ class Temperature { MeasurementState measure_ambient_temp(); MeasurementState measure_heatup(); MeasurementState measure_transfer(); - // TODO: This can be protected once the bulk of logic is in this class - MeasurementState housekeeping(millis_t &ms, const uint8_t e, millis_t &next_report_ms); celsius_float_t get_ambient_temp() { return ambient_temp; } celsius_float_t get_last_measured_temp() { return current_temp; } @@ -1226,7 +1224,9 @@ class Temperature { float get_power_fan255() { return power_fan255; } #endif - private: + protected: + MeasurementState housekeeping(millis_t &ms, millis_t &next_report_ms); + uint8_t e; float elapsed_heating_time; From 393bf6f18242e1fd5e94863d326490cc5f961d60 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:28:08 +0000 Subject: [PATCH 19/43] Moved timers into class variables to avoid code duplication --- Marlin/src/module/temperature.cpp | 22 ++++++++++++---------- Marlin/src/module/temperature.h | 4 +++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index b6be59bbe73a..694ac6ecf339 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -954,13 +954,14 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_ambient_temp() { - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; + init_timers(); + millis_t next_test_ms = ms + 10000UL; ambient_temp = current_temp; current_temp = degHotend(e); wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping() == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { if (current_temp >= ambient_temp) { @@ -977,11 +978,12 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 1000UL; + init_timers(); + millis_t next_test_ms = ms + 1000UL; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); - millis_t heat_start_time = ms; + millis_t heat_start_time_ms = ms; sample_count = 0; sample_distance = 1; t1_time = 0; @@ -991,7 +993,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping() == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { // Record samples between 100C and 200C @@ -1004,7 +1006,7 @@ volatile bool Temperature::raw_temps_ready = false; sample_distance *= 2; } - if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; + if (sample_count == 0) t1_time = float(ms - heat_start_time_ms) / 1000.0f; temp_samples[sample_count++] = current_temp; } @@ -1017,7 +1019,7 @@ volatile bool Temperature::raw_temps_ready = false; hotend.soft_pwm_amount = 0; - elapsed_heating_time = float(ms - heat_start_time) / 1000.0f; + elapsed_heating_time = float(ms - heat_start_time_ms) / 1000.0f; // Ensure sample count is odd so that we have 3 equally spaced samples if (sample_count == 0) @@ -1029,7 +1031,7 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + MPC_dT * 1000; + millis_t next_test_ms = ms + MPC_dT * 1000; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; @@ -1045,7 +1047,7 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, next_report_ms) == CANCELLED) return CANCELLED; + if (housekeeping() == CANCELLED) return CANCELLED; if (ELAPSED(ms, next_test_ms)) { hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; @@ -1087,7 +1089,7 @@ volatile bool Temperature::raw_temps_ready = false; return SUCCESS; } - Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping(millis_t &ms, millis_t &next_report_ms) { + Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping() { ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 5da34b6b9fec..9a82b972c704 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1225,8 +1225,10 @@ class Temperature { #endif protected: - MeasurementState housekeeping(millis_t &ms, millis_t &next_report_ms); + void init_timers() { ms = next_report_ms = millis(); } + MeasurementState housekeeping(); + millis_t ms, next_report_ms; uint8_t e; float elapsed_heating_time; From 39338eae172a10ff07dcdc6ce3154a7644d4bc6f Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:29:56 +0000 Subject: [PATCH 20/43] Made current time variable more explicit --- Marlin/src/module/temperature.cpp | 36 +++++++++++++++---------------- Marlin/src/module/temperature.h | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 694ac6ecf339..732a0fb2b406 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -955,7 +955,7 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_ambient_temp() { init_timers(); - millis_t next_test_ms = ms + 10000UL; + millis_t next_test_ms = curr_time_ms + 10000UL; ambient_temp = current_temp; current_temp = degHotend(e); @@ -963,7 +963,7 @@ volatile bool Temperature::raw_temps_ready = false; for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; - if (ELAPSED(ms, next_test_ms)) { + if (ELAPSED(curr_time_ms, next_test_ms)) { if (current_temp >= ambient_temp) { ambient_temp = (ambient_temp + current_temp) / 2.0f; break; @@ -979,11 +979,11 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); - millis_t next_test_ms = ms + 1000UL; + millis_t next_test_ms = curr_time_ms + 1000UL; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); - millis_t heat_start_time_ms = ms; + millis_t heat_start_time_ms = curr_time_ms; sample_count = 0; sample_distance = 1; t1_time = 0; @@ -995,7 +995,7 @@ volatile bool Temperature::raw_temps_ready = false; for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; - if (ELAPSED(ms, next_test_ms)) { + if (ELAPSED(curr_time_ms, next_test_ms)) { // Record samples between 100C and 200C if (current_temp >= 100.0f) { // If there are too many samples, space them more widely @@ -1006,7 +1006,7 @@ volatile bool Temperature::raw_temps_ready = false; sample_distance *= 2; } - if (sample_count == 0) t1_time = float(ms - heat_start_time_ms) / 1000.0f; + if (sample_count == 0) t1_time = float(curr_time_ms - heat_start_time_ms) / 1000.0f; temp_samples[sample_count++] = current_temp; } @@ -1019,7 +1019,7 @@ volatile bool Temperature::raw_temps_ready = false; hotend.soft_pwm_amount = 0; - elapsed_heating_time = float(ms - heat_start_time_ms) / 1000.0f; + elapsed_heating_time = float(curr_time_ms - heat_start_time_ms) / 1000.0f; // Ensure sample count is odd so that we have 3 equally spaced samples if (sample_count == 0) @@ -1031,12 +1031,12 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { - millis_t next_test_ms = ms + MPC_dT * 1000; + millis_t next_test_ms = curr_time_ms + MPC_dT * 1000; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; - millis_t settle_end_ms = ms + settle_time, + millis_t settle_end_ms = curr_time_ms + settle_time, test_end_ms = settle_end_ms + test_duration; float total_energy_fan0 = 0.0f; #if HAS_FAN @@ -1049,23 +1049,23 @@ volatile bool Temperature::raw_temps_ready = false; for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; - if (ELAPSED(ms, next_test_ms)) { + if (ELAPSED(curr_time_ms, next_test_ms)) { hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; - if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) + if (ELAPSED(curr_time_ms, settle_end_ms) && !ELAPSED(curr_time_ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; #if HAS_FAN - else if (ELAPSED(ms, test_end_ms) && !fan0_done) { + else if (ELAPSED(curr_time_ms, test_end_ms) && !fan0_done) { set_fan_speed(TERN(SINGLEFAN, 0, e), 255); planner.sync_fan_speeds(fan_speed); - settle_end_ms = ms + settle_time; + settle_end_ms = curr_time_ms + settle_time; test_end_ms = settle_end_ms + test_duration; fan0_done = true; } - else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) + else if (ELAPSED(curr_time_ms, settle_end_ms) && !ELAPSED(curr_time_ms, test_end_ms)) total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; #endif - else if (ELAPSED(ms, test_end_ms)) break; + else if (ELAPSED(curr_time_ms, test_end_ms)) break; last_temp = current_temp; next_test_ms += MPC_dT * 1000; @@ -1090,14 +1090,14 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping() { - ms = millis(); + curr_time_ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready current_temp = degHotend(e); - TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms)); + TERN_(HAS_FAN_LOGIC, manage_extruder_fans(curr_time_ms)); } - if (ELAPSED(ms, next_report_ms)) { + if (ELAPSED(curr_time_ms, next_report_ms)) { next_report_ms += 1000UL; print_heater_states(e); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 9a82b972c704..5833d51ffc33 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1225,10 +1225,10 @@ class Temperature { #endif protected: - void init_timers() { ms = next_report_ms = millis(); } + void init_timers() { curr_time_ms = next_report_ms = millis(); } MeasurementState housekeeping(); - millis_t ms, next_report_ms; + millis_t curr_time_ms, next_report_ms; uint8_t e; float elapsed_heating_time; From 4a4744b5594c767d3906eb3c40ab2aa708afe87f Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:33:19 +0000 Subject: [PATCH 21/43] Update temperature.cpp Make sure timers are initialised --- Marlin/src/module/temperature.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 732a0fb2b406..8d6285b5118b 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1031,6 +1031,7 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { + init_timers(); millis_t next_test_ms = curr_time_ms + MPC_dT * 1000; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; From 10bf30f386255503157db85cfd3decd64cd1352e Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:34:15 +0000 Subject: [PATCH 22/43] Pulled test intervals into their own variables --- Marlin/src/module/temperature.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 8d6285b5118b..615f5916d891 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -955,7 +955,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_ambient_temp() { init_timers(); - millis_t next_test_ms = curr_time_ms + 10000UL; + const millis_t test_interval = 10000UL; + millis_t next_test_ms = curr_time_ms + test_interval; ambient_temp = current_temp; current_temp = degHotend(e); @@ -969,7 +970,7 @@ volatile bool Temperature::raw_temps_ready = false; break; } ambient_temp = current_temp; - next_test_ms += 10000UL; + next_test_ms += test_interval; } } wait_for_heatup = false; @@ -979,7 +980,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); - millis_t next_test_ms = curr_time_ms + 1000UL; + const millis_t test_interval = 1000UL; + millis_t next_test_ms = curr_time_ms + test_interval; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); @@ -1012,7 +1014,7 @@ volatile bool Temperature::raw_temps_ready = false; if (current_temp >= 200.0f) break; - next_test_ms += 1000UL * sample_distance; + next_test_ms += test_interval * sample_distance; } } wait_for_heatup = false; @@ -1032,6 +1034,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { init_timers(); + const millis_t test_interval = 1000UL; + millis_t next_test_ms = curr_time_ms + MPC_dT * 1000; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; From 46e97bede0333e23158a4bf4a23648fdd526c819 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:43:06 +0000 Subject: [PATCH 23/43] Added macro to get float time from millis --- Marlin/src/core/millis_t.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Marlin/src/core/millis_t.h b/Marlin/src/core/millis_t.h index 95bc40e1ecbb..e7032a2e5579 100644 --- a/Marlin/src/core/millis_t.h +++ b/Marlin/src/core/millis_t.h @@ -28,6 +28,7 @@ typedef uint32_t millis_t; #define SEC_TO_MS(N) millis_t((N)*1000UL) #define MIN_TO_MS(N) SEC_TO_MS((N)*60UL) #define MS_TO_SEC(N) millis_t((N)/1000UL) +#define MS_TO_SEC_PRECISE(N) (float(N)/1000.0f) #define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0) #define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON)) From 0a16667776949d9e0f004485df31b13e7f48614f Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:44:11 +0000 Subject: [PATCH 24/43] Used macros for time conversion --- Marlin/src/module/temperature.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 615f5916d891..ace910d8034f 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1008,7 +1008,7 @@ volatile bool Temperature::raw_temps_ready = false; sample_distance *= 2; } - if (sample_count == 0) t1_time = float(curr_time_ms - heat_start_time_ms) / 1000.0f; + if (sample_count == 0) t1_time = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms); temp_samples[sample_count++] = current_temp; } @@ -1021,7 +1021,7 @@ volatile bool Temperature::raw_temps_ready = false; hotend.soft_pwm_amount = 0; - elapsed_heating_time = float(curr_time_ms - heat_start_time_ms) / 1000.0f; + elapsed_heating_time = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms); // Ensure sample count is odd so that we have 3 equally spaced samples if (sample_count == 0) @@ -1086,9 +1086,9 @@ volatile bool Temperature::raw_temps_ready = false; } wait_for_heatup = false; - power_fan0 = total_energy_fan0 * 1000 / test_duration; + power_fan0 = total_energy_fan0 / MS_TO_SEC_PRECISE(test_duration); #if HAS_FAN - power_fan255 = total_energy_fan255 * 1000 / test_duration; + power_fan255 = total_energy_fan255 / MS_TO_SEC_PRECISE(test_duration); #endif return SUCCESS; From afdf9d15bfd5f0f054ee89125f4a65d52e5d3beb Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:44:29 +0000 Subject: [PATCH 25/43] Use variable for test interval --- Marlin/src/module/temperature.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index ace910d8034f..f7bdf9088b7d 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1034,9 +1034,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { init_timers(); - const millis_t test_interval = 1000UL; - - millis_t next_test_ms = curr_time_ms + MPC_dT * 1000; + const millis_t test_interval = SEC_TO_MS(MPC_dT); + millis_t next_test_ms = curr_time_ms + test_interval; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; @@ -1073,7 +1072,7 @@ volatile bool Temperature::raw_temps_ready = false; else if (ELAPSED(curr_time_ms, test_end_ms)) break; last_temp = current_temp; - next_test_ms += MPC_dT * 1000; + next_test_ms += test_interval; } // Ensure we don't drift too far from the window between the last sampled temp and the target temperature From ddf28deec442fd9ee87284235cd77ddbe0e5a2c6 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:44:45 +0000 Subject: [PATCH 26/43] Used variable for report interval --- Marlin/src/module/temperature.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index f7bdf9088b7d..a336f571d028 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1094,6 +1094,7 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping() { + const millis_t report_interval = 1000UL; curr_time_ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready @@ -1102,7 +1103,7 @@ volatile bool Temperature::raw_temps_ready = false; } if (ELAPSED(curr_time_ms, next_report_ms)) { - next_report_ms += 1000UL; + next_report_ms += report_interval; print_heater_states(e); SERIAL_EOL(); From c59b117cf8eb502d660b87c9b3b145647d755aa8 Mon Sep 17 00:00:00 2001 From: Stevil Knevil Date: Sun, 12 Mar 2023 10:48:07 +0000 Subject: [PATCH 27/43] Added _ms postfix to intervals to fit with convention --- Marlin/src/module/temperature.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index a336f571d028..ac18c46f05e4 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -955,8 +955,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_ambient_temp() { init_timers(); - const millis_t test_interval = 10000UL; - millis_t next_test_ms = curr_time_ms + test_interval; + const millis_t test_interval_ms = 10000UL; + millis_t next_test_ms = curr_time_ms + test_interval_ms; ambient_temp = current_temp; current_temp = degHotend(e); @@ -970,7 +970,7 @@ volatile bool Temperature::raw_temps_ready = false; break; } ambient_temp = current_temp; - next_test_ms += test_interval; + next_test_ms += test_interval_ms; } } wait_for_heatup = false; @@ -980,8 +980,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); - const millis_t test_interval = 1000UL; - millis_t next_test_ms = curr_time_ms + test_interval; + const millis_t test_interval_ms = 1000UL; + millis_t next_test_ms = curr_time_ms + test_interval_ms; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); @@ -1014,7 +1014,7 @@ volatile bool Temperature::raw_temps_ready = false; if (current_temp >= 200.0f) break; - next_test_ms += test_interval * sample_distance; + next_test_ms += test_interval_ms * sample_distance; } } wait_for_heatup = false; @@ -1034,8 +1034,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_transfer() { init_timers(); - const millis_t test_interval = SEC_TO_MS(MPC_dT); - millis_t next_test_ms = curr_time_ms + test_interval; + const millis_t test_interval_ms = SEC_TO_MS(MPC_dT); + millis_t next_test_ms = curr_time_ms + test_interval_ms; MPCHeaterInfo &hotend = temp_hotend[e]; MPC_t &mpc = hotend.mpc; @@ -1072,7 +1072,7 @@ volatile bool Temperature::raw_temps_ready = false; else if (ELAPSED(curr_time_ms, test_end_ms)) break; last_temp = current_temp; - next_test_ms += test_interval; + next_test_ms += test_interval_ms; } // Ensure we don't drift too far from the window between the last sampled temp and the target temperature @@ -1094,7 +1094,7 @@ volatile bool Temperature::raw_temps_ready = false; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping() { - const millis_t report_interval = 1000UL; + const millis_t report_interval_ms = 1000UL; curr_time_ms = millis(); if (updateTemperaturesIfReady()) { // temp sample ready @@ -1103,7 +1103,7 @@ volatile bool Temperature::raw_temps_ready = false; } if (ELAPSED(curr_time_ms, next_report_ms)) { - next_report_ms += report_interval; + next_report_ms += report_interval_ms; print_heater_states(e); SERIAL_EOL(); From a56ae63398279feee90d745f6d11e1319d9e91b4 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Sun, 12 Mar 2023 14:52:46 +0000 Subject: [PATCH 28/43] Revert "Merge branch 'MPC-Code-Improvements' into #25496-Allow-MPCTEMP-tuning-to-use-the-Alternative-Method-" This reverts commit b05af7e3326124a2513d9c4e2eeaa005870ec126, reversing changes made to c59b117cf8eb502d660b87c9b3b145647d755aa8. --- Marlin/src/module/temperature.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 9859d543279d..ac18c46f05e4 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1005,7 +1005,7 @@ volatile bool Temperature::raw_temps_ready = false; for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) temp_samples[i] = temp_samples[i*2]; sample_count /= 2; - ticks_per_sample *= 2; + sample_distance *= 2; } if (sample_count == 0) t1_time = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms); @@ -1206,7 +1206,7 @@ volatile bool Temperature::raw_temps_ready = false; #if 0 SERIAL_ECHOLNPGM("t1_time ", t1_time); SERIAL_ECHOLNPGM("sample_count ", sample_count); - SERIAL_ECHOLNPGM("ticks_per_sample ", ticks_per_sample); + SERIAL_ECHOLNPGM("sample_distance ", sample_distance); for (uint8_t i = 0; i < sample_count; i++) SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); From a8a5ad2f41bef1356fd96cce2a1483adfb0db74c Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Sun, 12 Mar 2023 15:30:43 +0000 Subject: [PATCH 29/43] Updated comment --- Marlin/src/module/temperature.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 5833d51ffc33..8ad6efaeb33b 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1195,8 +1195,8 @@ class Temperature { #endif #if ENABLED(MPCTEMP) - // Utility class that contains the business logic for auto tuning MPCTEMP - class MPC_autotuner{ + // Utility class that contains the code for performing measurments when auto tuning MPCTEMP + class MPC_autotuner { public: enum MeasurementState { CANCELLED, From 68424a2fdeb6ffd255e79026171b061c8db4267c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Mar 2023 13:32:45 -0500 Subject: [PATCH 30/43] ws cleanup --- Marlin/src/HAL/LPC1768/HAL.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/HAL/LPC1768/HAL.h b/Marlin/src/HAL/LPC1768/HAL.h index 63bec2b720f4..15d61d30d1f6 100644 --- a/Marlin/src/HAL/LPC1768/HAL.h +++ b/Marlin/src/HAL/LPC1768/HAL.h @@ -249,9 +249,9 @@ class MarlinHAL { static bool adc_ready() { return LPC176x::adc_hardware.done(LPC176x::pin_get_adc_channel(adc_pin)); } // The current value of the ADC register - static uint16_t adc_value() { + static uint16_t adc_value() { adc_result = FilteredADC::read(adc_pin) >> (16 - HAL_ADC_RESOLUTION); // returns 16bit value, reduce to required bits - return uint16_t(adc_result); + return uint16_t(adc_result); } /** From c009d90dc5a4fe1d82b238bb5cdebd3ef71357f4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Mar 2023 13:38:29 -0500 Subject: [PATCH 31/43] Alternative MPC Tuning methods --- Marlin/Configuration.h | 2 +- Marlin/src/gcode/temp/M306.cpp | 26 ++++-- Marlin/src/module/temperature.cpp | 128 ++++++++++++++++++--------- Marlin/src/module/temperature.h | 27 +++--- buildroot/tests/STM32F103RE_creality | 9 +- 5 files changed, 128 insertions(+), 64 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 9544ac5566bc..47c504b285d2 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -691,7 +691,7 @@ * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5664-5882 bytes of flash) + //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~7390 bytes of flash) //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 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/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp index d0c005ea4eb1..7cfcaad8e177 100644 --- a/Marlin/src/gcode/temp/M306.cpp +++ b/Marlin/src/gcode/temp/M306.cpp @@ -42,7 +42,10 @@ * R Sensor responsiveness (= transfer coefficient / heat capcity). * * With MPC_AUTOTUNE: - * T Autotune the specified or active extruder. + * T Autotune the extruder specified with 'E' or the active extruder. + * S0 : Autotuning method AUTO (default) + * S1 : Autotuning method DIFFERENTIAL + * S2 : Autotuning method ASYMPTOTIC */ void GcodeSuite::M306() { @@ -52,14 +55,23 @@ void GcodeSuite::M306() { return; } - #if ENABLED(MPC_AUTOTUNE) - if (parser.seen_test('T')) { + if (parser.seen_test('T')) { + #if ENABLED(MPC_AUTOTUNE) + Temperature::MPCTuningType tuning_type; + const uint8_t type = parser.byteval('S', 0); + switch (type) { + case 1: tuning_type = Temperature::MPCTuningType::FORCE_DIFFERENTIAL; break; + case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; + default: tuning_type = Temperature::MPCTuningType::AUTO; break; + } LCD_MESSAGE(MSG_MPC_AUTOTUNE); - thermalManager.MPC_autotune(e); + thermalManager.MPC_autotune(e, tuning_type); ui.reset_status(); - return; - } - #endif + #else + SERIAL_ECHOLNPGM("M306 T requires MPC_AUTOTUNE."); + #endif + return; + } if (parser.seen("ACFPRH")) { MPC_t &mpc = thermalManager.temp_hotend[e].mpc; diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 6f5522086739..b0ab021e3810 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -939,8 +939,7 @@ volatile bool Temperature::raw_temps_ready = false; #define SINGLEFAN 1 #endif - Temperature::MPC_autotuner::MPC_autotuner(const uint8_t extruderIdx) : e(extruderIdx) - { + Temperature::MPC_autotuner::MPC_autotuner(const uint8_t extruderIdx) : e(extruderIdx) { TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); } @@ -989,7 +988,8 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); const millis_t test_interval_ms = 1000UL; - millis_t next_test_ms = curr_time_ms + test_interval_ms; + millis_t next_temperature_test_time_ms = curr_time_ms + test_interval_ms; + millis_t next_heating_test_time_ms = curr_time_ms + test_interval_ms; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); @@ -1001,17 +1001,41 @@ volatile bool Temperature::raw_temps_ready = false; hotend.target = 200.0f; // So M105 looks nice hotend.soft_pwm_amount = (MPC_MAX) >> 1; + float temp[2]; // Buffer to store 2 previous temperature reading to establish rate of change + + // Initialise rate of change to to steady state at current time + temp_fastest = temp[0] = temp[1] = temp[2] = current_temp; + time_fastest = rate_fastest = 0; + wait_for_heatup = true; for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; - if (ELAPSED(curr_time_ms, next_test_ms)) { - // Record samples between 100C and 200C + if (ELAPSED(curr_time_ms, next_heating_test_time_ms)) { + // Update the buffer of previous readings + temp[0] = temp[1]; + temp[1] = temp[2]; + temp[2] = current_temp; + + // Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative + float h = MS_TO_SEC_PRECISE(test_interval_ms); + float curr_rate = (temp[2] - temp[0]) / 2 * h; + if (curr_rate > rate_fastest) { + // Update fastest values + rate_fastest = curr_rate; + temp_fastest = temp[1]; + time_fastest = get_elapsed_heating_time(); + } + next_heating_test_time_ms += test_interval_ms * sample_distance; + } + + // Record samples between 100C and 200C + if (ELAPSED(curr_time_ms, next_temperature_test_time_ms)) { if (current_temp >= 100.0f) { // If there are too many samples, space them more widely if (sample_count == COUNT(temp_samples)) { for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) - temp_samples[i] = temp_samples[i*2]; + temp_samples[i] = temp_samples[i * 2]; sample_count /= 2; sample_distance *= 2; } @@ -1022,7 +1046,7 @@ volatile bool Temperature::raw_temps_ready = false; if (current_temp >= 200.0f) break; - next_test_ms += test_interval_ms * sample_distance; + next_temperature_test_time_ms += test_interval_ms * sample_distance; } } wait_for_heatup = false; @@ -1032,10 +1056,8 @@ volatile bool Temperature::raw_temps_ready = false; elapsed_heating_time = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms); // Ensure sample count is odd so that we have 3 equally spaced samples - if (sample_count == 0) - return FAILED; - if (sample_count%2 == 0) - sample_count--; + if (sample_count == 0) return FAILED; + if (sample_count % 2 == 0) sample_count--; return SUCCESS; } @@ -1094,42 +1116,39 @@ volatile bool Temperature::raw_temps_ready = false; wait_for_heatup = false; power_fan0 = total_energy_fan0 / MS_TO_SEC_PRECISE(test_duration); - #if HAS_FAN - power_fan255 = total_energy_fan255 / MS_TO_SEC_PRECISE(test_duration); - #endif + TERN_(HAS_FAN, power_fan255 = (total_energy_fan255 * 1000) / test_duration); return SUCCESS; } Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::housekeeping() { - const millis_t report_interval_ms = 1000UL; - curr_time_ms = millis(); + const millis_t report_interval_ms = 1000UL; + curr_time_ms = millis(); - if (updateTemperaturesIfReady()) { // temp sample ready - current_temp = degHotend(e); - TERN_(HAS_FAN_LOGIC, manage_extruder_fans(curr_time_ms)); - } - - if (ELAPSED(curr_time_ms, next_report_ms)) { - next_report_ms += report_interval_ms; + if (updateTemperaturesIfReady()) { // temp sample ready + current_temp = degHotend(e); + TERN_(HAS_FAN_LOGIC, manage_extruder_fans(curr_time_ms)); + } - print_heater_states(e); - SERIAL_EOL(); - } + if (ELAPSED(curr_time_ms, next_report_ms)) { + next_report_ms += report_interval_ms; + print_heater_states(e); + SERIAL_EOL(); + } - hal.idletask(); - TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); + hal.idletask(); + TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); - if (!wait_for_heatup) { - SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_INTERRUPTED); - TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_INTERRUPTED)); - return MeasurementState::CANCELLED; - } + if (!wait_for_heatup) { + SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_INTERRUPTED); + TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_INTERRUPTED)); + return MeasurementState::CANCELLED; + } - return MeasurementState::SUCCESS; - }; + return MeasurementState::SUCCESS; + } - void Temperature::MPC_autotune(const uint8_t e) { + void Temperature::MPC_autotune(const uint8_t e, MPCTuningType tuning_type = AUTO) { SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); MPC_autotuner tuner(e); @@ -1177,10 +1196,28 @@ 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(); + // Make initial guess at transfer coefficients mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - tuner.get_ambient_temp()); mpc.fan255_adjustment = 0.0f; - 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)); + + if (tuning_type == AUTO || tuning_type == FORCE_ASYMPTOTIC) { + // Analytic tuning + 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)); + } + + // If analytic tuning fails, fall back to differential tuning + // If analytic tuning fails, fall back to forcing differential tuning + if (tuning_type == AUTO) { + if (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0) + tuning_type = FORCE_DIFFERENTIAL; + } + + if (tuning_type == FORCE_DIFFERENTIAL) { + // 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()); + } hotend.modeled_block_temp = asymp_temp + (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_elapsed_heating_time()); hotend.modeled_sensor_temp = tuner.get_last_measured_temp(); @@ -1193,17 +1230,22 @@ volatile bool Temperature::raw_temps_ready = false; hotend.target = hotend.modeled_block_temp; if (tuner.measure_transfer() != MPC_autotuner::MeasurementState::SUCCESS) return; + // Calculate a new and better asymptotic temperature and re-evaluate the other constants + 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(); + + // Update the transfer coefficients mpc.ambient_xfer_coeff_fan0 = tuner.get_power_fan0() / (hotend.target - tuner.get_ambient_temp()); #if HAS_FAN const float ambient_xfer_coeff_fan255 = tuner.get_power_fan255() / (hotend.target - tuner.get_ambient_temp()); mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); #endif - // Calculate a new and better asymptotic temperature and re-evaluate the other constants - 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(); - 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)); + if (tuning_type == AUTO || tuning_type == FORCE_ASYMPTOTIC) { + // Update analytic tuning values based on the above + 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)); + } SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_DONE)); diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index c518a9dd8b0c..8ce1189f5337 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1194,17 +1194,13 @@ class Temperature { } #endif - #endif + #endif // HAS_PID_HEATING #if ENABLED(MPC_AUTOTUNE) - // Utility class that contains the code for performing measurments when auto tuning MPCTEMP + // Utility class to perform MPCTEMP auto tuning measurements class MPC_autotuner { public: - enum MeasurementState { - CANCELLED, - FAILED, - SUCCESS - }; + enum MeasurementState { CANCELLED, FAILED, SUCCESS }; MPC_autotuner(const uint8_t extruderIdx); ~MPC_autotuner(); MeasurementState measure_ambient_temp(); @@ -1221,6 +1217,10 @@ class Temperature { float get_sample_3_temp() { return temp_samples[sample_count - 1]; } float get_sample_interval() { return sample_distance * (sample_count >> 1); } + celsius_float_t get_temp_fastest() { return temp_fastest; } + float get_time_fastest() { return time_fastest; } + float get_rate_fastest() { return rate_fastest; } + float get_power_fan0() { return power_fan0; } #if HAS_FAN float get_power_fan255() { return power_fan255; } @@ -1234,21 +1234,26 @@ class Temperature { uint8_t e; float elapsed_heating_time; - celsius_float_t ambient_temp; - celsius_float_t current_temp; + celsius_float_t ambient_temp, current_temp; celsius_float_t temp_samples[16]; uint8_t sample_count; uint16_t sample_distance; float t1_time; + // Parameters from differential analysis + celsius_float_t temp_fastest; + float time_fastest, rate_fastest; + float power_fan0; #if HAS_FAN float power_fan255; #endif }; - void MPC_autotune(const uint8_t e); - #endif + enum MPCTuningType { AUTO, FORCE_ASYMPTOTIC, FORCE_DIFFERENTIAL }; + static void MPC_autotune(const uint8_t e, MPCTuningType tuning_type); + + #endif // MPC_AUTOTUNE #if ENABLED(PROBING_HEATERS_OFF) static void pause_heaters(const bool p); diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index a05f1d96bebb..f391d6f084cd 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -27,8 +27,13 @@ opt_enable DWIN_LCD_PROUI INDIVIDUAL_AXIS_HOMING_SUBMENU SET_PROGRESS_MANUALLY S opt_set PREHEAT_3_LABEL '"CUSTOM"' PREHEAT_3_TEMP_HOTEND 240 PREHEAT_3_TEMP_BED 60 PREHEAT_3_FAN_SPEED 128 exec_test $1 $2 "Ender-3 S1 with ProUI (PIDTEMP)" "$3" -opt_disable PIDTEMP -opt_enable MPCTEMP MPC_AUTOTUNE +use_example_configs "Creality/Ender-3 S1/STM32F1" +opt_disable PIDTEMP DWIN_CREALITY_LCD Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN AUTO_BED_LEVELING_BILINEAR CONFIGURATION_EMBEDDING CANCEL_OBJECTS FWRETRACT +opt_enable DWIN_LCD_PROUI INDIVIDUAL_AXIS_HOMING_SUBMENU SET_PROGRESS_MANUALLY SET_PROGRESS_PERCENT STATUS_MESSAGE_SCROLLING \ + SOUND_MENU_ITEM PRINTCOUNTER NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE FILAMENT_RUNOUT_SENSOR \ + MPCTEMP MPC_AUTOTUNE BLTOUCH Z_SAFE_HOMING AUTO_BED_LEVELING_UBL MESH_EDIT_MENU \ + LIMITED_MAX_FR_EDITING LIMITED_MAX_ACCEL_EDITING LIMITED_JERK_EDITING BAUD_RATE_GCODE +opt_set PREHEAT_3_LABEL '"CUSTOM"' PREHEAT_3_TEMP_HOTEND 240 PREHEAT_3_TEMP_BED 60 PREHEAT_3_FAN_SPEED 128 exec_test $1 $2 "Ender-3 S1 with ProUI (MPCTEMP)" "$3" restore_configs From 8df3c5ff86691c4b3607cffd8878be2f24a46e51 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Mar 2023 13:52:42 -0500 Subject: [PATCH 32/43] tweak --- Marlin/src/module/temperature.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index b0ab021e3810..a29dbcd86d91 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -987,9 +987,9 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); - const millis_t test_interval_ms = 1000UL; - millis_t next_temperature_test_time_ms = curr_time_ms + test_interval_ms; - millis_t next_heating_test_time_ms = curr_time_ms + test_interval_ms; + constexpr millis_t test_interval_ms = 1000UL; + millis_t next_temperature_test_time_ms, next_heating_test_time_ms; + next_temperature_test_time_ms = next_heating_test_time_ms = curr_time_ms + test_interval_ms; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); @@ -1148,7 +1148,7 @@ volatile bool Temperature::raw_temps_ready = false; return MeasurementState::SUCCESS; } - void Temperature::MPC_autotune(const uint8_t e, MPCTuningType tuning_type = AUTO) { + void Temperature::MPC_autotune(const uint8_t e, MPCTuningType tuning_type=AUTO) { SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); MPC_autotuner tuner(e); From 6b796eec974d547a7713733bbcd42f34f592d5f7 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Mon, 27 Mar 2023 11:12:06 +0100 Subject: [PATCH 33/43] Reuse the sample buffer during auto tune to save memory --- Marlin/Configuration.h | 2 +- Marlin/src/module/temperature.cpp | 58 +++++++++++++++++-------------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 47c504b285d2..d1a8e4b35f13 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -691,7 +691,7 @@ * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~7390 bytes of flash) + //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~7120 bytes of flash) //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 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 a29dbcd86d91..7caee9824bae 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -988,8 +988,7 @@ volatile bool Temperature::raw_temps_ready = false; Temperature::MPC_autotuner::MeasurementState Temperature::MPC_autotuner::measure_heatup() { init_timers(); constexpr millis_t test_interval_ms = 1000UL; - millis_t next_temperature_test_time_ms, next_heating_test_time_ms; - next_temperature_test_time_ms = next_heating_test_time_ms = curr_time_ms + test_interval_ms; + millis_t next_test_time_ms = curr_time_ms + test_interval_ms; MPCHeaterInfo &hotend = temp_hotend[e]; current_temp = degHotend(e); @@ -1004,34 +1003,37 @@ volatile bool Temperature::raw_temps_ready = false; float temp[2]; // Buffer to store 2 previous temperature reading to establish rate of change // Initialise rate of change to to steady state at current time - temp_fastest = temp[0] = temp[1] = temp[2] = current_temp; + temp_samples[0] = temp_samples[1] = temp_samples[2] = current_temp; time_fastest = rate_fastest = 0; wait_for_heatup = true; for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; - if (ELAPSED(curr_time_ms, next_heating_test_time_ms)) { - // Update the buffer of previous readings - temp[0] = temp[1]; - temp[1] = temp[2]; - temp[2] = current_temp; - - // Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative - float h = MS_TO_SEC_PRECISE(test_interval_ms); - float curr_rate = (temp[2] - temp[0]) / 2 * h; - if (curr_rate > rate_fastest) { - // Update fastest values - rate_fastest = curr_rate; - temp_fastest = temp[1]; - time_fastest = get_elapsed_heating_time(); - } - next_heating_test_time_ms += test_interval_ms * sample_distance; - } + if (ELAPSED(curr_time_ms, next_test_time_ms)) { + if (current_temp < 100.0f) { + // Initial regime (below 100deg): Measure rate of change of heating for differential tuning + + // Update the buffer of previous readings + temp_samples[0] = temp_samples[1]; + temp_samples[1] = temp_samples[2]; + temp_samples[2] = current_temp; + + // Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative + float h = MS_TO_SEC_PRECISE(test_interval_ms); + float 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[1]; + time_fastest = get_elapsed_heating_time(); + } + + next_test_time_ms += test_interval_ms; + + } else if (current_temp < 200.0f) { + // Second regime (after 100deg) measure 3 points to determine asymptotic temperature - // Record samples between 100C and 200C - if (ELAPSED(curr_time_ms, next_temperature_test_time_ms)) { - if (current_temp >= 100.0f) { // If there are too many samples, space them more widely if (sample_count == COUNT(temp_samples)) { for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) @@ -1042,11 +1044,15 @@ volatile bool Temperature::raw_temps_ready = false; if (sample_count == 0) t1_time = MS_TO_SEC_PRECISE(curr_time_ms - heat_start_time_ms); temp_samples[sample_count++] = current_temp; - } - if (current_temp >= 200.0f) break; + if (current_temp >= 200.0f) break; + + next_test_time_ms += test_interval_ms * sample_distance; - next_temperature_test_time_ms += test_interval_ms * sample_distance; + } else { + // Third regime (after 200deg) finished gathering data so finish + break; + } } } wait_for_heatup = false; From cc2a900499fb210a37a2a22a720a23d2ddc46c0b Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Tue, 28 Mar 2023 09:26:12 +0100 Subject: [PATCH 34/43] Avoided unnecessary calculations --- Marlin/src/module/temperature.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 7caee9824bae..c6332ede4523 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1236,10 +1236,6 @@ volatile bool Temperature::raw_temps_ready = false; hotend.target = hotend.modeled_block_temp; if (tuner.measure_transfer() != MPC_autotuner::MeasurementState::SUCCESS) return; - // Calculate a new and better asymptotic temperature and re-evaluate the other constants - 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(); - // Update the transfer coefficients mpc.ambient_xfer_coeff_fan0 = tuner.get_power_fan0() / (hotend.target - tuner.get_ambient_temp()); #if HAS_FAN @@ -1248,6 +1244,10 @@ volatile bool Temperature::raw_temps_ready = false; #endif if (tuning_type == AUTO || tuning_type == FORCE_ASYMPTOTIC) { + // Calculate a new and better asymptotic temperature and re-evaluate the other constants + 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(); + // Update analytic tuning values based on the above 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)); From 3afca5a114ad94e1adb42ed49d2dc043b632e7a7 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Tue, 28 Mar 2023 09:26:47 +0100 Subject: [PATCH 35/43] Fixed debug output for MPC Autotune --- Marlin/src/module/temperature.cpp | 49 ++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index c6332ede4523..52d8657ee39e 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -939,6 +939,8 @@ volatile bool Temperature::raw_temps_ready = false; #define SINGLEFAN 1 #endif + #define DEBUG_MPC_AUTOTUNE 1 + Temperature::MPC_autotuner::MPC_autotuner(const uint8_t extruderIdx) : e(extruderIdx) { TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); } @@ -982,6 +984,12 @@ volatile bool Temperature::raw_temps_ready = false; } wait_for_heatup = false; + #if ENABLED(DEBUG_MPC_AUTOTUNE) + SERIAL_ECHOLNPGM("MPC_autotuner::measure_ambient_temp() Completed"); + SERIAL_ECHOLNPGM("====="); + SERIAL_ECHOLNPGM("ambient_temp ", get_ambient_temp()); + #endif + return SUCCESS; } @@ -1065,6 +1073,17 @@ 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) + SERIAL_ECHOLNPGM("MPC_autotuner::measure_heatup() Completed"); + SERIAL_ECHOLNPGM("====="); + SERIAL_ECHOLNPGM("t1_time ", t1_time); + SERIAL_ECHOLNPGM("sample_count ", sample_count); + SERIAL_ECHOLNPGM("sample_distance ", sample_distance); + for (uint8_t i = 0; i < sample_count; i++) + SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); + SERIAL_ECHOLNPGM("t1 ", get_sample_1_temp(), " t2 ", get_sample_2_temp(), " t3 ", get_sample_3_temp()); + #endif + return SUCCESS; } @@ -1124,6 +1143,13 @@ 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) + SERIAL_ECHOLNPGM("MPC_autotuner::measure_transfer() Completed"); + SERIAL_ECHOLNPGM("====="); + SERIAL_ECHOLNPGM("power_fan0 ", power_fan0); + TERN_(HAS_FAN, SERIAL_ECHOLNPGM("power_fan255 ", power_fan255)); + #endif + return SUCCESS; } @@ -1202,6 +1228,11 @@ 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) + SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); + SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); + #endif + // Make initial guess at transfer coefficients mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - tuner.get_ambient_temp()); mpc.fan255_adjustment = 0.0f; @@ -1248,25 +1279,21 @@ 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) + SERIAL_ECHOLN("Refining estimates for:"); + SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); + SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); + #endif + // Update analytic tuning values based on the above 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)); + } SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_DONE)); - #if 0 - SERIAL_ECHOLNPGM("t1_time ", t1_time); - SERIAL_ECHOLNPGM("sample_count ", sample_count); - SERIAL_ECHOLNPGM("sample_distance ", sample_distance); - for (uint8_t i = 0; i < sample_count; i++) - SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); - SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); - SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); - SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); - #endif - SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", mpc.block_heat_capacity); SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", mpc.sensor_responsiveness, 4); SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", mpc.ambient_xfer_coeff_fan0, 4); From 4021571deb7743f5d11d1f1dfe32def053fafb23 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 31 Mar 2023 20:56:24 -0500 Subject: [PATCH 36/43] tweak --- Marlin/src/module/temperature.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index a0e0076090b3..023ce18dce92 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1028,8 +1028,8 @@ volatile bool Temperature::raw_temps_ready = false; temp_samples[2] = current_temp; // Measure the rate of change of temperature, https://en.wikipedia.org/wiki/Symmetric_derivative - float h = MS_TO_SEC_PRECISE(test_interval_ms); - float curr_rate = (temp_samples[2] - temp_samples[0]) / 2 * h; + const float h = MS_TO_SEC_PRECISE(test_interval_ms), + curr_rate = (temp_samples[2] - temp_samples[0]) / 2 * h; if (curr_rate > rate_fastest) { // Update fastest values rate_fastest = curr_rate; From 98099492a7945c270e3ce8c1a2329bed1cae1785 Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Fri, 28 Apr 2023 11:28:09 +0100 Subject: [PATCH 37/43] Fixed using old, uninitialised, variable --- Marlin/src/module/temperature.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 05f6ecf76e0e..d7fbb930af0f 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -1013,8 +1013,6 @@ volatile bool Temperature::raw_temps_ready = false; hotend.target = 200.0f; // So M105 looks nice hotend.soft_pwm_amount = (MPC_MAX) >> 1; - float temp[2]; // Buffer to store 2 previous temperature reading to establish rate of change - // Initialise rate of change to to steady state at current time temp_samples[0] = temp_samples[1] = temp_samples[2] = current_temp; time_fastest = rate_fastest = 0; @@ -1038,7 +1036,7 @@ volatile bool Temperature::raw_temps_ready = false; if (curr_rate > rate_fastest) { // Update fastest values rate_fastest = curr_rate; - temp_fastest = temp[1]; + temp_fastest = temp_samples[1]; time_fastest = get_elapsed_heating_time(); } From a7caba3ac698ba8a7c12842c20e4dd780487465f Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Mon, 1 May 2023 19:28:30 +0100 Subject: [PATCH 38/43] Added Executable flag --- buildroot/tests/STM32F103RE_creality | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 buildroot/tests/STM32F103RE_creality diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality old mode 100644 new mode 100755 From 55853dad6a511ffdbbb7d38394241b21d904e68f Mon Sep 17 00:00:00 2001 From: StevilKnevil Date: Wed, 3 May 2023 13:19:10 +0100 Subject: [PATCH 39/43] Update temperature.cpp Fixed initialisation of ambient_temp --- Marlin/src/module/temperature.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index d7fbb930af0f..1684674a0fea 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -971,10 +971,9 @@ volatile bool Temperature::raw_temps_ready = false; init_timers(); const millis_t test_interval_ms = 10000UL; millis_t next_test_ms = curr_time_ms + test_interval_ms; - ambient_temp = current_temp; - - current_temp = degHotend(e); + ambient_temp = current_temp = degHotend(e); wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; From 43d21d53368732326165acd632fc9abaeddb4447 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 10 May 2023 06:36:28 -0500 Subject: [PATCH 40/43] Keep smaller option --- Marlin/Configuration.h | 3 +- Marlin/src/gcode/temp/M306.cpp | 37 ++-- Marlin/src/inc/SanityCheck.h | 5 + Marlin/src/module/temperature.cpp | 251 ++++++++++++++++++++++++++- Marlin/src/module/temperature.h | 9 +- buildroot/tests/STM32F103RE_creality | 2 +- 6 files changed, 284 insertions(+), 23 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b1a31ac4e912..e2154e66f563 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -686,7 +686,8 @@ * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~7120 bytes of flash) + //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5664-5882 bytes of flash) + //#define MPC_AUTOTUNE_FANCY // Include a fancier method to do MPC auto-tuning (~7120 bytes of flash) //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 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/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp index 7cfcaad8e177..561b44a14dff 100644 --- a/Marlin/src/gcode/temp/M306.cpp +++ b/Marlin/src/gcode/temp/M306.cpp @@ -43,6 +43,8 @@ * * With MPC_AUTOTUNE: * T Autotune the extruder specified with 'E' or the active extruder. + * + * With MPC_AUTOTUNE_FANCY: * S0 : Autotuning method AUTO (default) * S1 : Autotuning method DIFFERENTIAL * S2 : Autotuning method ASYMPTOTIC @@ -55,23 +57,26 @@ void GcodeSuite::M306() { return; } - if (parser.seen_test('T')) { - #if ENABLED(MPC_AUTOTUNE) - Temperature::MPCTuningType tuning_type; - const uint8_t type = parser.byteval('S', 0); - switch (type) { - case 1: tuning_type = Temperature::MPCTuningType::FORCE_DIFFERENTIAL; break; - case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; - default: tuning_type = Temperature::MPCTuningType::AUTO; break; - } - LCD_MESSAGE(MSG_MPC_AUTOTUNE); - thermalManager.MPC_autotune(e, tuning_type); + #if EITHER(MPC_AUTOTUNE, MPC_AUTOTUNE_FANCY) + if (parser.seen_test('T')) { + #if ENABLED(MPC_AUTOTUNE_FANCY) + Temperature::MPCTuningType tuning_type; + const uint8_t type = parser.byteval('S', 0); + switch (type) { + case 1: tuning_type = Temperature::MPCTuningType::FORCE_DIFFERENTIAL; break; + case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; + default: tuning_type = Temperature::MPCTuningType::AUTO; break; + } + LCD_MESSAGE(MSG_MPC_AUTOTUNE); + thermalManager.MPC_autotune(e, tuning_type); + #else + LCD_MESSAGE(MSG_MPC_AUTOTUNE); + thermalManager.MPC_autotune(e); + #endif ui.reset_status(); - #else - SERIAL_ECHOLNPGM("M306 T requires MPC_AUTOTUNE."); - #endif - return; - } + return; + } + #endif if (parser.seen("ACFPRH")) { MPC_t &mpc = thermalManager.temp_hotend[e].mpc; diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 9c54208c538f..449910b65759 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -976,9 +976,14 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "Only enable PIDTEMP or MPCTEMP, but not both." #undef MPCTEMP #undef MPC_AUTOTUNE + #undef MPC_AUTOTUNE_FANCY #undef MPC_EDIT_MENU #undef MPC_AUTOTUNE_MENU #endif +#if BOTH(MPC_AUTOTUNE, MPC_AUTOTUNE_FANCY) + #error "Only enable MPC_AUTOTUNE or MPC_AUTOTUNE_FANCY, but not both." + #undef MPC_AUTOTUNE_FANCY +#endif #if ENABLED(MPC_INCLUDE_FAN) #if !HAS_FAN diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 8c68969aa033..eb5840ba5320 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -938,7 +938,7 @@ volatile bool Temperature::raw_temps_ready = false; #endif // HAS_PID_HEATING -#if ENABLED(MPC_AUTOTUNE) +#if ENABLED(MPC_AUTOTUNE_FANCY) #if EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) #define SINGLEFAN 1 @@ -1041,7 +1041,8 @@ volatile bool Temperature::raw_temps_ready = false; 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 // If there are too many samples, space them more widely @@ -1059,7 +1060,8 @@ volatile bool Temperature::raw_temps_ready = false; next_test_time_ms += test_interval_ms * sample_distance; - } else { + } + else { // Third regime (after 200deg) finished gathering data so finish break; } @@ -1302,6 +1304,249 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4)); } +#elif ENABLED(MPC_AUTOTUNE) + + #if EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) + #define SINGLEFAN 1 + #endif + + void Temperature::MPC_autotune(const uint8_t e) { + auto housekeeping = [] (millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms) { + ms = millis(); + + if (updateTemperaturesIfReady()) { // temp sample ready + current_temp = degHotend(e); + TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms)); + } + + if (ELAPSED(ms, next_report_ms)) { + next_report_ms += 1000UL; + + print_heater_states(e); + SERIAL_EOL(); + } + + hal.idletask(); + TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); + + if (!wait_for_heatup) { + SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_INTERRUPTED); + TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_INTERRUPTED)); + return true; + } + + return false; + }; + + struct OnExit { + uint8_t e; + OnExit(const uint8_t _e) { this->e = _e; } + ~OnExit() { + wait_for_heatup = false; + + ui.reset_status(); + + temp_hotend[e].target = 0.0f; + temp_hotend[e].soft_pwm_amount = 0; + #if HAS_FAN + set_fan_speed(TERN(SINGLEFAN, 0, e), 0); + planner.sync_fan_speeds(fan_speed); + #endif + + do_z_clearance(MPC_TUNING_END_Z, false); + + TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); + } + } on_exit(e); + + SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); + MPCHeaterInfo &hotend = temp_hotend[e]; + MPC_t &mpc = hotend.mpc; + + TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); + + // Move to center of bed, just above bed height and cool with max fan + gcode.home_all_axes(true); + disable_all_heaters(); + #if HAS_FAN + zero_fan_speeds(); + set_fan_speed(TERN(SINGLEFAN, 0, e), 255); + planner.sync_fan_speeds(fan_speed); + #endif + do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS)); + + SERIAL_ECHOLNPGM(STR_MPC_COOLING_TO_AMBIENT); + #if ENABLED(DWIN_LCD_PROUI) + DWIN_MPCTuning(MPCTEMP_START); + LCD_ALERTMESSAGE(MSG_MPC_COOLING_TO_AMBIENT); + #else + LCD_MESSAGE(MSG_COOLING); + #endif + + millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; + celsius_float_t current_temp = degHotend(e), + ambient_temp = current_temp; + + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, current_temp, next_report_ms)) return; + + if (ELAPSED(ms, next_test_ms)) { + if (current_temp >= ambient_temp) { + ambient_temp = (ambient_temp + current_temp) / 2.0f; + break; + } + ambient_temp = current_temp; + next_test_ms += 10000UL; + } + } + wait_for_heatup = false; + + #if HAS_FAN + set_fan_speed(TERN(SINGLEFAN, 0, e), 0); + planner.sync_fan_speeds(fan_speed); + #endif + + hotend.modeled_ambient_temp = ambient_temp; + + SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); + TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); + hotend.target = 200.0f; // So M105 looks nice + hotend.soft_pwm_amount = (MPC_MAX) >> 1; + const millis_t heat_start_time = next_test_ms = ms; + celsius_float_t temp_samples[16]; + uint8_t sample_count = 0; + uint16_t sample_distance = 1; + float t1_time = 0; + + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, current_temp, next_report_ms)) return; + + if (ELAPSED(ms, next_test_ms)) { + // Record samples between 100C and 200C + if (current_temp >= 100.0f) { + // If there are too many samples, space them more widely + if (sample_count == COUNT(temp_samples)) { + for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) + temp_samples[i] = temp_samples[i*2]; + sample_count /= 2; + sample_distance *= 2; + } + + if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; + temp_samples[sample_count++] = current_temp; + } + + if (current_temp >= 200.0f) break; + + next_test_ms += 1000UL * sample_distance; + } + } + wait_for_heatup = false; + + hotend.soft_pwm_amount = 0; + + // Calculate physical constants from three equally-spaced samples + sample_count = (sample_count + 1) / 2 * 2 - 1; + const float t1 = temp_samples[0], + t2 = temp_samples[(sample_count - 1) >> 1], + t3 = temp_samples[sample_count - 1]; + float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + + mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); + mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); + TERN_(MPC_INCLUDE_FAN, mpc.fan255_adjustment = 0.0f); + + hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); + hotend.modeled_sensor_temp = current_temp; + + // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan + SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); + TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_MEASURING_AMBIENT), LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT)); + hotend.target = hotend.modeled_block_temp; + next_test_ms = ms + MPC_dT * 1000; + constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; + millis_t settle_end_ms = ms + settle_time, + test_end_ms = settle_end_ms + test_duration; + float total_energy_fan0 = 0.0f; + #if HAS_FAN + bool fan0_done = false; + float total_energy_fan255 = 0.0f; + #endif + float last_temp = current_temp; + + wait_for_heatup = true; + for (;;) { // Can be interrupted with M108 + if (housekeeping(ms, e, current_temp, next_report_ms)) return; + + if (ELAPSED(ms, next_test_ms)) { + hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; + + if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) + total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; + #if HAS_FAN + else if (ELAPSED(ms, test_end_ms) && !fan0_done) { + set_fan_speed(TERN(SINGLEFAN, 0, e), 255); + planner.sync_fan_speeds(fan_speed); + settle_end_ms = ms + settle_time; + test_end_ms = settle_end_ms + test_duration; + fan0_done = true; + } + else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) + total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; + #endif + else if (ELAPSED(ms, test_end_ms)) break; + + last_temp = current_temp; + next_test_ms += MPC_dT * 1000; + } + + if (!WITHIN(current_temp, t3 - 15.0f, hotend.target + 15.0f)) { + SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); + TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); + break; + } + } + wait_for_heatup = false; + + const float power_fan0 = total_energy_fan0 * 1000 / test_duration; + mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); + + #if HAS_FAN + const float power_fan255 = total_energy_fan255 * 1000 / test_duration, + ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); + mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); + #endif + + // Calculate a new and better asymptotic temperature and re-evaluate the other constants + asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; + block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); + mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; + mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); + + SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); + TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_DONE)); + + #if 0 + SERIAL_ECHOLNPGM("t1_time ", t1_time); + SERIAL_ECHOLNPGM("sample_count ", sample_count); + SERIAL_ECHOLNPGM("sample_distance ", sample_distance); + for (uint8_t i = 0; i < sample_count; i++) + SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); + SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); + SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); + SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); + #endif + + SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", mpc.block_heat_capacity); + SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", mpc.sensor_responsiveness, 4); + SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", mpc.ambient_xfer_coeff_fan0, 4); + TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4)); + } + #endif // MPC_AUTOTUNE int16_t Temperature::getHeaterPower(const heater_id_t heater_id) { diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index e93e93f7fb7d..e5c21d23d5cf 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1217,7 +1217,8 @@ class Temperature { #endif // HAS_PID_HEATING - #if ENABLED(MPC_AUTOTUNE) + #if ENABLED(MPC_AUTOTUNE_FANCY) + // Utility class to perform MPCTEMP auto tuning measurements class MPC_autotuner { public: @@ -1274,7 +1275,11 @@ class Temperature { enum MPCTuningType { AUTO, FORCE_ASYMPTOTIC, FORCE_DIFFERENTIAL }; static void MPC_autotune(const uint8_t e, MPCTuningType tuning_type); - #endif // MPC_AUTOTUNE + #elif ENABLED(MPC_AUTOTUNE) + + void MPC_autotune(const uint8_t e); + + #endif #if ENABLED(PROBING_HEATERS_OFF) static void pause_heaters(const bool p); diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index 834580fac8e3..918c9944932a 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -20,7 +20,7 @@ exec_test $1 $2 "Ender-3 v2 - JyersUI (ABL Bilinear/Manual)" "$3" use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI" opt_disable DWIN_CREALITY_LCD PIDTEMP -opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE +opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE_FANCY exec_test $1 $2 "Ender-3 v2 - MarlinUI (UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP_TEST)" "$3" use_example_configs "Creality/Ender-3 S1/STM32F1" From 88482057089db82bf89f590a92288b55b8373ab4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 11 May 2023 13:21:28 -0500 Subject: [PATCH 41/43] Reduce size by 1382 bytes (AVR) --- Marlin/Configuration.h | 2 +- Marlin/src/module/temperature.cpp | 15 ++++++++++++++- Marlin/src/module/temperature.h | 27 ++++++++++++++------------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index e2154e66f563..739632cb7234 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -687,7 +687,7 @@ */ #if ENABLED(MPCTEMP) //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5664-5882 bytes of flash) - //#define MPC_AUTOTUNE_FANCY // Include a fancier method to do MPC auto-tuning (~7120 bytes of flash) + //#define MPC_AUTOTUNE_FANCY // Include a fancier method to do MPC auto-tuning (~5466 bytes of flash) //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 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 eb5840ba5320..00f7882373dd 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -946,6 +946,19 @@ volatile bool Temperature::raw_temps_ready = false; #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]; + uint8_t Temperature::MPC_autotuner::sample_count; + uint16_t Temperature::MPC_autotuner::sample_distance; + + // Parameters from differential analysis + celsius_float_t Temperature::MPC_autotuner::temp_fastest; + + #if HAS_FAN + float Temperature::MPC_autotuner::power_fan255; + #endif + Temperature::MPC_autotuner::MPC_autotuner(const uint8_t extruderIdx) : e(extruderIdx) { TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); } @@ -973,7 +986,7 @@ volatile bool Temperature::raw_temps_ready = false; millis_t next_test_ms = curr_time_ms + test_interval_ms; ambient_temp = current_temp = degHotend(e); wait_for_heatup = true; - + for (;;) { // Can be interrupted with M108 if (housekeeping() == CANCELLED) return CANCELLED; diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index e5c21d23d5cf..cc96f692dde5 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1234,41 +1234,42 @@ class Temperature { float get_elapsed_heating_time() { return elapsed_heating_time; } float get_sample_1_time() { return t1_time; } - float get_sample_1_temp() { return temp_samples[0]; } - float get_sample_2_temp() { return temp_samples[(sample_count - 1) >> 1]; } - float get_sample_3_temp() { return temp_samples[sample_count - 1]; } - float get_sample_interval() { return sample_distance * (sample_count >> 1); } + static float get_sample_1_temp() { return temp_samples[0]; } + static float get_sample_2_temp() { return temp_samples[(sample_count - 1) >> 1]; } + static float get_sample_3_temp() { return temp_samples[sample_count - 1]; } + static float get_sample_interval() { return sample_distance * (sample_count >> 1); } - celsius_float_t get_temp_fastest() { return temp_fastest; } + static celsius_float_t get_temp_fastest() { return temp_fastest; } float get_time_fastest() { return time_fastest; } float get_rate_fastest() { return rate_fastest; } float get_power_fan0() { return power_fan0; } #if HAS_FAN - float get_power_fan255() { return power_fan255; } + static float get_power_fan255() { return power_fan255; } #endif protected: - void init_timers() { curr_time_ms = next_report_ms = millis(); } + static void init_timers() { curr_time_ms = next_report_ms = millis(); } MeasurementState housekeeping(); - millis_t curr_time_ms, next_report_ms; uint8_t e; float elapsed_heating_time; celsius_float_t ambient_temp, current_temp; - celsius_float_t temp_samples[16]; - uint8_t sample_count; - uint16_t sample_distance; float t1_time; + static millis_t curr_time_ms, next_report_ms; + static celsius_float_t temp_samples[16]; + static uint8_t sample_count; + static uint16_t sample_distance; + // Parameters from differential analysis - celsius_float_t temp_fastest; + static celsius_float_t temp_fastest; float time_fastest, rate_fastest; float power_fan0; #if HAS_FAN - float power_fan255; + static float power_fan255; #endif }; From 9b9a622faeb094ce2fd354818b3fe859413c4009 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 11 May 2023 14:04:30 -0500 Subject: [PATCH 42/43] Tweak configs, use of hysteresis --- Marlin/Configuration.h | 58 +++++++++++++++++-------------- Marlin/src/module/temperature.cpp | 12 +++---- Marlin/src/module/temperature.h | 4 +-- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 739632cb7234..a5f95dc87b3b 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -650,14 +650,18 @@ // @section hotend temp -// Enable PIDTEMP for PID control or MPCTEMP for Predictive Model. -// temperature control. Disable both for bang-bang heating. -#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning -//#define MPCTEMP // ** EXPERIMENTAL ** +/** + * Temperature Control + * + * (NONE) : Bang-bang heating + * PIDTEMP : PID temperature control (~4.1K) + * MPCTEMP : Predictive Model temperature control. (~1.8K without auto-tune) + */ +#define PIDTEMP // See the PID Tuning Guide at https://reprap.org/wiki/PID_Tuning +//#define MPCTEMP // ** EXPERIMENTAL ** See https://marlinfw.org/docs/features/model_predictive_control.html -#define BANG_MAX 255 // Limits current to nozzle while in bang-bang mode; 255=full current -#define PID_MAX BANG_MAX // Limits current to nozzle while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current -#define PID_K1 0.95 // Smoothing factor within any PID loop +#define PID_MAX 255 // Limit hotend current while PID is active (see PID_FUNCTIONAL_RANGE below); 255=full current +#define PID_K1 0.95 // Smoothing factor within any PID loop #if ENABLED(PIDTEMP) //#define PID_DEBUG // Print PID debug data to the serial port. Use 'M303 D' to toggle activation. @@ -675,6 +679,8 @@ #define DEFAULT_Ki 1.08 #define DEFAULT_Kd 114.00 #endif +#else + #define BANG_MAX 255 // Limit hotend current while in bang-bang mode; 255=full current #endif /** @@ -686,12 +692,12 @@ * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5664-5882 bytes of flash) - //#define MPC_AUTOTUNE_FANCY // Include a fancier method to do MPC auto-tuning (~5466 bytes of flash) - //#define MPC_EDIT_MENU // Add MPC editing to the "Advanced Settings" menu. (~1300 bytes of flash) + //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5.7K bytes of flash) + //#define MPC_AUTOTUNE_FANCY // Include a fancier method to do MPC auto-tuning (~6.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_MAX BANG_MAX // (0..255) Current to nozzle while MPC is active. + #define MPC_MAX 255 // (0..255) Current to nozzle while MPC is active. #define MPC_HEATER_POWER { 40.0f } // (W) Heat cartridge powers. #define MPC_INCLUDE_FAN // Model the fan speed? @@ -726,32 +732,30 @@ //====================== PID > Bed Temperature Control ====================== //=========================================================================== +// @section bed temp + +/** + * Max Bed Power + * Applies to all forms of bed control (PID, bang-bang, and bang-bang with hysteresis). + * When set to any value below 255, enables a form of PWM to the bed that acts like a divider + * so don't use it unless you are OK with PWM on your bed. (See the comment on enabling PIDTEMPBED) + */ +#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current + /** * PID Bed Heating * - * If this option is enabled set PID constants below. - * If this option is disabled, bang-bang will be used and BED_LIMIT_SWITCHING will enable hysteresis. - * * The PID frequency will be the same as the extruder PWM. * If PID_dT is the default, and correct for the hardware/configuration, that means 7.689Hz, * which is fine for driving a square wave into a resistive load and does not significantly * impact FET heating. This also works fine on a Fotek SSR-10DA Solid State Relay into a 250W * heater. If your configuration is significantly different than this and you don't understand * the issues involved, don't use bed PID until someone else verifies that your hardware works. - * @section bed temp + * + * With this option disabled, bang-bang will be used. BED_LIMIT_SWITCHING enables hysteresis. */ //#define PIDTEMPBED -//#define BED_LIMIT_SWITCHING - -/** - * Max Bed Power - * Applies to all forms of bed control (PID, bang-bang, and bang-bang with hysteresis). - * When set to any value below 255, enables a form of PWM to the bed that acts like a divider - * so don't use it unless you are OK with PWM on your bed. (See the comment on enabling PIDTEMPBED) - */ -#define MAX_BED_POWER 255 // limits duty cycle to bed; 255=full current - #if ENABLED(PIDTEMPBED) //#define MIN_BED_POWER 0 //#define PID_BED_DEBUG // Print Bed PID debug data to the serial port. @@ -763,7 +767,9 @@ #define DEFAULT_bedKd 305.4 // FIND YOUR OWN: "M303 E-1 C8 S90" to run autotune on the bed at 90 degreesC for 8 cycles. -#endif // PIDTEMPBED +#else + //#define BED_LIMIT_SWITCHING // Keep the bed temperature within BED_HYSTERESIS of the target +#endif //=========================================================================== //==================== PID > Chamber Temperature Control ==================== diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 00f7882373dd..314807c1e1bf 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -2081,9 +2081,9 @@ void Temperature::mintemp_error(const heater_id_t heater_id) { // Check if temperature is within the correct band if (WITHIN(temp_bed.celsius, BED_MINTEMP, BED_MAXTEMP)) { #if ENABLED(BED_LIMIT_SWITCHING) - if (temp_bed.is_above_target((BED_HYSTERESIS) - 1)) + if (temp_bed.is_above_target(BED_HYSTERESIS)) temp_bed.soft_pwm_amount = 0; - else if (temp_bed.is_below_target((BED_HYSTERESIS) - 1)) + else if (temp_bed.is_below_target(BED_HYSTERESIS)) temp_bed.soft_pwm_amount = MAX_BED_POWER >> 1; #else // !PIDTEMPBED && !BED_LIMIT_SWITCHING temp_bed.soft_pwm_amount = temp_bed.is_below_target() ? MAX_BED_POWER >> 1 : 0; @@ -2157,7 +2157,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id) { #ifndef MIN_COOLING_SLOPE_DEG_CHAMBER_VENT #define MIN_COOLING_SLOPE_DEG_CHAMBER_VENT 1.5 #endif - if (!flag_chamber_excess_heat && temp_chamber.is_above_target((HIGH_EXCESS_HEAT_LIMIT) - 1)) { + if (!flag_chamber_excess_heat && temp_chamber.is_above_target(HIGH_EXCESS_HEAT_LIMIT)) { // Open vent after MIN_COOLING_SLOPE_TIME_CHAMBER_VENT seconds if the // temperature didn't drop at least MIN_COOLING_SLOPE_DEG_CHAMBER_VENT if (next_cool_check_ms == 0 || ELAPSED(ms, next_cool_check_ms)) { @@ -2171,7 +2171,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id) { next_cool_check_ms = 0; old_temp = 9999; } - if (flag_chamber_excess_heat && temp_chamber.is_above_target((LOW_EXCESS_HEAT_LIMIT) - 1)) + if (flag_chamber_excess_heat && temp_chamber.is_above_target(LOW_EXCESS_HEAT_LIMIT)) flag_chamber_excess_heat = false; #endif } @@ -2203,9 +2203,9 @@ void Temperature::mintemp_error(const heater_id_t heater_id) { } else { #if ENABLED(CHAMBER_LIMIT_SWITCHING) - if (temp_chamber.is_above_target((TEMP_CHAMBER_HYSTERESIS) - 1)) + if (temp_chamber.is_above_target(TEMP_CHAMBER_HYSTERESIS)) temp_chamber.soft_pwm_amount = 0; - else if (temp_chamber.is_below_target((TEMP_CHAMBER_HYSTERESIS) - 1)) + else if (temp_chamber.is_below_target(TEMP_CHAMBER_HYSTERESIS)) temp_chamber.soft_pwm_amount = (MAX_CHAMBER_POWER) >> 1; #else temp_chamber.soft_pwm_amount = temp_chamber.is_below_target() ? (MAX_CHAMBER_POWER) >> 1 : 0; diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index cc96f692dde5..20b433a99b31 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -150,7 +150,7 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; #if HAS_PID_HEATING - #define PID_K2 (1-float(PID_K1)) + #define PID_K2 (1.0f - float(PID_K1)) #define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / (TEMP_TIMER_FREQUENCY)) // Apply the scale factors to the PID values @@ -231,7 +231,7 @@ typedef struct { float p, i, d, c, f; } raw_pidcf_t; }; -#endif +#endif // HAS_PID_HEATING #if ENABLED(PIDTEMP) From fec8d50489acad55c6a281d401fd40499fd9fd7c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 11 May 2023 18:00:20 -0500 Subject: [PATCH 43/43] go for it --- Marlin/Configuration.h | 3 +- Marlin/src/gcode/temp/M306.cpp | 27 +-- Marlin/src/inc/SanityCheck.h | 5 - Marlin/src/module/temperature.cpp | 261 +-------------------------- Marlin/src/module/temperature.h | 8 +- buildroot/tests/STM32F103RE_creality | 2 +- 6 files changed, 20 insertions(+), 286 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index a5f95dc87b3b..fee89898a375 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -692,8 +692,7 @@ * @section mpctemp */ #if ENABLED(MPCTEMP) - //#define MPC_AUTOTUNE // Include a method to do MPC auto-tuning (~5.7K bytes of flash) - //#define MPC_AUTOTUNE_FANCY // Include a fancier 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) //#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/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp index 561b44a14dff..7d2d94952ff0 100644 --- a/Marlin/src/gcode/temp/M306.cpp +++ b/Marlin/src/gcode/temp/M306.cpp @@ -43,8 +43,6 @@ * * With MPC_AUTOTUNE: * T Autotune the extruder specified with 'E' or the active extruder. - * - * With MPC_AUTOTUNE_FANCY: * S0 : Autotuning method AUTO (default) * S1 : Autotuning method DIFFERENTIAL * S2 : Autotuning method ASYMPTOTIC @@ -57,22 +55,17 @@ void GcodeSuite::M306() { return; } - #if EITHER(MPC_AUTOTUNE, MPC_AUTOTUNE_FANCY) + #if ENABLED(MPC_AUTOTUNE) if (parser.seen_test('T')) { - #if ENABLED(MPC_AUTOTUNE_FANCY) - Temperature::MPCTuningType tuning_type; - const uint8_t type = parser.byteval('S', 0); - switch (type) { - case 1: tuning_type = Temperature::MPCTuningType::FORCE_DIFFERENTIAL; break; - case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; - default: tuning_type = Temperature::MPCTuningType::AUTO; break; - } - LCD_MESSAGE(MSG_MPC_AUTOTUNE); - thermalManager.MPC_autotune(e, tuning_type); - #else - LCD_MESSAGE(MSG_MPC_AUTOTUNE); - thermalManager.MPC_autotune(e); - #endif + Temperature::MPCTuningType tuning_type; + const uint8_t type = parser.byteval('S', 0); + switch (type) { + case 1: tuning_type = Temperature::MPCTuningType::FORCE_DIFFERENTIAL; break; + case 2: tuning_type = Temperature::MPCTuningType::FORCE_ASYMPTOTIC; break; + default: tuning_type = Temperature::MPCTuningType::AUTO; break; + } + LCD_MESSAGE(MSG_MPC_AUTOTUNE); + thermalManager.MPC_autotune(e, tuning_type); ui.reset_status(); return; } diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 449910b65759..9c54208c538f 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -976,14 +976,9 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "Only enable PIDTEMP or MPCTEMP, but not both." #undef MPCTEMP #undef MPC_AUTOTUNE - #undef MPC_AUTOTUNE_FANCY #undef MPC_EDIT_MENU #undef MPC_AUTOTUNE_MENU #endif -#if BOTH(MPC_AUTOTUNE, MPC_AUTOTUNE_FANCY) - #error "Only enable MPC_AUTOTUNE or MPC_AUTOTUNE_FANCY, but not both." - #undef MPC_AUTOTUNE_FANCY -#endif #if ENABLED(MPC_INCLUDE_FAN) #if !HAS_FAN diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 314807c1e1bf..8bcaf5d83fc5 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -722,16 +722,14 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(DWIN_PID_TUNE, DWIN_PidTuning(isbed ? PIDTEMPBED_START : PIDTEMP_START)); if (target > GHV(CHAMBER_MAX_TARGET, BED_MAX_TARGET, temp_range[heater_id].maxtemp - (HOTEND_OVERSHOOT))) { - SERIAL_ECHOPGM(STR_PID_AUTOTUNE); - SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); + SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH))); return; } - SERIAL_ECHOPGM(STR_PID_AUTOTUNE); - SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_START); + SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_START); disable_all_heaters(); TERN_(AUTO_POWER_CONTROL, powerManager.power_on()); @@ -816,8 +814,7 @@ volatile bool Temperature::raw_temps_ready = false; #define MAX_OVERSHOOT_PID_AUTOTUNE 30 #endif if (current_temp > target + MAX_OVERSHOOT_PID_AUTOTUNE) { - SERIAL_ECHOPGM(STR_PID_AUTOTUNE); - SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); + SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_TEMP_TOO_HIGH); TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TEMP_TOO_HIGH)); TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TEMP_TOO_HIGH)); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH))); @@ -859,14 +856,12 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(DWIN_PID_TUNE, DWIN_PidTuning(PID_TUNING_TIMEOUT)); TERN_(EXTENSIBLE_UI, ExtUI::onPidTuning(ExtUI::result_t::PID_TUNING_TIMEOUT)); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TIMEOUT))); - SERIAL_ECHOPGM(STR_PID_AUTOTUNE); - SERIAL_ECHOLNPGM(STR_PID_TIMEOUT); + SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_TIMEOUT); break; } if (cycles > ncycles && cycles > 2) { - SERIAL_ECHOPGM(STR_PID_AUTOTUNE); - SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_FINISHED); + SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_AUTOTUNE_FINISHED); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE))); #if EITHER(PIDTEMPBED, PIDTEMPCHAMBER) @@ -938,7 +933,7 @@ volatile bool Temperature::raw_temps_ready = false; #endif // HAS_PID_HEATING -#if ENABLED(MPC_AUTOTUNE_FANCY) +#if ENABLED(MPC_AUTOTUNE) #if EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) #define SINGLEFAN 1 @@ -1261,7 +1256,6 @@ volatile bool Temperature::raw_temps_ready = false; } // If analytic tuning fails, fall back to differential tuning - // If analytic tuning fails, fall back to forcing differential tuning if (tuning_type == AUTO) { if (mpc.sensor_responsiveness <= 0 || mpc.block_heat_capacity <= 0) tuning_type = FORCE_DIFFERENTIAL; @@ -1317,249 +1311,6 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4)); } -#elif ENABLED(MPC_AUTOTUNE) - - #if EITHER(MPC_FAN_0_ALL_HOTENDS, MPC_FAN_0_ACTIVE_HOTEND) - #define SINGLEFAN 1 - #endif - - void Temperature::MPC_autotune(const uint8_t e) { - auto housekeeping = [] (millis_t &ms, const uint8_t e, celsius_float_t ¤t_temp, millis_t &next_report_ms) { - ms = millis(); - - if (updateTemperaturesIfReady()) { // temp sample ready - current_temp = degHotend(e); - TERN_(HAS_FAN_LOGIC, manage_extruder_fans(ms)); - } - - if (ELAPSED(ms, next_report_ms)) { - next_report_ms += 1000UL; - - print_heater_states(e); - SERIAL_EOL(); - } - - hal.idletask(); - TERN(DWIN_CREALITY_LCD, DWIN_Update(), ui.update()); - - if (!wait_for_heatup) { - SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_INTERRUPTED); - TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_INTERRUPTED)); - return true; - } - - return false; - }; - - struct OnExit { - uint8_t e; - OnExit(const uint8_t _e) { this->e = _e; } - ~OnExit() { - wait_for_heatup = false; - - ui.reset_status(); - - temp_hotend[e].target = 0.0f; - temp_hotend[e].soft_pwm_amount = 0; - #if HAS_FAN - set_fan_speed(TERN(SINGLEFAN, 0, e), 0); - planner.sync_fan_speeds(fan_speed); - #endif - - do_z_clearance(MPC_TUNING_END_Z, false); - - TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = true); - } - } on_exit(e); - - SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); - MPCHeaterInfo &hotend = temp_hotend[e]; - MPC_t &mpc = hotend.mpc; - - TERN_(TEMP_TUNING_MAINTAIN_FAN, adaptive_fan_slowing = false); - - // Move to center of bed, just above bed height and cool with max fan - gcode.home_all_axes(true); - disable_all_heaters(); - #if HAS_FAN - zero_fan_speeds(); - set_fan_speed(TERN(SINGLEFAN, 0, e), 255); - planner.sync_fan_speeds(fan_speed); - #endif - do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS)); - - SERIAL_ECHOLNPGM(STR_MPC_COOLING_TO_AMBIENT); - #if ENABLED(DWIN_LCD_PROUI) - DWIN_MPCTuning(MPCTEMP_START); - LCD_ALERTMESSAGE(MSG_MPC_COOLING_TO_AMBIENT); - #else - LCD_MESSAGE(MSG_COOLING); - #endif - - millis_t ms = millis(), next_report_ms = ms, next_test_ms = ms + 10000UL; - celsius_float_t current_temp = degHotend(e), - ambient_temp = current_temp; - - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - if (current_temp >= ambient_temp) { - ambient_temp = (ambient_temp + current_temp) / 2.0f; - break; - } - ambient_temp = current_temp; - next_test_ms += 10000UL; - } - } - wait_for_heatup = false; - - #if HAS_FAN - set_fan_speed(TERN(SINGLEFAN, 0, e), 0); - planner.sync_fan_speeds(fan_speed); - #endif - - hotend.modeled_ambient_temp = ambient_temp; - - SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); - TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200), LCD_MESSAGE(MSG_HEATING)); - hotend.target = 200.0f; // So M105 looks nice - hotend.soft_pwm_amount = (MPC_MAX) >> 1; - const millis_t heat_start_time = next_test_ms = ms; - celsius_float_t temp_samples[16]; - uint8_t sample_count = 0; - uint16_t sample_distance = 1; - float t1_time = 0; - - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - // Record samples between 100C and 200C - if (current_temp >= 100.0f) { - // If there are too many samples, space them more widely - if (sample_count == COUNT(temp_samples)) { - for (uint8_t i = 0; i < COUNT(temp_samples) / 2; i++) - temp_samples[i] = temp_samples[i*2]; - sample_count /= 2; - sample_distance *= 2; - } - - if (sample_count == 0) t1_time = float(ms - heat_start_time) / 1000.0f; - temp_samples[sample_count++] = current_temp; - } - - if (current_temp >= 200.0f) break; - - next_test_ms += 1000UL * sample_distance; - } - } - wait_for_heatup = false; - - hotend.soft_pwm_amount = 0; - - // Calculate physical constants from three equally-spaced samples - sample_count = (sample_count + 1) / 2 * 2 - 1; - const float t1 = temp_samples[0], - t2 = temp_samples[(sample_count - 1) >> 1], - t3 = temp_samples[sample_count - 1]; - float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); - - mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp); - mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); - TERN_(MPC_INCLUDE_FAN, mpc.fan255_adjustment = 0.0f); - - hotend.modeled_block_temp = asymp_temp + (ambient_temp - asymp_temp) * exp(-block_responsiveness * (ms - heat_start_time) / 1000.0f); - hotend.modeled_sensor_temp = current_temp; - - // Allow the system to stabilize under MPC, then get a better measure of ambient loss with and without fan - SERIAL_ECHOLNPGM(STR_MPC_MEASURING_AMBIENT, hotend.modeled_block_temp); - TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_MEASURING_AMBIENT), LCD_MESSAGE(MSG_MPC_MEASURING_AMBIENT)); - hotend.target = hotend.modeled_block_temp; - next_test_ms = ms + MPC_dT * 1000; - constexpr millis_t settle_time = 20000UL, test_duration = 20000UL; - millis_t settle_end_ms = ms + settle_time, - test_end_ms = settle_end_ms + test_duration; - float total_energy_fan0 = 0.0f; - #if HAS_FAN - bool fan0_done = false; - float total_energy_fan255 = 0.0f; - #endif - float last_temp = current_temp; - - wait_for_heatup = true; - for (;;) { // Can be interrupted with M108 - if (housekeeping(ms, e, current_temp, next_report_ms)) return; - - if (ELAPSED(ms, next_test_ms)) { - hotend.soft_pwm_amount = (int)get_pid_output_hotend(e) >> 1; - - if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms) && TERN1(HAS_FAN, !fan0_done)) - total_energy_fan0 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; - #if HAS_FAN - else if (ELAPSED(ms, test_end_ms) && !fan0_done) { - set_fan_speed(TERN(SINGLEFAN, 0, e), 255); - planner.sync_fan_speeds(fan_speed); - settle_end_ms = ms + settle_time; - test_end_ms = settle_end_ms + test_duration; - fan0_done = true; - } - else if (ELAPSED(ms, settle_end_ms) && !ELAPSED(ms, test_end_ms)) - total_energy_fan255 += mpc.heater_power * hotend.soft_pwm_amount / 127 * MPC_dT + (last_temp - current_temp) * mpc.block_heat_capacity; - #endif - else if (ELAPSED(ms, test_end_ms)) break; - - last_temp = current_temp; - next_test_ms += MPC_dT * 1000; - } - - if (!WITHIN(current_temp, t3 - 15.0f, hotend.target + 15.0f)) { - SERIAL_ECHOLNPGM(STR_MPC_TEMPERATURE_ERROR); - TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_TEMP_ERROR)); - break; - } - } - wait_for_heatup = false; - - const float power_fan0 = total_energy_fan0 * 1000 / test_duration; - mpc.ambient_xfer_coeff_fan0 = power_fan0 / (hotend.target - ambient_temp); - - #if HAS_FAN - const float power_fan255 = total_energy_fan255 * 1000 / test_duration, - ambient_xfer_coeff_fan255 = power_fan255 / (hotend.target - ambient_temp); - mpc.applyFanAdjustment(ambient_xfer_coeff_fan255); - #endif - - // Calculate a new and better asymptotic temperature and re-evaluate the other constants - asymp_temp = ambient_temp + mpc.heater_power * (MPC_MAX) / 255 / mpc.ambient_xfer_coeff_fan0; - block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1)); - mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; - mpc.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp)); - - SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_FINISHED); - TERN_(DWIN_LCD_PROUI, DWIN_MPCTuning(MPC_DONE)); - - #if 0 - SERIAL_ECHOLNPGM("t1_time ", t1_time); - SERIAL_ECHOLNPGM("sample_count ", sample_count); - SERIAL_ECHOLNPGM("sample_distance ", sample_distance); - for (uint8_t i = 0; i < sample_count; i++) - SERIAL_ECHOLNPGM("sample ", i, " : ", temp_samples[i]); - SERIAL_ECHOLNPGM("t1 ", t1, " t2 ", t2, " t3 ", t3); - SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); - SERIAL_ECHOLNPAIR_F("block_responsiveness ", block_responsiveness, 4); - #endif - - SERIAL_ECHOLNPGM("MPC_BLOCK_HEAT_CAPACITY ", mpc.block_heat_capacity); - SERIAL_ECHOLNPAIR_F("MPC_SENSOR_RESPONSIVENESS ", mpc.sensor_responsiveness, 4); - SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF ", mpc.ambient_xfer_coeff_fan0, 4); - TERN_(HAS_FAN, SERIAL_ECHOLNPAIR_F("MPC_AMBIENT_XFER_COEFF_FAN255 ", ambient_xfer_coeff_fan255, 4)); - } - #endif // MPC_AUTOTUNE int16_t Temperature::getHeaterPower(const heater_id_t heater_id) { diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index 20b433a99b31..4bd185c4251b 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1217,7 +1217,7 @@ class Temperature { #endif // HAS_PID_HEATING - #if ENABLED(MPC_AUTOTUNE_FANCY) + #if ENABLED(MPC_AUTOTUNE) // Utility class to perform MPCTEMP auto tuning measurements class MPC_autotuner { @@ -1276,11 +1276,7 @@ class Temperature { enum MPCTuningType { AUTO, FORCE_ASYMPTOTIC, FORCE_DIFFERENTIAL }; static void MPC_autotune(const uint8_t e, MPCTuningType tuning_type); - #elif ENABLED(MPC_AUTOTUNE) - - void MPC_autotune(const uint8_t e); - - #endif + #endif // MPC_AUTOTUNE #if ENABLED(PROBING_HEATERS_OFF) static void pause_heaters(const bool p); diff --git a/buildroot/tests/STM32F103RE_creality b/buildroot/tests/STM32F103RE_creality index 918c9944932a..834580fac8e3 100755 --- a/buildroot/tests/STM32F103RE_creality +++ b/buildroot/tests/STM32F103RE_creality @@ -20,7 +20,7 @@ exec_test $1 $2 "Ender-3 v2 - JyersUI (ABL Bilinear/Manual)" "$3" use_example_configs "Creality/Ender-3 V2/CrealityV422/CrealityUI" opt_disable DWIN_CREALITY_LCD PIDTEMP -opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE_FANCY +opt_enable DWIN_MARLINUI_LANDSCAPE LCD_ENDSTOP_TEST AUTO_BED_LEVELING_UBL BLTOUCH Z_SAFE_HOMING MPCTEMP MPC_AUTOTUNE exec_test $1 $2 "Ender-3 v2 - MarlinUI (UBL+BLTOUCH, MPCTEMP, LCD_ENDSTOP_TEST)" "$3" use_example_configs "Creality/Ender-3 S1/STM32F1"