diff --git a/threat.csv b/threat.csv new file mode 100644 index 0000000..22cccfb --- /dev/null +++ b/threat.csv @@ -0,0 +1,12 @@ +敌机速度,敌机距离,威胁 +0.00,0.00,0.75,0.75,0.75 +10.00,10.00,0.68,0.68,0.69 +50.00,10.00,0.70,0.70,0.69 +10.00,50.00,0.50,0.50,0.50 +50.00,50.00,0.50,0.50,0.50 +10.00,70.00,0.32,0.38,0.39 +50.00,70.00,0.40,0.40,0.40 +70.00,10.00,0.82,0.74,0.70 +70.00,50.00,0.70,0.60,0.61 +70.00,70.00,0.56,0.49,0.50 +100.00,100.00,0.50,0.50,0.50 diff --git a/威胁感知.py b/威胁感知.py new file mode 100644 index 0000000..9a41aa5 --- /dev/null +++ b/威胁感知.py @@ -0,0 +1,182 @@ +from enum import Enum +from functools import reduce +from scipy import integrate +import itertools + +DELIMETER = "," + + +class FuzzDistance(Enum): + Short = 0 + Medium = 1 + Long = 2 + + def membership_grade(self, distance: float) -> float: + k = 1 / 50 + fns = { + FuzzDistance.Short: lambda t: -k * (t - 50), + FuzzDistance.Medium: lambda t: min(k * (t - 0), -k * (t - 100)), + FuzzDistance.Long: lambda t: min(k * (t - 50), 1), + } + return max(0, fns[self](distance)) + + +class FuzzVelocity(Enum): + Low = 0 + Medium = 1 + High = 2 + + def membership_grade(self, v: float) -> float: + k = 1 / 50 + fns = { + FuzzVelocity.Low: lambda t: -k * (t - 50), + FuzzVelocity.Medium: lambda t: min(k * (t - 0), -k * (t - 100)), + FuzzVelocity.High: lambda t: k * (t - 50), + } + return max(0, fns[self](v)) + + +class FuzzThreat(Enum): + VL = 0 + L = 1 + M = 2 + H = 3 + VH = 4 + + def reverse_membership_grade(self) -> float: + v = [0, 0.25, 0.5, 0.75, 1] + return v[self.value] + + def membership_grade(self, threat: float) -> float: + k = 1 / 0.25 + fns = { + FuzzThreat.VL: lambda t: -k * (t - 0.25), + FuzzThreat.L: lambda t: min(k * (t - 0), -k * (t - 0.5)), + FuzzThreat.M: lambda t: min(k * (t - 0.25), -k * (t - 0.75)), + FuzzThreat.H: lambda t: min(k * (t - 0.5), -k * (t - 1)), + FuzzThreat.VH: lambda t: k * (t - 0.75), + } + return max(0, fns[self](threat)) + + +class Rule: + def __init__( + self, dirtness: FuzzVelocity, type_of_dirt: FuzzDistance, wash_time: FuzzThreat + ) -> None: + self.dirtness = dirtness + self.type_of_dirt = type_of_dirt + self.wash_time = wash_time + + def rule_support(self, dirtness: float, type_of_dirt: float) -> float: + # 计算隶属度 + dirtness_grade = self.dirtness.membership_grade(dirtness) + type_of_dirt_grade = self.type_of_dirt.membership_grade(type_of_dirt) + # 计算t范数 min + return min(dirtness_grade, type_of_dirt_grade) + + +class InferenceEngine: + def __init__(self, rules: list[Rule]) -> None: + self.rules = rules + + def output( + self, dirtness: float, type_of_dirt: float + ) -> list[tuple[float, FuzzThreat]]: + # 使用规则 + ans = map( + lambda rule: (rule.rule_support(dirtness, type_of_dirt), rule.wash_time), + self.rules, + ) + ans = list(ans) + return ans + + +# 聚合模糊输出,使用离散的质心计算方式,数学积 +def aggregate_discret_AP(pairs: list[tuple[float, FuzzThreat]]) -> float: + return sum( + map(lambda pair: pair[0] * pair[1].reverse_membership_grade(), pairs) + ) / sum(map(lambda pair: pair[0], pairs)) + + +# 使用连续的质心计算方式,数学积和代数和 +def aggregate_continue_AP(pairs: list[tuple[float, FuzzThreat]]) -> float: + def f(time: float) -> float: + return S_AS(map(lambda pair: pair[0] * pair[1].membership_grade(time), pairs)) + + base = integrate.quad(f, 0, 1)[0] + return integrate.quad(lambda v: v * f(v), 0, 1)[0] / base + + +def S_AS(iter) -> float: + "代数和,输入数组" + ans = 0 + iter = tuple(iter) + for i in range(len(iter)): + n = i + 1 + if n & 1: + flag = 1 + else: + flag = -1 + # 选择n个数,相乘再相加 + for collection in itertools.combinations(iter, n): + ans += flag * reduce(lambda x, y: x * y, collection) + return ans + + +# 标准交 +def aggregate_continue_SI(pairs: list[tuple[float, FuzzThreat]]) -> float: + """lambda: fi=min(alpha, mu), f=max(fi)""" + + def f(time: float) -> float: + return max( + map(lambda pair: min(pair[0], pair[1].membership_grade(time)), pairs) + ) + + return integrate.quad(lambda v: v * f(v), 0, 1)[0] / integrate.quad(f, 0, 1)[0] + + +rules = [ + Rule(FuzzVelocity.Low, FuzzDistance.Short, FuzzThreat.H), + Rule(FuzzVelocity.Medium, FuzzDistance.Short, FuzzThreat.H), + Rule(FuzzVelocity.High, FuzzDistance.Short, FuzzThreat.VH), + Rule(FuzzVelocity.Low, FuzzDistance.Medium, FuzzThreat.M), + Rule(FuzzVelocity.Medium, FuzzDistance.Medium, FuzzThreat.M), + Rule(FuzzVelocity.High, FuzzDistance.Medium, FuzzThreat.VH), + Rule(FuzzVelocity.Low, FuzzDistance.Long, FuzzThreat.VL), + Rule(FuzzVelocity.Medium, FuzzDistance.Long, FuzzThreat.L), + Rule(FuzzVelocity.High, FuzzDistance.Long, FuzzThreat.M), +] + +inputs = [ + [0, 0], + [10, 10], + [50, 10], + [10, 50], + [50, 50], + [10, 70], + [50, 70], + [70, 10], + [70, 50], + [70, 70], + [100, 100], +] + + +def main(inputs, rules): + print(DELIMETER.join(["敌机速度", "敌机距离", "威胁"])) + engine = InferenceEngine(rules) + for input in inputs: + # print("脏的程度", input[0], "脏的类型", input[1]) + outputs = engine.output(input[0], input[1]) + output = aggregate_discret_AP(outputs) + output1 = aggregate_continue_AP(outputs) + output2 = aggregate_continue_SI(outputs) + print( + DELIMETER.join(["{:.2f}"] * 5).format( + input[0], input[1], output, output1, output2 + ) + ) + + +if __name__ == "__main__": + main(inputs, rules)