diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index a4634e10..d6ac4f51 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7586,7 +7586,8 @@ Sigma_Exit: M310 [ A ] [ F ] ; autotune M310 [ S ] ; set 0=disable 1=enable M310 [ I ] [ R ] ; set resistance at index - M310 [ P | C ] ; set power, capacitance + M310 [ P | U | V | C ] ; set power, temperature coefficient, intercept, capacitance + M310 [ D | L ] ; set simulation filter, lag M310 [ B | E | W ] ; set beeper, warning and error threshold M310 [ T ] ; set ambient temperature correction @@ -7594,7 +7595,11 @@ Sigma_Exit: - `I` - resistance index position (0-15) - `R` - resistance value at index (K/W; requires `I`) - `P` - power (W) + - `U` - linear temperature coefficient (W/K/power) + - `V` - linear temperature intercept (W/power) - `C` - capacitance (J/K) + - `D` - sim. 1st order IIR filter factor (f=100/27) + - `L` - sim. response lag (ms, 0-2160) - `S` - set 0=disable 1=enable - `B` - beep and warn when reaching warning threshold 0=disable 1=enable (default: 1) - `E` - error threshold (K/s; default in variant) @@ -7606,31 +7611,39 @@ Sigma_Exit: case 310: { // parse all parameters - float P = NAN, C = NAN, R = NAN, E = NAN, W = NAN, T = NAN; + float R = NAN, P = NAN, U = NAN, V = NAN, C = NAN, D = NAN, T = NAN, W = NAN, E = NAN; int8_t I = -1, S = -1, B = -1, F = -1; - int16_t A = -1; - if(code_seen('C')) C = code_value(); - if(code_seen('P')) P = code_value(); + int16_t A = -1, L = -1; if(code_seen('I')) I = code_value_short(); if(code_seen('R')) R = code_value(); + if(code_seen('P')) P = code_value(); + if(code_seen('U')) U = code_value(); + if(code_seen('V')) V = code_value(); + if(code_seen('C')) C = code_value(); + if(code_seen('D')) D = code_value(); + if(code_seen('L')) L = code_value_short(); if(code_seen('S')) S = code_value_short(); if(code_seen('B')) B = code_value_short(); + if(code_seen('T')) T = code_value(); if(code_seen('E')) E = code_value(); if(code_seen('W')) W = code_value(); - if(code_seen('T')) T = code_value(); if(code_seen('A')) A = code_value_short(); if(code_seen('F')) F = code_value_short(); // report values if nothing has been requested - if(isnan(C) && isnan(P) && isnan(R) && isnan(E) && isnan(W) && isnan(T) && I < 0 && S < 0 && B < 0 && A < 0) { + if(isnan(R) && isnan(P) && isnan(U) && isnan(V) && isnan(C) && isnan(D) && isnan(T) && isnan(W) && isnan(E) + && I < 0 && S < 0 && B < 0 && A < 0 && L < 0) { temp_model_report_settings(); break; } // update all parameters - if(B >= 0) temp_model_set_warn_beep(B); - if(!isnan(C) || !isnan(P) || !isnan(T) || !isnan(W) || !isnan(E)) temp_model_set_params(C, P, T, W, E); - if(I >= 0 && !isnan(R)) temp_model_set_resistance(I, R); + if(B >= 0) + temp_model_set_warn_beep(B); + if(!isnan(P) || !isnan(U) || !isnan(V) || !isnan(C) || !isnan(D) || (L >= 0) || !isnan(T) || !isnan(W) || !isnan(E)) + temp_model_set_params(P, U, V, C, D, L, T, W, E); + if(I >= 0 && !isnan(R)) + temp_model_set_resistance(I, R); // enable the model last, if requested if(S >= 0) temp_model_set_enabled(S); diff --git a/Firmware/temp_model.h b/Firmware/temp_model.h index 492781fd..97eb5b3b 100644 --- a/Firmware/temp_model.h +++ b/Firmware/temp_model.h @@ -7,11 +7,10 @@ constexpr uint8_t TEMP_MODEL_CAL_S = 60; // Maximum recording lenght during calibration (s) constexpr uint8_t TEMP_MODEL_CAL_R_STEP = 4; // Fan interpolation steps during calibration -constexpr float TEMP_MODEL_fS = 0.065; // simulation filter (1st-order IIR factor) constexpr float TEMP_MODEL_fE = 0.05; // error filter (1st-order IIR factor) // transport delay buffer size (samples) -constexpr uint8_t TEMP_MODEL_LAG_SIZE = (TEMP_MODEL_LAG / TEMP_MGR_INTV + 0.5); +constexpr uint8_t TEMP_MODEL_MAX_LAG_SIZE = 8; // * TEMP_MGR_INTV = 2160 // resistance values for all fan levels constexpr uint8_t TEMP_MODEL_R_SIZE = (1 << FAN_SOFT_PWM_BITS); @@ -22,14 +21,18 @@ namespace temp_model { struct model_data { // temporary buffers - float dT_lag_buf[TEMP_MODEL_LAG_SIZE]; // transport delay buffer - uint8_t dT_lag_idx = 0; // transport delay buffer index - float dT_err_prev = 0; // previous temperature delta error - float T_prev = 0; // last temperature extruder + float dT_lag_buf[TEMP_MODEL_MAX_LAG_SIZE]; // transport delay buffer + uint8_t dT_lag_idx = 0; // transport delay buffer index + float dT_err_prev = 0; // previous temperature delta error + float T_prev = 0; // last temperature extruder // configurable parameters float P; // heater power (W) + float U; // linear temperature coefficient (W/K/W) + float V; // linear temperature intercept (W/W) float C; // heatblock capacitance (J/K) + float fS; // sim. 1st order IIR filter factor (f=100/27) + uint16_t L; // sim. response lag (ms) float R[TEMP_MODEL_R_SIZE]; // heatblock resistance for all fan levels (K/W) float Ta_corr; // ambient temperature correction (K) diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index cf3f9364..f7995c1f 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -2540,15 +2540,27 @@ void temp_model_set_warn_beep(bool enabled) temp_model::warn_beep = enabled; } -void temp_model_set_params(float C, float P, float Ta_corr, float warn, float err) +// set the model lag rounding to the effective sample resolution, ensuring the reported/stored lag +// matches the current model constraints (future-proofing for model changes) +static void temp_model_set_lag(uint16_t ms) +{ + static const uint16_t intv_ms = (uint16_t)(TEMP_MGR_INTV * 1000); + temp_model::data.L = ((ms + intv_ms/2) / intv_ms) * intv_ms; +} + +void temp_model_set_params(float P, float U, float V, float C, float D, int16_t L, float Ta_corr, float warn, float err) { TempMgrGuard temp_mgr_guard; - if(!isnan(C) && C > 0) temp_model::data.C = C; if(!isnan(P) && P > 0) temp_model::data.P = P; + if(!isnan(U)) temp_model::data.U = U; + if(!isnan(V)) temp_model::data.V = V; + if(!isnan(C) && C > 0) temp_model::data.C = C; + if(!isnan(D)) temp_model::data.fS = D; + if(L >= 0) temp_model_set_lag(L); if(!isnan(Ta_corr)) temp_model::data.Ta_corr = Ta_corr; - if(!isnan(err) && err > 0) temp_model::data.err = err; if(!isnan(warn) && warn > 0) temp_model::data.warn = warn; + if(!isnan(err) && err > 0) temp_model::data.err = err; // ensure warn <= err if (temp_model::data.warn > temp_model::data.err) @@ -2573,8 +2585,9 @@ void temp_model_report_settings() SERIAL_ECHOLNPGM("Temperature Model settings:"); for(uint8_t i = 0; i != TEMP_MODEL_R_SIZE; ++i) printf_P(PSTR("%S M310 I%u R%.2f\n"), echomagic, (unsigned)i, (double)temp_model::data.R[i]); - printf_P(PSTR("%S M310 P%.2f C%.2f S%u B%u E%.2f W%.2f T%.2f\n"), - echomagic, (double)temp_model::data.P, (double)temp_model::data.C, + printf_P(PSTR("%S M310 P%.2f U%.4f V%.2f C%.2f D%.4f L%u S%u B%u E%.2f W%.2f T%.2f\n"), + echomagic, (double)temp_model::data.P, (double)temp_model::data.U, (double)temp_model::data.V, + (double)temp_model::data.C, (double)temp_model::data.fS, (unsigned)temp_model::data.L, (unsigned)temp_model::enabled, (unsigned)temp_model::warn_beep, (double)temp_model::data.err, (double)temp_model::data.warn, (double)temp_model::data.Ta_corr); @@ -2585,7 +2598,11 @@ void temp_model_reset_settings() TempMgrGuard temp_mgr_guard; temp_model::data.P = TEMP_MODEL_P; + temp_model::data.U = TEMP_MODEL_U; + temp_model::data.V = TEMP_MODEL_V; temp_model::data.C = TEMP_MODEL_C; + temp_model::data.fS = TEMP_MODEL_fS; + temp_model::data.L = (uint16_t)(TEMP_MODEL_LAG / (TEMP_MGR_INTV * 1000) + 0.5) * (uint16_t)(TEMP_MGR_INTV * 1000); for(uint8_t i = 0; i != TEMP_MODEL_R_SIZE; ++i) temp_model::data.R[i] = pgm_read_float(TEMP_MODEL_R_DEFAULT + i); temp_model::data.Ta_corr = TEMP_MODEL_Ta_corr; @@ -2601,9 +2618,21 @@ void temp_model_load_settings() static_assert(TEMP_MODEL_R_SIZE == 16); // ensure we don't desync with the eeprom table TempMgrGuard temp_mgr_guard; + // handle upgrade from a model without UVDL (FW<3.13) + // WARNING: this only works as long as UVDL are the same constants/model type as FW 3.12, + // it needs to consider the upgrading FW version otherwise! + eeprom_init_default_float((float*)EEPROM_TEMP_MODEL_U, TEMP_MODEL_U); + eeprom_init_default_float((float*)EEPROM_TEMP_MODEL_V, TEMP_MODEL_V); + eeprom_init_default_float((float*)EEPROM_TEMP_MODEL_D, TEMP_MODEL_fS); + eeprom_init_default_word((uint16_t*)EEPROM_TEMP_MODEL_L, TEMP_MODEL_LAG); + temp_model::enabled = eeprom_read_byte((uint8_t*)EEPROM_TEMP_MODEL_ENABLE); temp_model::data.P = eeprom_read_float((float*)EEPROM_TEMP_MODEL_P); + temp_model::data.U = eeprom_read_float((float*)EEPROM_TEMP_MODEL_U); + temp_model::data.V = eeprom_read_float((float*)EEPROM_TEMP_MODEL_V); temp_model::data.C = eeprom_read_float((float*)EEPROM_TEMP_MODEL_C); + temp_model::data.fS = eeprom_read_float((float*)EEPROM_TEMP_MODEL_D); + temp_model_set_lag(eeprom_read_word((uint16_t*)EEPROM_TEMP_MODEL_L)); for(uint8_t i = 0; i != TEMP_MODEL_R_SIZE; ++i) temp_model::data.R[i] = eeprom_read_float((float*)EEPROM_TEMP_MODEL_R + i); temp_model::data.Ta_corr = eeprom_read_float((float*)EEPROM_TEMP_MODEL_Ta_corr); @@ -2621,7 +2650,11 @@ void temp_model_save_settings() { eeprom_update_byte((uint8_t*)EEPROM_TEMP_MODEL_ENABLE, temp_model::enabled); eeprom_update_float((float*)EEPROM_TEMP_MODEL_P, temp_model::data.P); + eeprom_update_float((float*)EEPROM_TEMP_MODEL_U, temp_model::data.U); + eeprom_update_float((float*)EEPROM_TEMP_MODEL_V, temp_model::data.V); eeprom_update_float((float*)EEPROM_TEMP_MODEL_C, temp_model::data.C); + eeprom_update_float((float*)EEPROM_TEMP_MODEL_D, temp_model::data.fS); + eeprom_update_word((uint16_t*)EEPROM_TEMP_MODEL_L, temp_model::data.L); for(uint8_t i = 0; i != TEMP_MODEL_R_SIZE; ++i) eeprom_update_float((float*)EEPROM_TEMP_MODEL_R + i, temp_model::data.R[i]); eeprom_update_float((float*)EEPROM_TEMP_MODEL_Ta_corr, temp_model::data.Ta_corr); diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 03629db1..7e608e23 100755 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -220,7 +220,8 @@ void PID_autotune(float temp, int extruder, int ncycles); bool temp_model_enabled(); // return temperature model state void temp_model_set_enabled(bool enabled); void temp_model_set_warn_beep(bool enabled); -void temp_model_set_params(float C = NAN, float P = NAN, float Ta_corr = NAN, float warn = NAN, float err = NAN); +void temp_model_set_params(float P=NAN, float U=NAN, float V=NAN, float C=NAN, float D=NAN, + int16_t L=-1, float Ta_corr=NAN, float warn=NAN, float err=NAN); void temp_model_set_resistance(uint8_t index, float R); void temp_model_report_settings(); diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h index df08de9e..40dcb929 100644 --- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h @@ -415,6 +415,8 @@ #define TEMP_MODEL_DEBUG 1 // extended runtime logging #define TEMP_MODEL_P 38. // heater power (W) +#define TEMP_MODEL_U 1. // linear temperature coefficient (W/K/power) +#define TEMP_MODEL_V 0. // linear temperature intercept (W/power) #define TEMP_MODEL_C 12.1 // initial guess for heatblock capacitance (J/K) #define TEMP_MODEL_Cl 5 // C estimation lower limit @@ -422,6 +424,9 @@ #define TEMP_MODEL_C_thr 0.01 // C estimation iteration threshold #define TEMP_MODEL_C_itr 30 // C estimation iteration limit +#define TEMP_MODEL_fS 0.065 // sim. 1st order IIR filter factor (f=100/27) +#define TEMP_MODEL_LAG 2100 // sim. response lag (ms, 0-2160) + #define TEMP_MODEL_R 20.5 // initial guess for heatblock resistance (K/W) #define TEMP_MODEL_Rl 5 // R estimation lower limit #define TEMP_MODEL_Rh 50 // R estimation upper limit @@ -429,8 +434,6 @@ #define TEMP_MODEL_R_itr 30 // R estimation iteration limit #define TEMP_MODEL_Ta_corr -7 // Default ambient temperature correction -#define TEMP_MODEL_LAG 2.1 // Temperature transport delay (s) - #define TEMP_MODEL_W 1.2 // Default warning threshold (K/s) #define TEMP_MODEL_E 1.74 // Default error threshold (K/s) diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h index af6ffa3b..f5d6d2f8 100644 --- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h @@ -419,6 +419,8 @@ #define TEMP_MODEL_DEBUG 1 // extended runtime logging #define TEMP_MODEL_P 38. // heater power (W) +#define TEMP_MODEL_U 1. // linear temperature coefficient (W/K/power) +#define TEMP_MODEL_V 0. // linear temperature intercept (W/power) #define TEMP_MODEL_C 12.1 // initial guess for heatblock capacitance (J/K) #define TEMP_MODEL_Cl 5 // C estimation lower limit @@ -426,6 +428,9 @@ #define TEMP_MODEL_C_thr 0.01 // C estimation iteration threshold #define TEMP_MODEL_C_itr 30 // C estimation iteration limit +#define TEMP_MODEL_fS 0.065 // sim. 1st order IIR filter factor (f=100/27) +#define TEMP_MODEL_LAG 2100 // sim. response lag (ms, 0-2160) + #define TEMP_MODEL_R 20.5 // initial guess for heatblock resistance (K/W) #define TEMP_MODEL_Rl 5 // R estimation lower limit #define TEMP_MODEL_Rh 50 // R estimation upper limit @@ -433,8 +438,6 @@ #define TEMP_MODEL_R_itr 30 // R estimation iteration limit #define TEMP_MODEL_Ta_corr -7 // Default ambient temperature correction -#define TEMP_MODEL_LAG 2.1 // Temperature transport delay (s) - #define TEMP_MODEL_W 1.2 // Default warning threshold (K/s) #define TEMP_MODEL_E 1.74 // Default error threshold (K/s)