| 1323 | } |
| 1324 | |
| 1325 | void Temperature::MPC_autotune(const uint8_t e, MPCTuningType tuning_type=AUTO) { |
| 1326 | SERIAL_ECHOLNPGM(STR_MPC_AUTOTUNE_START, e); |
| 1327 | |
| 1328 | MPC_autotuner tuner(e); |
| 1329 | |
| 1330 | MPCHeaterInfo &hotend = temp_hotend[e]; |
| 1331 | MPC_t &mpc = hotend.mpc; |
| 1332 | |
| 1333 | // Move to center of bed, just above bed height and cool with max fan |
| 1334 | gcode.home_all_axes(true); |
| 1335 | disable_all_heaters(); |
| 1336 | #if HAS_FAN |
| 1337 | zero_fan_speeds(); |
| 1338 | set_fan_speed(TERN(SINGLEFAN, 0, e), 255); |
| 1339 | planner.sync_fan_speeds(fan_speed); |
| 1340 | #endif |
| 1341 | do_blocking_move_to(xyz_pos_t(MPC_TUNING_POS)); |
| 1342 | |
| 1343 | // Determine ambient temperature. |
| 1344 | SERIAL_ECHOLNPGM(STR_MPC_COOLING_TO_AMBIENT); |
| 1345 | TERN_(EXTENSIBLE_UI, ExtUI::onMPCTuning(ExtUI::mpcresult_t::MPC_STARTED)); |
| 1346 | TERN(DWIN_LCD_PROUI, LCD_ALERTMESSAGE(MSG_MPC_COOLING_TO_AMBIENT), LCD_MESSAGE(MSG_COOLING)); |
| 1347 | |
| 1348 | if (tuner.measure_ambient_temp() != MPC_autotuner::MeasurementState::SUCCESS) return; |
| 1349 | hotend.modeled_ambient_temp = tuner.get_ambient_temp(); |
| 1350 | |
| 1351 | #if HAS_FAN |
| 1352 | set_fan_speed(TERN(SINGLEFAN, 0, e), 0); |
| 1353 | planner.sync_fan_speeds(fan_speed); |
| 1354 | #endif |
| 1355 | |
| 1356 | // Heat to 200 degrees |
| 1357 | SERIAL_ECHOLNPGM(STR_MPC_HEATING_PAST_200); |
| 1358 | LCD_ALERTMESSAGE(MSG_MPC_HEATING_PAST_200); |
| 1359 | |
| 1360 | if (tuner.measure_heatup() != MPC_autotuner::MeasurementState::SUCCESS) return; |
| 1361 | |
| 1362 | // Calculate physical constants from three equally-spaced samples |
| 1363 | const float t1 = tuner.get_sample_1_temp(), |
| 1364 | t2 = tuner.get_sample_2_temp(), |
| 1365 | t3 = tuner.get_sample_3_temp(); |
| 1366 | float asymp_temp = (t2 * t2 - t1 * t3) / (2 * t2 - t1 - t3), |
| 1367 | block_responsiveness = -log((t2 - asymp_temp) / (t1 - asymp_temp)) / tuner.get_sample_interval(); |
| 1368 | |
| 1369 | #if ENABLED(MPC_AUTOTUNE_DEBUG) |
| 1370 | SERIAL_ECHOLNPGM("asymp_temp ", asymp_temp); |
| 1371 | SERIAL_ECHOLNPGM("block_responsiveness ", p_float_t(block_responsiveness, 4)); |
| 1372 | #endif |
| 1373 | |
| 1374 | // Make initial guess at transfer coefficients |
| 1375 | mpc.ambient_xfer_coeff_fan0 = mpc.heater_power * (MPC_MAX) / 255 / (asymp_temp - tuner.get_ambient_temp()); |
| 1376 | TERN_(MPC_INCLUDE_FAN, mpc.fan255_adjustment = 0.0f); |
| 1377 | |
| 1378 | if (tuning_type == AUTO || tuning_type == FORCE_ASYMPTOTIC) { |
| 1379 | // Analytic tuning |
| 1380 | mpc.block_heat_capacity = mpc.ambient_xfer_coeff_fan0 / block_responsiveness; |
| 1381 | mpc.sensor_responsiveness = block_responsiveness / (1.0f - (tuner.get_ambient_temp() - asymp_temp) * exp(-block_responsiveness * tuner.get_sample_1_time()) / (t1 - asymp_temp)); |
| 1382 | } |
no test coverage detected