Skip to content

Commit

Permalink
- working on documentation of closed-loop-unit-identifier
Browse files Browse the repository at this point in the history
- minor tweaks CLUI global search - return heuritisc if global search fails.
- removing some uneccessary dynamicSISO tests for CLUI
  • Loading branch information
Steinar Elgsæter committed Dec 13, 2024
1 parent 4b579aa commit b9b2766
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 88 deletions.
4 changes: 2 additions & 2 deletions Dynamic/Identification/ClosedLoopGainGlobalSearchResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,15 @@ double[] Scale(double[] v_in)
var v1_scaled = Scale(v1);

// if setpoint changes then v2 will be non-all-zero
if (!Vec.IsAllValue(v2, 0))
if (!Vec.IsAllValue(v2, 0) && v2_Strength>0)
{
var v2_scaled = Scale(v2);
objFun = vec.Add(objFun, vec.Multiply(v2_scaled, v2_factor));
retString = "Kp:v2(strength: " + v2_Strength.ToString("F2", CultureInfo.InvariantCulture) + ")" ;
}

// if the system has external inputs, and they change in value
if (!Vec.IsAllValue(v3, 0))
if (!Vec.IsAllValue(v3, 0) && v3_Strength > 0)
{
var v3_scaled = Scale(v3);
objFun = vec.Add(objFun, vec.Multiply(v3_scaled, v3_factor));
Expand Down
51 changes: 31 additions & 20 deletions Dynamic/Identification/ClosedLoopUnitIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,11 @@ public static (UnitModel, double[]) Identify(UnitDataSet dataSet, PidParameters
if (doConsoleDebugOut)
Console.WriteLine("Step1: " + unitModel_step1.GetModelParameters().LinearGains.ElementAt(pidInputIdx).ToString("F3", CultureInfo.InvariantCulture));

// var KPest = EstimateDisturbanceLF(dataSetRun1, unitModel_step1, pidInputIdx, pidParams);
// if (doConsoleDebugOut)
// Console.WriteLine("experimental: " + KPest);



idUnitModelsList.Add(unitModel_step1);

// var KPest = EstimateDisturbanceLF(dataSetRun1, unitModel_step1, pidInputIdx, pidParams);
// if (doConsoleDebugOut)
// Console.WriteLine("experimental: " + KPest);

// run1: ident (attempt to identify any other inputs)
if (isMISO)
Expand Down Expand Up @@ -165,12 +163,14 @@ public static (UnitModel, double[]) Identify(UnitDataSet dataSet, PidParameters
if (pidProcessInputInitalGainEstimate > 0)
{
max_gain = pidProcessInputInitalGainEstimate * initalGuessFactor_higherbound;
min_gain = pidProcessInputInitalGainEstimate * 1 / initalGuessFactor_higherbound;
min_gain = pidProcessInputInitalGainEstimate * 1 / initalGuessFactor_higherbound; // mostly works, but not for sinus disturbances
//min_gain = 0;
}
else
{
min_gain = pidProcessInputInitalGainEstimate * initalGuessFactor_higherbound;
max_gain = pidProcessInputInitalGainEstimate * 1 / initalGuessFactor_higherbound;
// max_gain = 0;
}
if (doConsoleDebugOut)
{
Expand All @@ -187,6 +187,8 @@ public static (UnitModel, double[]) Identify(UnitDataSet dataSet, PidParameters
GSdescription = bestUnitModel.GetModelParameters().Fitting.SolverID;
wasGainGlobalSearchDone = true;
}


if (doConsoleDebugOut && retGlobalSearch1.Item1 != null)
{

Expand Down Expand Up @@ -447,7 +449,7 @@ public static (UnitModel, double[]) Identify(UnitDataSet dataSet, PidParameters
identUnitModel.modelParameters.Fitting.SolverID = "ClosedLoop/w gain global search "+ GSdescription;
}
else
identUnitModel.modelParameters.Fitting.SolverID = "ClosedLoop local (NO global search)";
identUnitModel.modelParameters.Fitting.SolverID = "ClosedLoop heuritic (global search no minimum found)";
identUnitModel.modelParameters.Fitting.NFittingTotalDataPoints = dataSet.GetNumDataPoints();
identUnitModel.modelParameters.Fitting.NFittingBadDataPoints = dataSet.IndicesToIgnore.Count();

Expand Down Expand Up @@ -491,12 +493,19 @@ private static double EstimateDisturbanceLF(UnitDataSet dataSet, UnitModel unit
var unitParams = umInternal.GetModelParameters();

var dList = new List<double[]>();
var nameList = new List<string>();
var dNameList = new List<string>();
var v2List = new List<double[]>();
var v2NameList = new List<string>();

dList.Add(d_HF);
nameList.Add("y1=dHF");

var dHF_energy = vec.Mean(d_HF).Value;
for (double Kp = 0.5; Kp < 5.6; Kp += 0.5)
dNameList.Add("y1=dHF");
v2List.Add(dataSet.Y_meas);
v2NameList.Add("y3=y_meas");

var KpList = new List<double> { 0.5, 1, 2, 4 };

// var dHF_energy = vec.Mean(d_HF).Value;
foreach (var Kp in KpList)
{
unitParams.LinearGains = new double[] { Kp };
umInternal.SetModelParameters(unitParams);
Expand All @@ -505,20 +514,22 @@ private static double EstimateDisturbanceLF(UnitDataSet dataSet, UnitModel unit
var d_est1 = vec.Add(d_HF, d_LF);
var d_est2 = vec.Subtract(dataSet.Y_meas, y_proc);
dList.Add(d_est2);
nameList.Add("y1=destKp"+Kp.ToString("F2",CultureInfo.InvariantCulture));
var dLF_energy = vec.Mean(d_LF).Value;
dNameList.Add("y1=destKp"+Kp.ToString("F2",CultureInfo.InvariantCulture));
// var dLF_energy = vec.Mean(d_LF).Value;

//Debug.WriteLine("Kp="+Kp.ToString("F2", CultureInfo.InvariantCulture) + "dLFenergy:"+ dLF_energy.ToString("F2", CultureInfo.InvariantCulture)
// + "dHFenergy" +dHF_energy.ToString("F2", CultureInfo.InvariantCulture)) ;


Debug.WriteLine("Kp="+Kp.ToString("F2", CultureInfo.InvariantCulture) + "dLFenergy:"+ dLF_energy.ToString("F2", CultureInfo.InvariantCulture)
+ "dHFenergy" +dHF_energy.ToString("F2", CultureInfo.InvariantCulture)) ;
v2List.Add(y_proc);
v2NameList.Add("y3=yProcKp" + Kp.ToString("F2", CultureInfo.InvariantCulture));

// if the energy of t

}

dList.AddRange(v2List);
dNameList.AddRange(v2NameList);
Shared.EnablePlots();
Plot.FromList(dList, nameList,dataSet.GetTimeBase(), "exp_Kp");
Plot.FromList(dList, dNameList, dataSet.GetTimeBase(), "exp_Kp");
Shared.DisablePlots();


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,40 +43,14 @@ public void SetUp()
}


//
// does not work in general for any seed
// [TestCase(1, 1.5, 25, 1)]
// [TestCase(1, 1.5, 25, 2)]
// [TestCase(1, 1.5, 25, 3)]// TODO: redo for more seeds. use seed to avoid test buidl failing on server by chance
public void Static_RandomWalk_EstimatesOk(double noiseAmplitude, double systemGain,
double precisionPrc, int seed, bool doNegativeGain = false)
{
UnitParameters staticModelParameters = new UnitParameters
{
TimeConstant_s = 0,
LinearGains = new double[] { systemGain },
TimeDelay_s = 0,
Bias = 5
};
// Shared.EnablePlots();
var trueDisturbance = TimeSeriesCreator.RandomWalk( N, noiseAmplitude,0,seed);
CluiCommonTests.GenericDisturbanceTest(new UnitModel(staticModelParameters, "StaticProcess"), trueDisturbance,
doNegativeGain,true, null,precisionPrc);
// Shared.DisablePlots();
}

/*
This is currently a work-in-progress!!!
*/

[TestCase(5,1.0), NonParallelizable]
[TestCase(1,1.0)]
[TestCase(1,5.0)]
public void DistANDSetpointStep(double distStepAmplitude, double ysetStepAmplitude)
// [TestCase(1,5.0)]
public void StepDisturbanceANDSetpointStep(double distStepAmplitude, double ysetStepAmplitude)
{
double precisionPrc = 30;

var modelParameters = new UnitParameters
var locParams = new UnitParameters
{
TimeConstant_s = 10,
LinearGains = new double[] { 1.2 },
Expand All @@ -85,7 +59,7 @@ public void DistANDSetpointStep(double distStepAmplitude, double ysetStepAmplitu
};
var trueDisturbance = TimeSeriesCreator.Step(160, N, 0, distStepAmplitude);
var yset = TimeSeriesCreator.Step(50, N, 50, 50+ ysetStepAmplitude);//do step before disturbance
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "StaticProcess"), trueDisturbance,
CluiCommonTests.GenericDisturbanceTest(new UnitModel(locParams, "DynProcess"), trueDisturbance,
false, true, yset, precisionPrc);
}

Expand All @@ -94,12 +68,12 @@ I think the reason this test struggles is that closedloopestimator tries to find
disturbance with the smallest average change, but for continously acting disturbances like this sinus disturbance,
this may not be as good an assumption as for the step disturbances considered in other tests.
*/

/*
[TestCase(5, 1.0, Category="NotWorking_AcceptanceTest"), NonParallelizable]
[TestCase(1, 1.0, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, 5.0 )]// this only works when the step change is much bigger than the disturbance
public void SinusDistANDSetpointStep(double distSinusAmplitude, double ysetStepAmplitude)
public void SinusDisturbanceANDSetpointStep(double distSinusAmplitude, double ysetStepAmplitude)
{
double precisionPrc = 20;
Expand All @@ -115,6 +89,9 @@ public void SinusDistANDSetpointStep(double distSinusAmplitude, double ysetStepA
CluiCommonTests.GenericDisturbanceTest(new UnitModel(staticModelParameters, "Process"), trueDisturbance,
false, true, yset, precisionPrc);
}
*/

/*
[TestCase(2, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, Category = "NotWorking_AcceptanceTest")]
[TestCase(0.5, Category = "NotWorking_AcceptanceTest")]
Expand All @@ -127,26 +104,24 @@ public void SinusDisturbance(double distSinusAmplitude)
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,
false, true, yset, precisionPrc);
}

*/

// 0.25: saturates the controller
[TestCase(0.5, 0.1, Category = "NotWorking_AcceptanceTest")]
[TestCase(0.5, 1, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, 0.1, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, 1, Category = "NotWorking_AcceptanceTest")]
[TestCase(2, 0.1, Category = "NotWorking_AcceptanceTest")]
[TestCase(2, 1, Category = "NotWorking_AcceptanceTest")]
[TestCase(0.5, 0.1,30, Category = "NotWorking_AcceptanceTest")]
[TestCase(0.5, 1, 30, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, 0.1, 30, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, 1, 30, Category = "NotWorking_AcceptanceTest")]
[TestCase(2, 0.1, 30, Category = "NotWorking_AcceptanceTest")]
[TestCase(2, 1, 30, Category = "NotWorking_AcceptanceTest")]
// gain of 5 starts giving huge oscillations...

public void RandomWalkDisturbance(double procGain, double distAmplitude)
public void RandomWalkDisturbance(double procGain, double distAmplitude, double gainPrecisionPrc)
{
// int seed = 50;// works fairly well..
// int seed = 100;// much harder for some reason
int seed = 105;
double precisionPrc = 20;
int seed = 150;

int N = 2000;

var modelParameters = new UnitParameters
var locParameters = new UnitParameters
{
TimeConstant_s = 15,
LinearGains = new double[] { procGain },
Expand All @@ -156,8 +131,8 @@ public void RandomWalkDisturbance(double procGain, double distAmplitude)
var trueDisturbance = TimeSeriesCreator.RandomWalk(N,distAmplitude, 0, seed);
var yset = TimeSeriesCreator.Constant( 50, N);
Shared.EnablePlots();
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,
false, true, yset, precisionPrc);
CluiCommonTests.GenericDisturbanceTest(new UnitModel(locParameters, "Process"), trueDisturbance,
false, true, yset, gainPrecisionPrc);
Shared.DisablePlots();
}

Expand All @@ -172,31 +147,31 @@ public void Static_StepDistANDSetpointSinus(double distStepAmplitude, double yse
Vec vec = new Vec();

double precisionPrc = 20;// works when run indivdually
UnitParameters staticModelParameters = new UnitParameters
/* UnitParameters staticModelParameters = new UnitParameters
{
TimeConstant_s = 0,
TimeConstant_s = 15,
LinearGains = new double[] { 1.2 },
TimeDelay_s = 0,
Bias = 5
};
};*/
var trueDisturbance = TimeSeriesCreator.Step(100, N, 0, distStepAmplitude);
var yset = vec.Add(TimeSeriesCreator.Sinus(ysetStepAmplitude, N / 4, timeBase_s, N),TimeSeriesCreator.Constant(50,N));

CluiCommonTests.GenericDisturbanceTest(new UnitModel(staticModelParameters, "Process"), trueDisturbance,
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,
false, true, yset, precisionPrc);
}



[TestCase(5)]
[TestCase(-5)]
public void LongStepDist_EstimatesOk(double stepAmplitude)
[TestCase(5,20)]
[TestCase(-5,20)]
public void LongStepDist_EstimatesOk(double stepAmplitude,double procGainAllowedOffSetPrc)
{
bool doInvertGain = false;
// Shared.EnablePlots();
N = 1000;
var trueDisturbance = TimeSeriesCreator.Step(100, N, 0, stepAmplitude);
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,doInvertGain);
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,doInvertGain,true,null,procGainAllowedOffSetPrc);
// Shared.DisablePlots();
}

Expand All @@ -213,10 +188,10 @@ public void StepAtStartOfDataset_IsExcludedFromAnalysis()
trueDisturbance, false, true,null,10, doAddBadData);
}

[TestCase(-5,10)]
[TestCase(5, 10)]
[TestCase(10, 10)]
public void Dynamic_DistStep_EstimatesOk(double stepAmplitude, double processGainAllowedOffsetPrc,
[TestCase(-5,25)]
[TestCase(5, 25)]
[TestCase(10, 25)]
public void StepDisturbance_EstimatesOk(double stepAmplitude, double processGainAllowedOffsetPrc,
bool doNegativeGain =false)
{
//Shared.EnablePlots();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ public void SinusDisturbanceANDSetpointStep(double distSinusAmplitude, double ys
false, true, yset, precisionPrc,false, isStatic);
}

[TestCase(2, Category = "NotWorking_AcceptanceTest")]
// does not work in the static case, no sens in doing dynamic case too

/* [TestCase(2, Category = "NotWorking_AcceptanceTest")]
[TestCase(1, Category = "NotWorking_AcceptanceTest")]
[TestCase(0.5, Category = "NotWorking_AcceptanceTest")]
public void SinusDisturbance(double distSinusAmplitude)
Expand All @@ -86,7 +88,7 @@ public void SinusDisturbance(double distSinusAmplitude)
var yset = TimeSeriesCreator.Step(N / 2, N, 50, 50 );
CluiCommonTests.GenericDisturbanceTest(new UnitModel(modelParameters, "Process"), trueDisturbance,
false, true, yset, precisionPrc,doAddBadData,isStatic);
}
}*/


// 0.25: saturates the controller
Expand Down
Loading

0 comments on commit b9b2766

Please sign in to comment.