blob: 7e8c0360b00bfdb5d5459e066c7b979233d2a89f [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_CLL_LoadRegulator_Functions
//
// Purpose:
// This module contains function definitions for EPTF LoadRegulator
//
// Module Parameters:
// tsp_debug_EPTF_CLL_LoadRegulator_Functions - *boolean*, default value: false
// tsp_debug_EPTF_CLL_LoadRegulator_Functions_smoothing - *boolean*, default value: false
// tsp_EPTF_loadRegulator_measWinSize - *integer*, default value: 3
// tsp_EPTF_loadRegulator_updateTimeout - *float*, default value: 2.0
// tsp_EPTF_loadRegulator_LoadVarianceThreshold - *float*, default value: 5.0
// tsp_EPTF_loadregulator_cpsDelta - *float*, default value: 10.0
// tsp_EPTF_loadRegulator_errorTolerance - *float*, default value: 5.0
// tsp_EPTF_loadRegulator_smoothingFactor - *float*, default value: 0.5
//
// Module depends on:
// <EPTF_CLL_Common_Definitions>
// <EPTF_CLL_Common_Functions>
// <EPTF_CLL_LoadRegulator_Definitions>
// <EPTF_CLL_Variable_Definitions>
// <EPTF_CLL_Variable_Functions>
// <EPTF_CLL_Base_Functions>
// <EPTF_CLL_Logging_Definitions>
// <EPTF_CLL_Logging_Functions>
//
// Current Owner:
// Gabor Tatarka (egbotat)
//
// Last Review Date:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
module EPTF_CLL_LoadRegulator_Functions
{
import from EPTF_CLL_DataSourceClient_Functions all;
import from EPTF_CLL_DataSource_Definitions all;
//=========================================================================
// Imports
//=======================================================================
import from EPTF_CLL_Common_Definitions all;
import from EPTF_CLL_Common_Functions all;
import from EPTF_CLL_LoadRegulator_Definitions all;
import from EPTF_CLL_Variable_Definitions all;
import from EPTF_CLL_Variable_Functions all;
import from EPTF_CLL_Base_Functions all;
import from EPTF_CLL_Logging_Definitions all;
import from EPTF_CLL_Logging_Functions all;
import from EPTF_CLL_DataSource_Functions all;
//FIXME:
friend module EPTF_CLL_LoadRegulatorUI_Functions;
modulepar boolean tsp_debug_EPTF_CLL_LoadRegulator_Functions := false;
modulepar boolean tsp_debug_EPTF_CLL_LoadRegulator_Functions_smoothing := false;
modulepar integer tsp_EPTF_loadRegulator_measWinSize := 3;
modulepar float tsp_EPTF_loadRegulator_updateTimeout := 2.0; // 2 secs
modulepar float tsp_EPTF_loadRegulator_LoadVarianceThreshold := 5.0; // in %
modulepar float tsp_EPTF_loadregulator_cpsDelta := 10.0;
modulepar float tsp_EPTF_loadRegulator_errorTolerance := 5.0; // in %
modulepar float tsp_EPTF_loadRegulator_smoothingFactor := 0.5; // should be between 0.0:extreme smoothing and 1,0:no smoothing
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_init_CT
//
// Purpose:
// initialisation for EPTF_LoadRegulator_CT
//
// Parameters:
// pl_selfName - *in charstring* - name of the component
// pl_getSutLoad - <ft_EPTF_LoadRegulator_getSUTLoad> - the function that
// determines the SUT load
// pl_calcNextCps - <ft_EPTF_LoadRegulator_calculateNextCps> - the algorithm
// to change the CPS so that the SUT load reach the target load.
// pl_postCalcCps - <ft_EPTF_LoadRegulator_postCalculateCPS> - function that will be
// called after the CPS value is changed
// pl_EPTF_loadRegulator_measWinSize - *in integer* - measure window size
// pl_EPTF_loadRegulator_updateTimeout - *in float* - the period of SUT load measurement
// pl_EPTF_loadRegulator_LoadVarianceThreshold - *in float* - load variance threshold (percentage)
// pl_EPTF_loadregulator_cpsDelta - *in float* - the max value that the CPS value
// will be changed with
// pl_EPTF_loadRegulator_errorTolerance - *in float* - the precision of the target load (percentage)
// pl_EPTF_loadRegulator_smoothingFactor - *in float* - a smoothing is applied on the
// measured load values to avoid spikes. The amount of smoothing can be set here.
// Its value should be between 0.0:extreme smoothing and 1,0:no smoothing.
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_init_CT(
in charstring pl_selfName,
in ft_EPTF_LoadRegulator_getSUTLoad pl_getSutLoad,
in ft_EPTF_LoadRegulator_calculateNextCps pl_calcNextCps := null,
in ft_EPTF_LoadRegulator_postCalculateCPS pl_postCalcCps := null,
in integer pl_EPTF_loadRegulator_measWinSize := tsp_EPTF_loadRegulator_measWinSize,
in float pl_EPTF_loadRegulator_updateTimeout := tsp_EPTF_loadRegulator_updateTimeout, // 2 secs
in float pl_EPTF_loadRegulator_LoadVarianceThreshold := tsp_EPTF_loadRegulator_LoadVarianceThreshold, // in %
in float pl_EPTF_loadregulator_cpsDelta := tsp_EPTF_loadregulator_cpsDelta,
in float pl_EPTF_loadRegulator_errorTolerance := tsp_EPTF_loadRegulator_errorTolerance, // in %
in float pl_EPTF_loadRegulator_smoothingFactor := tsp_EPTF_loadRegulator_smoothingFactor, // should be between 0.0:extreme smoothing and 1,0:no smoothing
in EPTF_DataSource_CT pl_dataSource_compRef := null
)
runs on EPTF_LoadRegulator_CT
{
f_EPTF_Logging_init_CT(pl_selfName);
var charstring vl_selfName := f_EPTF_Base_selfName();
v_LoadRegulator_loggingMaskId := f_EPTF_Logging_registerComponentMasks(tsp_EPTF_LoadRegulator_loggingComponentMask, c_EPTF_LoadRegulator_loggingEventClasses, EPTF_Logging_CLL);
if(tsp_debug_EPTF_CLL_LoadRegulator_Functions) {
f_EPTF_Logging_enableLocalMask(v_LoadRegulator_loggingMaskId, c_EPTF_LoadRegulator_loggingClassIdx_Debug);
} else {
f_EPTF_Logging_disableLocalMask(v_LoadRegulator_loggingMaskId, c_EPTF_LoadRegulator_loggingClassIdx_Debug);
}
if(v_EPTF_LoadRegulator_initialized) {
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_init_CT(): already initialized");
return;
}
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_init_CT() started");
f_EPTF_Var_init_CT(vl_selfName);
// initialize parameters:
v_EPTF_loadRegulator_measWinSize := pl_EPTF_loadRegulator_measWinSize;
v_EPTF_loadRegulator_updateTimeout := pl_EPTF_loadRegulator_updateTimeout;
v_EPTF_loadRegulator_LoadVarianceThreshold := pl_EPTF_loadRegulator_LoadVarianceThreshold;
v_EPTF_loadregulator_cpsDelta := pl_EPTF_loadregulator_cpsDelta;
v_EPTF_loadRegulator_errorTolerance := pl_EPTF_loadRegulator_errorTolerance;
v_EPTF_loadRegulator_smoothingFactor := pl_EPTF_loadRegulator_smoothingFactor;
//Connect to DataSource server
f_EPTF_DataSourceClient_init_CT(vl_selfName, pl_dataSource_compRef);
if(null != pl_dataSource_compRef){
f_EPTF_DataSourceClient_registerData(c_LoadRegulator_sourceId, vl_selfName, refers(f_EPTF_LoadRegulator_ProcessData));
f_EPTF_DataSourceClient_registerDataValue(c_LoadRegulator_sourceId, vl_selfName, refers(f_EPTF_LoadRegulator_DSProcessDataValue));
}
for (var integer i:=0;i<v_EPTF_loadRegulator_measWinSize;i:=i+1) {
vc_loadRegMeasWindow[i] := 0.0;
}
vc_EPTF_getSutLoad := pl_getSutLoad;
// Setting defalult regulation algorithm, the user may overwrite it in f_loadRegulator_user_init()
if(pl_calcNextCps == null) {
vc_EPTF_calculateNextCps := refers(f_EPTF_LoadRegulator_calculateNextCps);
} else {
vc_EPTF_calculateNextCps := pl_calcNextCps;
}
//Create EPTF vars for former component vars
f_EPTF_Var_newBool(f_EPTF_Base_selfName()&c_LoadRegulator_loadIsStableVarName, false, v_LoadRegulator_loadIsStableVarIdx);
//------------------------------
// create var for the totalCPS variable:
var charstring pl_varName := c_LoadRegulator_totalValueVarName&f_EPTF_Base_selfName();
f_EPTF_Var_newFloat(
pl_varName,
0.0,
v_LoadRegulator_cpsToReachVarIdx
);
// create var for the targetLoad variable:
pl_varName := c_LoadRegulator_targetLoadVarName&f_EPTF_Base_selfName();
f_EPTF_Var_newFloat(
pl_varName,
0.0,
v_LoadRegulator_loadToReachVarIdx
);
// create var for the currentLoad variable:
pl_varName := c_LoadRegulator_currentLoadVarName&f_EPTF_Base_selfName();
f_EPTF_Var_newFloat(
pl_varName,
0.0,
v_LoadRegulator_currentLoadVarIdx
);
f_EPTF_Var_setSubsCanAdjust(v_LoadRegulator_currentLoadVarIdx,false);
// create var for the connected variable:
pl_varName := "EPTF_LoadRegulator.Regulator.status."&f_EPTF_Base_selfName();
f_EPTF_Var_newStatusLED(
pl_varName,
{led_red, "Disconnected"},
v_EPTF_loadRegulator_execCtrlVar_statusIdx
);
f_EPTF_Var_setSubsCanAdjust(v_EPTF_loadRegulator_execCtrlVar_statusIdx,false);
// create var for regulator enable:
pl_varName := c_LoadRegulator_enabledVarName&f_EPTF_Base_selfName();
f_EPTF_Var_newBool(
pl_varName,
false,
v_LoadRegulator_enabledVarIdx
);
f_EPTF_DataSourceClient_sendReady(c_LoadRegulator_sourceId,f_EPTF_Base_selfName());
v_EPTF_postCalcCPS := pl_postCalcCps;
v_EPTF_LoadRegulator_altstep := activate(as_EPTF_LoadRegulator_behavior());
T_EPTF_loadReg.start(v_EPTF_loadRegulator_updateTimeout);
v_EPTF_loadRegulator_originalCPS := -1.0;
v_EPTF_LoadRegulator_initialized := true;
f_EPTF_Base_registerCleanup(refers(f_EPTF_LoadRegulator_cleanup_CT));
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_init_CT() finished");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_ProcessData
//
// Purpose:
// Processes the incoming Data requests - iterators and external data elements - and gives back a variable name.
// It should be registered in the ExecCtrl_init_CT. Type function fcb_EPTF_DataSourceClient_dataHandler
//
// Parameters:
// *out charstring pl_dataVarName* - this variable contains the value of the data or the iterator result
// *in charstring pl_source* - the name of the data source 'feature'
// *in charstring pl_ptcName* - the name of the ptc (ID of the PTC)
// *in charstring pl_element* - the name of the data element
// *in* <EPTF_DataSource_Params> *pl_params* - the parameters
// of the data for the dataElement
//
// Return Value:
// integer - error code (0 of OK, non zero if unsuccessful: e.g. invalid parameters given in pl_params)
//
// Detailed Comments:
// When this function is called in the first time it creates the variable that contains the
// names of the variables that store the values of the elements of the data or the iterator. This variable name
// is returned in pl_dataVarName.
//
///////////////////////////////////////////////////////////
private function f_EPTF_LoadRegulator_ProcessData(out charstring pl_dataVarName,
in charstring pl_source,
in charstring pl_ptcName,
in charstring pl_element,
in EPTF_DataSource_Params pl_params)
runs on EPTF_LoadRegulator_CT
return integer{
select( pl_element )
{
case (c_LoadRegulator_dataElement_enabled){
pl_dataVarName :=c_LoadRegulator_enabledVarName&f_EPTF_Base_selfName();
}
case (c_LoadRegulator_dataElement_cpsToReach){
pl_dataVarName :=c_LoadRegulator_totalValueVarName&f_EPTF_Base_selfName();
}
case (c_LoadRegulator_dataElement_loadToReach){
pl_dataVarName :=c_LoadRegulator_targetLoadVarName&f_EPTF_Base_selfName();
}
case (c_LoadRegulator_dataElement_currentLoad){
pl_dataVarName :=c_LoadRegulator_currentLoadVarName&f_EPTF_Base_selfName();
}
case (c_LoadRegulator_dataElement_loadIsStable){
pl_dataVarName :=f_EPTF_Base_selfName()&c_LoadRegulator_loadIsStableVarName;
}
case else{
pl_dataVarName := "";
f_EPTF_LoadRegulator_warning(%definitionId& ": unhandled element: "& pl_element);
return -1;
}
}
var integer vl_iteratorVarIdx := f_EPTF_Var_getId(pl_dataVarName);
if(vl_iteratorVarIdx == -1){
f_EPTF_LoadRegulator_warning(%definitionId&": Invalid externalData: "&
"\nSource: "&pl_source&
"\nPTC : "&pl_ptcName &
"\nElement Name : " &pl_element/*&
"\nParams: " & log2str(pl_params)*/);
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_DSProcessDataValue
//
// Purpose:
// Processes the incoming DataValue requests - iterators and external data elements - and gives back the value.
// It should be registered in the LoadRegulator_init_CT. Type function fcb_EPTF_DataSourceClient_dataValueHandler
//
// Parameters:
// *out *<EPTF_Var_DirectContent>* pl_dataValue* - the value of the data or the iterator result
// *in charstring pl_source* - the name of the data source 'feature'
// *in charstring pl_ptcName* - the name of the ptc (ID of the PTC)
// *in charstring pl_element* - the name of the data element
// *in* <EPTF_DataSource_Params> *pl_params* - the parameters
// of the data for the dataElement
//
// Return Value:
// integer - error code (0 of OK, non zero if unsuccessful: e.g. invalid parameters given in pl_params)
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_LoadRegulator_DSProcessDataValue(out EPTF_Var_DirectContent pl_dataValue,
in charstring pl_source,
in charstring pl_ptcName,
in charstring pl_element,
in EPTF_DataSource_Params pl_params)
runs on EPTF_LoadRegulator_CT return integer{
var integer vl_errorCode := -1;
pl_dataValue := {unknownVal := {omit}}; // set it to invalid
select( pl_element )
{
case(c_EPTF_DataSource_dataElement_Help) {
vl_errorCode := f_EPTF_DataSource_handleHelp(pl_dataValue,pl_source,pl_params,c_EPTF_LoadRegulator_help);
}
case else
{
}
}
return vl_errorCode;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_getCpsToReach
//
// Purpose:
// Returns the current CPS-to-reach value.
//
// Parameters:
// -
//
// Return Value:
// *float* - CPS-to-reach value
//
// Errors:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_getCpsToReach()
runs on EPTF_LoadRegulator_CT
return float
{
return f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_getLoadToReach
//
// Purpose:
// Returns the current Load-to-reach value.
//
// Parameters:
// -
//
// Return Value:
// *float* - Load-to-reach value
//
// Errors:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_getLoadToReach()
runs on EPTF_LoadRegulator_CT
return float
{
return f_EPTF_Var_getFloatValue(v_LoadRegulator_loadToReachVarIdx);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_setLoadToReach
//
// Purpose:
// Sets the Load-to-reach value.
//
// Parameters:
// pl_loadToReach - *in* *float*
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_setLoadToReach(in float pl_loadToReach)
runs on EPTF_LoadRegulator_CT
{
if(v_LoadRegulator_loadToReachVarIdx >= 0) {
f_EPTF_LoadRegulator_adjustTargetLoadInExecCtrl(pl_loadToReach);
} else {
f_EPTF_Var_adjustContent(v_LoadRegulator_loadToReachVarIdx, {floatVal := pl_loadToReach});
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_cleanup_CT()
//
// Purpose:
// Load regulator interface cleanup for EPTF_LoadRegulator_CT
//
// Parameters:
// -
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
///////////////////////////////////////////////////////////
private function f_EPTF_LoadRegulator_cleanup_CT() runs on EPTF_LoadRegulator_CT
{
if(not v_EPTF_LoadRegulator_initialized) {
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_cleanup_CT(): not yet initialized");
return;
}
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_cleanup_CT() started");
if(T_EPTF_loadReg.running) { T_EPTF_loadReg.stop; }
deactivate(v_EPTF_LoadRegulator_altstep);
v_EPTF_LoadRegulator_initialized := false;
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_cleanup_CT() finished");
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_registerToExecCtrl
//
// Purpose:
// Register the load regulator into execCtrl: it uses selfName to identify the loadRegulator in tsp_EPTF_ExecCtrl_RegulatorNames
//
// Parameters:
// pl_execCtrlCompRef - *in* <EPTF_Var_CT> - the component reference of the ExecCtrl component
//
// Return Value:
//
// Errors:
// -
//
// Detailed Comments:
// Automatically subscribes for the targetValue variable in ExecCtrl that belongs to the load regulator with name selfName.
// Also subscribes for the start/stop variable to enable/disable regulation automatically if start/stop button is pressed
// Automatically sets the v_EPTF_postCalcCPS function to adjust the correct targetValue in ExecCtrl
//
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_registerToExecCtrl(
in EPTF_Var_CT pl_execCtrlCompRef
) runs on EPTF_LoadRegulator_CT {
timer t_wait;
if(T_EPTF_loadReg.running) { T_EPTF_loadReg.stop; }
f_EPTF_Base_registerCleanup(refers(f_EPTF_LoadRegulator_cleanup_ExecCtrl));
t_wait.start(2.0);
t_wait.timeout;
var integer pl_idx;
var float vl_current_loadToReach := f_EPTF_Var_getFloatValue(v_LoadRegulator_loadToReachVarIdx); // save the original value
var charstring pl_varName;
// register
// set remote vars to signal registration to ExecCtrl:
f_EPTF_Var_adjustRemoteContent(pl_execCtrlCompRef,"EPTF_ExecCtrl.Regulator.currentLoad."&f_EPTF_Base_selfName(),{floatVal := int2float(f_EPTF_Base_upcast(self))});
f_EPTF_Var_adjustRemoteContent(pl_execCtrlCompRef,"EPTF_ExecCtrl.Regulator.status."&f_EPTF_Base_selfName(),{ statusLEDVal := {led_yellow, "Registering..."} });
// set local vars
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx, { statusLEDVal := {led_green, "Connected"} });
f_EPTF_Var_adjustContent(v_LoadRegulator_currentLoadVarIdx,{floatVal := 0.0});
// set the ft_EPTF_LoadRegulator_postCalculateCPS:
v_EPTF_postCalcCPS := refers(f_EPTF_LoadRegulator_postCalcCPS_ExecCtrl);
f_EPTF_LoadRegulator_adjustTargetLoadInExecCtrl(vl_current_loadToReach); // restore the original value
T_EPTF_loadReg.start(v_EPTF_loadRegulator_updateTimeout);
}
private function f_EPTF_LoadRegulator_cleanup_ExecCtrl() runs on EPTF_LoadRegulator_CT {
if (v_EPTF_loadRegulator_execCtrlVar_statusIdx != -1) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx, { statusLEDVal := {led_red, "Disconnected"} });
v_EPTF_loadRegulator_execCtrlVar_statusIdx := -1;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_adjustTargetLoadInExecCtrl
//
// Purpose:
// This function is used as to set the targetLoad via ExecCtrl for this load regulator
//
// Parameters:
// pl_targetLoad - *in* *float* - target load
//
// Return Value:
//
// Errors:
// -
//
// Detailed Comments:
//
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_adjustTargetLoadInExecCtrl(in float pl_targetLoad) runs on EPTF_LoadRegulator_CT {
f_EPTF_Var_adjustContent(v_LoadRegulator_loadToReachVarIdx,{ floatVal := pl_targetLoad });
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_postCalcCPS_ExecCtrl
//
// Purpose:
// This function is used as the postCalcCPS function for ExecCtrl regulation
//
// Parameters:
//
// Return Value:
//
// Errors:
// -
//
// Detailed Comments:
//
///////////////////////////////////////////////////////////
private function f_EPTF_LoadRegulator_postCalcCPS_ExecCtrl() runs on EPTF_LoadRegulator_CT {
var float vl_temp :=f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx);
if (f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx)!=vl_temp) {
f_EPTF_LoadRegulator_debug(%definitionId&"TotalValue updated to "&float2str(vl_temp));
f_EPTF_Var_adjustContent(v_LoadRegulator_cpsToReachVarIdx,{floatVal := vl_temp});
}
}
// refreshes the value of the statusLed and currentLoad
private function f_EPTF_LoadRegulator_ExecCtrl_refreshVars() runs on EPTF_LoadRegulator_CT {
if (v_LoadRegulator_currentLoadVarIdx==-1) {
return; // not registered into execCtrl
}
if (f_EPTF_Var_getFloatValue(v_LoadRegulator_currentLoadVarIdx)!=v_EPTF_LoadRegulator_ctx.vl_currLoad) {
f_EPTF_Var_adjustContent(v_LoadRegulator_currentLoadVarIdx,{ floatVal := v_EPTF_LoadRegulator_ctx.vl_currLoad /*vl_measuredLoad /*v_EPTF_LoadRegulator_currentLoad*/ });
}
var EPTF_StatusLED vl_currentVal := f_EPTF_Var_getStatusLEDValue(v_EPTF_loadRegulator_execCtrlVar_statusIdx);
if (not f_EPTF_Var_getBoolValue(v_LoadRegulator_enabledVarIdx)) {
if (vl_currentVal != {led_blue, "Disabled"}) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx,{ statusLEDVal := {led_blue, "Disabled"} });
}
} else if (f_EPTF_Var_getBoolValue(v_LoadRegulator_loadIsStableVarIdx)) {
if (vl_currentVal.text != "Auto-off" and vl_currentVal != {led_green, "Stable"}) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx,{ statusLEDVal := {led_green, "Stable"} });
}
} else {
if (vl_currentVal.text != "Auto-off" and vl_currentVal != {led_yellow, "Unstable"}) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx,{ statusLEDVal := {led_yellow, "Unstable"} });
}
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_calculateNextCps_limitMax
//
// Purpose:
// A variation of the function <f_EPTF_LoadRegulator_calculateNextCps>.
// It only regulates the CPS if the current load reaches the target load
// setting. Below that boundary the original CPS is used, no regulation
// takes place.
//
// Parameters:
// loadToReach - *in* *float* - the target load level to reach
// oldCps - *in* *float* - previous CPS value
//
// Return Value:
// *float* - new CPS value
//
// Errors:
// -
//
// Detailed Comments:
// The generic load regulator algorithm is a simple fuzzy regulator.
// It calculates the next cps from the previous cps and the last two
// cpu/network loads, according to the specified load to reach.
//
// If the target load is above the current load, the algorithm
// continues regulation until the original CPS value, that before
// the regulation was started, is restored. The regulator
// switches to "Auto-off" mode: regulation is disabled,
// the CPS value of the regulated items can be changed.
//
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_calculateNextCps_limitMax(
in float loadToReach,
in float oldCps)
runs on EPTF_LoadRegulator_CT
return float
{
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_calculateNextCps_limitMax() started");
if (v_LoadRegulator_cpsToReachVarIdx==-1) {
return oldCps;
}
if (loadToReach == 0.0) { return 0.0 }
var integer measWindowSize := sizeof(vc_loadRegMeasWindow);
var float loadNew := 0.0;
var float loadErrorNew := 0.0;
//calculate last two load values
if(vc_measWinIdx == 0) {
loadNew := vc_loadRegMeasWindow[measWindowSize-1];
}
else if(vc_measWinIdx == 1) {
loadNew := vc_loadRegMeasWindow[0];
}
else {
loadNew := vc_loadRegMeasWindow[vc_measWinIdx-1];
}
//calculate load error and delta-error
loadErrorNew := loadToReach-loadNew;
var float errorTolerance := 0.0;//v_EPTF_loadRegulator_errorTolerance; // eg. +- x% of load is tolerated
f_EPTF_LoadRegulator_debug(log2str("loadToReach: ", loadToReach, " oldCps: ", oldCps, " errorTolerance: ", errorTolerance, " loadErrorNew: ", loadErrorNew));
if(loadErrorNew >= errorTolerance) {
// no regulation needed:
f_EPTF_LoadRegulator_debug("LOW LOAD, NO REGULATION NEEDED");
// update status led:
if (v_EPTF_loadRegulator_execCtrlVar_statusIdx!=-1) {
var EPTF_StatusLED vl_currentVal := f_EPTF_Var_getStatusLEDValue(v_EPTF_loadRegulator_execCtrlVar_statusIdx);
if (vl_currentVal.text != "Auto-off" and (oldCps == v_EPTF_loadRegulator_originalCPS or v_EPTF_loadRegulator_originalCPS == -1.0)) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx,{ statusLEDVal := {led_blue, "Auto-off"} })
}
}
// if regulation is on:
if (v_EPTF_loadRegulator_originalCPS>=0.0) {
// if original cps level is not reached:
if (oldCps<v_EPTF_loadRegulator_originalCPS) {
// continue regulation until original CPS level is reached:
var float vl_newCps := f_EPTF_LoadRegulator_calculateNextCps(loadToReach,oldCps);
// if new cps is below the original, continue regulation:
if (vl_newCps<v_EPTF_loadRegulator_originalCPS) {
f_EPTF_LoadRegulator_debug("Regulation enabled until original CPS is restored");
return vl_newCps;
}
// otherwise restore original cps
}
// restore original cps if old or new cps is above the original:
oldCps := v_EPTF_loadRegulator_originalCPS;
v_EPTF_loadRegulator_originalCPS := -1.0;
f_EPTF_LoadRegulator_debug(log2str("Regulation switched off, original cps restored: ", oldCps));
} else {
// use current CPS:
//if (oldCps==0.0) {
oldCps := f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx);
//}
}
f_EPTF_LoadRegulator_debug(log2str("using original cps: ", oldCps));
// regulation disabled
return oldCps;
}
else {
// regulation enabled
// store the original CPS value:
f_EPTF_LoadRegulator_debug(log2str("REGULATION ON!!!"));
if (v_EPTF_loadRegulator_originalCPS<0.0) {
v_EPTF_loadRegulator_originalCPS := f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx);
f_EPTF_LoadRegulator_debug(log2str("original CPS stored: ",v_EPTF_loadRegulator_originalCPS));
oldCps := v_EPTF_loadRegulator_originalCPS;
}
// prevent increment cps above the original:
var float vl_newCps := f_EPTF_LoadRegulator_calculateNextCps(loadToReach,oldCps);
if (vl_newCps>v_EPTF_loadRegulator_originalCPS) {
vl_newCps := v_EPTF_loadRegulator_originalCPS;
}
if (v_EPTF_loadRegulator_execCtrlVar_statusIdx!=-1) {
var EPTF_StatusLED vl_currentVal := f_EPTF_Var_getStatusLEDValue(v_EPTF_loadRegulator_execCtrlVar_statusIdx);
if (vl_currentVal.text == "Auto-off" and vl_newCps<v_EPTF_loadRegulator_originalCPS) {
f_EPTF_Var_adjustContent(v_EPTF_loadRegulator_execCtrlVar_statusIdx,{ statusLEDVal := {led_yellow, "Unstable"} })
}
}
return vl_newCps;
}
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_calculateNextCps
//
// Purpose:
// The generic load regulation algorithm is implemented here
//
// Parameters:
// loadToReach - *in* *float* - the target load to reach
// oldCps - *in* *float* - the previous CPS value
//
// Return Value:
// *float* - new CPS value
//
// Errors:
// -
//
// Detailed Comments:
// The generic load regulator algorithm is a simple fuzzy regulator.
// It calculates the next cps from the previous cps and the last two
// cpu/network loads, according to the specified load to reach.
//
///////////////////////////////////////////////////////////
public function f_EPTF_LoadRegulator_calculateNextCps(
in float loadToReach,
in float oldCps)
runs on EPTF_LoadRegulator_CT
return float
{
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_calculateNextCps() started");
if (loadToReach == 0.0) { return 0.0 }
var integer measWindowSize := sizeof(vc_loadRegMeasWindow);
var float loadNew := 0.0;
var float loadOld := 0.0;
var float loadErrorNew := 0.0;
var float loadErrorOld := 0.0;
var float loadErrorDelta := 0.0;
//calculate last two load values
if(vc_measWinIdx == 0) {
loadNew := vc_loadRegMeasWindow[measWindowSize-1];
loadOld := vc_loadRegMeasWindow[measWindowSize-2];
}
else if(vc_measWinIdx == 1) {
loadNew := vc_loadRegMeasWindow[0];
loadOld := vc_loadRegMeasWindow[measWindowSize-1];
}
else {
loadNew := vc_loadRegMeasWindow[vc_measWinIdx-1];
loadOld := vc_loadRegMeasWindow[vc_measWinIdx-2];
}
//calculate load error and delta-error
loadErrorNew := loadToReach-loadNew;
loadErrorOld := loadToReach-loadOld;
loadErrorDelta := loadErrorNew-loadErrorOld;
//parameters of LoadRegulator (to be tuned for specific project)
var float errorTolerance := v_EPTF_loadRegulator_errorTolerance; // eg. +- x% of load is tolerated
var float errorDeltaTolerance := v_EPTF_loadRegulator_errorTolerance; // eg. +- x% of delta is tolerated
var float cpsDelta := v_EPTF_loadregulator_cpsDelta; // max cpsToReach increas/decrease parameter value
/* Regulation "functions" */
// (errorNew > 0) && (errorDelta > 0) --> output > 0
var float h1, h1a, h1b;
if(loadErrorNew <= -errorTolerance) { h1a := 0.0; }
else if(loadErrorNew >= errorTolerance) { h1a := 1.0; }
else {
h1a := (1.0 / (2.0*errorTolerance)) * (loadErrorNew + errorTolerance);
}
if(loadErrorDelta <= -errorDeltaTolerance) { h1b := 0.0; }
else if(loadErrorDelta >= errorDeltaTolerance) { h1b := 1.0; }
else {
h1b := (1.0 / (2.0*errorDeltaTolerance)) * (loadErrorDelta + errorDeltaTolerance);
}
if(h1a < h1b) { h1 := h1a; }
else { h1 := h1b; }
// (errorNew < 0) && (errorDelta > 0) --> output = 0
var float h2, h2a, h2b;
if(loadErrorNew <= -errorTolerance) { h2a := 1.0; }
else if(loadErrorNew >= errorTolerance) { h2a := 0.0; }
else {
h2a := (-1.0 / (2.0*errorTolerance)) * (loadErrorNew - errorTolerance);
}
h2b := h1b;
if(h2a < h2b) { h2 := h2a; }
else { h2 := h2b; }
// (errorNew > 0) && (errorDelta < 0) --> output = 0
var float h3, h3a, h3b;
h3a := h1a;
if(loadErrorDelta <= -errorDeltaTolerance) { h3b := 1.0; }
else if(loadErrorDelta >= errorDeltaTolerance) { h3b := 0.0; }
else {
h3b := (-1.0 / (2.0*errorDeltaTolerance)) * (loadErrorDelta - errorDeltaTolerance);
}
if(h3a < h3b) { h3 := h3a; }
else { h3 := h3b; }
// (errorNew < 0) && (errorDelta < 0) --> output < 0
var float h4, h4a, h4b;
h4a := h2a;
h4b := h3b;
if(h4a < h4b) { h4 := h4a; }
else { h4 := h4b; }
var float delta := (cpsDelta*h1 - cpsDelta*h4) / (h1+h2+h3+h4);
var float newCps := oldCps + delta;
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_calculateNextCps() -------- regulation data start --------");
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- Load to reach is: ", loadToReach));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- Load old: ",loadOld));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- Load new: ",loadNew));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- Load error: [",loadErrorOld,", ",loadErrorNew,"]"));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- Load error delta: ",loadErrorDelta));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- delta cps: ",delta));
f_EPTF_LoadRegulator_debug(log2str("f_EPTF_LoadRegulator_calculateNextCps() --- new cps: ",newCps));
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_calculateNextCps() -------- regulation data finish -------");
f_EPTF_LoadRegulator_debug("f_EPTF_LoadRegulator_calculateNextCps() finished");
if(newCps > 0.0) { return newCps; }
else { return oldCps; }
}
///////////////////////////////////////////////////////////
// Function: as_EPTF_LoadRegulator_behavior
//
// Purpose:
// Main behavior altstep for EPTF_LoadRegulator
//
// Parameters:
// -
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// This altstep is activated as default by f_EPTF_LoadRegulator_init_CT
///////////////////////////////////////////////////////////
private altstep as_EPTF_LoadRegulator_behavior()
runs on EPTF_LoadRegulator_CT
{
[] T_EPTF_loadReg.timeout
{
f_EPTF_LoadRegulator_ExecCtrl_refreshVars();
v_EPTF_LoadRegulator_ctx.vl_measuredLoad := vc_EPTF_getSutLoad.apply();
v_EPTF_LoadRegulator_ctx.vl_currLoad := f_EPTF_exponentialSmoothingFunction(
v_EPTF_LoadRegulator_ctx.vl_measuredLoad,
v_EPTF_LoadRegulator_ctx.vl_currLoad,
v_EPTF_loadRegulator_smoothingFactor);
// Storing the value in the meas list
vc_loadRegMeasWindow[vc_measWinIdx] := v_EPTF_LoadRegulator_ctx.vl_currLoad;
vc_measWinIdx := vc_measWinIdx + 1;
if (vc_measWinIdx == v_EPTF_loadRegulator_measWinSize) {
vc_measWinIdx := 0;
}
if (v_EPTF_LoadRegulator_ctx.vl_currLoad>v_EPTF_LoadRegulator_ctx.vl_prevLoad) {
v_EPTF_LoadRegulator_ctx.vl_diffLoad := v_EPTF_LoadRegulator_ctx.vl_currLoad - v_EPTF_LoadRegulator_ctx.vl_prevLoad;
} else {
v_EPTF_LoadRegulator_ctx.vl_diffLoad := v_EPTF_LoadRegulator_ctx.vl_prevLoad - v_EPTF_LoadRegulator_ctx.vl_currLoad;
}
if (v_EPTF_LoadRegulator_ctx.vl_diffLoad>v_EPTF_loadRegulator_LoadVarianceThreshold) {
// Update the new load value
f_EPTF_Var_adjustContent(v_LoadRegulator_currentLoadVarIdx, {floatVal := v_EPTF_LoadRegulator_ctx.vl_currLoad})
//v_EPTF_LoadRegulator_currentLoad := v_EPTF_LoadRegulator_ctx.vl_currLoad;
v_EPTF_LoadRegulator_ctx.vl_prevLoad := v_EPTF_LoadRegulator_ctx.vl_currLoad;
}
if (v_EPTF_LoadRegulator_ctx.vl_currLoad>v_EPTF_LoadRegulator_ctx.vl_prevLoad) {
v_EPTF_LoadRegulator_ctx.vl_diffLoad := v_EPTF_LoadRegulator_ctx.vl_currLoad - v_EPTF_LoadRegulator_ctx.vl_prevLoad;
} else {
v_EPTF_LoadRegulator_ctx.vl_diffLoad := v_EPTF_LoadRegulator_ctx.vl_prevLoad - v_EPTF_LoadRegulator_ctx.vl_currLoad;
}
// Calculate loadToReachDiff
v_EPTF_LoadRegulator_ctx.vl_loadToReach := f_EPTF_Var_getFloatValue(v_LoadRegulator_loadToReachVarIdx);
if (v_EPTF_LoadRegulator_ctx.vl_currLoad>v_EPTF_LoadRegulator_ctx.vl_loadToReach) {
v_EPTF_LoadRegulator_ctx.vl_loadToReachDiff := v_EPTF_LoadRegulator_ctx.vl_currLoad - v_EPTF_LoadRegulator_ctx.vl_loadToReach;
} else {
v_EPTF_LoadRegulator_ctx.vl_loadToReachDiff := v_EPTF_LoadRegulator_ctx.vl_loadToReach - v_EPTF_LoadRegulator_ctx.vl_currLoad;
}
// Storing the value in the stable list
if (v_EPTF_LoadRegulator_ctx.vl_loadToReachDiff>v_EPTF_loadRegulator_LoadVarianceThreshold) {
vc_loadRegStableWindow[vc_stableWinIdx] := 0.0; //not stable
} else {
vc_loadRegStableWindow[vc_stableWinIdx] := 1.0; //stable
}
// Updating stable list index
vc_stableWinIdx := vc_stableWinIdx + 1;
if (vc_stableWinIdx == 3) {
vc_stableWinIdx := 0;
}
// Calculate sum of StableWindow
var float sumStableWindow := 0.0;
if(sizeof(vc_loadRegStableWindow)==3) {
for(var integer i:=0; i<3; i:=i+1) {
sumStableWindow := sumStableWindow + vc_loadRegStableWindow[i];
}
}
// Calculate and update new cpsToReach only if load regulation is required...
// Update loadIsStable if necessary
if (f_EPTF_Var_getBoolValue(v_LoadRegulator_enabledVarIdx)) {
f_EPTF_Var_adjustContent(v_LoadRegulator_cpsToReachVarIdx,{floatVal :=
vc_EPTF_calculateNextCps.apply(
f_EPTF_Var_getFloatValue(v_LoadRegulator_loadToReachVarIdx),
f_EPTF_Var_getFloatValue(v_LoadRegulator_cpsToReachVarIdx))});
if(v_EPTF_postCalcCPS != null) {
v_EPTF_postCalcCPS.apply();
}
if(sumStableWindow == 3.0) {
f_EPTF_Var_adjustContent(v_LoadRegulator_loadIsStableVarIdx,{boolVal := true});
}
else {
f_EPTF_Var_adjustContent(v_LoadRegulator_loadIsStableVarIdx,{boolVal := false});
}
}
if(null != v_LoadRegulator_updateCallback){
v_LoadRegulator_updateCallback.apply();
}
T_EPTF_loadReg.start(v_EPTF_loadRegulator_updateTimeout);
repeat;
}
}
friend function f_EPTF_LoadRegulator_setUpdateCallback(
in EPTF_LoadRegulator_updateCallback_FT pl_callback)
runs on EPTF_LoadRegulator_CT
{
v_LoadRegulator_updateCallback := pl_callback;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_exponentialSmoothingFunction
//
// Purpose:
// This function is used to smooth the measured load using exponential smoothing
//
// Parameters:
// pl_measuredLoad - *in* *float* - value of the currently measured load
//
// pl_prevLoad - *in* *float* - value of the previous smoothed load
//
// pl_smoothingFactor - *in* *float* - smoothing factor, should be between
// 0.0 (extreme smoothing) and 1.0 (no smoothing)
//
// Return Value:
// float - smoothed load
//
// Errors:
// -
//
// Detailed Comments:
// This function can be used to remove high fluctuations of the measured data.
// The function uses exponetial smoothing, which is based on the following formula:
//
// s_0 = x_0
//
// s_t = alpha * x_t + (1-alpha) * s_(t-1)
//
// x_t is the measured data at t iteration, s_t is the smoothed value
//
///////////////////////////////////////////////////////////
public function f_EPTF_exponentialSmoothingFunction(in float pl_measuredLoad, in float pl_prevLoad, in float pl_smoothingFactor)
return float
{
if(tsp_debug_EPTF_CLL_LoadRegulator_Functions_smoothing){f_EPTF_Common_user(log2str("f_EPTF_exponentialSmoothingFunction: measured load: " & float2str(pl_measuredLoad)));}
var float vl_currLoad := pl_smoothingFactor*pl_measuredLoad+(1.0-pl_smoothingFactor)*pl_prevLoad;
if(tsp_debug_EPTF_CLL_LoadRegulator_Functions_smoothing){f_EPTF_Common_user(log2str("f_EPTF_exponentialSmoothingFunction: smoothed load: " & float2str(vl_currLoad)));}
return vl_currLoad;
}
///////////////////////////////////////////////////////////
// Group: Private
//
// Purpose:
// Private functions. These functions must not be called by the user of <EPTF_LoadRegulator_CT>
//
// Elements:
///////////////////////////////////////////////////////////
group Private {
group Logging {
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_error
//
// Purpose:
// Function to log an error from LoadRegulator feature.
//
// Parameters:
// - pl_message - *in* *charstring* - the message to log
//
// Return Value:
// -
//
// Errors & assertions:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
friend function f_EPTF_LoadRegulator_error(in charstring pl_message)
runs on EPTF_LoadRegulator_CT
{
f_EPTF_Logging_error(true, tsp_EPTF_LoadRegulator_loggingComponentMask&": "&pl_message);
f_EPTF_Base_stopAll();
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_warning
//
// Purpose:
// Function to log a warning from LoadRegulator feature.
//
// Parameters:
// - pl_message - *in* *charstring* - the message to log
//
// Return Value:
// -
//
// Errors & assertions:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
friend function f_EPTF_LoadRegulator_warning(in @lazy charstring pl_message)
runs on EPTF_LoadRegulator_CT
{
f_EPTF_Logging_warningV2(pl_message, v_LoadRegulator_loggingMaskId, {c_EPTF_LoadRegulator_loggingClassIdx_Warning});
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_debug
//
// Purpose:
// Function to log a debug message from LoadRegulator feature.
//
// Parameters:
// - pl_message - *in* *charstring* - the message to log
//
// Return Value:
// -
//
// Errors & assertions:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
friend function f_EPTF_LoadRegulator_debug(in @lazy charstring pl_message)
runs on EPTF_LoadRegulator_CT
{
f_EPTF_Logging_debugV2(pl_message, v_LoadRegulator_loggingMaskId, {c_EPTF_LoadRegulator_loggingClassIdx_Debug});
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_LoadRegulator_debugEnabled
//
// Purpose:
// Function to check if debug is enabled for LoadRegulator
//
// Parameters:
// -
//
// Return Value:
// *boolean* - true if debug enalbed
//
// Errors & assertions:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_LoadRegulator_debugEnabled()
runs on EPTF_LoadRegulator_CT
return boolean
{
return f_EPTF_Logging_isEnabled(v_LoadRegulator_loggingMaskId, c_EPTF_LoadRegulator_loggingClassIdx_Debug);
}
} // group Logging
public function f_EPTF_LoadRegulator_getVarRef_enabled()
runs on EPTF_LoadRegulator_CT
return integer
{
return v_LoadRegulator_enabledVarIdx;
}
public function f_EPTF_LoadRegulator_getVarRef_cpsToReach()
runs on EPTF_LoadRegulator_CT
return integer
{
return v_LoadRegulator_cpsToReachVarIdx;
}
public function f_EPTF_LoadRegulator_getVarRef_loadToReach()
runs on EPTF_LoadRegulator_CT
return integer
{
return v_LoadRegulator_loadToReachVarIdx;
}
public function f_EPTF_LoadRegulator_getVarRef_currentLoad()
runs on EPTF_LoadRegulator_CT
return integer
{
return v_LoadRegulator_currentLoadVarIdx;
}
public function f_EPTF_LoadRegulator_getVarRef_loadIsStable()
runs on EPTF_LoadRegulator_CT
return integer
{
return v_LoadRegulator_loadIsStableVarIdx;
}
} // group Private
} // module