Skip to content

Commit

Permalink
- refactored GainSchedModelParameter to treat OperatingPoint u and Y …
Browse files Browse the repository at this point in the history
…as private,because directly altering these haphazardly is dangerous and can cause unwanted side-effects

- fixed issue with non-zero U in gain-sched models leading to strange "bumps" in simulated output
- moved IntegrateGains() from GainSchedModel to GainSchedModelParameters
- GainSchedIdentifier: use vec.GetValues and filter out dataSet.IndicesToIngore whereever possible, so as to be able to support ignoreindices in the future
  • Loading branch information
Steinar Elgsæter committed Nov 5, 2024
1 parent 62002bc commit 070b8d3
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 249 deletions.
99 changes: 57 additions & 42 deletions Dynamic/Identification/GainSchedIdentifier.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Dynamic/PlantSimulator/PlantSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ public static (bool, double[]) SimulateSingle(UnitDataSet unitData, ISimulatabl
/// <param name="writeToYmeas">if set to true, the simulated result is written to unitData.Y_meas instead of Y_sim</param>
/// <param name="noiseAmplitude">if writing to Ymeas, it is possible to add noise of the given amplitude to signal</param>
/// <param name="addSimToUnitData">if true, the Y_sim of unitData has the simulation result written two i</param>
/// <param name="seedNr">the seed value of the noise to be added</param>
/// <returns>a tuple, first aa true if able to simulate, otherwise false, second is the simulated time-series</returns>
static private (bool, double[]) SimulateSingle(UnitDataSet unitData, ISimulatableModel model,bool writeToYmeas= false,
double noiseAmplitude=0,
Expand Down
122 changes: 5 additions & 117 deletions Dynamic/SimulatableModels/GainSchedModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,6 @@ public bool IsModelSimulatable(out string explainStr)
return true;
}

/// <summary>
/// Adjusts the model so operating point
///
/// OperatingPoint_Y is calculate dased on the given input.
///
/// </summary>
/// <param name="newOperatingPointU">the new desired operating point</param>
public void SetOperatingPoint(double newOperatingPointU)
{
var oldOpPointU = modelParameters.OperatingPoint_U;
var oldOpPointY = modelParameters.OperatingPoint_Y;
modelParameters.OperatingPoint_U = newOperatingPointU;

var deltaGain = IntegrateGains(oldOpPointU, newOperatingPointU, modelParameters.GainSchedParameterIndex);

modelParameters.OperatingPoint_Y = oldOpPointY+ deltaGain;
}

/// <summary>
/// Initalize the process model
Expand Down Expand Up @@ -311,105 +294,10 @@ private double CalculateLinearProcessGainTerm(int inputIndex, double u, double u
{
double processGainTerm = 0;
processGainTerm = 0;
processGainTerm += IntegrateGains(modelParameters.OperatingPoint_U, u, inputIndex);
processGainTerm += modelParameters.IntegrateGains(modelParameters.GetOperatingPointU(), u, inputIndex);
return processGainTerm;
}

/// <summary>
///
/// </summary>
/// <param name="uGainSched_Start"></param>
/// <param name="uGainSched_End"></param>
/// <param name="inputIndex"></param>
/// <returns></returns>
private double IntegrateGains(double uGainSched_Start, double uGainSched_End, int inputIndex)
{
if (uGainSched_Start == uGainSched_End)
return 0;
double gainsToReturn = 0;
int gainSchedStartModelIdx = 0;
for (int idx = 0; idx < modelParameters.LinearGainThresholds.Length; idx++)
{
if (uGainSched_Start < modelParameters.LinearGainThresholds[idx])
{
gainSchedStartModelIdx = idx;
break;
}
else if (idx == modelParameters.LinearGainThresholds.Length - 1)
{
gainSchedStartModelIdx = idx + 1;
}
}
int gainSchedEndModelIdx = 0;
for (int idx = 0; idx < modelParameters.LinearGainThresholds.Length; idx++)
{
if (uGainSched_End < modelParameters.LinearGainThresholds[idx])
{
gainSchedEndModelIdx = idx;
break;
}
else if (idx == modelParameters.LinearGainThresholds.Length - 1)
{
gainSchedEndModelIdx = idx + 1;
}
}

// integrate
// if from left -> right
if (uGainSched_Start < uGainSched_End)
{
if (gainSchedStartModelIdx == gainSchedEndModelIdx)
{
double deltaU = uGainSched_End - uGainSched_Start;
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
else
{
// first portion (might be from a u between two tresholds to a threshold)
double deltaU = (modelParameters.LinearGainThresholds[gainSchedStartModelIdx] - uGainSched_Start);
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
// middle entire portions
for (int curGainSchedModIdx = gainSchedStartModelIdx + 1; curGainSchedModIdx < gainSchedEndModelIdx; curGainSchedModIdx++)
{
deltaU = (modelParameters.LinearGainThresholds[curGainSchedModIdx] - modelParameters.LinearGainThresholds[curGainSchedModIdx - 1]);
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(curGainSchedModIdx)[inputIndex];
}
// last portions (might be a treshold to inbetween two tresholds)
deltaU = uGainSched_End - modelParameters.LinearGainThresholds[gainSchedEndModelIdx-1];
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedEndModelIdx)[inputIndex];
}
}
else // integrate from left<-right
{
if (gainSchedStartModelIdx == gainSchedEndModelIdx)
{
double deltaU = uGainSched_End - uGainSched_Start;
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
else
{
double deltaU = 0;
// first portion (might be from a u between two tresholds to a threshold)
// if (modelParameters.LinearGainThresholds.Length - 1 >= gainSchedStartModelIdx)
{
// remember if there are N gains, there are N-1 gain tresholds
deltaU = (modelParameters.LinearGainThresholds[gainSchedStartModelIdx-1] - uGainSched_Start);
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
// middle entire portions
for (int curGainSchedModIdx = gainSchedStartModelIdx - 1; curGainSchedModIdx > gainSchedEndModelIdx; curGainSchedModIdx--)
{
deltaU = (modelParameters.LinearGainThresholds[curGainSchedModIdx] -
modelParameters.LinearGainThresholds[curGainSchedModIdx - 1]);
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(curGainSchedModIdx)[inputIndex];
}
// last portions (might be a treshold to inbetween two tresholds)
deltaU = uGainSched_End - modelParameters.LinearGainThresholds[gainSchedEndModelIdx];
gainsToReturn += deltaU * modelParameters.LinearGains.ElementAt(gainSchedEndModelIdx)[inputIndex];
}
}
return gainsToReturn;
}

/// <summary>
/// Determine the time constant for a particular sceduling input
Expand Down Expand Up @@ -619,7 +507,6 @@ override public string ToString()
numberFormat.NumberDecimalSeparator = ".";

int sDigits = 3;
int sDigitsUnc = 2;

int cutOffForUsingDays_s = 86400;
int cutOffForUsingHours_s = 3600;
Expand All @@ -645,8 +532,8 @@ override public string ToString()

sb.AppendLine("Gain-scheduling parameter index:" + modelParameters.GainSchedParameterIndex);

sb.AppendLine("Operating point U:" + SignificantDigits.Format(modelParameters.OperatingPoint_U, sDigits).ToString(writeCulture) );
sb.AppendLine("Operating point Y:" + SignificantDigits.Format(modelParameters.OperatingPoint_Y, sDigits).ToString(writeCulture) );
sb.AppendLine("Operating point U:" + SignificantDigits.Format(modelParameters.GetOperatingPointU(), sDigits).ToString(writeCulture) );
sb.AppendLine("Operating point Y:" + SignificantDigits.Format(modelParameters.GetOperatingPointY(), sDigits).ToString(writeCulture) );

////////////////////////////////
// time delay
Expand Down Expand Up @@ -741,7 +628,8 @@ override public string ToString()
sb.AppendLine("R2(diffs): " + SignificantDigits.Format(modelParameters.Fitting.RsqDiff, 4).ToString(writeCulture));
sb.AppendLine("R2(abs): " + SignificantDigits.Format(modelParameters.Fitting.RsqAbs, 4).ToString(writeCulture));
*/
sb.AppendLine("model fit data points: " + modelParameters.Fitting.NFittingTotalDataPoints + " of which " + modelParameters.Fitting.NFittingBadDataPoints + " were excluded");
sb.AppendLine("model fit data points: " + modelParameters.Fitting.NFittingTotalDataPoints
+ " of which " + modelParameters.Fitting.NFittingBadDataPoints + " were ignored");
foreach (var warning in modelParameters.GetWarningList())
sb.AppendLine("model fit warning :" + warning.ToString());
if (modelParameters.GetWarningList().Count == 0)
Expand Down
167 changes: 164 additions & 3 deletions Dynamic/SimulatableModels/GainSchedParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,21 @@ public class GainSchedParameters : ModelParametersBaseClass

/// <summary>
/// The "operating point" specifies the value y that the model should have for the gain scheduled input u.
/// so y = OperatingPoint_Y when u = OperatingPoint_U
/// so y = OperatingPoint_Y when u = OperatingPoint_U. Change the operating point by using <c>SetOperatingPoint()</c>
/// </summary>
public double OperatingPoint_U=0, OperatingPoint_Y=0;
private double OperatingPoint_U=0, OperatingPoint_Y=0;

private List<GainSchedIdentWarnings> errorsAndWarningMessages;

/// <summary>
/// Default constructor
/// </summary>
public GainSchedParameters()
public GainSchedParameters(double OperatingPoint_U = 0, double OperatingPoint_Y = 0)
{
Fitting = null;
errorsAndWarningMessages = new List<GainSchedIdentWarnings>();
this.OperatingPoint_U = OperatingPoint_U;
this.OperatingPoint_Y = OperatingPoint_Y;
}

/// <summary>
Expand Down Expand Up @@ -156,6 +158,165 @@ public int GetNumInputs()
}


/// <summary>
/// Sets a new operating point U, and adjusts the operating point Y so that the model
/// output will be the same as before the change
///
/// </summary>
/// <param name="newOperatingPointU">the new desired operating point</param>
public void MoveOperatingPointUWithoutChangingModel(double newOperatingPointU)
{
var oldOpPointU = OperatingPoint_U;
var oldOpPointY = OperatingPoint_Y;
OperatingPoint_U = newOperatingPointU;

var deltaGain = IntegrateGains(oldOpPointU, newOperatingPointU, GainSchedParameterIndex);
OperatingPoint_Y = oldOpPointY + deltaGain;
}

/// <summary>
/// This set the (u,y) through which a model may pass.
///
/// Careful! only use this when initalizing a new model, otherwise, you should use
/// <c>MoveOperatingPointUWithoutChangingModel</c> to preserve model behavior
/// </summary>
/// <param name="newOperatingPointU"></param>
/// <param name="newOperatingPointY"></param>
public void SetOperatingPoint(double newOperatingPointU, double newOperatingPointY)
{
OperatingPoint_Y = newOperatingPointU;
OperatingPoint_Y = newOperatingPointY;
}

/// <summary>
/// Changes the operating point by a given delta.
///
/// Give negative values to decrease the operating point.
///
/// </summary>
/// <param name="deltaOperatingPoint_Y"></param>
public void IncreaseOperatingPointY(double deltaOperatingPoint_Y)
{
OperatingPoint_Y+= deltaOperatingPoint_Y;
}

/// <summary>
/// Get the U of the operating point
/// </summary>
/// <returns></returns>
public double GetOperatingPointU()
{
return OperatingPoint_U;
}

/// <summary>
/// Get the Y of the operating point
/// </summary>
/// <returns></returns>
public double GetOperatingPointY()
{
return OperatingPoint_Y;
}

/// <summary>
/// Integrate a model from a start point to an end point
/// </summary>
/// <param name="uGainSched_Start"></param>
/// <param name="uGainSched_End"></param>
/// <param name="inputIndex"></param>
/// <returns></returns>
public double IntegrateGains(double uGainSched_Start, double uGainSched_End, int inputIndex)
{
if (uGainSched_Start == uGainSched_End)
return 0;
double gainsToReturn = 0;
int gainSchedStartModelIdx = 0;
for (int idx = 0; idx < LinearGainThresholds.Length; idx++)
{
if (uGainSched_Start < LinearGainThresholds[idx])
{
gainSchedStartModelIdx = idx;
break;
}
else if (idx == LinearGainThresholds.Length - 1)
{
gainSchedStartModelIdx = idx + 1;
}
}
int gainSchedEndModelIdx = 0;
for (int idx = 0; idx < LinearGainThresholds.Length; idx++)
{
if (uGainSched_End < LinearGainThresholds[idx])
{
gainSchedEndModelIdx = idx;
break;
}
else if (idx == LinearGainThresholds.Length - 1)
{
gainSchedEndModelIdx = idx + 1;
}
}

// integrate
// if from left -> right
if (uGainSched_Start < uGainSched_End)
{
if (gainSchedStartModelIdx == gainSchedEndModelIdx)
{
double deltaU = uGainSched_End - uGainSched_Start;
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
else
{
// first portion (might be from a u between two tresholds to a threshold)
double deltaU = (LinearGainThresholds[gainSchedStartModelIdx] - uGainSched_Start);
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
// middle entire portions
for (int curGainSchedModIdx = gainSchedStartModelIdx + 1; curGainSchedModIdx < gainSchedEndModelIdx; curGainSchedModIdx++)
{
deltaU = (LinearGainThresholds[curGainSchedModIdx] - LinearGainThresholds[curGainSchedModIdx - 1]);
gainsToReturn += deltaU * LinearGains.ElementAt(curGainSchedModIdx)[inputIndex];
}
// last portions (might be a treshold to inbetween two tresholds)
deltaU = uGainSched_End - LinearGainThresholds[gainSchedEndModelIdx - 1];
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedEndModelIdx)[inputIndex];
}
}
else // integrate from left<-right
{
if (gainSchedStartModelIdx == gainSchedEndModelIdx)
{
double deltaU = uGainSched_End - uGainSched_Start;
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
else
{
double deltaU = 0;
// first portion (might be from a u between two tresholds to a threshold)
// if (modelParameters.LinearGainThresholds.Length - 1 >= gainSchedStartModelIdx)
{
// remember if there are N gains, there are N-1 gain tresholds
deltaU = (LinearGainThresholds[gainSchedStartModelIdx - 1] - uGainSched_Start);
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedStartModelIdx)[inputIndex];
}
// middle entire portions
for (int curGainSchedModIdx = gainSchedStartModelIdx - 1; curGainSchedModIdx > gainSchedEndModelIdx; curGainSchedModIdx--)
{
deltaU = (LinearGainThresholds[curGainSchedModIdx] -
LinearGainThresholds[curGainSchedModIdx - 1]);
gainsToReturn += deltaU * LinearGains.ElementAt(curGainSchedModIdx)[inputIndex];
}
// last portions (might be a treshold to inbetween two tresholds)
deltaU = uGainSched_End - LinearGainThresholds[gainSchedEndModelIdx];
gainsToReturn += deltaU * LinearGains.ElementAt(gainSchedEndModelIdx)[inputIndex];
}
}
return gainsToReturn;
}




/// <summary>
/// Adds a identifiation warning to the object
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion Dynamic/SimulatableModels/UnitModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,8 @@ override public string ToString()
sb.AppendLine("R2(diffs): " + SignificantDigits.Format(modelParameters.Fitting.RsqDiff, 4).ToString(writeCulture));
sb.AppendLine("R2(abs): " + SignificantDigits.Format(modelParameters.Fitting.RsqAbs, 4).ToString(writeCulture));

sb.AppendLine("model fit data points: " + modelParameters.Fitting.NFittingTotalDataPoints + " of which " + modelParameters.Fitting.NFittingBadDataPoints + " were excluded");
sb.AppendLine("model fit data points: " + modelParameters.Fitting.NFittingTotalDataPoints
+ " of which " + modelParameters.Fitting.NFittingBadDataPoints + " were ignored");
foreach (var warning in modelParameters.GetWarningList())
sb.AppendLine("model fit warning :" + warning.ToString());
if (modelParameters.GetWarningList().Count == 0)
Expand Down
Loading

0 comments on commit 070b8d3

Please sign in to comment.