diff --git a/Esiur.Analysis.Test/Esiur.Analysis.Test.csproj b/Esiur.Analysis.Test/Esiur.Analysis.Test.csproj new file mode 100644 index 0000000..f11fa12 --- /dev/null +++ b/Esiur.Analysis.Test/Esiur.Analysis.Test.csproj @@ -0,0 +1,19 @@ + + + + WinExe + net6.0-windows + enable + true + enable + + + + + + + + + + + \ No newline at end of file diff --git a/Esiur.Analysis.Test/FMain.Designer.cs b/Esiur.Analysis.Test/FMain.Designer.cs new file mode 100644 index 0000000..77a7cb0 --- /dev/null +++ b/Esiur.Analysis.Test/FMain.Designer.cs @@ -0,0 +1,72 @@ +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 new file mode 100644 index 0000000..12752ad --- /dev/null +++ b/Esiur.Analysis.Test/FMain.cs @@ -0,0 +1,345 @@ +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/FMain.resx b/Esiur.Analysis.Test/FMain.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/Esiur.Analysis.Test/FMain.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Esiur.Analysis.Test/Program.cs b/Esiur.Analysis.Test/Program.cs new file mode 100644 index 0000000..959e116 --- /dev/null +++ b/Esiur.Analysis.Test/Program.cs @@ -0,0 +1,17 @@ +namespace Esiur.Analysis.Test +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new FMain()); + } + } +} \ No newline at end of file diff --git a/Esiur.Analysis/Signals/DSP.cs b/Esiur.Analysis/DSP/Functions.cs similarity index 84% rename from Esiur.Analysis/Signals/DSP.cs rename to Esiur.Analysis/DSP/Functions.cs index ee6fa6a..8ec331c 100644 --- a/Esiur.Analysis/Signals/DSP.cs +++ b/Esiur.Analysis/DSP/Functions.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace Esiur.Analysis.Signals +namespace Esiur.Analysis.DSP { - public static class DSP + public static class Functions { public static double[] ConvolveMany(params double[][] signals) { @@ -27,9 +27,11 @@ namespace Esiur.Analysis.Signals for (var i = 0; i < length; i++) { - for (var j = 0; j < signal.Length && i - j >= 0 && i - j < filter.Length; j++) + + for (var j = 0; j < signal.Length; j++) { - rt[i] = signal[j] * filter[i - j]; + if (i - j >= 0 && i - j < filter.Length) + rt[i] += signal[j] * filter[i - j]; } } diff --git a/Esiur.Analysis/DSP/TransferFunction.cs b/Esiur.Analysis/DSP/TransferFunction.cs new file mode 100644 index 0000000..6781a09 --- /dev/null +++ b/Esiur.Analysis/DSP/TransferFunction.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.WebSockets; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Xml.Schema; + +namespace Esiur.Analysis.DSP +{ + public class TransferFunction + { + + public double Step { get; set; } + + double[] inputs; + double[] outputs; + + public double[] InputCoefficients { get; set; } + public double[] OutputCoefficients { get; set; } + + public TransferFunction(double[] numerator, double[] denominator, double step = 0.01) + { + inputs = new double[numerator.Length]; + outputs = new double[denominator.Length]; + + InputCoefficients = numerator.Reverse().ToArray(); + OutputCoefficients = denominator.Reverse().ToArray(); + + Step = step; + } + + public double Evaluate(double value) + { + var xs = new double[inputs.Length]; + xs[0] = value;// * InputCoefficients.Last(); + + + // diffrentiate + for(var i = 1; i < xs.Length; i++) + xs[i] = (xs[i - 1] - inputs[i - 1]) / Step; + + var ys = new double[outputs.Length]; + + // integrate + for (var i = outputs.Length - 2; i >= 0; i--) + { + var iy = outputs[i] + (Step * outputs[i + 1]); + if (double.IsNaN(iy) || double.IsInfinity(iy)) + ys[i] = outputs[i]; + else + ys[i] = iy; + } + + var v = xs.Zip(InputCoefficients, (x, c) => x * c).Sum() - ys.Zip(OutputCoefficients, (y, c) => y * c).Sum(); + + if (double.IsNaN(v) || double.IsInfinity(v)) + ys[ys.Length - 1] = outputs[ys.Length - 1]; + else + ys[ys.Length - 1] = v; + + inputs = xs; + outputs = ys; + + return ys[0]; + } + + public double[] Evaluate(double[] value) + { + return value.Select(x => Evaluate(x)).ToArray(); + } + } +} diff --git a/Esiur.Analysis/Esiur.Analysis.csproj b/Esiur.Analysis/Esiur.Analysis.csproj index 1700991..31b8f90 100644 --- a/Esiur.Analysis/Esiur.Analysis.csproj +++ b/Esiur.Analysis/Esiur.Analysis.csproj @@ -3,6 +3,7 @@ netstandard2.1 enable + True @@ -12,11 +13,14 @@ - + + + + diff --git a/Esiur.Analysis/Optimization/Genetic.cs b/Esiur.Analysis/Optimization/Genetic.cs new file mode 100644 index 0000000..b1610b8 --- /dev/null +++ b/Esiur.Analysis/Optimization/Genetic.cs @@ -0,0 +1,135 @@ +using Esiur.Data; +using Esiur.Resource; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace Esiur.Analysis.Optimization +{ + public class Genetic where T : unmanaged + { + + Random rand = new Random(); + + public static unsafe byte[] Encode(in T value) + { + byte[] result = new byte[sizeof(T)]; + fixed (byte* dst = result) + *(T*)dst = value; + return result; + } + + public static unsafe T Decode(byte[] data) + { + fixed (byte* src = data) + return *(T*)src; + } + + public List Population = new List(); + + public int PopulationSize { get; set; } + private int DataSize { get; set; } + + public Func FitnessFunction { get; set; } + + public unsafe Genetic(int populationSize, Func fitnessFunction) + { + FitnessFunction = fitnessFunction; + PopulationSize = populationSize; + DataSize = sizeof(T); + } + + void GeneratePopultation() + { + for (var i = 0; i < PopulationSize; i++) + { + byte[] buffer = new byte[DataSize]; + rand.NextBytes(buffer); + var record = Decode(buffer); + Population.Add(record); + } + } + + + KeyValuePair[] GetFitness() + { + var rt = new List>(); + + foreach (var record in Population) + rt.Add(new KeyValuePair( record, FitnessFunction(record))); + + return rt.ToArray(); + } + + T Mate(T parent1, T parent2) + { + var dp1 = Encode(parent1); + var dp2 = Encode(parent2); + + var dc = new byte[dp1.Length]; + + + for (var i = 0; i < dc.Length; i++) + { + var prop = rand.NextDouble(); + if (prop < 0.45) + dc[i] = dp1[i]; + else if (prop < 0.9) + dc[i] = dp2[i]; + else + dc[i] = (byte)rand.Next(0, 255); + } + + return Decode(dc); + + } + + public T Evaluate(int maxIterations) + { + GeneratePopultation(); + + var generation = 0; + + T best; + + do + { + var ordered = GetFitness().OrderBy(x => x.Value).ToArray(); + + best = ordered[0].Key; + + if (ordered[0].Value == 0) + break; + + // Elitism selection ( 10% of fittest population ) + + var eliteCount = (int)(ordered.Length * 0.1); + var neededCount = (int)(ordered.Length * 0.9); + + var newGeneration = ordered.Select(x => x.Key).Take(eliteCount).ToList(); + + for (var i = 0; i < neededCount; i++) + { + var p1 = Population[rand.Next(0, PopulationSize / 2)]; + var p2 = Population[rand.Next(0, PopulationSize / 2)]; + + var offspring = Mate(p1, p2); + newGeneration.Add(offspring); + } + + 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; + } + + } +} diff --git a/Esiur.Analysis/Statistics/StatisticalFunctions.cs b/Esiur.Analysis/Statistics/StatisticalFunctions.cs index 00744d2..40e490f 100644 --- a/Esiur.Analysis/Statistics/StatisticalFunctions.cs +++ b/Esiur.Analysis/Statistics/StatisticalFunctions.cs @@ -33,7 +33,13 @@ namespace Esiur.Analysis.Statistics } - public static double RMS(this double[] x) => Math.Sqrt(x.Sum(x => x * x) / x.Length); + public static double RMS(this double[] x) + { + var r = Math.Sqrt(x.Sum(x => x * x) / x.Length); + if (double.IsNaN(r)) + Console.WriteLine(); + return r; + } public static double Correlation(this double[] x, double[] y) diff --git a/Esiur.sln b/Esiur.sln index b7e0ef6..3594207 100644 --- a/Esiur.sln +++ b/Esiur.sln @@ -10,7 +10,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.EntityCore", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{331F82B6-6B90-4533-9718-F7C8090D8F19}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Esiur.Analysis", "Esiur.Analysis\Esiur.Analysis.csproj", "{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Analysis", "Esiur.Analysis\Esiur.Analysis.csproj", "{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Esiur.Analysis.Test", "Esiur.Analysis.Test\Esiur.Analysis.Test.csproj", "{72115ABD-BD54-4E88-8DB6-B2A953F57F0A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -38,6 +40,10 @@ Global {8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Debug|Any CPU.Build.0 = Debug|Any CPU {8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Release|Any CPU.ActiveCfg = Release|Any CPU {8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Release|Any CPU.Build.0 = Release|Any CPU + {72115ABD-BD54-4E88-8DB6-B2A953F57F0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72115ABD-BD54-4E88-8DB6-B2A953F57F0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72115ABD-BD54-4E88-8DB6-B2A953F57F0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72115ABD-BD54-4E88-8DB6-B2A953F57F0A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Test/Program.cs b/Test/Program.cs index b4343d3..f9c956f 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -56,53 +56,6 @@ namespace Test { static async Task Main(string[] args) { - //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); - - - Console.WriteLine(temp + " " + v); - } - // Create stores to keep objects. var system = await Warehouse.Put("sys", new MemoryStore()); var server = await Warehouse.Put("sys/server", new DistributedServer());