/*
** Copyright 2023 Tjitte van der Ploeg, tjitte@tpee.nl
**
** This file is part of the OpenBoost firmware.
** The Open-SEC firmware is free software: you can redistribute
** it and/or modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version. The Open-SEC firmware is
** distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program. If not, see .
*/
#include "mppt.h"
#include "commands.h"
#include
uint32_t lastSPsw;
uint32_t laststep;
uint32_t lastsweep;
extern UART_HandleTypeDef huart1;
extern ConverterSettings_t settings;
modMPPTsettings_t * modMpptsettings;
modMPPTstate_t currentmode;
float pv;
float pp;
int mpptSweepIndex = 0;
float mpptSweepStepsize = 1.0e3;
float mpptSweepSP;
int mpptSweepSize = MPPT_SWEEP_SIZE;
int oscillationnumber = 0;
float changedStepSize = 0;
bool justjumped = 0;
uint32_t tsweepstart;
uint32_t tinit;
uint32_t loopdelay;
void modMPPTinit(modMPPTsettings_t *s) {
modMpptsettings = s;
modConverterPWMOutputDisable();
if (settings.outputEnalbeOnStartup){
currentmode = MpptState_init;
} else{
currentmode = MpptState_Disable;
}
modConverterPWMOutputDisable();
MpptLastAckion = MpptAcktionState_Init;
loopdelay = modMpptsettings->PO_Timestep;
}
void modMPPTtask() {
if(modMpptsettings->Sweep_eneable){
if(modDelayTick1ms(&lastsweep, modMpptsettings->Sweep_interval)){
if(modMpptsettings->Sweep_direction == MPPT_SWEEP_UP)
modMpptStartSweep(HW_MIN_SETPOINT, settings.LowSideVoltageLimitSoft, modMpptsettings->Sweep_datapoints);
else
modMpptStartSweep(settings.LowSideVoltageLimitSoft, HW_MIN_SETPOINT, modMpptsettings->Sweep_datapoints);
}
}
if (modDelayTick1ms(&laststep, loopdelay)) {
switch(currentmode){
case MpptState_init:
tinit = HAL_GetTick();
currentmode = MpptState_delay;
break;
case MpptState_delay:
if(HAL_GetTick() - tinit > settings.startupDelay){
control_set_setpoint(control_get_regulated_voltage());
currentmode = MpptState_PO;
modConverterPWMOutputEnable();
}
case MpptState_PO:
modMPPTPerturbAndObserve();
scope_trigger();
loopdelay = modMpptsettings->PO_Timestep;
break;
case MpptState_SweepStart:
mpptSweepIndex = 0;
control_set_setpoint(mpptSweepSP);
currentmode = MpptState_SweepStartupdelay;
tsweepstart = HAL_GetTick();
loopdelay = modMpptsettings->Sweep_timestep;
break;
case MpptState_SweepStartupdelay:
if ((HAL_GetTick() - tsweepstart) > modMpptsettings->PO_Timestep){
currentmode = MpptState_Sweep;
}
break;
case MpptState_Sweep:
//if(modConverterGetMode() != PhaseMode_CIC){
mppt_is[mpptSweepIndex] = control_get_regulated_current();
mppt_vs[mpptSweepIndex] = control_get_regulated_voltage();
mpptSweepSP += mpptSweepStepsize;
control_set_setpoint(mpptSweepSP);
if(mpptSweepIndex >= mpptSweepSize){
float vmpp = settings.LowSideVoltageLimitSoft;
float pmax = 0.0f;
for(int i = 0; i < mpptSweepSize; i++){
float p = mppt_is[i]*mppt_vs[i];
if(p > pmax){
pmax = p;
vmpp = mppt_vs[i]*1000.0f;
}
}
control_set_setpoint(vmpp);
currentmode = MpptState_PO;
modCommandsSendSweep(mpptSweepSize);
if(modMpptsettings->Sweep_publishOnCan){
modCANSendSweep(mppt_is, mppt_vs, mpptSweepSize);
}
}
mpptSweepIndex++;
//}
break;
case MpptState_ConstantVoltage:
break;
case MpptState_Disable:
default:
modConverterPWMOutputDisable();
break;
}
}
}
float randomf(float min, float max){
float f = ((float)(rand()%(1<<12))) / ((float)(1<<12));
return f*(max-min) + min;
}
void modMPPTPerturbAndObserve(){
float Vsp = control_get_setpoint();
float i = control_get_regulated_current();
float v = control_get_regulated_voltage();
float p = i*v;
switch(modConverterGetMode()){
case PhaseMode_MinInputCurrent:
//Vsp -= modMpptsettings->PO_Stepsize;
Vsp = 1e3*control_get_regulated_voltage() - (0.1*modMpptsettings->PO_Stepsize);
control_set_setpoint(Vsp );
pv = v;
pp = p;
return;
case PhaseMode_TD:
case PhaseMode_CIC:
case PhaseMode_MinInputVoltage:
Vsp += modMpptsettings->PO_Stepsize;
control_set_setpoint(Vsp);
pv = v;
pp=p;
return;
case PhaseMode_COC:
case PhaseMode_COV:
case PhaseMode_Fault:
//No setpoint voltage setable
pv = v;
pp=p;
return;
case PhaseMode_CIV:
//Contineu to PO
break;
}
float dv = v - pv;
float dp = p - pp;
float dpdv = 0;
if(dv != 0){
dpdv = dp/dv;
}
else {
//Stuck in some kind of limit
Vsp -= modMpptsettings->PO_Stepsize;
control_set_setpoint(Vsp);
}
//If the previous iteration was a random jump, check if the power did not decrease too much.
if (justjumped){
justjumped = false;
//Jump back if the power is not enough.
if(p < (pp - modMpptsettings->jump_PowerThreshold)){
Vsp = changedStepSize;
}
}
//Start P&O right away.
//If jump rate is zero, do not ever jump.
if ((oscillationnumber > modMpptsettings->jump_Rate) && (modMpptsettings->jump_Rate != 0)){
//save the current position, so we can jump back afterwards.
changedStepSize = Vsp;
Vsp = randomf(HW_MIN_SETPOINT, settings.LowSideVoltageLimitSoft);
oscillationnumber = 0;
justjumped = true;
}
else {
float stepsize;
if(modMpptsettings->PO_StepSizeGain > 0.0f){
stepsize = modMpptsettings->PO_Stepsize * (1.0f+(fabsf(dpdv)*modMpptsettings->PO_StepSizeGain));
//Maximize step size to some reasonable number.
if (stepsize > 5000) stepsize = 5000;
}else{
stepsize = modMpptsettings->PO_Stepsize;
}
if(dpdv > 0){
MpptLastAckion = MpptAcktionState_Up;
Vsp += stepsize;
}else{
MpptLastAckion = MpptAcktionState_down;
Vsp -= stepsize;
}
}
pv = v;
pp=p;
oscillationnumber ++;
control_set_setpoint(Vsp);
}
void modMpptStartSweep(float start, float end, int size){
//Only allow sweep when tracking.
if(currentmode != MpptState_PO){
return;
}
mpptSweepSize = size;
if (mpptSweepSize < 4){
mpptSweepSize = 4;
}
if (mpptSweepSize > MPPT_SWEEP_SIZE){
mpptSweepSize = MPPT_SWEEP_SIZE;
}
mpptSweepStepsize = (end-start)/(mpptSweepSize-1);
mpptSweepSP = start;
currentmode = MpptState_SweepStart;
MpptLastAckion = MpptAcktionState_Init;
}
void modMpptSetMode(modMPPTmode_t mode){
switch(mode){
case MpptMode_ConstantVoltage:
currentmode = MpptState_ConstantVoltage;
break;
case MpptMode_PO:
currentmode = MpptState_init;
break;
default:
case MpptMode_Disable:
currentmode = MpptState_Disable;
}
}