Files
FluidSimCpp/include/FluidSim/DynoCurve.hpp
2026-10-22 23:52:20 +02:00

65 lines
2.5 KiB
C++

#pragma once
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <vector>
namespace fluidsim::port {
struct DynoPoint {
float power_kw{};
float torque_nm{};
};
// Shared rolling peak curve from the C# Scenario base class. Each bin stores
// the greatest observed power and torque independently, with missing bins
// interpolated when the engine crosses an RPM range too quickly to sample it.
class DynoCurve {
public:
static constexpr float rpm_bin_size = 50.0f;
void reset() {
bins_.clear();
last_bin_ = invalid_bin;
}
void update(float rpm, float power_kw, float torque_nm) {
if (!std::isfinite(rpm) || rpm <= 0.0f || !std::isfinite(power_kw) || !std::isfinite(torque_nm))
return;
const auto bin = static_cast<std::size_t>(rpm / rpm_bin_size);
if (bin >= bins_.max_size()) return;
while (bins_.size() <= bin) bins_.push_back({});
if (last_bin_ != invalid_bin && bin > last_bin_ + 1) {
const float last_power = bins_[last_bin_].power_kw > 0.0f ? bins_[last_bin_].power_kw : 0.0f;
const float last_torque = bins_[last_bin_].torque_nm > 0.0f ? bins_[last_bin_].torque_nm : 0.0f;
for (std::size_t missing = last_bin_ + 1; missing < bin; ++missing) {
const float t = static_cast<float>(missing - last_bin_) /
static_cast<float>(bin - last_bin_);
const float interpolated_power = last_power + (power_kw - last_power) * t;
const float interpolated_torque = last_torque + (torque_nm - last_torque) * t;
auto& point = bins_[missing];
if (interpolated_power > point.power_kw || point.power_kw <= 0.0f)
point.power_kw = interpolated_power;
if (interpolated_torque > point.torque_nm || point.torque_nm <= 0.0f)
point.torque_nm = interpolated_torque;
}
}
auto& current = bins_[bin];
if (power_kw > current.power_kw || current.power_kw <= 0.0f) current.power_kw = power_kw;
if (torque_nm > current.torque_nm || current.torque_nm <= 0.0f) current.torque_nm = torque_nm;
last_bin_ = bin;
}
const std::vector<DynoPoint>& bins() const { return bins_; }
private:
static constexpr std::size_t invalid_bin = static_cast<std::size_t>(-1);
std::vector<DynoPoint> bins_;
std::size_t last_bin_{invalid_bin};
};
} // namespace fluidsim::port