OrcaSlicer/src/libslic3r/GCode/AdaptivePAInterpolator.cpp
Ioannis Giannakas 529c44d8e3
Enhancement: Adaptive Pressure advance (#5609)
* Adaptive Pressure advance options setup

* Dynamic PA - PCHIP interpolator code and tests

* Integrate dynamic PA with slicing code - emit new PA values per speed change

* Link adaptive PA to role change instead of speed change

* Adaptive PA - Alpha 2

Reduce the frequency of requested PA changes by introducing a "state" variable.
Implement user toggle for adapting PA for external walls for overhangs

* Hide adaptive PA for overhangs

* Convert Adaptive PA to use volumetric flow model and start preparing for converting to Gcode post processor

* Converted Dynamic PA to a post processing filter. Reverted changes in GCode cpp and created tagging mechanism to allow filter to apply PA changes.

* Removed adaptive PA for overhangs

* Foundations for two dimensional adaptive PA based on acceleration and volumetric flow speed

* Minor code cleanup and updating of tooltips

* Renaming files for better clarity and generate classes documentation

* Update src/libslic3r/PrintConfig.cpp

Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com>

* Update src/libslic3r/PrintConfig.cpp

Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com>

* Update src/libslic3r/PrintConfig.cpp

Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com>

* Introduce average mm3_mm over the length of a multipath for adaptive PA

* Updates for multipath handling part 2

* Introduce average mm3_mm over the length of a multipath for adaptive PA

* Trigger PA evaluation more frequently to catch edge cases where speed changes across islands of the same feature type.

* Updates for multipath handling part 2

* Adaptive PA: Implement average flow estimation on loops

* Code formatting

* Fix adaptive PA not adapting for small disconnected external wall line segments.

* Updated to take max print speed of upcoming feature to calculate new PA value.

This is to resolve issue of incorrect PA value used when starting a new feature at an overhang.

* Code clean up

* Performance tuning

* Further performance tuning by reducing use of regex commands in the nested loops and fix bug preventing gcode line output

* Further performance tuning and tweaks to stop searching for max speed after the first travel move.

* Reduce debug information

* Updated debug info

* Fix an issue on seams on specific models when wipe before external perimeter was enabled. Also cleanup documentation and add new to-do's

* Prepare for adaptive PA for overhangs, fix wipe bug & clean up code and comments

* Initial commit for adapting PA when extruding fully overhanging perimeters

* Ignore wipe command when identifying current print speed

* Option to evaluate adaptive PA on overhang regions in preparation for Klipper experimental option testing

* Update to issue PA changes for varying flow conditions within the same feature

* Fix bug where adaptive PA was enabled erroneously for role changes and ignoring user's preference.

* Refactored some code

* More refactoring

* Some bug fixes and enabled comments only when verbose g-code is enabled

* Introduced dedicated PA option for bridges

* Code refactoring to optimise initialisation of PA processor (making it faster). Fix a bug where PA was not always set after a toolchange. Improve general error handling and robustness.

* Updates to adaptive PA tooltips

* Bridging PA check with Epsilon instead of 0.

* Adaptive PA: addressing comments

---------

Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com>
2024-07-28 22:52:08 +08:00

114 lines
4.2 KiB
C++

// AdaptivePAInterpolator.cpp
// OrcaSlicer
//
// Implementation file for the AdaptivePAInterpolator class, providing methods to parse data and perform PA interpolation.
#include "AdaptivePAInterpolator.hpp"
#include <stdexcept>
#include <cmath>
#include <algorithm>
#include <sstream>
/**
* @brief Parses the input data and sets up the interpolators.
* @param data A string containing the data in CSV format (PA, flow rate, acceleration).
* @return 0 on success, -1 on error.
*/
int AdaptivePAInterpolator::parseAndSetData(const std::string& data) {
flow_interpolators_.clear();
accelerations_.clear();
try {
std::istringstream ss(data);
std::string line;
std::map<double, std::vector<std::pair<double, double>>> acc_to_flow_pa;
while (std::getline(ss, line)) {
std::istringstream lineStream(line);
std::string value;
double paValue, flowRate, acceleration;
paValue = flowRate = acceleration = 0.f; // initialize all to zero.
// Parse PA value
if (std::getline(lineStream, value, ',')) {
paValue = std::stod(value);
}
// Parse flow rate value
if (std::getline(lineStream, value, ',')) {
flowRate = std::stod(value);
}
// Parse acceleration value
if (std::getline(lineStream, value, ',')) {
acceleration = std::stod(value);
}
// Store the parsed values in a map with acceleration as the key
acc_to_flow_pa[acceleration].emplace_back(flowRate, paValue);
}
// Iterate through the map to set up the interpolators
for (const auto& kv : acc_to_flow_pa) {
double acceleration = kv.first;
const auto& data = kv.second;
std::vector<double> flowRates;
std::vector<double> paValues;
for (const auto& pair : data) {
flowRates.push_back(pair.first);
paValues.push_back(pair.second);
}
// Only set up the interpolator if there are enough data points
if (flowRates.size() > 1) {
PchipInterpolatorHelper interpolator(flowRates, paValues);
flow_interpolators_[acceleration] = interpolator;
accelerations_.push_back(acceleration);
}
}
} catch (const std::exception&) {
m_isInitialised = false;
return -1; // Error: Exception during parsing
}
m_isInitialised = true;
return 0; // Success
}
/**
* @brief Interpolates the PA value for the given flow rate and acceleration.
* @param flow_rate The flow rate at which to interpolate.
* @param acceleration The acceleration at which to interpolate.
* @return The interpolated PA value, or -1 if interpolation fails.
*/
double AdaptivePAInterpolator::operator()(double flow_rate, double acceleration) {
std::vector<double> pa_values;
std::vector<double> acc_values;
// Estimate PA value for every flow to PA model for the given flow rate
for (const auto& kv : flow_interpolators_) {
double pa_value = kv.second.interpolate(flow_rate);
// Check if the interpolated PA value is valid
if (pa_value != -1) {
pa_values.push_back(pa_value);
acc_values.push_back(kv.first);
}
}
// Check if there are enough acceleration values for interpolation
if (acc_values.size() < 2) {
// Special case: Only one acceleration value
if (acc_values.size() == 1) {
return std::round(pa_values[0] * 1000.0) / 1000.0; // Rounded to 3 decimal places
}
return -1; // Error: Not enough data points for interpolation
}
// Create a new PchipInterpolatorHelper for PA-acceleration interpolation
// Use the estimated PA values from the for loop above and their corresponding accelerations to
// generate the new PCHIP model. Then run this model to interpolate the PA value for the given acceleration value.
PchipInterpolatorHelper pa_accel_interpolator(acc_values, pa_values);
return std::round(pa_accel_interpolator.interpolate(acceleration) * 1000.0) / 1000.0; // Rounded to 3 decimal places
}