From 610fa84fb90ea4e6be395cc050b01ceb7e2ca348 Mon Sep 17 00:00:00 2001 From: n-akram <31505221+n-akram@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:53:13 +0200 Subject: [PATCH] Complete example, GPS and collision risk --- SafeDrones/core/SafeDrones.py | 130 ++++++++++++++++++++------- example/SafeDrone-demo-2.ipynb | 155 +++++++++++++++++++++++++-------- 2 files changed, 215 insertions(+), 70 deletions(-) diff --git a/SafeDrones/core/SafeDrones.py b/SafeDrones/core/SafeDrones.py index 8926146..ea6a6d7 100644 --- a/SafeDrones/core/SafeDrones.py +++ b/SafeDrones/core/SafeDrones.py @@ -33,13 +33,15 @@ def __init__(self): self.danger_threshold = None self.collision_threshold = None self.GPS_Lambda = None + self.SatStatus = None self.Set_Variables() def Set_Variables(self, MotorStatus=[1,1,1,1,1,1], Motors_Configuration='PNPNPN',\ Motors_Lambda = 0.001, Batt_Lambda = 0.001, alpha = 0.008, beta = 0.007, \ Battery_degradation_rate = 0.0064, BatteryLevel=80, MTTFref=400, \ - Tr=30, Ta=50, u=1,b=1, time=100, danger_threshold=2, collision_threshold=0, GPS_Lambda=0.001): + Tr=30, Ta=50, u=1,b=1, time=100, danger_threshold=2, collision_threshold=0, \ + GPS_Lambda=0.001, SatStatus = 0): #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Version : 1.0.0 % # Description : set variables used in the program % @@ -72,6 +74,7 @@ def Set_Variables(self, MotorStatus=[1,1,1,1,1,1], Motors_Configuration='PNPNPN' self.danger_threshold = danger_threshold self.collision_threshold = collision_threshold self.GPS_Lambda = GPS_Lambda + self.SatStatus = SatStatus def Motor_Failure_Risk_Calc(self, MotorStatus=None, Motors_Configuration=None, Motors_Lambda=None, time=None): @@ -587,45 +590,106 @@ def Chip_MTTF_Model(self,MTTFref=None, Tr=None, Ta = None, u=None,b = None, time return P_Fail.evalf(subs={t: time}), MTTFchip.evalf(subs={t: time}) - def GPS_Failure_Risk_Calc(self): - L = self.GPS_Lambda - t = self.time - - M = np.array([[-14*L, 0, 0, 0, 0, 0, 0, 0, 0], - [ 14*L, -13*L, 0, 0, 0, 0, 0, 0, 0], - [ 0, 13*L, -12*L, 0, 0, 0, 0, 0, 0], - [ 0, 0, 12*L, -11*L, 0, 0, 0, 0, 0], - [ 0, 0, 0, 11*L, -10*L, 0, 0, 0, 0], - [ 0, 0, 0, 0, 10*L, -9*L, 0, 0, 0], - [ 0, 0, 0, 0, 0, 9*L, -8*L, 0, 0], - [ 0, 0, 0, 0, 0, 0, 8*L, -7*L, 0], - [ 0, 0, 0, 0, 0, 0, 0, 7*L, 0]]) - - P = np.dot(sym.exp(M*t), self.SatStatus) + def GPS_Failure_Risk_Calc(self, SatStatus=None, time=None, Lambda = None, ): - P_Fail = P[-1] - - N = np.array([[-14*L, 0, 0, 0, 0, 0, 0, 0], - [ 14*L, -13*L, 0, 0, 0, 0, 0, 0], - [ 0, 13*L, -12*L, 0, 0, 0, 0, 0], - [ 0, 0, 12*L, -11*L, 0, 0, 0, 0], - [ 0, 0, 0, 11*L, -10*L, 0, 0, 0], - [ 0, 0, 0, 0, 10*L, -9*L, 0, 0], - [ 0, 0, 0, 0, 0, 9*L, -8*L, 0], - [ 0, 0, 0, 0, 0, 0, 8*L, -7*L]]) - - Time_Symbolic = np.sum(np.sum(-1.*np.linalg.inv(N), axis=1)*(self.SatStatus[:8])) - - MTTF = Time_Symbolic - - return P_Fail, MTTF + #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + # Program Name : Markov-based Drone's Reliability and MTTF Estimator % + # Author : Koorosh Aslansefat % + # Version : 1.0.0 % + # Description : A Markov Process-Based Approach for Reliability % + # Evaluation of the GPS System for Drones % + #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + ''' + + SatStatus: is an integer between 0 and 11. 0 means no satellite is available and 14 means fully satellite coverage. + + Lambda: Failure Rate of the GPS System. + + time: Time of the mission + ''' + + import numpy as np # linear algebra + import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv) + import sympy as sym # Symbolic Calculation + + t = sym.Symbol('t') + + if SatStatus == None: + SatStatus = self.SatStatus + if Lambda == None: + Lambda = self.GPS_Lambda + L = Lambda - def calculate_collision_risk(self, uav_1_trajectory, uav_2_trajectory): # self.danger_threshold, self.collision_threshold + if SatStatus == 14: + P0_GPS = sym.Matrix([[1],[0],[0],[0],[0],[0],[0],[0],[0]]) + Sflag = 7 + elif SatStatus == 13: + P0_GPS = sym.Matrix([[0],[1],[0],[0],[0],[0],[0],[0],[0]]) + Sflag = 6 + elif SatStatus == 12: + P0_GPS = sym.Matrix([[0],[0],[1],[0],[0],[0],[0],[0],[0]]) + Sflag = 5 + elif SatStatus == 11: + P0_GPS = sym.Matrix([[0],[0],[0],[1],[0],[0],[0],[0],[0]]) + Sflag = 4 + elif SatStatus == 10: + P0_GPS = sym.Matrix([[0],[0],[0],[0],[1],[0],[0],[0],[0]]) + Sflag = 3 + elif SatStatus == 9: + P0_GPS = sym.Matrix([[0],[0],[0],[0],[0],[1],[0],[0],[0]]) + Sflag = 2 + elif SatStatus == 8: + P0_GPS = sym.Matrix([[0],[0],[0],[0],[0],[0],[1],[0],[0]]) + Sflag = 1 + elif SatStatus == 7: + P0_GPS = sym.Matrix([[0],[0],[0],[0],[0],[0],[0],[1],[0]]) + Sflag = 0 + else: + P_Fail = 1 + MTTF = 0 + return P_Fail, MTTF + + M_GPS = sym.Matrix([[-14*L, 0, 0, 0, 0, 0, 0, 0, 0], + [ 14*L, -13*L, 0, 0, 0, 0, 0, 0, 0], + [ 0, 13*L, -12*L, 0, 0, 0, 0, 0, 0], + [ 0, 0, 12*L, -11*L, 0, 0, 0, 0, 0], + [ 0, 0, 0, 11*L, -10*L, 0, 0, 0, 0], + [ 0, 0, 0, 0, 10*L, -9*L, 0, 0, 0], + [ 0, 0, 0, 0, 0, 9*L, -8*L, 0, 0], + [ 0, 0, 0, 0, 0, 0, 8*L, -7*L, 0], + [ 0, 0, 0, 0, 0, 0, 0, 7*L, 0]]) + + P_GPS = sym.exp(M_GPS*t)*P0_GPS + + P_GPS_Fail = P_GPS[-1] + + N_GPS = sym.Matrix([[-14*L, 0, 0, 0, 0, 0, 0, 0], + [ 14*L, -13*L, 0, 0, 0, 0, 0, 0], + [ 0, 13*L, -12*L, 0, 0, 0, 0, 0], + [ 0, 0, 12*L, -11*L, 0, 0, 0, 0], + [ 0, 0, 0, 11*L, -10*L, 0, 0, 0], + [ 0, 0, 0, 0, 10*L, -9*L, 0, 0], + [ 0, 0, 0, 0, 0, 9*L, -8*L, 0], + [ 0, 0, 0, 0, 0, 0, 8*L, -7*L]]) + + tt = -1*N_GPS.inv() + + MTTF_GPS = sum(tt[Sflag,:]) + + return P_GPS_Fail.evalf(subs={t: time}), MTTF_GPS.evalf(subs={t: time}) + + def calculate_collision_risk(self, uav_1_trajectory, uav_2_trajectory, danger_threshold=-1, collision_threshold=-1): # self.danger_threshold, self.collision_threshold # Check that both trajectories have the same length assert len(uav_1_trajectory) == len(uav_2_trajectory), "Trajectories must have the same length" danger_zone_count = 0 collision_zone_count = 0 + + if danger_threshold != -1: + self.danger_threshold = danger_threshold + if collision_threshold != -1: + self.collision_threshold = collision_threshold for point_1, point_2 in zip(uav_1_trajectory, uav_2_trajectory): distance = np.linalg.norm(np.array(point_1) - np.array(point_2)) diff --git a/example/SafeDrone-demo-2.ipynb b/example/SafeDrone-demo-2.ipynb index a759d3b..67c6bd2 100644 --- a/example/SafeDrone-demo-2.ipynb +++ b/example/SafeDrone-demo-2.ipynb @@ -30,6 +30,9 @@ "from IPython.display import Markdown as md\n", "\n", "from sys import platform\n", + "import pandas as pd\n", + "import numpy as np\n", + "import random\n", "\n", "if platform == \"linux\" or platform == \"linux2\":\n", " currentdir = os.path.dirname(os.path.realpath(inspect.getfile(inspect.currentframe())))\n", @@ -48,7 +51,15 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np" + "eval = SafeDrones()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize the variables . . . .\n", + "Use $5$ as collision threshold, and $10$ as danger threshold. GPS lambda can be used the default ($0.001$)." ] }, { @@ -57,98 +68,168 @@ "metadata": {}, "outputs": [], "source": [ - "eval = SafeDrones()" + "eval.Set_Variables(collision_threshold=5, danger_threshold=10, GPS_Lambda=0.001)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Initialize the variables . . . .\n", - "Use $5$ as collision threshold, and $10$ as danger threshold. GPS lambda can be used the default ($0.001$)." + "Sample trajectories . . . . " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.5\n", + "0.5\n" + ] + } + ], "source": [ - "eval.Set_Variables(collision_threshold=5, danger_threshold=10, GPS_Lambda=0.001)" + "uav_1_trajectory = [(x, 0, 0) for x in range(10)]\n", + "uav_2_trajectory = [(x, 0, x) for x in range(10)]\n", + "\n", + "danger_zone_risk, collision_zone_risk = eval.calculate_collision_risk(uav_1_trajectory, uav_2_trajectory)\n", + "\n", + "print(danger_zone_risk)\n", + "print(collision_zone_risk)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.3\n", + "0.2\n" + ] + } + ], + "source": [ + "danger_threshold = 5\n", + "collision_threshold = 2\n", + "\n", + "danger_zone_risk, collision_zone_risk = eval.calculate_collision_risk(uav_1_trajectory, uav_2_trajectory, danger_threshold, collision_threshold)\n", + "\n", + "print(danger_zone_risk)\n", + "print(collision_zone_risk)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Sample trajectories . . . . " + "To check the risk of GPS failure, let us first set the satellite status. The satellite status is a number between 0 to 18. Let us randomly assign the the status . . . ." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The satellite status is set as : 8\n" + ] + } + ], "source": [ - "traj_1 = np.array([1, 2, 3, 4, 5, 6])\n", - "traj_2 = np.array([1, 2, 3, 4, 5, 6])" + "sat_status = random.randint(0, 18)\n", + "eval.Set_Variables(SatStatus = sat_status)\n", + "print(\"The satellite status is set as : \", sat_status)" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "(0.0, 1.0)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "0.172620318489205\n", + "153.846153846154\n" + ] } ], "source": [ - "risk = eval.calculate_collision_risk(traj_1, traj_2)\n", - "risk" + "GPS_P_Fail, GPS_MTTF = eval.GPS_Failure_Risk_Calc(time=100)\n", + "print(GPS_P_Fail)\n", + "print(GPS_MTTF)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 8, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.19038762535297e-5\n", + "1142.85714285714\n" + ] + } + ], "source": [ - "Check the risk of GPS failure . . . . " + "GPS_P_Fail, GPS_MTTF = eval.GPS_Failure_Risk_Calc(SatStatus=14, time=100, Lambda = 0.001)\n", + "print(GPS_P_Fail)\n", + "print(GPS_MTTF)" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 9, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0107555729878382\n", + "363.636363636364\n" + ] + } + ], "source": [ - "## INCOMPLETE . . . ." + "GPS_P_Fail, GPS_MTTF = eval.GPS_Failure_Risk_Calc(SatStatus=10, time=100, Lambda = 0.001)\n", + "print(GPS_P_Fail)\n", + "print(GPS_MTTF)" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "metadata": {}, "outputs": [ { - "ename": "AttributeError", - "evalue": "'SafeDrones' object has no attribute 'SatStatus'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32mc:\\AKRAM-Local\\github\\SafeDrones\\example\\SafeDrone-demo-2.ipynb Cell 12\u001b[0m line \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[0m gps_risk \u001b[39m=\u001b[39m \u001b[39meval\u001b[39;49m\u001b[39m.\u001b[39;49mGPS_Failure_Risk_Calc()\n", - "File \u001b[1;32mc:\\AKRAM-Local\\github\\SafeDrones\\SafeDrones\\core\\SafeDrones.py:604\u001b[0m, in \u001b[0;36mSafeDrones.GPS_Failure_Risk_Calc\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 592\u001b[0m t \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mtime\n\u001b[0;32m 594\u001b[0m M \u001b[39m=\u001b[39m np\u001b[39m.\u001b[39marray([[\u001b[39m-\u001b[39m\u001b[39m14\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[0;32m 595\u001b[0m [ \u001b[39m14\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m13\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[0;32m 596\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m13\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m12\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 601\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m8\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m7\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m],\n\u001b[0;32m 602\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m7\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m]])\n\u001b[1;32m--> 604\u001b[0m P \u001b[39m=\u001b[39m np\u001b[39m.\u001b[39mdot(sym\u001b[39m.\u001b[39mexp(M\u001b[39m*\u001b[39mt), \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mSatStatus)\n\u001b[0;32m 606\u001b[0m P_Fail \u001b[39m=\u001b[39m P[\u001b[39m-\u001b[39m\u001b[39m1\u001b[39m]\n\u001b[0;32m 608\u001b[0m N \u001b[39m=\u001b[39m np\u001b[39m.\u001b[39marray([[\u001b[39m-\u001b[39m\u001b[39m14\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[0;32m 609\u001b[0m [ \u001b[39m14\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m13\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[0;32m 610\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m13\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m12\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m],\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 614\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m9\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m8\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m0\u001b[39m],\n\u001b[0;32m 615\u001b[0m [ \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m0\u001b[39m, \u001b[39m8\u001b[39m\u001b[39m*\u001b[39mL, \u001b[39m-\u001b[39m\u001b[39m7\u001b[39m\u001b[39m*\u001b[39mL]])\n", - "\u001b[1;31mAttributeError\u001b[0m: 'SafeDrones' object has no attribute 'SatStatus'" + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "0\n" ] } ], "source": [ - "gps_risk = eval.GPS_Failure_Risk_Calc()" + "GPS_P_Fail, GPS_MTTF = eval.GPS_Failure_Risk_Calc(SatStatus=0, time=100, Lambda = 0.001)\n", + "print(GPS_P_Fail)\n", + "print(GPS_MTTF)" ] } ],