TM: Handle UVDL set/load/report/upgrade

- Expose TEMP_MODEL_fS and TEMP_MODEL_LAG as D and L respectively,
  initializing the default values based on the previous hard-coded
  values.
- Always round L to the effective sample lag to future-proof model
  upgrades or changes (the stored value _is_ the effective value).
- Introduce UV as a new linear term for PTC heaters, defaulting
  to an identity for model backward-compatibility.
This commit is contained in:
Yuri D'Elia 2023-01-26 22:18:09 +01:00
parent 5a1ed1519c
commit 70fd9a336b
6 changed files with 82 additions and 26 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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)