Introduction
The code is a Fuzzy evaluator, that takes some Crisp values as input and evaluates a new Crisp value as output. My main gools was to create a Fuzzy evaluator with a good GUI, and easy to setup by using the C# operator overloading
Background
As I'm developing an application for my solar heating system I neede a Fuzzy logic evaluator with a good GUI and this code is a spinoff.
Using the code
The main class is SetResult that is created with name and min/max Crisp output values
Motor = new Fuzzy.SetResult("Motor", 0, 30);
Then the waveforms are added. Waveforms are created with a Lagrange curvefitting algorithm so we only need to specify the name and zeropoints. I have predefined some often used waveforms, but its easy to create new ones.
Motor += WaveForm.ParabolicLow("SLOW", -20, 0, 20);
Motor += WaveForm.Parabolic("MEDIUM", 10, 20);
Motor += WaveForm.ParabolicHigh("FAST", 10, 30, 40);
Then create input sets in the same manner, param 2, (0 and 1) is the index of the inputs in Evaluate described below.
set Fuzzy.Set Temperature = new Fuzzy.Set("Temperature", 0, 20, 90);
Temperature += WaveForm.ParabolicLow("LOW", 0, 20, 40);
Temperature += WaveForm.Parabolic("MEDIUM", 30, 80);
Temperature += WaveForm.ParabolicHigh("HIGH", 60, 90, 120);
set Fuzzy.Set DeltaTemperature = new Fuzzy.Set("DeltaTemperature", 1, 0.0, 5.0);
DeltaTemperature += WaveForm.ParabolicLow("LOW", -2.5, 0, 2.5);
DeltaTemperature += WaveForm.Parabolic("MEDIUM", 2.0, 3.0);
DeltaTemperature += WaveForm.ParabolicHigh("HIGH", 2.5, 5.0, 7.5);
As I have not yet seen any good way to define the rules in C# - I came up with this, that uses overloading, first I defined the If and THEN classes that use the lingual normaly used by the Fuzzy papers, but I feel more comfortable with the explicit way, decleare the rule with parameteres, the rule and IF logic is stored in "Motor" object by the overloading. I have overloads for ==, !=, & , | .
new Fuzzy.Rule("Rule FAST", Temperature == "LOW" & DeltaTemperature == "LOW", Motor == "FAST");
new Fuzzy.Rule("Rule MEDIUM", Temperature != "MEDIUM" & DeltaTemperature == "LOW", Motor == "MEDIUM");
new Fuzzy.Rule("Rule MEDIUM", Temperature == "HIGH" | DeltaTemperature == "LOW", Motor == "MEDIUM");
new IF(Temperature == "HIGH" & DeltaTemperature == "HIGH", new THEN(Motor == "SLOW"));
It's posible to alter the curves(Zeropoints) by the GUI(right click and select member function).
So not to lose the new settings I have added a XML generator of the zeropoints, that can be saved and reloaded.
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
String xmlStore = Motor.GetXml();
Settings.Default.SetResultXML = xmlStore;
Settings.Default.Save();
}
And load at program initialization.
if (!String.IsNullOrEmpty(Settings.Default.SetResultXML) &&
Settings.Default.SetResultXML.Contains("SetResult"))
{
Motor.LoadXml(Settings.Default.SetResultXML);
}
The its time to connect the GUI and the Fuzzy logic.
The GUI is defined in code because we do not know how many sets we are using at design time! Actualiy we do but I like the GUI to alter with code, not having to alter both code and WPF by hand.
ucFuzzySet set = new ucFuzzySet(Motor);
set.Height = 100;
wpfFuzzySet.Children.Add(set);
Motor.UpdateUI();
foreach (Fuzzy.Set S in Motor.Sets)
{
set = new ucFuzzySet(S);
set.Height = 100;
wpfFuzzySet.Children.Add(set);
S.UpdateUI();
}
The execution of the Fuzzy logic is done by caling Motor.COG, I have implmented the Center Of Gravity methode that are often used. The params are indexed as param 2 in the Set declation.
public void Evaluate()
{
Double result = Motor.COG(wpfTemp.Value, wpfDelta.Value);
}
I have not yet found a briliant way to get rid of the Set in the call to ucFuzzySet(Motor);
as this must break the MVVM pattern!!. Mybe some use of MVVM messageing can do the trick.
Points of Interest
The most wierd thing is the use of lagrange to make the curves used for member functions. The code also demostrate some use of the MVVM light toolkit and the OxyPlot lib.