From b866e2509b24fbc227e47ed8d529f50da4d47e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steinar=20Elgs=C3=A6ter?= <stelg@equinor.com> Date: Thu, 1 Feb 2024 14:16:00 +0100 Subject: [PATCH] -added test and gain sched identify method to attempt to estiamate a large number of gains when thresholds are given. --- Dynamic/Identification/GainSchedIdentifier.cs | 46 ++++++++++++++- .../Tests/GainSchedIdentifyTests.cs | 58 ++++++++++++++++--- 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/Dynamic/Identification/GainSchedIdentifier.cs b/Dynamic/Identification/GainSchedIdentifier.cs index c44f1134..0bc01283 100644 --- a/Dynamic/Identification/GainSchedIdentifier.cs +++ b/Dynamic/Identification/GainSchedIdentifier.cs @@ -112,7 +112,48 @@ static public GainSchedParameters Identify(UnitDataSet dataSet, GainSchedFitting /// <returns></returns> public static GainSchedParameters IdentifyGainsForGivenThresholds(UnitDataSet dataSet, GainSchedFittingSpecs gsFittingSpecs) { - return null; + var vec = new Vec(); + GainSchedParameters ret = new GainSchedParameters(); + ret.GainSchedParameterIndex = gsFittingSpecs.uGainScheduledInputIndex; + ret.LinearGainThresholds = gsFittingSpecs.uGainThresholds; + + const int WIDTH = 1; // + + int number_of_inputs = dataSet.U.GetLength(1); + double gsVarMinU = vec.Min(Array2D<double>.GetColumn(dataSet.U, ret.GainSchedParameterIndex)); + double gsVarMaxU = 0; + var linearGains = new List<double[]>(); + for (int curGainIdx = 0; curGainIdx < ret.LinearGainThresholds.Count()+1; curGainIdx++) + { + double[] uMinFit = new double[number_of_inputs]; + double[] uMaxFit = new double[number_of_inputs]; + + if (curGainIdx < ret.LinearGainThresholds.Count()- WIDTH) + gsVarMaxU = ret.LinearGainThresholds[curGainIdx+ WIDTH];//NB! +1 + else + gsVarMaxU = vec.Max(Array2D<double>.GetColumn(dataSet.U, ret.GainSchedParameterIndex)); + for (int idx = 0; idx < number_of_inputs; idx++) + { + if (idx == ret.GainSchedParameterIndex) + { + uMinFit[idx] = gsVarMinU; + uMaxFit[idx] = gsVarMaxU; + } + else + { + uMinFit[idx] = double.NaN; + uMaxFit[idx] = double.NaN; + } + } + var idResults = IdentifySingleGainForGivenThresholds(ref dataSet, uMinFit, uMaxFit); + if (curGainIdx>-1+ WIDTH) + gsVarMinU = ret.LinearGainThresholds[curGainIdx- WIDTH]; + // if (idResults.Item1 != null) + linearGains.Add(idResults.Item1); + } + // final gain:above the highest threshold + ret.LinearGains = linearGains; + return ret; } @@ -203,7 +244,8 @@ private static (double[], double) IdentifySingleGainForGivenThresholds(ref UnitD fittingSpecs.U_min_fit = u_min_fit; fittingSpecs.U_max_fit = u_max_fit; fittingSpecs.u0 = new double[] { u_min_fit[0] + (u_max_fit[0] - u_min_fit[0]) / 2 }; - var unitModel = UnitIdentifier.IdentifyLinear(ref dataSet, fittingSpecs, false); ; + // var unitModel = UnitIdentifier.IdentifyLinear(ref dataSet, fittingSpecs, false); ; + var unitModel = UnitIdentifier.IdentifyLinearAndStatic(ref dataSet, fittingSpecs, false); ; var unitParams = unitModel.GetModelParameters(); return (unitParams.LinearGains, unitParams.TimeConstant_s); diff --git a/TimeSeriesAnalysis.Tests/Tests/GainSchedIdentifyTests.cs b/TimeSeriesAnalysis.Tests/Tests/GainSchedIdentifyTests.cs index fc75d3ee..086ac17e 100644 --- a/TimeSeriesAnalysis.Tests/Tests/GainSchedIdentifyTests.cs +++ b/TimeSeriesAnalysis.Tests/Tests/GainSchedIdentifyTests.cs @@ -15,6 +15,48 @@ public class GainSchedIdentifyTests int timeBase_s = 1; const double TimeConstantAllowedDev_s = 0.5; + [Test] + public void GainEstOnly_CorrectTresholdsGiven_CorrectGainsReturned() + { + int N = 100; + + var gainSched_tenThresholds_singleInput = new GainSchedParameters + { + TimeConstant_s = null, + TimeConstantThresholds = null, + LinearGains = new List<double[]> { new double[] { 0 }, new double[] { 1 }, new double[] { 2 }, new double[] { 3 }, new double[] { 4 }, new double[] { 5 }, + new double[] { 6 }, new double[] { 7 }, new double[] { 8 }, new double[] { 9 }, new double[] { 10 } }, + LinearGainThresholds = new double[] { 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5 }, + TimeDelay_s = 0, + Bias = 5, + GainSchedParameterIndex = 0 + }; + + var refModel = new GainSchedModel(gainSched_tenThresholds_singleInput); + var gsFittingSpecs= new GainSchedFittingSpecs(); + gsFittingSpecs.uGainThresholds = refModel.GetModelParameters().LinearGainThresholds; + + var plantSim = new PlantSimulator(new List<ISimulatableModel> { refModel }); + var inputData = new TimeSeriesDataSet(); + var input = TimeSeriesCreator.ThreeSteps(N / 4, N * 2 / 4, N * 3 / 4, N, 0, 1, 2, 3). + Concat(TimeSeriesCreator.ThreeSteps(N / 4, N * 2 / 4, N * 3 / 4, N, 4, 5, 6, 7)). + Concat(TimeSeriesCreator.ThreeSteps(N / 4, N * 2 / 4, N * 3 / 4, N, 8, 9, 10, 11)).ToArray(); + inputData.Add(plantSim.AddExternalSignal(refModel, SignalType.External_U, (int)INDEX.FIRST), input); + inputData.CreateTimestamps(timeBase_s); + + // Act + var isSimulatable = plantSim.Simulate(inputData, out TimeSeriesDataSet simData); + Assert.IsTrue(isSimulatable); + var dataSet = new UnitDataSet(); + dataSet.Y_meas = simData.GetValues(refModel.ID, SignalType.Output_Y); + dataSet.U = Array2D<double>.CreateFromList(new List<double[]> { inputData.GetValues(refModel.ID,SignalType.External_U)}); + + GainSchedIdentifier.IdentifyGainsForGivenThresholds(dataSet, gsFittingSpecs); + + } + + + /* [TestCase()] public void ReturnsParametersWithNumberOfLinearGainsNotExceeding2() @@ -82,7 +124,7 @@ public void ReturnsParametersWithNumberOfLinearGainsNotExceeding2() } */ [TestCase()] - public void GainEstimationOnly_GainsNotLargerThanTheBiggestPossibleGain() + public void GainAndThreshold_GainsNotLargerThanTheBiggestPossibleGain() { int N = 500; @@ -161,7 +203,7 @@ public void GainEstimationOnly_GainsNotLargerThanTheBiggestPossibleGain() [TestCase(5, 2.5)] [TestCase(6, 3.0)]*/ [TestCase(7, 4.0)] - public void ThresholdEstimation_LinearGainThresholdAtReasonablePlace(int ver, double gain_sched_threshold) + public void GainAndThreshold_LinearGainThresholdAtReasonablePlace(int ver, double gain_sched_threshold) { int N = 300; // Arrange @@ -231,11 +273,10 @@ public void ThresholdEstimation_LinearGainThresholdAtReasonablePlace(int ver, do [TestCase(1, 35)] [TestCase(38, 40)] [TestCase(40, 20)]*/ - public void GainEstimationOnly_TwoGains_TimeConstantsAndThresholdFoundOk(double TimeConstant1_s, double TimeConstant2_s) + public void GainAndThreshold_TwoGains_TimeConstantsAndThresholdFoundOk(double TimeConstant1_s, double TimeConstant2_s) { int N = 300; - // Arrange var unitData = new UnitDataSet("test"); double[] u1 = TimeSeriesCreator.ThreeSteps(N/5, N/3, N/2, N, -2, -1, 0, 1); @@ -288,9 +329,6 @@ public void GainEstimationOnly_TwoGains_TimeConstantsAndThresholdFoundOk(double } - - - /* Shared.EnablePlots(); Plot.FromList(new List<double[]> { simY1, @@ -309,7 +347,7 @@ public void GainEstimationOnly_TwoGains_TimeConstantsAndThresholdFoundOk(double [TestCase(5, 3.5)] [TestCase(6, 4.0)]*/ // [TestCase(7, 4.5)] - public void ThresholdEstimation_ThresholdsWithinUminAndUmax(int ver, double gain_sched_threshold) + public void GainAndThreshold_ThresholdsWithinUminAndUmax(int ver, double gain_sched_threshold) { int N = 250; // Arrange @@ -449,5 +487,9 @@ public void GainSchedIdentify_AllTimeConstantsArePositive(int ver, double gain_s // Shared.DisablePlots(); } */ + + + + } }