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);
}
-
+
}
}