# import libraries import streamlit as st import joblib import numpy as np import pandas as pd from sklearn.ensemble import IsolationForest st.set_page_config( page_title="NASA Turbofan Playground", page_icon="🧊", initial_sidebar_state="expanded", ) # Set the background image background_image = """ """ st.markdown(background_image, unsafe_allow_html=True) # Title with Rainbow Transition Effect and Neon Glow html_code = """

NASA Turbofan Playground

""" st.markdown(html_code, unsafe_allow_html=True) st.markdown( """ """, unsafe_allow_html=True ) # Load your ML model model = joblib.load('random_forest_model.joblib') # Define the columns and their min/max values along with descriptions columns = { 'cycles': {'min': 1, 'max': 362, 'type': 'int', 'desc': 'Number of operational cycles the turbofan engine has undergone.'}, 'T24': {'min': 641.21, 'max': 644.53, 'type': 'float', 'desc': 'Total temperature at fan inlet (sensor measurement).'}, 'T30': {'min': 1571.04, 'max': 1616.91, 'type': 'float', 'desc': 'Total temperature at Low-Pressure Compressor (LPC) outlet (sensor measurement).'}, 'T50': {'min': 1382.25, 'max': 1441.49, 'type': 'float', 'desc': 'Total temperature at High-Pressure Turbine (HPT) outlet (sensor measurement).'}, 'P30': {'min': 549.85, 'max': 556.06, 'type': 'float', 'desc': 'Pressure at HPC outlet (sensor measurement).'}, 'Nf': {'min': 2387.90, 'max': 2388.56, 'type': 'float', 'desc': 'Physical fan speed (shaft rotational speed).'}, 'Nc': {'min': 9021.73, 'max': 9244.59, 'type': 'float', 'desc': 'Physical core speed (shaft rotational speed).'}, 'Ps30': {'min': 46.85, 'max': 48.53, 'type': 'float', 'desc': 'Static pressure at HPC outlet (sensor measurement).'}, 'phi': {'min': 518.69, 'max': 523.38, 'type': 'float', 'desc': 'Ratio of fuel flow to the engine core airflow (calculated parameter).'}, 'NRf': {'min': 2387.88, 'max': 2388.56, 'type': 'float', 'desc': 'Corrected fan speed (shaft rotational speed).'}, 'NRc': {'min': 8099.94, 'max': 8293.72, 'type': 'float', 'desc': 'Corrected core speed (shaft rotational speed).'}, 'BPR': {'min': 8.3249, 'max': 8.5848, 'type': 'float', 'desc': 'Bypass ratio (ratio of the mass of air bypassing the engine core to the mass of air passing through the core).'}, 'htBleed': {'min': 388.00, 'max': 400.00, 'type': 'float', 'desc': 'Bleed Enthalpy (energy loss due to air bled off for use in other aircraft systems).'}, 'W31': {'min': 38.14, 'max': 39.43, 'type': 'float', 'desc': 'High-pressure turbine cooling bleed flow (sensor measurement).'}, 'W32': {'min': 22.8942, 'max': 23.6184, 'type': 'float', 'desc': 'Low-pressure turbine cooling bleed flow (sensor measurement).'} } # Sidebar inputs st.sidebar.title("NASA Turbofan Playground") inputs = {} for col, limits in columns.items(): if limits['type'] == 'int': inputs[col] = st.sidebar.number_input(col, min_value=limits['min'], max_value=limits['max'], value=(limits['min'] + limits['max']) // 2, step=1, help=limits['desc']) else: inputs[col] = st.sidebar.number_input(col, min_value=limits['min'], max_value=limits['max'], value=(limits['min'] + limits['max']) / 2, help=limits['desc']) # Main page # st.title("Turbofan Engine RUL Prediction") # st.markdown('

Turbofan Engine RUL Prediction and Anomaly Detection

', unsafe_allow_html=True) # st.markdown('

Provide the necessary inputs in the sidebar to predict the Remaining Useful Life (RUL) of the turbofan engine.

', unsafe_allow_html=True) # st.write("Provide the necessary inputs in the sidebar to predict the Remaining Useful Life (RUL) of the turbofan engine.") # Prepare the input for prediction input_data = [inputs[col] for col in columns] input_data = [input_data] # Assuming the model expects a 2D array inp_sensor_data = input_data[0][1:] # Predict the RUL predict_rul = st.sidebar.button("Predict RUL") sensor_button = st.sidebar.button("Detect Anomaly of Sensors") if not any([predict_rul,sensor_button]): # Title and Description st.write("Welcome to the NASA Turbofan Playground. This tool leverages machine learning " "to predict Remaining Useful Life (RUL) and detect anomalies in turbofan engine sensor data.") st.divider() # About the Application st.header("About the Application") st.markdown(""" This application provides two main features: - **Remaining Useful Life (RUL) Prediction:** Predicts when a turbofan engine is likely to fail based on its current sensor readings. - **Sensor Anomaly Detection:** Identifies anomalies in the sensor data to detect potential issues before they lead to failures. """) st.divider() # Key Features st.header("Key Features") st.markdown(""" - **RUL Prediction:** Input current sensor readings manually or via file upload to predict RUL. - **Anomaly Detection:** Detect anomalies in sensor readings to monitor engine health. """) st.divider() # Supported Sensors st.header("Supported Sensors") st.markdown(""" - **Temperature Sensors:** T24, T30, T50 - **Pressure Sensors:** P30, Ps30 - **Speed Sensors:** Nf, Nc, NRf, NRc - **Bleed Air Sensors:** BPR, htBleed - **Flow Sensors:** W31, W32 - **Other Parameters:** phi """) st.divider() # Technology Stack st.header("Technology Stack") st.markdown(""" - **Frontend:** Streamlit - **Backend:** Python - **Machine Learning Models:** Random Forest (RUL Prediction), Isolation Forest (Anomaly Detection) """) if predict_rul: prediction = model.predict(input_data) predicted_rul = int(prediction[0]) input_cycles = inputs['cycles'] # Calculate percentage of RUL percentage_rul = input_cycles / predicted_rul st.divider() st.subheader(f"The predicted Remaining Useful Life (RUL) is: {predicted_rul} cycles") st.divider() # Determine engine health status if percentage_rul >=1: st.markdown('

The RUL is less than Current Cycle, this may be due to wrong prediction or Sensor Anomalies.

', unsafe_allow_html=True) max_deviation = 0 anomaly_sensor = None for col, limits in columns.items(): deviation = min(abs(inputs[col] - limits['min']), abs(inputs[col] - limits['max'])) if deviation > max_deviation: max_deviation = deviation anomaly_sensor = col st.markdown(f'

Potential anomaly detected in sensor: {anomaly_sensor}.

', unsafe_allow_html=True) elif percentage_rul < 0.4: st.markdown('

The Remaining Useful is more than 60%, \nEngine Health is Excellent.

', unsafe_allow_html=True) elif percentage_rul < 0.6: st.markdown('

The Remaining Useful is more than 40%, \nEngine Health is Fine.

', unsafe_allow_html=True) elif percentage_rul < 0.8: st.markdown('

Warning: The Remaining Useful is between 60 to 80%, \nEngine needs to be checked.

', unsafe_allow_html=True) else: st.markdown('

Warning: The Remaining Useful is critical and less than 20%, \nEngine maintenance Required.

', unsafe_allow_html=True) # Identify the sensor responsible for the anomaly max_deviation = 0 anomaly_sensor = None for col, limits in columns.items(): deviation = min(abs(inputs[col] - limits['min']), abs(inputs[col] - limits['max'])) if deviation > max_deviation: max_deviation = deviation anomaly_sensor = col st.markdown(f'

Potential anomaly detected in sensor: {anomaly_sensor}.

', unsafe_allow_html=True) # Load the pre-trained model model_path = 'AnomalyDetection.joblib' iso_forest = joblib.load(model_path) # Define sensor columns based on the dataset (excluding 'RUL' since it's not used for anomaly detection) sensor_columns = ['T24', 'T30', 'T50', 'P30', 'Nf', 'Nc', 'Ps30', 'phi', 'NRf', 'NRc', 'BPR', 'htBleed', 'W31', 'W32'] # Button to run anomaly detection with the provided sensor data if sensor_button: # Convert inputs to DataFrame input_data = pd.DataFrame([inp_sensor_data], columns=sensor_columns) # Predict anomaly anomaly_score = iso_forest.decision_function(input_data) anomaly_flag = iso_forest.predict(input_data) # Display results st.write(f"Anomaly Score: {anomaly_score[0]:.4f}") if anomaly_flag[0] == -1: st.write("Anomaly Detected!") else: st.write("No Anomaly Detected.") # Identify contributing sensors sensor_importance = {} for sensor in sensor_columns: input_temp = input_data.copy() input_temp[sensor] = 0 # Remove the influence of this sensor temp_scores = iso_forest.decision_function(input_temp) importance = np.mean(np.abs(anomaly_score - temp_scores)) sensor_importance[sensor] = importance sorted_sensors = sorted(sensor_importance.items(), key=lambda x: x[1], reverse=True) st.write("Sensors contributing to anomalies in descending order of importance: ") for sensor, importance in sorted_sensors: st.write(f"{sensor}: {importance:.4f}")