Overview
In This example we will solving a problem in which we want to control the acceleration of car.
run the example
you can run the example with the following command.
cargo run --example speed-control
Problem Definition
Control the acceleration of a vehicle using data from speedometer and a radar that measures the distance between the ego vehicle and the vehicle in the front.
Import
We will import the necessary modules:
use fuzzy_logic_rs::{
aggregations::Aggregations,
defuzzifications::Defuzzifiers,
fuzzy_inference_systems::MamdaniFIS,
implications::Implications,
membership_functions::{MFKind, Triangle, MF},
membership_ranges::MembershipRange,
rules::Rule,
s_norms::SNorms,
t_norms::TNorms,
variables::{InputVariable, OutputVariable},
};
Setup
We will using Mamdani FIS with the following configurations.
let mut fis = MamdaniFIS::new(
SNorms::Max,
TNorms::Min,
Implications::Min,
Aggregations::Max,
Defuzzifiers::Bisection,
);
Inputs
As the problem stated we have to input that we can use in our calculation, speed and distance. I'll assume the speed will vary in the range of [0 140] and distance in the range of [0 50].
Input range
please do not use the values outside of these ranges, in the current setup. change to the membership that are also defined outside of this range like LinearZ
and LinearS
or a custom one.
I choose 3 triangular membership functions for each input.
speed: S - M - L
let mut v1 = InputVariable::new("speed".to_string(), (0.0, 140.0));
v1.add_membership(MF::new(
"S".to_string(),
MFKind::Triangle(Triangle::new(-58.3, 0.0, 58.3)),
));
v1.add_membership(MF::new(
"M".to_string(),
MFKind::Triangle(Triangle::new(11.67, 70.0, 128.3)),
));
v1.add_membership(MF::new(
"L".to_string(),
MFKind::Triangle(Triangle::new(81.67, 140.0, 198.3)),
));
fis.add_input(v1);
distance: S - M - L
let mut v2 = InputVariable::new("Distance".to_string(), (0.0, 50.0));
v2.add_membership(MF::new(
"S".to_string(),
MFKind::Triangle(Triangle::new(-20.83, 0.0, 20.83)),
));
v2.add_membership(MF::new(
"M".to_string(),
MFKind::Triangle(Triangle::new(4.168, 25.0, 45.82)),
));
v2.add_membership(MF::new(
"L".to_string(),
MFKind::Triangle(Triangle::new(29.17, 50.0, 70.82)),
));
fis.add_input(v2);
Outputs
We have to control the acceleration so I will assume the accusation will change between [-1 1]. I choose 5 Gaussian membership function for acceleration.
acceleration: NB(negative big) - NS(negative small) - ZR(zero) - PS(positive small) - PB(positive big)
let mut o1 = OutputVariable::new(String::from("Acceleration"), (-1.0, 1.0), 100);
o1.add_membership(MembershipRange::new_gaussian(
o1.get_universe(),
"NB".to_string(),
-1.0,
0.2123,
));
o1.add_membership(MembershipRange::new_gaussian(
o1.get_universe(),
"NS".to_string(),
-0.5,
0.2123,
));
o1.add_membership(MembershipRange::new_gaussian(
o1.get_universe(),
"ZR".to_string(),
0.0,
0.2123,
));
o1.add_membership(MembershipRange::new_gaussian(
o1.get_universe(),
"PS".to_string(),
0.5,
0.2123,
));
o1.add_membership(MembershipRange::new_gaussian(
o1.get_universe(),
"PB".to_string(),
1.0,
0.2123,
));
fis.add_input(o1);
Rules
We can define the rules as follows:
- IF speed IS S AND distance IS S Then acceleration is ZR
- IF speed IS S AND distance IS M Then acceleration is PS
- IF speed IS S AND distance IS L Then acceleration is PB
- IF speed IS M AND distance IS S Then acceleration is NS
- IF speed IS M AND distance IS M Then acceleration is ZR
- IF speed IS M AND distance IS L Then acceleration is PS
- IF speed IS L AND distance IS S Then acceleration is NB
- IF speed IS L AND distance IS M Then acceleration is NS
- IF speed IS L AND distance IS L Then acceleration is ZR
We can define the rules:
fis.add_rule(Rule::new_and(vec![0, 0, 2], 1.0));
fis.add_rule(Rule::new_and(vec![0, 1, 3], 1.0));
fis.add_rule(Rule::new_and(vec![0, 2, 4], 1.0));
fis.add_rule(Rule::new_and(vec![1, 0, 1], 1.0));
fis.add_rule(Rule::new_and(vec![1, 1, 2], 1.0));
fis.add_rule(Rule::new_and(vec![1, 2, 3], 1.0));
fis.add_rule(Rule::new_and(vec![2, 0, 0], 1.0));
fis.add_rule(Rule::new_and(vec![2, 1, 1], 1.0));
fis.add_rule(Rule::new_and(vec![2, 2, 2], 1.0));
Weights and Complements
You can change weights and changing the second argument, and you can add -
sign to complement that variables
Output
The problem formulation is done and we can use this to compute the output of the system:
let output = fis.compute_outputs(vec![40.0, 43.0]);
println!("{:#?}", output);
If we run it the output will be:
>cargo run --example speed-control
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target\debug\examples\speed-control.exe`
[
0.45999999999999996,
]