From 2844eb60ec9bd61f1c21ece26d4b2ea585439e20 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Sun, 6 Nov 2022 13:25:49 +0300 Subject: [PATCH] Soft Computing --- Esiur.Analysis.Test/FMain.Designer.cs | 72 --- Esiur.Analysis.Test/FMain.cs | 345 ----------- Esiur.Analysis.Test/FSoft.Designer.cs | 169 ++++++ Esiur.Analysis.Test/FSoft.cs | 564 ++++++++++++++++++ .../{FMain.resx => FSoft.resx} | 0 Esiur.Analysis.Test/Program.cs | 2 +- Esiur.Analysis/DSP/Functions.cs | 1 - Esiur.Analysis/Fuzzy/DiscreteSet.cs | 8 +- Esiur.Analysis/Fuzzy/FuzzyExtensions.cs | 37 ++ Esiur.Analysis/Fuzzy/MembershipFunction.cs | 4 +- Esiur.Analysis/Optimization/Genetic.cs | 18 +- 11 files changed, 790 insertions(+), 430 deletions(-) delete mode 100644 Esiur.Analysis.Test/FMain.Designer.cs delete mode 100644 Esiur.Analysis.Test/FMain.cs create mode 100644 Esiur.Analysis.Test/FSoft.Designer.cs create mode 100644 Esiur.Analysis.Test/FSoft.cs rename Esiur.Analysis.Test/{FMain.resx => FSoft.resx} (100%) diff --git a/Esiur.Analysis.Test/FMain.Designer.cs b/Esiur.Analysis.Test/FMain.Designer.cs deleted file mode 100644 index 77a7cb0..0000000 --- a/Esiur.Analysis.Test/FMain.Designer.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Esiur.Analysis.Test -{ - partial class FMain - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.formsPlot1 = new ScottPlot.FormsPlot(); - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // formsPlot1 - // - this.formsPlot1.Location = new System.Drawing.Point(57, 47); - this.formsPlot1.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); - this.formsPlot1.Name = "formsPlot1"; - this.formsPlot1.Size = new System.Drawing.Size(1006, 576); - this.formsPlot1.TabIndex = 0; - // - // button1 - // - this.button1.Location = new System.Drawing.Point(12, 316); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(85, 31); - this.button1.TabIndex = 1; - this.button1.Text = "button1"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // FMain - // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1175, 658); - this.Controls.Add(this.button1); - this.Controls.Add(this.formsPlot1); - this.Name = "FMain"; - this.Text = "PID Controller with Fuzzy"; - this.Load += new System.EventHandler(this.FMain_Load); - this.ResumeLayout(false); - - } - - #endregion - - private ScottPlot.FormsPlot formsPlot1; - private Button button1; - } -} \ No newline at end of file diff --git a/Esiur.Analysis.Test/FMain.cs b/Esiur.Analysis.Test/FMain.cs deleted file mode 100644 index 12752ad..0000000 --- a/Esiur.Analysis.Test/FMain.cs +++ /dev/null @@ -1,345 +0,0 @@ -using Esiur.Analysis.DSP; -using Esiur.Analysis.Fuzzy; -using Esiur.Analysis.Optimization; -using Esiur.Analysis.Signals; -using Esiur.Analysis.Units; -using Microsoft.VisualBasic.Logging; -using ScottPlot; -using ScottPlot.Drawing.Colormaps; -using System.Security.Cryptography; -using Esiur.Analysis.Statistics; -using System.Diagnostics; - -namespace Esiur.Analysis.Test -{ - public partial class FMain : Form - { - public FMain() - { - InitializeComponent(); - - //var outage = Capacity.ComputeOutage(20000000, new Capacity.CSI[] - //{ - // new Capacity.CSI(PowerUnit.FromDb(20), 0.1), - // new Capacity.CSI(PowerUnit.FromDb(15), 0.15), - // new Capacity.CSI(PowerUnit.FromDb(10), 0.25), - // new Capacity.CSI(PowerUnit.FromDb(5), 0.25), - // new Capacity.CSI(PowerUnit.FromDb(0), 0.15), - // new Capacity.CSI(PowerUnit.FromDb(-5), 0.1), - //}); - var outage = Capacity.ComputeOutage(1, new Capacity.CSI[] - { - new Capacity.CSI(PowerUnit.FromDb(30), 0.2), - new Capacity.CSI(PowerUnit.FromDb(20), 0.3), - new Capacity.CSI(PowerUnit.FromDb(10), 0.3), - new Capacity.CSI(PowerUnit.FromDb(0), 0.2), - }); - - - var low = new ContinuousSet(MembershipFunctions.Descending(20, 40)); - var mid = new ContinuousSet(MembershipFunctions.Triangular(20, 40, 60)); - var high = new ContinuousSet(MembershipFunctions.Ascending(40, 60)); - - var bad = new ContinuousSet(MembershipFunctions.Descending(0, 30)); - var ok = new ContinuousSet(MembershipFunctions.Triangular(20, 50, 80)); - var excelent = new ContinuousSet(MembershipFunctions.Ascending(70, 100)); - - var small = new ContinuousSet(MembershipFunctions.Descending(100, 200)); - var avg = new ContinuousSet(MembershipFunctions.Triangular(100, 200, 300)); - var big = new ContinuousSet(MembershipFunctions.Ascending(200, 300)); - - //var speedIsLowThenSmall = new FuzzyRule("Low=>Small", low, small); - - double rating = 80; - - for (double temp = 60; temp < 100; temp++) - { - var v = MamdaniDefuzzifier.Evaluate(new INumericalSet[] - { - temp.Is(low).And(rating.Is(bad)).Then(small), - temp.Is(mid).And(rating.Is(ok)).Then(avg), - temp.Is(high).And(rating.Is(excelent)).Then(big), - }, MamdaniDefuzzifierMethod.CenterOfGravity, 100, 300, 1); - - } - - } - - private void FMain_Load(object sender, EventArgs e) - { - - var lowErr = new ContinuousSet(MembershipFunctions.Descending(-5, 4.5)); - var midErr = new ContinuousSet(MembershipFunctions.Triangular(-4, 6.5, 16.5)); - var highErr = new ContinuousSet(MembershipFunctions.Ascending(8, 18)); - - var lowAccErr = new ContinuousSet(MembershipFunctions.Descending(0, 0.02)); - var midAccErr = new ContinuousSet(MembershipFunctions.Triangular(0.02, 0.04, 0.06)); - var highAccErr = new ContinuousSet(MembershipFunctions.Ascending(0.04, 0.06)); - - var small = new ContinuousSet(MembershipFunctions.Descending(0.1, 0.5)); - var avg = new ContinuousSet(MembershipFunctions.Triangular(0.1, 0.5, 1.1)); - var big = new ContinuousSet(MembershipFunctions.Ascending(-10, 1.1)); - - - var x = Enumerable.Range(0, 1000).Select(x => x * 0.01).ToArray(); - - - var step = Enumerable.Repeat(1, 1000).Select(x => (double)x).ToArray(); - step[0] = 0; - - var motor = new TransferFunction(new double[] { 1, 2 }, new double[] { 1, 1, 2 }, 0.01); - var motorPID = new TransferFunction(new double[] { 1, 2 }, new double[] { 1, 1, 2 }, 0.01); - var motorFuzzyPID = new TransferFunction(new double[] { 1, 2 }, new double[] { 1, 1, 2 }, 0.01); - - //double Kp = 2, Ki = 0.4, Kd = 0.4; - - double Ki = -1.9181372, Kp = 18.625, Kd = 0.38281253; - - - var pid = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); - var fuzzyPID = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); - - - var sysOut = new double[step.Length]; - var sysOutFuzzyPID = new double[step.Length]; - var sysOutPID = new double[step.Length]; - - var pidOut = new double[step.Length]; - var pidOutFuzzy = new double[step.Length]; - var errorOutPID = new double[step.Length]; - - var errOut = new double[step.Length]; - var errAccOut = new double[step.Length]; - - //var errorAccOut = new double[step.Length]; - - var errorOutFuzzy = new double[step.Length]; - var errorOutAccFuzzy = new double[step.Length]; - - for (var i = 0; i < step.Length; i++) - { - sysOut[i] = motor.Evaluate(step[i]); - errOut[i] = step[i] - sysOut[i]; - errAccOut[i] = errOut[i] - (i == 0 ? 0 : errOut[i - 1]); - - sysOutPID[i] = motorPID.Evaluate(step[i] + (i == 0 ? 0 : pidOut[i - 1])); - sysOutFuzzyPID[i] = motorFuzzyPID.Evaluate(step[i] + (i == 0 ? 0 : pidOutFuzzy[i - 1])); - - - errorOutPID[i] = (step[i] - sysOutPID[i]); - errorOutFuzzy[i] = (step[i] - sysOutFuzzyPID[i]); - errorOutAccFuzzy[i] = (errorOutFuzzy[i] - (i == 0 ? 0 : errorOutFuzzy[i - 1])); - - pidOut[i] = pid.Evaluate(errorOutPID[i]); - pidOutFuzzy[i] = fuzzyPID.Evaluate(errorOutFuzzy[i]); - - - var k = MamdaniDefuzzifier.Evaluate(new INumericalSet[] - { - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(small), - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(small), - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(avg), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(small), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(avg), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(big), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(avg), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(big), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(big), - }, MamdaniDefuzzifierMethod.CenterOfGravity, 0, 1, 0.05); - - fuzzyPID.InputCoefficients[1] = k; - fuzzyPID.InputCoefficients[1] = k; - fuzzyPID.InputCoefficients[1] = k; - } - - Debug.WriteLine($"Error Values Min: {errOut.Min()} Max: {errOut.Max()} "); - Debug.WriteLine($"Error Acc Values Min: {errAccOut.Min()} Max: {errAccOut.Max()} "); - - formsPlot1.Plot.AddScatter(x, sysOut, Color.Red); - formsPlot1.Plot.AddScatter(x, sysOutPID, Color.Blue); - formsPlot1.Plot.AddScatter(x, sysOutFuzzyPID, Color.Green); - - formsPlot1.Refresh(); - - } - - - struct KK - { - public float Ki; - public float Kp; - public float Kd; - - public override string ToString() - { - return $"Ki {Ki} Kp {Kp} Kd {Kd}"; - } - } - - struct FuzzyChromosome - { - public sbyte KiInputErrPosition; - public sbyte KiInputErrScale; - - public sbyte KiInputErrAccPosition; - public sbyte KiInputErrAccScale; - - public sbyte KiOutputPosition; - public sbyte KiOutputScale; - } - - private double CalculateFuzzyPIDStepError(FuzzyChromosome config, double errStart, double errEnd) - { - var errPos = config.KiInputErrPosition * 0.1; - var errScale = config.KiInputErrPosition * 0.1; - - var lowErr = new ContinuousSet(MembershipFunctions.Descending(config.KiInputErrPosition * 0.1, config.kiLowStart * 0.1 + Math.Abs(config.kiLowEnd * 0.1))); - var midErr = new ContinuousSet(MembershipFunctions.Triangular(config.KiInputErrPosition * 0.1, config.kiMidStart * 0.1 + Math.Abs(config.kiMidMid * 0.1), config.kiMidStart * 0.1 + Math.Abs(config.kiMidMid * 0.1) + Math.Abs(config.kiMidEnd * 0.1))); - var highErr = new ContinuousSet(MembershipFunctions.Ascending(config.KiInputErrPosition * 0.1, config.kiHiStart * 0.1 + Math.Abs(config.kiHiEnd * 0.1))); - - var lowAccErr = new ContinuousSet(MembershipFunctions.Descending(config.KiInputErrAccPosition * 0.1, Math.Abs(config.kiLowAccStart * 0.1) + Math.Abs(config.kiLowAccEnd * 0.1))); - var midAccErr = new ContinuousSet(MembershipFunctions.Triangular(config.KiInputErrAccPosition * 0.1, Math.Abs(config.kiMidAccStart * 0.1) + Math.Abs(config.kiMidAccMid * 0.1), config.kiMidAccStart * 0.1 + Math.Abs(config.kiMidAccMid * 0.1) + Math.Abs(config.kiMidAccEnd * 0.1))); - var highAccErr = new ContinuousSet(MembershipFunctions.Ascending(config.KiInputErrAccPosition * 0.1, config.kiHiAccStart * 0.1 + Math.Abs(config.kiHiAccEnd * 0.1))); - - var small = new ContinuousSet(MembershipFunctions.Descending(config.kiSmallStart * 0.1, config.kiSmallStart * 0.1 + Math.Abs(config.kiSmallEnd * 0.1))); - var avg = new ContinuousSet(MembershipFunctions.Triangular(config.kiAvgStart * 0.1, config.kiAvgStart * 0.1 + Math.Abs(config.kiAvgMid * 0.1), config.kiAvgStart * 0.1 + Math.Abs(config.kiAvgMid * 0.1) + Math.Abs(config.kiAvgEnd * 0.1))); - var big = new ContinuousSet(MembershipFunctions.Ascending(config.kiBigStart * 0.1, config.kiBigStart * 0.1 + Math.Abs(config.kiBigEnd * 0.1))); - - double Ki = -1.9181372, Kp = 18.625, Kd = 0.38281253; - - var step = Enumerable.Repeat(1, 1000).Select(x => (double)x).ToArray(); - step[0] = 0; - - var motor = new TransferFunction(new double[] { 1, 2 }, new double[] { 1, 1, 2 }, 0.01); - var fuzzyPID = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); - - var sysOutFuzzyPID = new double[step.Length]; - - var pidOut = new double[step.Length]; - var pidOutFuzzy = new double[step.Length]; - - var errorOutFuzzy = new double[step.Length]; - var errorOutAccFuzzy = new double[step.Length]; - - for (var i = 0; i < step.Length; i++) - { - sysOutFuzzyPID[i] = motor.Evaluate(step[i] + (i == 0 ? 0 : pidOutFuzzy[i - 1])); - - - errorOutFuzzy[i] = (step[i] - sysOutFuzzyPID[i]); - errorOutAccFuzzy[i] = (errorOutFuzzy[i] - (i == 0 ? 0 : errorOutFuzzy[i - 1])); - - pidOutFuzzy[i] = fuzzyPID.Evaluate(errorOutFuzzy[i]); - - - var k = MamdaniDefuzzifier.Evaluate(new INumericalSet[] - { - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(small), - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(small), - errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(avg), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(small), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(avg), - errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(big), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(avg), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(big), - errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(big), - }, MamdaniDefuzzifierMethod.CenterOfGravity, -100, 100, 0.5); - - fuzzyPID.InputCoefficients[1] = k; - //fuzzyPID.InputCoefficients[1] = k; - //fuzzyPID.InputCoefficients[1] = k; - } - - return errorOutFuzzy.RMS(); - - } - - private double CalculatePIDStepError(double Kd, double Kp, double Ki) - { - var step = Enumerable.Repeat(1, 1000).Select(x => (double)x).ToArray(); - step[0] = 0; - - var motor = new TransferFunction(new double[] { 1, 2 }, new double[] { 1, 1, 2 }, 0.01); - - var sysOutPID = new double[step.Length]; - - var pidOut = new double[step.Length]; - var errorOutPID = new double[step.Length]; - var pid = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); - - for (var i = 0; i < step.Length; i++) - { - sysOutPID[i] = motor.Evaluate(step[i] + (i == 0 ? 0 : pidOut[i - 1])); - - if (double.IsInfinity(sysOutPID[i])) - Console.WriteLine(); - - errorOutPID[i] = (step[i] - sysOutPID[i]); - - if (double.IsNaN(errorOutPID[i])) - Console.WriteLine(); - - pidOut[i] = pid.Evaluate(errorOutPID[i]); - - if (double.IsInfinity(pidOut[i])) - Console.WriteLine(); - - } - - return errorOutPID.RMS(); - } - - private void button1_Click(object sender, EventArgs e) - { - - //var gen = new Genetic(100, k => - //{ - // if (float.IsNaN(k.Ki) || float.IsNaN(k.Kp) || float.IsNaN(k.Kd)) - // return (double.MaxValue); - - - // var r = CalculatePIDStepError(k.Kd, k.Kp, k.Ki); - // if (double.IsNaN(r)) - // Console.WriteLine(); - // return r; - //}); - - var gen = new Genetic(100, k => - { - if (float.IsNaN(k.kiAvgEnd) - || float.IsNaN(k.kiAvgMid) - || float.IsNaN(k.kiAvgStart) - || float.IsNaN(k.kiBigEnd) - || float.IsNaN(k.kiBigStart) - || float.IsNaN(k.kiHiAccEnd) - || float.IsNaN(k.kiHiAccStart) - || float.IsNaN(k.kiHiEnd) - || float.IsNaN(k.kiHiStart) - || float.IsNaN(k.kiLowAccEnd) - || float.IsNaN(k.kiLowAccStart) - || float.IsNaN(k.kiLowEnd) - || float.IsNaN(k.kiLowStart) - || float.IsNaN(k.kiMidAccEnd) - || float.IsNaN(k.kiMidAccMid) - || float.IsNaN(k.kiMidAccStart) - || float.IsNaN(k.kiMidEnd) - || float.IsNaN(k.kiMidMid) - || float.IsNaN(k.kiMidStart) - || float.IsNaN(k.kiSmallEnd) - || float.IsNaN(k.kiSmallStart)) - return (double.MaxValue); - - - var r = CalculateFuzzyPIDStepError(k); - if (double.IsNaN(r)) - Console.WriteLine(); - return r; - }); - - - var ev = gen.Evaluate(1000); - - Console.WriteLine(ev); - } - } -} \ No newline at end of file diff --git a/Esiur.Analysis.Test/FSoft.Designer.cs b/Esiur.Analysis.Test/FSoft.Designer.cs new file mode 100644 index 0000000..e4b9434 --- /dev/null +++ b/Esiur.Analysis.Test/FSoft.Designer.cs @@ -0,0 +1,169 @@ +namespace Esiur.Analysis.Test +{ + partial class FSoft + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.formsPlot1 = new ScottPlot.FormsPlot(); + this.button1 = new System.Windows.Forms.Button(); + this.formsPlot2 = new ScottPlot.FormsPlot(); + this.formsPlot3 = new ScottPlot.FormsPlot(); + this.formsPlot4 = new ScottPlot.FormsPlot(); + this.button2 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // formsPlot1 + // + this.formsPlot1.Location = new System.Drawing.Point(14, 47); + this.formsPlot1.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.formsPlot1.Name = "formsPlot1"; + this.formsPlot1.Size = new System.Drawing.Size(901, 703); + this.formsPlot1.TabIndex = 0; + this.formsPlot1.Load += new System.EventHandler(this.formsPlot1_Load); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(545, 753); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(183, 31); + this.button1.TabIndex = 1; + this.button1.Text = "Genetic Fuzzy PID"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // formsPlot2 + // + this.formsPlot2.Location = new System.Drawing.Point(908, 47); + this.formsPlot2.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.formsPlot2.Name = "formsPlot2"; + this.formsPlot2.Size = new System.Drawing.Size(369, 243); + this.formsPlot2.TabIndex = 2; + // + // formsPlot3 + // + this.formsPlot3.Location = new System.Drawing.Point(908, 273); + this.formsPlot3.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.formsPlot3.Name = "formsPlot3"; + this.formsPlot3.Size = new System.Drawing.Size(369, 241); + this.formsPlot3.TabIndex = 3; + // + // formsPlot4 + // + this.formsPlot4.Location = new System.Drawing.Point(908, 522); + this.formsPlot4.Margin = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.formsPlot4.Name = "formsPlot4"; + this.formsPlot4.Size = new System.Drawing.Size(369, 241); + this.formsPlot4.TabIndex = 4; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(734, 753); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(193, 31); + this.button2.TabIndex = 5; + this.button2.Text = "Fuzzy PID"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(116, 753); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(176, 27); + this.textBox1.TabIndex = 6; + this.textBox1.Text = "10 / 1 1 0.1"; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(314, 753); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(143, 31); + this.button3.TabIndex = 7; + this.button3.Text = "System"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // button4 + // + this.button4.Location = new System.Drawing.Point(757, 33); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(143, 31); + this.button4.TabIndex = 8; + this.button4.Text = "Clear"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(472, 755); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(67, 27); + this.textBox2.TabIndex = 9; + this.textBox2.Text = "100"; + this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); + // + // FMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1291, 828); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.button4); + this.Controls.Add(this.button3); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.button2); + this.Controls.Add(this.formsPlot4); + this.Controls.Add(this.formsPlot3); + this.Controls.Add(this.formsPlot2); + this.Controls.Add(this.button1); + this.Controls.Add(this.formsPlot1); + this.Name = "FMain"; + this.Text = "PID Controller with Fuzzy"; + this.Load += new System.EventHandler(this.FMain_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ScottPlot.FormsPlot formsPlot1; + private Button button1; + private ScottPlot.FormsPlot formsPlot2; + private ScottPlot.FormsPlot formsPlot3; + private ScottPlot.FormsPlot formsPlot4; + private Button button2; + private TextBox textBox1; + private Button button3; + private Button button4; + private TextBox textBox2; + } +} \ No newline at end of file diff --git a/Esiur.Analysis.Test/FSoft.cs b/Esiur.Analysis.Test/FSoft.cs new file mode 100644 index 0000000..0f3fa93 --- /dev/null +++ b/Esiur.Analysis.Test/FSoft.cs @@ -0,0 +1,564 @@ +using Esiur.Analysis.DSP; +using Esiur.Analysis.Fuzzy; +using Esiur.Analysis.Optimization; +using Esiur.Analysis.Signals; +using Esiur.Analysis.Units; +using Microsoft.VisualBasic.Logging; +using ScottPlot; +using ScottPlot.Drawing.Colormaps; +using System.Security.Cryptography; +using Esiur.Analysis.Statistics; +using System.Diagnostics; + +namespace Esiur.Analysis.Test +{ + public partial class FSoft : Form + { + + private double[] num = new double[] { 10 }; + private double[] denum = new double[] { 1, 1, 0.1 }; + private int interval = 3000; + private double stability = 100; + + public FSoft() + { + InitializeComponent(); + + //var outage = Capacity.ComputeOutage(20000000, new Capacity.CSI[] + //{ + // new Capacity.CSI(PowerUnit.FromDb(20), 0.1), + // new Capacity.CSI(PowerUnit.FromDb(15), 0.15), + // new Capacity.CSI(PowerUnit.FromDb(10), 0.25), + // new Capacity.CSI(PowerUnit.FromDb(5), 0.25), + // new Capacity.CSI(PowerUnit.FromDb(0), 0.15), + // new Capacity.CSI(PowerUnit.FromDb(-5), 0.1), + //}); + var outage = Capacity.ComputeOutage(1, new Capacity.CSI[] + { + new Capacity.CSI(PowerUnit.FromDb(30), 0.2), + new Capacity.CSI(PowerUnit.FromDb(20), 0.3), + new Capacity.CSI(PowerUnit.FromDb(10), 0.3), + new Capacity.CSI(PowerUnit.FromDb(0), 0.2), + }); + + + var low = new ContinuousSet(MembershipFunctions.Descending(20, 40)); + var mid = new ContinuousSet(MembershipFunctions.Triangular(20, 40, 60)); + var high = new ContinuousSet(MembershipFunctions.Ascending(40, 60)); + + var bad = new ContinuousSet(MembershipFunctions.Descending(0, 30)); + var ok = new ContinuousSet(MembershipFunctions.Triangular(20, 50, 80)); + var excelent = new ContinuousSet(MembershipFunctions.Ascending(70, 100)); + + var small = new ContinuousSet(MembershipFunctions.Descending(100, 200)); + var avg = new ContinuousSet(MembershipFunctions.Triangular(100, 200, 300)); + var big = new ContinuousSet(MembershipFunctions.Ascending(200, 300)); + + //var speedIsLowThenSmall = new FuzzyRule("Low=>Small", low, small); + + double rating = 80; + + for (double temp = 60; temp < 100; temp++) + { + var v = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + temp.Is(low).And(rating.Is(bad)).Then(small), + temp.Is(mid).And(rating.Is(ok)).Then(avg), + temp.Is(high).And(rating.Is(excelent)).Then(big), + }, MamdaniDefuzzifierMethod.CenterOfGravity, 100, 300, 1); + + } + + } + + private void FMain_Load(object sender, EventArgs e) + { + //Ki -29:69 Kp -54:121 Kd 29:112 + var config = new FuzzyChromosome() { KiStart = -29, KiLength = 69, KpStart = -54, KpLength = 121, KdStart = 29, KdLength = 112 }; + + double errStart = -0.412312, errEnd = 1, errAccStart = 0.011, errAccEnd = 0.1; + + var lowErr = new ContinuousSet(MembershipFunctions.Descending(errStart, errEnd / 2.0)); + var midErr = new ContinuousSet(MembershipFunctions.Triangular(errStart, errEnd / 2, errEnd)); + var highErr = new ContinuousSet(MembershipFunctions.Ascending(errEnd / 2.0, errEnd)); + + var lowAccErr = new ContinuousSet(MembershipFunctions.Descending(errAccStart, errAccEnd / 2.0)); + var midAccErr = new ContinuousSet(MembershipFunctions.Triangular(errAccStart, errAccEnd / 2.0, errAccEnd)); + var highAccErr = new ContinuousSet(MembershipFunctions.Ascending(errEnd / 2.0, errAccEnd)); + + + var kiSmall = new ContinuousSet(MembershipFunctions.Descending(config.KiStart * 0.1, (config.KiStart + (config.KiLength * 0.5)) * 0.1)); + var kiAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KiStart * 0.1, (config.KiStart + (config.KiLength * 0.5)) * 0.1, (config.KiStart + config.KiLength) * 0.1)); + var kiBig = new ContinuousSet(MembershipFunctions.Ascending((config.KiStart + (config.KiLength * 0.5)) * 0.1, (config.KiStart + config.KiLength) * 0.1)); + + var kdSmall = new ContinuousSet(MembershipFunctions.Descending(config.KdStart * 0.1, (config.KdStart + (config.KdLength * 0.5)) * 0.1)); + var kdAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KdStart * 0.1, (config.KdStart + (config.KdLength * 0.5)) * 0.1, (config.KdStart + config.KdLength) * 0.1)); + var kdBig = new ContinuousSet(MembershipFunctions.Ascending((config.KdStart + (config.KdLength * 0.5)) * 0.1, (config.KdStart + config.KdLength) * 0.1)); + + var kpSmall = new ContinuousSet(MembershipFunctions.Descending(config.KpStart * 0.1, (config.KpStart + (config.KpLength * 0.5)) * 0.1)); + var kpAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KpStart * 0.1, (config.KpStart + (config.KpLength * 0.5)) * 0.1, (config.KpStart + config.KpLength) * 0.1)); + var kpBig = new ContinuousSet(MembershipFunctions.Ascending((config.KpStart + (config.KpLength * 0.5)) * 0.1, (config.KpStart + config.KpLength) * 0.1)); + + + var x = Enumerable.Range(0, interval).Select(x => x * 0.01).ToArray(); + + + var step = Enumerable.Repeat(1, interval).Select(x => (double)x).ToArray(); + step[0] = 0; + + var motor = new TransferFunction(num, denum, 0.01); + var motorPID = new TransferFunction(num, denum, 0.01); + var motorFuzzyPID = new TransferFunction(num, denum, 0.01); + + //double Kp = 2, Ki = 0.4, Kd = 0.4; + + double Ki = -1.9181372, Kp = 18.625, Kd = 0.38281253; + + + var pid = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); + var fuzzyPID = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); + + + var sysOut = new double[step.Length]; + var sysOutFuzzyPID = new double[step.Length]; + var sysOutPID = new double[step.Length]; + + var pidOut = new double[step.Length]; + var pidOutFuzzy = new double[step.Length]; + var errorOutPID = new double[step.Length]; + + var errOut = new double[step.Length]; + var errAccOut = new double[step.Length]; + + //var errorAccOut = new double[step.Length]; + + var errorOutFuzzy = new double[step.Length]; + var errorOutAccFuzzy = new double[step.Length]; + + for (var i = 0; i < step.Length; i++) + { + sysOut[i] = motor.Evaluate(step[i]); + errOut[i] = stability - sysOut[i]; + errAccOut[i] = errOut[i] - (i == 0 ? 0 : errOut[i - 1]); + + sysOutPID[i] = motorPID.Evaluate(step[i] + (i == 0 ? 0 : pidOut[i - 1])); + sysOutFuzzyPID[i] = motorFuzzyPID.Evaluate(step[i] + (i == 0 ? 0 : pidOutFuzzy[i - 1])); + + + errorOutPID[i] = (stability - sysOutPID[i]); + errorOutFuzzy[i] = (stability - sysOutFuzzyPID[i]); + errorOutAccFuzzy[i] = (errorOutFuzzy[i] - (i == 0 ? 0 : errorOutFuzzy[i - 1])); + + pidOut[i] = pid.Evaluate(errorOutPID[i]); + pidOutFuzzy[i] = fuzzyPID.Evaluate(errorOutFuzzy[i]); + + + var ki = MamdaniDefuzzifier.Evaluate(new INumericalSet[] +{ + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiBig), +}, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + var kp = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpBig), + }, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + var kd = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdBig), + }, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + fuzzyPID.InputCoefficients[0] = ki; + fuzzyPID.InputCoefficients[1] = kp; + fuzzyPID.InputCoefficients[1] = kd; + + + + } + + Debug.WriteLine($"Error Values Min: {errOut.Min()} Max: {errOut.Max()} "); + Debug.WriteLine($"Error Acc Values Min: {errAccOut.Min()} Max: {errAccOut.Max()} "); + + formsPlot1.Plot.AddScatter(x, sysOut, Color.Red); + formsPlot1.Plot.AddScatter(x, sysOutPID, Color.Blue); + formsPlot1.Plot.AddScatter(x, sysOutFuzzyPID, Color.Green); + + formsPlot1.Refresh(); + + } + + + struct KK + { + public float Ki; + public float Kp; + public float Kd; + + public override string ToString() + { + return $"Ki {Ki} Kp {Kp} Kd {Kd}"; + } + } + + struct FuzzyChromosome + { + ////public sbyte KiInputErrPosition; + //public sbyte KiInputErrScale; + + ////public sbyte KiInputErrAccPosition; + //public sbyte KiInputErrAccScale; + + ////public sbyte KiOutputPosition; + //public sbyte KiOutputScale; + + public sbyte KiStart; + public sbyte KiLength; + public sbyte KdStart; + public sbyte KdLength; + public sbyte KpStart; + public sbyte KpLength; + + public override string ToString() + { + return $"Ki {KiStart}:{KiLength} Kp {KpStart}:{KpLength} Kd {KdStart}:{KdLength}"; + } + } + + private double CalculateFuzzyPIDStepError(FuzzyChromosome config, double errStart, double errEnd, double errAccStart, double errAccEnd, bool draw, string label) + { + + var lowErr = new ContinuousSet(MembershipFunctions.Descending(errStart, errStart + (errEnd - errStart) * 0.5)); + var midErr = new ContinuousSet(MembershipFunctions.Triangular(errStart, errStart + (errEnd - errStart) * 0.5, errEnd)); + var highErr = new ContinuousSet(MembershipFunctions.Ascending(errStart + (errEnd - errStart) * 0.5, errEnd)); + + var lowAccErr = new ContinuousSet(MembershipFunctions.Descending(errAccStart, errAccStart + (errAccEnd - errAccStart) * 0.5)); + var midAccErr = new ContinuousSet(MembershipFunctions.Triangular(errAccStart, errAccStart + (errAccEnd - errAccStart) * 0.5, errAccEnd)); + var highAccErr = new ContinuousSet(MembershipFunctions.Ascending(errAccStart + (errAccEnd - errAccStart) * 0.5, errAccEnd)); + + + var kiSmall = new ContinuousSet(MembershipFunctions.Descending(config.KiStart * 0.1, (config.KiStart + (config.KiLength * 0.5)) * 0.1)); + var kiAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KiStart * 0.1, (config.KiStart + (config.KiLength * 0.5)) * 0.1, (config.KiStart + config.KiLength) * 0.1)); + var kiBig = new ContinuousSet(MembershipFunctions.Ascending((config.KiStart + (config.KiLength * 0.5)) * 0.1, (config.KiStart + config.KiLength) * 0.1)); + + var kdSmall = new ContinuousSet(MembershipFunctions.Descending(config.KdStart * 0.1, (config.KdStart + (config.KdLength * 0.5)) * 0.1)); + var kdAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KdStart * 0.1, (config.KdStart + (config.KdLength * 0.5)) * 0.1, (config.KdStart + config.KdLength) * 0.1)); + var kdBig = new ContinuousSet(MembershipFunctions.Ascending((config.KdStart + (config.KdLength * 0.5)) * 0.1, (config.KdStart + config.KdLength) * 0.1)); + + var kpSmall = new ContinuousSet(MembershipFunctions.Descending(config.KpStart * 0.1, (config.KpStart + (config.KpLength * 0.5)) * 0.1)); + var kpAvg = new ContinuousSet(MembershipFunctions.Triangular(config.KpStart * 0.1, (config.KpStart + (config.KpLength * 0.5)) * 0.1, (config.KpStart + config.KpLength) * 0.1)); + var kpBig = new ContinuousSet(MembershipFunctions.Ascending((config.KpStart + (config.KpLength * 0.5)) * 0.1, (config.KpStart + config.KpLength) * 0.1)); + + + double Ki = -1.9181372, Kp = 18.625, Kd = 0.38281253; + //double Ki = 1, Kp = 1, Kd = 1; + + var step = Enumerable.Repeat(1, interval).Select(x => (double)x).ToArray(); + step[0] = 0; + + var motor = new TransferFunction(num, denum, 0.01); + + var fuzzyPID = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); + + var sysOutFuzzyPID = new double[step.Length]; + + + var pidOutFuzzy = new double[step.Length]; + + var errorOutFuzzy = new double[step.Length]; + var errorOutAccFuzzy = new double[step.Length]; + + for (var i = 0; i < step.Length; i++) + { + sysOutFuzzyPID[i] = motor.Evaluate(step[i] + (i == 0 ? 0 : pidOutFuzzy[i - 1])); + + + errorOutFuzzy[i] = (stability - sysOutFuzzyPID[i]); + errorOutAccFuzzy[i] = (errorOutFuzzy[i] - (i == 0 ? 0 : errorOutFuzzy[i - 1])); + + + + var ki = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kiAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kiBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kiBig), + }, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + if (double.IsNaN(ki)) + return double.MaxValue; + + var kp = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kpAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kpBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kpBig), + }, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + if (double.IsNaN(kp)) + return double.MaxValue; + + var kd = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(lowErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdSmall), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(midErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(lowAccErr)).Then(kdAvg), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(midAccErr)).Then(kdBig), + errorOutFuzzy[i].Is(highAccErr).And(errorOutAccFuzzy[i].Is(highAccErr)).Then(kdBig), + }, MamdaniDefuzzifierMethod.CenterOfGravity, -20, 20, 0.5); + + if (double.IsNaN(kd)) + return double.MaxValue; + + fuzzyPID.InputCoefficients[0] = ki; + fuzzyPID.InputCoefficients[1] = kp; + fuzzyPID.InputCoefficients[1] = kd; + + pidOutFuzzy[i] = fuzzyPID.Evaluate(errorOutFuzzy[i]); + + } + + if (draw) + { + formsPlot1.Plot.Clear(); + var x = Enumerable.Range(0, interval).Select(x => x * 0.01).ToArray(); + + formsPlot1.Plot.AddScatter(x, sysOutFuzzyPID, Color.Green); + + formsPlot1.Plot.AddText(label, 0, 1.5, 24, Color.DarkOrange); + + formsPlot1.Refresh(); + + formsPlot2.Plot.Clear(); + var range = FuzzyExtensions.Range(config.KiStart * 0.1, (config.KiStart + config.KiLength) * 0.1, 0.1); + + formsPlot2.Plot.AddScatter(range, kiSmall.Sample(range)); + formsPlot2.Plot.AddScatter(range, kiAvg.Sample(range)); + formsPlot2.Plot.AddScatter(range, kiBig.Sample(range)); + //formsPlot2.Plot.AddText("Ki", 0, 0, 20); + + formsPlot2.Refresh(); + + formsPlot3.Plot.Clear(); + + range = FuzzyExtensions.Range(config.KpStart * 0.1, (config.KpStart + config.KpLength) * 0.1, 0.1); + + formsPlot3.Plot.AddScatter(range, kpSmall.Sample(range)); + formsPlot3.Plot.AddScatter(range, kpAvg.Sample(range)); + formsPlot3.Plot.AddScatter(range, kpBig.Sample(range)); + //formsPlot2.Plot.AddText("Kp", 0, 0, 20); + + formsPlot3.Refresh(); + + formsPlot4.Plot.Clear(); + + range = FuzzyExtensions.Range(config.KdStart * 0.1, (config.KdStart + config.KdLength) * 0.1, 0.1); + + formsPlot4.Plot.AddScatter(range, kdSmall.Sample(range)); + formsPlot4.Plot.AddScatter(range, kdAvg.Sample(range)); + formsPlot4.Plot.AddScatter(range, kdBig.Sample(range)); + //formsPlot2.Plot.AddText("Kd", 0, 0, 20); + + formsPlot4.Refresh(); + + + } + + //Debug.WriteLine("ERR " + errorOutFuzzy.Max() + " " + errorOutFuzzy.Min()); + return errorOutFuzzy.RMS(); + + } + + private double CalculatePIDStepError(double Kd, double Kp, double Ki, bool draw, string label) + { + var step = Enumerable.Repeat(1, interval).Select(x => (double)x).ToArray(); + step[0] = 0; + + var motor = new TransferFunction(num, denum, 0.01); + + var sysOutPID = new double[step.Length]; + + var pidOut = new double[step.Length]; + var errorOutPID = new double[step.Length]; + var pid = new TransferFunction(new double[] { Kd, Kp, Ki }, new double[] { 1, 1 }, 0.01); + + for (var i = 0; i < step.Length; i++) + { + sysOutPID[i] = motor.Evaluate(step[i] + (i == 0 ? 0 : pidOut[i - 1])); + + if (double.IsInfinity(sysOutPID[i])) + Console.WriteLine(); + + errorOutPID[i] = (stability - sysOutPID[i]); + + if (double.IsNaN(errorOutPID[i])) + Console.WriteLine(); + + pidOut[i] = pid.Evaluate(errorOutPID[i]); + + if (double.IsInfinity(pidOut[i])) + Console.WriteLine(); + + + + } + + + if (draw) + { + formsPlot1.Plot.Clear(); + var x = Enumerable.Range(0, interval).Select(x => x * 0.01).ToArray(); + formsPlot1.Plot.AddText(label, 0, 1.5, 24, Color.DarkOliveGreen); + formsPlot1.Plot.AddScatter(x, sysOutPID, Color.DeepSkyBlue); + formsPlot1.Refresh(); + } + + return errorOutPID.RMS(); + } + + private void button1_Click(object sender, EventArgs e) + { + + + + var genetic = new Genetic(100, k => + { + if (float.IsNaN(k.KiStart) + || float.IsNaN(k.KiLength) + || float.IsNaN(k.KpStart) + || float.IsNaN(k.KiLength) + || float.IsNaN(k.KdStart) + || float.IsNaN(k.KiLength)) + return (double.MaxValue); + + if (k.KiLength < 0 || k.KpLength < 0 || k.KdLength < 0)// k.KiStart > k.KiEnd || k.KpStart > k.KpEnd || k.KdStart > k.KdEnd) + return (double.MaxValue); + + var r = CalculateFuzzyPIDStepError(k, -(stability / 2), stability / 2, -(stability / 2), stability / 2, false, null); + if (double.IsNaN(r)) + Console.WriteLine(); + return r; + }); + + + foreach (var (generation, fitness, k) in genetic.Evaluate(100)) + CalculateFuzzyPIDStepError(k, -(stability / 2), stability / 2, -(stability / 2), stability / 2, true, $"Fuzzy PID: Generation {generation} Fitness {fitness}\r\n{k}"); + + + // Console.WriteLine(best); + } + + private void button2_Click(object sender, EventArgs e) + { + var gen = new Genetic(100, k => + { + if (float.IsNaN(k.Ki) || float.IsNaN(k.Kp) || float.IsNaN(k.Kd)) + return (double.MaxValue); + + + var r = CalculatePIDStepError(k.Kd, k.Kp, k.Ki, false, null); + if (double.IsNaN(r)) + Console.WriteLine(); + return r; + }); + + foreach (var (generation, fitness, k) in gen.Evaluate(100)) + CalculatePIDStepError(k.Kd, k.Kp, k.Ki, true, $"PID: Generation {generation} Fitness {fitness}\r\n {k}"); + + } + + private void button3_Click(object sender, EventArgs e) + { + + num = textBox1.Text.Split("/").First().Trim().Split(" ").Select(x=>Convert.ToDouble(x)).ToArray(); + denum = textBox1.Text.Split("/").Last().Trim().Split(" ").Select(x=>Convert.ToDouble(x)).ToArray(); + + var x = Enumerable.Range(0, interval).Select(x => x * 0.01).ToArray(); + + var step = Enumerable.Repeat(1, interval).Select(x => (double)x).ToArray(); + step[0] = 0; + + var motor = new TransferFunction(num, denum, 0.01); + + var sysOut = new double[step.Length]; + + var errOut = new double[step.Length]; + var errAccOut = new double[step.Length]; + + + for (var i = 0; i < step.Length; i++) + { + sysOut[i] = motor.Evaluate(step[i]); + errOut[i] = stability - sysOut[i]; + errAccOut[i] = errOut[i] - (i == 0 ? 0 : errOut[i - 1]); + + + + } + + Debug.WriteLine($"Error Values Min: {errOut.Min()} Max: {errOut.Max()} "); + Debug.WriteLine($"Error Acc Values Min: {errAccOut.Min()} Max: {errAccOut.Max()} "); + + formsPlot1.Plot.AddScatter(x, sysOut, Color.Red); + + formsPlot1.Refresh(); + } + + private void button4_Click(object sender, EventArgs e) + { + formsPlot1.Plot.Clear(); + formsPlot1.Refresh(); + } + + private void formsPlot1_Load(object sender, EventArgs e) + { + + } + + private void textBox2_TextChanged(object sender, EventArgs e) + { + double s; + if (double.TryParse(textBox2.Text, out s)) + stability = s; + } + } +} \ No newline at end of file diff --git a/Esiur.Analysis.Test/FMain.resx b/Esiur.Analysis.Test/FSoft.resx similarity index 100% rename from Esiur.Analysis.Test/FMain.resx rename to Esiur.Analysis.Test/FSoft.resx diff --git a/Esiur.Analysis.Test/Program.cs b/Esiur.Analysis.Test/Program.cs index 959e116..8bdfbe6 100644 --- a/Esiur.Analysis.Test/Program.cs +++ b/Esiur.Analysis.Test/Program.cs @@ -11,7 +11,7 @@ namespace Esiur.Analysis.Test // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); - Application.Run(new FMain()); + Application.Run(new FSoft()); } } } \ No newline at end of file diff --git a/Esiur.Analysis/DSP/Functions.cs b/Esiur.Analysis/DSP/Functions.cs index 8ec331c..16c6106 100644 --- a/Esiur.Analysis/DSP/Functions.cs +++ b/Esiur.Analysis/DSP/Functions.cs @@ -15,7 +15,6 @@ namespace Esiur.Analysis.DSP return rt; } - public static double[] Convolve(this double[] signal, double[] filter) { var length = signal.Length + filter.Length - 1; diff --git a/Esiur.Analysis/Fuzzy/DiscreteSet.cs b/Esiur.Analysis/Fuzzy/DiscreteSet.cs index 91d7f87..a2e442c 100644 --- a/Esiur.Analysis/Fuzzy/DiscreteSet.cs +++ b/Esiur.Analysis/Fuzzy/DiscreteSet.cs @@ -66,7 +66,11 @@ namespace Esiur.Analysis.Fuzzy { var r = vector.Where(x => x.Key >= from && x.Key <= to).ToArray(); - return r.Sum(x => x.Key * x.Value ) / r.Sum(x=>x.Value); + var total = r.Sum(x => x.Value); + if (total == 0) + return 0; + else + return r.Sum(x => x.Key * x.Value ) / total; } public KeyValuePair[] Minimas @@ -78,6 +82,6 @@ namespace Esiur.Analysis.Fuzzy } } - + public double[] ToArray() => vector.Values.ToArray(); } } diff --git a/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs b/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs index f17725c..0c8b7d1 100644 --- a/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs +++ b/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs @@ -41,5 +41,42 @@ namespace Esiur.Analysis.Fuzzy return rt; } + + public static double[] Sample(this INumericalSet set, double[] time) + { + var rt = new double[time.Length]; + for (var i = 0; i < time.Length; i++) + rt[i] = set[time[i]]; + return rt; + } + + public static double[] Sample(this INumericalSet set, double from, double to, double step) + { + var size = (int)((to - from) / step); + + var rt = new double[size]; + var s = 0; + for (var i = from; i < to && s < size; i+=step) + rt[s++] = set[i]; + return rt; + + } + + public static double[] Range(double from, double to, double step) + { + var size = (int)((to - from) / step); + + if (size == 0) + return new double[] { from }; + + var rt = new double[size]; + var s = 0; + for (var i = from; i < to && s < size; i += step) + rt[s++] = i; + return rt; + + } + + } } diff --git a/Esiur.Analysis/Fuzzy/MembershipFunction.cs b/Esiur.Analysis/Fuzzy/MembershipFunction.cs index 908d66b..550915a 100644 --- a/Esiur.Analysis/Fuzzy/MembershipFunction.cs +++ b/Esiur.Analysis/Fuzzy/MembershipFunction.cs @@ -23,7 +23,7 @@ namespace Esiur.Analysis.Fuzzy { return new MembershipFunction(x => { - if (x <= peak) return 1; + if (x <= peak) return 0; if (x > peak && x < end) return (end - x) / (end - peak); return 0; }); @@ -33,7 +33,7 @@ namespace Esiur.Analysis.Fuzzy { return new MembershipFunction(x => { - if (x >= peak) return 1; + if (x >= peak) return 0; if (x < peak && x > start) return (x - start) / (peak - start); return 0; }); diff --git a/Esiur.Analysis/Optimization/Genetic.cs b/Esiur.Analysis/Optimization/Genetic.cs index b1610b8..34ca1ad 100644 --- a/Esiur.Analysis/Optimization/Genetic.cs +++ b/Esiur.Analysis/Optimization/Genetic.cs @@ -88,23 +88,25 @@ namespace Esiur.Analysis.Optimization } - public T Evaluate(int maxIterations) + public IEnumerable<(int, double, T)> Evaluate(int maxIterations) { GeneratePopultation(); var generation = 0; - T best; + KeyValuePair best; do { var ordered = GetFitness().OrderBy(x => x.Value).ToArray(); - best = ordered[0].Key; - - if (ordered[0].Value == 0) + best = ordered[0]; + + if (best.Value == 0) break; + yield return (generation, best.Value, best.Key); + // Elitism selection ( 10% of fittest population ) var eliteCount = (int)(ordered.Length * 0.1); @@ -124,12 +126,14 @@ namespace Esiur.Analysis.Optimization Population = newGeneration; Debug.WriteLine($"Gen {generation} Fittest: {ordered.First().Value} {ordered.First().Key.ToString()} "); + + } while (generation++ < maxIterations); Debug.WriteLine($"Gen {generation} Best: {best.ToString()} "); - return best; + yield return (generation, best.Value, best.Key); } - + } }