Skip to content

Commit

Permalink
Charger: Fix soft over current detection when PWM changes often (#762)
Browse files Browse the repository at this point in the history
Signed-off-by: Cornelius Claussen <[email protected]>
Co-authored-by: Kai Hermann <[email protected]>
  • Loading branch information
corneliusclaussen and hikinggrass authored Jul 8, 2024
1 parent eb5cbc4 commit 11e8b3f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 11 deletions.
43 changes: 33 additions & 10 deletions modules/EvseManager/Charger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ void Charger::run_state_machine() {
// make sure we are enabling PWM
if (not hlc_use_5percent_current_session) {
auto m = get_max_current_internal();
update_pwm_now_if_changed(ampere_to_duty_cycle(m));
update_pwm_now_if_changed_ampere(m);
} else {
update_pwm_now_if_changed(PWM_5_PERCENT);
}
Expand Down Expand Up @@ -569,12 +569,12 @@ void Charger::run_state_machine() {
if (hlc_use_5percent_current_session) {
update_pwm_now_if_changed(PWM_5_PERCENT);
} else {
update_pwm_now_if_changed(ampere_to_duty_cycle(get_max_current_internal()));
update_pwm_now_if_changed_ampere(get_max_current_internal());
}
} else {
// update PWM if it has changed and 5 seconds have passed since last update
if (not hlc_use_5percent_current_session) {
update_pwm_max_every_5seconds(ampere_to_duty_cycle(get_max_current_internal()));
update_pwm_max_every_5seconds_ampere(get_max_current_internal());
}
}
}
Expand Down Expand Up @@ -643,7 +643,7 @@ void Charger::run_state_machine() {
} else {
// update PWM if it has changed and 5 seconds have passed since last update
if (not errors_prevent_charging_internal()) {
update_pwm_max_every_5seconds(ampere_to_duty_cycle(get_max_current_internal()));
update_pwm_max_every_5seconds_ampere(get_max_current_internal());
}
}
}
Expand Down Expand Up @@ -887,13 +887,15 @@ void Charger::process_cp_events_independent(CPEvent cp_event) {
}
}

void Charger::update_pwm_max_every_5seconds(float dc) {
void Charger::update_pwm_max_every_5seconds_ampere(float ampere) {
float dc = ampere_to_duty_cycle(ampere);
if (dc not_eq internal_context.update_pwm_last_dc) {
auto now = std::chrono::steady_clock::now();
auto timeSinceLastUpdate =
auto time_since_last_update =
std::chrono::duration_cast<std::chrono::milliseconds>(now - internal_context.last_pwm_update).count();
if (timeSinceLastUpdate >= 5000) {
if (time_since_last_update >= IEC_PWM_MAX_UPDATE_INTERVAL) {
update_pwm_now(dc);
internal_context.pwm_set_last_ampere = ampere;
}
}
}
Expand All @@ -919,17 +921,27 @@ void Charger::update_pwm_now_if_changed(float dc) {
}
}

void Charger::update_pwm_now_if_changed_ampere(float ampere) {
float dc = ampere_to_duty_cycle(ampere);
if (internal_context.update_pwm_last_dc not_eq dc) {
update_pwm_now(dc);
internal_context.pwm_set_last_ampere = ampere;
}
}

void Charger::pwm_off() {
session_log.evse(false, "Set PWM Off");
shared_context.pwm_running = false;
internal_context.update_pwm_last_dc = 1.;
internal_context.pwm_set_last_ampere = 0.;
bsp->set_pwm_off();
}

void Charger::pwm_F() {
session_log.evse(false, "Set PWM F");
shared_context.pwm_running = false;
internal_context.update_pwm_last_dc = 0.;
internal_context.pwm_set_last_ampere = 0.;
bsp->set_pwm_F();
}

Expand Down Expand Up @@ -1486,6 +1498,16 @@ float Charger::get_max_current_internal() {
return maxc;
}

float Charger::get_max_current_signalled_to_ev_internal() {
// For basic charging, the max current signalled to the EV may be different from the actual current limit
// for up to 5 seconds as the PWM may only be updated every 5 seconds according to IEC61851-1.
if (not shared_context.hlc_charging_active) {
return internal_context.pwm_set_last_ampere;
} else {
return get_max_current_internal();
}
}

void Charger::set_current_drawn_by_vehicle(float l1, float l2, float l3) {
Everest::scoped_lock_timeout lock(state_machine_mutex,
Everest::MutexDescription::Charger_set_current_drawn_by_vehicle);
Expand All @@ -1495,8 +1517,9 @@ void Charger::set_current_drawn_by_vehicle(float l1, float l2, float l3) {
}

void Charger::check_soft_over_current() {

// Allow some tolerance
float limit = (get_max_current_internal() + soft_over_current_measurement_noise_A) *
float limit = (get_max_current_signalled_to_ev_internal() + soft_over_current_measurement_noise_A) *
(1. + soft_over_current_tolerance_percent / 100.);

if (shared_context.current_drawn_by_vehicle[0] > limit or shared_context.current_drawn_by_vehicle[1] > limit or
Expand All @@ -1515,9 +1538,9 @@ void Charger::check_soft_over_current() {
internal_context.over_current = false;
}
auto now = std::chrono::steady_clock::now();
auto timeSinceOverCurrentStarted =
auto time_since_over_current_started =
std::chrono::duration_cast<std::chrono::milliseconds>(now - internal_context.last_over_current_event).count();
if (internal_context.over_current and timeSinceOverCurrentStarted >= SOFT_OVER_CURRENT_TIMEOUT) {
if (internal_context.over_current and time_since_over_current_started >= SOFT_OVER_CURRENT_TIMEOUT) {
auto errstr =
fmt::format("Soft overcurrent event (L1:{}, L2:{}, L3:{}, limit {}) triggered",
shared_context.current_drawn_by_vehicle[0], shared_context.current_drawn_by_vehicle[1],
Expand Down
7 changes: 6 additions & 1 deletion modules/EvseManager/Charger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class Charger {
// external input to charger: update max_current and new validUntil
bool set_max_current(float ampere, std::chrono::time_point<date::utc_clock> validUntil);
float get_max_current();

sigslot::signal<float> signal_max_current;

void setup(bool three_phases, bool has_ventilation, const std::string& country_code, const ChargeMode charge_mode,
Expand Down Expand Up @@ -206,6 +207,7 @@ class Charger {

bool errors_prevent_charging_internal();
float get_max_current_internal();
float get_max_current_signalled_to_ev_internal();
bool deauthorize_internal();
bool pause_charging_wait_for_power_internal();

Expand All @@ -218,7 +220,8 @@ class Charger {

void update_pwm_now(float dc);
void update_pwm_now_if_changed(float dc);
void update_pwm_max_every_5seconds(float dc);
void update_pwm_now_if_changed_ampere(float dc);
void update_pwm_max_every_5seconds_ampere(float dc);
void pwm_off();
void pwm_F();

Expand Down Expand Up @@ -327,6 +330,7 @@ class Charger {

bool pp_warning_printed{false};
bool no_energy_warning_printed{false};
float pwm_set_last_ampere{0};
} internal_context;

// main Charger thread
Expand Down Expand Up @@ -368,6 +372,7 @@ class Charger {
// 4 seconds according to table 3 of ISO15118-3
static constexpr int T_STEP_EF = 4000;
static constexpr int SOFT_OVER_CURRENT_TIMEOUT = 7000;
static constexpr int IEC_PWM_MAX_UPDATE_INTERVAL = 5000;

types::evse_manager::EnableDisableSource active_enable_disable_source{
types::evse_manager::Enable_source::Unspecified, types::evse_manager::Enable_state::Unassigned, 10000};
Expand Down

0 comments on commit 11e8b3f

Please sign in to comment.