From fc1a620b878b45675b9a7972be6c1fb2882b8092 Mon Sep 17 00:00:00 2001
From: tombrazier <68918209+tombrazier@users.noreply.github.com>
Date: Sat, 28 May 2022 23:40:08 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A9=20MPC=20update=20(#24253)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Marlin/Configuration.h            |  6 +++---
 Marlin/src/gcode/temp/M306.cpp    |  8 ++++++--
 Marlin/src/module/settings.cpp    |  3 +++
 Marlin/src/module/temperature.cpp |  6 +++---
 Marlin/src/module/temperature.h   | 11 ++++++-----
 buildroot/tests/BIGTREE_GTR_V1_0  |  3 ++-
 6 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index a3c762a72eb..96bfc59428f 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -646,15 +646,15 @@
     //#define MPC_FAN_0_ACTIVE_HOTEND
   #endif
 
-  #define FILAMENT_HEAT_CAPACITY_PERMM 5.6e-3f        // 0.0056 J/K/mm for 1.75mm PLA (0.0149 J/K/mm for 2.85mm PLA).
-  //#define FILAMENT_HEAT_CAPACITY_PERMM 3.6e-3f      // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG).
+  #define FILAMENT_HEAT_CAPACITY_PERMM { 5.6e-3f }    // 0.0056 J/K/mm for 1.75mm PLA (0.0149 J/K/mm for 2.85mm PLA).
+  //#define FILAMENT_HEAT_CAPACITY_PERMM { 3.6e-3f }  // 0.0036 J/K/mm for 1.75mm PETG (0.0094 J/K/mm for 2.85mm PETG).
 
   // Advanced options
   #define MPC_SMOOTHING_FACTOR 0.5f                   // (0.0...1.0) Noisy temperature sensors may need a lower value for stabilization.
   #define MPC_MIN_AMBIENT_CHANGE 1.0f                 // (K/s) Modeled ambient temperature rate of change, when correcting model inaccuracies.
   #define MPC_STEADYSTATE 0.5f                        // (K/s) Temperature change rate for steady state logic to be enforced.
 
-  #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center just above the surface.
+  #define MPC_TUNING_POS { X_CENTER, Y_CENTER, 1.0f } // (mm) M306 Autotuning position, ideally bed center at first layer height.
   #define MPC_TUNING_END_Z 10.0f                      // (mm) M306 Autotuning final Z position.
 #endif
 
diff --git a/Marlin/src/gcode/temp/M306.cpp b/Marlin/src/gcode/temp/M306.cpp
index 0f286e73b23..4286b2017e2 100644
--- a/Marlin/src/gcode/temp/M306.cpp
+++ b/Marlin/src/gcode/temp/M306.cpp
@@ -36,6 +36,7 @@
  *  C<joules/kelvin>          Block heat capacity.
  *  E<extruder>               Extruder number to set. (Default: E0)
  *  F<watts/kelvin>           Ambient heat transfer coefficient (fan on full).
+ *  H<joules/kelvin/mm>       Filament heat capacity per mm.
  *  P<watts>                  Heater power.
  *  R<kelvin/second/kelvin>   Sensor responsiveness (= transfer coefficient / heat capcity).
  */
@@ -43,7 +44,7 @@
 void GcodeSuite::M306() {
   if (parser.seen_test('T')) { thermalManager.MPC_autotune(); return; }
 
-  if (parser.seen("ACFPR")) {
+  if (parser.seen("ACFPRH")) {
     const heater_id_t hid = (heater_id_t)parser.intval('E', 0);
     MPC_t &constants = thermalManager.temp_hotend[hid].constants;
     if (parser.seenval('P')) constants.heater_power = parser.value_float();
@@ -53,6 +54,7 @@ void GcodeSuite::M306() {
     #if ENABLED(MPC_INCLUDE_FAN)
       if (parser.seenval('F')) constants.fan255_adjustment = parser.value_float() - constants.ambient_xfer_coeff_fan0;
     #endif
+    if (parser.seenval('H')) constants.filament_heat_capacity_permm = parser.value_float();
     return;
   }
 
@@ -70,8 +72,10 @@ void GcodeSuite::M306_report(const bool forReplay/*=true*/) {
     SERIAL_ECHOPAIR_F(" R", constants.sensor_responsiveness, 4);
     SERIAL_ECHOPAIR_F(" A", constants.ambient_xfer_coeff_fan0, 4);
     #if ENABLED(MPC_INCLUDE_FAN)
-      SERIAL_ECHOLNPAIR_F(" F", constants.ambient_xfer_coeff_fan0 + constants.fan255_adjustment, 4);
+      SERIAL_ECHOPAIR_F(" F", constants.ambient_xfer_coeff_fan0 + constants.fan255_adjustment, 4);
     #endif
+    SERIAL_ECHOPAIR_F(" M", constants.filament_heat_capacity_permm, 4);
+    SERIAL_EOL();
   }
 }
 
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index bde60098abc..dd360e9cd8a 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -3266,6 +3266,7 @@ void MarlinSettings::reset() {
     #if ENABLED(MPC_INCLUDE_FAN)
       constexpr float _mpc_ambient_xfer_coeff_fan255[] = MPC_AMBIENT_XFER_COEFF_FAN255;
     #endif
+    constexpr float _filament_heat_capacity_permm[] = FILAMENT_HEAT_CAPACITY_PERMM;
 
     static_assert(COUNT(_mpc_heater_power) == HOTENDS, "MPC_HEATER_POWER must have HOTENDS items.");
     static_assert(COUNT(_mpc_block_heat_capacity) == HOTENDS, "MPC_BLOCK_HEAT_CAPACITY must have HOTENDS items.");
@@ -3274,6 +3275,7 @@ void MarlinSettings::reset() {
     #if ENABLED(MPC_INCLUDE_FAN)
       static_assert(COUNT(_mpc_ambient_xfer_coeff_fan255) == HOTENDS, "MPC_AMBIENT_XFER_COEFF_FAN255 must have HOTENDS items.");
     #endif
+    static_assert(COUNT(_filament_heat_capacity_permm) == HOTENDS, "FILAMENT_HEAT_CAPACITY_PERMM must have HOTENDS items.");
 
     HOTEND_LOOP() {
       thermalManager.temp_hotend[e].constants.heater_power = _mpc_heater_power[e];
@@ -3283,6 +3285,7 @@ void MarlinSettings::reset() {
       #if ENABLED(MPC_INCLUDE_FAN)
         thermalManager.temp_hotend[e].constants.fan255_adjustment = _mpc_ambient_xfer_coeff_fan255[e] - _mpc_ambient_xfer_coeff[e];
       #endif
+      thermalManager.temp_hotend[e].constants.filament_heat_capacity_permm = _filament_heat_capacity_permm[e];
     }
   #endif
 
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index ce84b592336..f65de00f61e 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -998,7 +998,7 @@ volatile bool Temperature::raw_temps_ready = false;
     float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3),
           block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1));
 
-    constants.ambient_xfer_coeff_fan0 = constants.heater_power * MPC_MAX / 255 / (asymp_temp - ambient_temp);
+    constants.ambient_xfer_coeff_fan0 = constants.heater_power * (MPC_MAX) / 255 / (asymp_temp - ambient_temp);
     constants.fan255_adjustment = 0.0f;
     constants.block_heat_capacity = constants.ambient_xfer_coeff_fan0 / block_responsiveness;
     constants.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
@@ -1062,7 +1062,7 @@ volatile bool Temperature::raw_temps_ready = false;
     #endif
 
     // Calculate a new and better asymptotic temperature and re-evaluate the other constants
-    asymp_temp = ambient_temp + constants.heater_power / constants.ambient_xfer_coeff_fan0;
+    asymp_temp = ambient_temp + constants.heater_power * (MPC_MAX) / 255 / constants.ambient_xfer_coeff_fan0;
     block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / (sample_distance * (sample_count >> 1));
     constants.block_heat_capacity = constants.ambient_xfer_coeff_fan0 / block_responsiveness;
     constants.sensor_responsiveness = block_responsiveness / (1.0f - (ambient_temp - asymp_temp) * exp(-block_responsiveness * t1_time) / (t1 - asymp_temp));
@@ -1446,7 +1446,7 @@ void Temperature::min_temp_error(const heater_id_t heater_id) {
         if (fabs(e_speed) > planner.settings.max_feedrate_mm_s[E_AXIS])
           mpc_e_position = e_position;
         else if (e_speed > 0.0f) {  // Ignore retract/recover moves
-          ambient_xfer_coeff += e_speed * FILAMENT_HEAT_CAPACITY_PERMM;
+          ambient_xfer_coeff += e_speed * constants.filament_heat_capacity_permm;
           mpc_e_position = e_position;
         }
       }
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index a9980f4890e..9dc41129b28 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -96,13 +96,14 @@ hotend_pid_t;
 
 #if ENABLED(MPCTEMP)
   typedef struct {
-    float heater_power;             // M306 P
-    float block_heat_capacity;      // M306 C
-    float sensor_responsiveness;    // M306 R
-    float ambient_xfer_coeff_fan0;  // M306 A
+    float heater_power;                 // M306 P
+    float block_heat_capacity;          // M306 C
+    float sensor_responsiveness;        // M306 R
+    float ambient_xfer_coeff_fan0;      // M306 A
     #if ENABLED(MPC_INCLUDE_FAN)
-      float fan255_adjustment;      // M306 F
+      float fan255_adjustment;          // M306 F
     #endif
+    float filament_heat_capacity_permm; // M306 M
   } MPC_t;
 #endif
 
diff --git a/buildroot/tests/BIGTREE_GTR_V1_0 b/buildroot/tests/BIGTREE_GTR_V1_0
index 93342ed4a47..13ec7ca3a2f 100755
--- a/buildroot/tests/BIGTREE_GTR_V1_0
+++ b/buildroot/tests/BIGTREE_GTR_V1_0
@@ -37,7 +37,8 @@ opt_set MOTHERBOARD BOARD_BTT_GTR_V1_0 SERIAL_PORT -1 \
         MPC_BLOCK_HEAT_CAPACITY '{ 16.7f, 16.7f, 16.7f }' \
         MPC_SENSOR_RESPONSIVENESS '{ 0.22f, 0.22f, 0.22f }' \
         MPC_AMBIENT_XFER_COEFF '{ 0.068f, 0.068f, 0.068f }' \
-        MPC_AMBIENT_XFER_COEFF_FAN255 '{ 0.097f, 0.097f, 0.097f }'
+        MPC_AMBIENT_XFER_COEFF_FAN255 '{ 0.097f, 0.097f, 0.097f }' \
+        FILAMENT_HEAT_CAPACITY_PERMM '{ 5.6e-3f, 3.6e-3f, 5.6e-3f }'
 opt_enable SWITCHING_TOOLHEAD TOOL_SENSOR MPCTEMP MPC_EDIT_MENU MPC_AUTOTUNE_MENU
 opt_disable PIDTEMP
 exec_test $1 $2 "BigTreeTech GTR | MPC | Switching Toolhead | Tool Sensors" "$3"