Python-Fuzzylogic / fuzzylogic

Fuzzy Logic and Fuzzy Inference for Python 3
MIT License
129 stars 26 forks source link

Fuzzy Logic Controller Issue #21

Closed Scarf195 closed 2 years ago

Scarf195 commented 2 years ago

Hi, I'm using fuzzylogic library to implement a Fuzzy Logic Controller. I've started implementing a P Controller with this rule attached: kp

I'm getting issue during the execution, in fact by setting the error values and error speed the result is almost always "None". Probably I’m setting the rules wrong but I can't figure it out...

Entire script:

from copy import error
from fuzzylogic.classes import Domain, Rule
from fuzzylogic.functions import S, R, triangular
from matplotlib import pyplot

def membership(domain, max):
    x = max/4
    domain.Z = triangular(-x, x)
    domain.NS = triangular(-2*x, 0.0)
    domain.PS = triangular(0.0, 2*x)
    domain.NM = triangular(-3*x, -x)
    domain.PM = triangular(x, 3*x)
    domain.NL = S(-3*x, -2*x)
    domain.PL = R(2*x, 3*x)
    return domain

def rules_kp(error, delta, kp):
    r6 = Rule({(error.NL, delta.NL) or
                (error.NL, delta.NM) or
                (error.NM, delta.NL) or
                (error.NM, delta.NM) : kp.PL})

    r5 = Rule({(error.NL, delta.NS) or
                (error.NL, delta.Z)  or
                (error.NM, delta.NS) or
                (error.NS, delta.NL) or
                (error.NS, delta.NM) or
                (error.NS, delta.NS) or
                (error.Z, delta.NL) or
                (error.Z, delta.NM) : kp.PM})

    r4 = Rule({(error.NL, delta.PS) or
                (error.NM, delta.Z)  or
                (error.NM, delta.PS) or
                (error.NS, delta.Z) or
                (error.Z, delta.NS) or
                (error.PS, delta.NL) or
                (error.PS, delta.NM) or
                (error.PM, delta.NL) : kp.PS})

    r3 = Rule({(error.NL, delta.PM) or
                    (error.NL, delta.PL)  or
                    (error.NM, delta.PM) or
                    (error.NS, delta.PS) or
                    (error.Z, delta.Z) or
                    (error.PS, delta.NS) or
                    (error.PM, delta.NM) or
                    (error.PL, delta.NL) or
                    (error.PL, delta.NM) : kp.Z})

    r2 = Rule({(error.NM, delta.PL) or
                    (error.NS, delta.PM)  or
                    (error.NS, delta.PL) or
                    (error.Z, delta.PS) or
                    (error.PS, delta.Z) or
                    (error.PS, delta.PM) or
                    (error.PM, delta.NS) : kp.NS})

    r1 = Rule({(error.Z, delta.PM) or
                    (error.Z, delta.PL) or
                    (error.PS, delta.PM) or
                    (error.PM, delta.Z) or
                    (error.PM, delta.PS) or
                    (error.PM, delta.PM) or
                    (error.PL, delta.NS) or
                    (error.PL, delta.Z) or
                    (error.PL, delta.PS) : kp.NM})

    r0 = Rule({(error.PL, delta.PL) or
            (error.PM, delta.PL)  or
            (error.PL, delta.PM) or
            (error.PS, delta.PL) : kp.NL})

    return (r0 | r1 | r2 | r3 | r4 | r5 | r6)

error = Domain("error", -180, 180, res = 0.01)
delta = Domain("delta", -25, 25, res = 0.01)

kp = Domain("delta_kp", -1, 1, res = 0.01)
error = membership(error, 90)
delta = membership(delta, 20)
kp = membership(kp, 10.0)
rules = rules_kp(error, delta, kp)

values = {error: 23, delta: 2}
print(rules(values))

Returning this output: None

amogorkon commented 2 years ago

Hi, that's quite an interesting way of calling/assigning Sets and Domains! If I may ask, what kind of application are you working at or is this purely academic? Regarding your problem, two things come to my mind: the way you write those rules, you explicitly write or between tuples, which python will always evaluate to True, so that's probably one issue. The other thing is, fuzzylogic Rules reduce insignificant weights to None instead of working with zeros to be able to entirely ignore irrelevant stuff, optimizing performance a little. I hope that helps.

amogorkon commented 2 years ago

I guess Rules should be type-checked to avoid this kind of issue.. note to self

Scarf195 commented 2 years ago

I'm working with Autonomous Underwater Vehicles and I would like to implement a Fuzzy PID Controller for vehicle heading control. Yes, the way in which I explicit rules is wrong, however I've made this to avoid expliciting rules one by one (some lead to the same result in terms of membership).

amogorkon commented 2 years ago

I'm working with Autonomous Underwater Vehicles and I would like to implement a Fuzzy PID Controller for vehicle heading control. Yes, the way in which I explicit rules is wrong, however I've made this to avoid expliciting rules one by one (some lead to the same result in terms of membership).

That's awesome! I don't work with fuzzy rules much myself, only implemented them by request of a guy who worked on industrial climate control and fleshed it out some for a lady who was using it in her master's thesis.. I'd love to help you out with a better way of defining complex rules, but currently I'm restricted to snail internet via mobile phone. If you have any suggestions on how to improve that or maybe a pull request, I'll take it.

Scarf195 commented 2 years ago

Hi @amogorkon, thank you very much for your interesting. It could be very useful implementing complex rules definition, maybe in matrix form for example

amogorkon commented 2 years ago

Hi @amogorkon, thank you very much for your interesting. It could be very useful implementing complex rules definition, maybe in matrix form for example

When you say matrix form, I'm thinking numpy or pandas, could there be a possible solution?

amogorkon commented 2 years ago

Okay, I experimented a little and found that numpy arrays of Sets could work for this as a possible solution. Since Set functions are closures, it won't be possible to serialize them as-is, but with a proper __repr__ it might be feasible to work around that limitation.

amogorkon commented 2 years ago

Ahh, I have an idea! Since proper serialization won't work anyway and I have to make __repr__ work, the round-trip will require calling eval() on each cell, it would be required to have a function anyway that could take a numpy array of str - THAT on the other hand would make it possible to take a pandas dataframe of str and since pandas has no problem with loading from Excel, you could basically prepare the whole table of functions in excel, load that in via pandas, eval and turn the table into Rules.. sounds probably more convoluted than it is. Question is whether Excel actually works well with inputting those function names. There are well known issues with data conversion and broken name completion with Excel.. also, IDEs can't help with sanity checks, name completion/typo checking..on the other hand, if you already have your whole logic worked out that way, there's less chance to typo between.. question is what is your tool of choice to work on that table of logic?

amogorkon commented 2 years ago

Well, it doesn't have to be excel, but pandas could interface with any table input, so that'd be a plus. Only drawback is that the functions are in str repr for the input, but that's a given.

amogorkon commented 2 years ago

I found a way to actually serialize those closures. The dill package seems to be able to do it, but I'm not sure if it would actually help us..

amogorkon commented 2 years ago

Experimenting with table-rules, I'm wondering how you would want to specify rules that depend on more than two variables?

amogorkon commented 2 years ago

I figured out how to write a table as text like you posted initially and make it work with Rules, but it's still some way off to get it in the code. Need to write tests and make sure everything works as it should.

amogorkon commented 2 years ago

I got it all working rather nicely, but I can only upload it by next week (no internet on my PC).

You will be able to write a table just like you posted initially as input.

amogorkon commented 2 years ago

Finally got internet back again. Tested and pushed to release 1.2.0. Check https://github.com/amogorkon/fuzzylogic/blob/master/docs/Showcase.ipynb on the bottom for an example.