Spaces:
Sleeping
Sleeping
File size: 6,169 Bytes
d80edbe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | """
Vitals Guard AI β Shared Utilities
Common constants, vital ranges, and helper functions used across all models.
"""
import numpy as np
import pandas as pd
# ββββββββββββββββββββββββββββββββββββββββββββββ
# Normal Vital Ranges
# ββββββββββββββββββββββββββββββββββββββββββββββ
VITAL_RANGES = {
"heart_rate": {"min": 60, "max": 100, "unit": "bpm"},
"spo2": {"min": 95, "max": 100, "unit": "%"},
"temperature": {"min": 36.1, "max": 37.2, "unit": "Β°C"},
"respiratory_rate": {"min": 12, "max": 20, "unit": "breaths/min"},
"systolic_bp": {"min": 90, "max": 140, "unit": "mmHg"},
"diastolic_bp": {"min": 60, "max": 90, "unit": "mmHg"},
"rr_interval": {"min": 0.6, "max": 1.0, "unit": "seconds"},
}
# ββββββββββββββββββββββββββββββββββββββββββββββ
# Condition Labels
# ββββββββββββββββββββββββββββββββββββββββββββββ
HEALTH_CONDITIONS = [
"Normal",
"Hypertension",
"Hypotension",
"Tachycardia",
"Bradycardia",
"Hypoxia",
"Fever",
"Hypothermia",
"Cardiac_Arrhythmia",
"Respiratory_Distress",
]
SEVERITY_LEVELS = ["stable", "warning", "critical"]
DISEASE_FINGERPRINTS = {
"COVID_like": {"spo2": "low", "temp": "high", "rr": "high", "hr": "high"},
"Cardiac": {"hr": "irregular", "rr_interval": "irregular", "bp": "high"},
"Sepsis_like": {"temp": "high", "hr": "high", "bp": "low", "rr": "high"},
"Respiratory_Distress": {"spo2": "low", "rr": "high", "hr": "high"},
"Heat_Stroke": {"temp": "very_high", "hr": "high", "bp": "low", "spo2": "low"},
}
BEHAVIORAL_FEATURES = ["sleep_hours", "stress_level", "activity_level"]
# ββββββββββββββββββββββββββββββββββββββββββββββ
# Helper Functions
# ββββββββββββββββββββββββββββββββββββββββββββββ
def add_noise(values, noise_level=0.02):
"""Add Gaussian noise to an array of values."""
noise = np.random.normal(0, noise_level * np.std(values), size=len(values))
return values + noise
def normalize_vitals(df, columns=None):
"""Min-max normalize specified columns in a DataFrame."""
if columns is None:
columns = df.select_dtypes(include=[np.number]).columns.tolist()
df_normalized = df.copy()
for col in columns:
col_min = df[col].min()
col_max = df[col].max()
if col_max - col_min > 0:
df_normalized[col] = (df[col] - col_min) / (col_max - col_min)
else:
df_normalized[col] = 0.0
return df_normalized
def generate_normal_vitals(n=1):
"""Generate n samples of normal vital signs."""
return {
"heart_rate": np.random.uniform(60, 100, n),
"spo2": np.random.uniform(95, 100, n),
"temperature": np.random.uniform(36.1, 37.2, n),
"respiratory_rate": np.random.uniform(12, 20, n),
"systolic_bp": np.random.uniform(90, 140, n),
"diastolic_bp": np.random.uniform(60, 90, n),
}
def generate_ecg_wave(duration_sec=2.0, sampling_rate=250, heart_rate=72, noise_level=0.05):
"""
Generate a synthetic ECG-like signal using a simplified PQRST model.
Returns (time_array, ecg_signal).
"""
t = np.linspace(0, duration_sec, int(duration_sec * sampling_rate), endpoint=False)
ecg = np.zeros_like(t)
beat_interval = 60.0 / heart_rate
num_beats = int(duration_sec / beat_interval) + 1
for i in range(num_beats):
beat_start = i * beat_interval
# P wave
p_center = beat_start + 0.1
ecg += 0.15 * np.exp(-((t - p_center) ** 2) / (2 * 0.01 ** 2))
# QRS complex
q_center = beat_start + 0.2
ecg -= 0.1 * np.exp(-((t - q_center) ** 2) / (2 * 0.005 ** 2))
r_center = beat_start + 0.22
ecg += 1.0 * np.exp(-((t - r_center) ** 2) / (2 * 0.005 ** 2))
s_center = beat_start + 0.24
ecg -= 0.15 * np.exp(-((t - s_center) ** 2) / (2 * 0.005 ** 2))
# T wave
t_center = beat_start + 0.4
ecg += 0.3 * np.exp(-((t - t_center) ** 2) / (2 * 0.02 ** 2))
ecg += np.random.normal(0, noise_level, len(ecg))
return t, ecg
def calculate_ews(hr, spo2, temp, rr, systolic_bp):
"""
Calculate a simplified Early Warning Score (inspired by NEWS2).
Returns integer score (0 = best, higher = worse).
"""
score = 0
# Heart Rate scoring
if hr <= 40 or hr >= 131:
score += 3
elif hr <= 50 or (hr >= 111 and hr <= 130):
score += 2
elif (hr >= 91 and hr <= 110):
score += 1
# SpO2 scoring
if spo2 <= 91:
score += 3
elif spo2 <= 93:
score += 2
elif spo2 <= 95:
score += 1
# Temperature scoring
if temp <= 35.0:
score += 3
elif temp <= 36.0 or temp >= 39.1:
score += 2
elif (temp >= 38.1 and temp <= 39.0):
score += 1
# Respiratory Rate scoring
if rr <= 8 or rr >= 25:
score += 3
elif rr >= 21 and rr <= 24:
score += 2
elif rr >= 9 and rr <= 11:
score += 1
# Systolic BP scoring
if systolic_bp <= 90 or systolic_bp >= 220:
score += 3
elif systolic_bp <= 100 or (systolic_bp >= 180 and systolic_bp <= 219):
score += 2
elif systolic_bp <= 110:
score += 1
return score
def ews_to_severity(ews_score):
"""Convert EWS score to severity level."""
if ews_score <= 4:
return "stable"
elif ews_score <= 8:
return "warning"
else:
return "critical"
def get_project_root():
"""Get the project root directory."""
return "."
|