-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimuladorAPV
More file actions
204 lines (181 loc) · 12.1 KB
/
Copy pathSimuladorAPV
File metadata and controls
204 lines (181 loc) · 12.1 KB
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ver UTI - Simulação: Duplo Disparo em SDRA</title>
<script src="https://cdn.tailwindcss.com"></script>
<!-- Versões de biblioteca especificadas para garantir compatibilidade -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon@3.0.1/build/global/luxon.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.1.0/dist/chartjs-adapter-luxon.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0/dist/chartjs-plugin-streaming.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Inter', sans-serif; }
.monitor-screen {
background-color: #0d1a2e;
border: 4px solid #374151;
box-shadow: 0 0 20px rgba(0, 191, 255, 0.4);
}
.vital-sign { border-bottom: 1px solid #1f2937; }
</style>
</head>
<body class="bg-gray-800 flex items-center justify-center min-h-screen p-4">
<div class="bg-gray-200 p-6 rounded-xl shadow-2xl w-full max-w-5xl">
<div class="text-center border-b-2 border-gray-300 pb-4 mb-6">
<h1 class="text-3xl font-bold text-blue-800">Simulação: Duplo Disparo (Double Triggering)</h1>
<p id="case-status" class="text-gray-600 mt-1 font-semibold">Cenário Inicial</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="lg:col-span-1 bg-white p-4 rounded-lg shadow-md">
<h2 class="text-xl font-bold text-gray-800 border-b pb-2 mb-3">Caso Clínico</h2>
<div id="case-description" class="text-gray-700 space-y-2 text-sm">
<p>Paciente feminina, 45 anos, admitida com Síndrome do Desconforto Respiratório Agudo (SDRA) secundária a pancreatite.</p>
<p>Está em ventilação mecânica com estratégia protetora.</p>
<p><strong>Configurações Iniciais:</strong> PCV, Pressão Controlada: 18 cmH₂O, PEEP: 10 cmH₂O, T-insp: 0.8s, FR: 18 rpm, FiO₂: 80%.</p>
<p>O paciente apresenta alto drive respiratório, apesar da sedação leve.</p>
</div>
<hr class="my-4">
<h2 class="text-xl font-bold text-gray-800 border-b pb-2 mb-3">Ações</h2>
<div id="actions-area" class="space-y-3">
<p class="text-center text-gray-500 italic">Aguardando evolução do caso...</p>
</div>
</div>
<div class="lg:col-span-2 monitor-screen p-4 rounded-lg">
<div class="grid grid-cols-4 gap-4 text-white text-center mb-4">
<div class="vital-sign pb-1"><span class="text-xs text-green-400">FC</span><p id="hr-value" class="text-2xl font-bold">110</p></div>
<div class="vital-sign pb-1"><span class="text-xs text-red-400">PA</span><p id="bp-value" class="text-2xl font-bold">110/65</p></div>
<div class="vital-sign pb-1"><span class="text-xs text-blue-400">SpO₂</span><p id="spo2-value" class="text-2xl font-bold">92%</p></div>
<div class="vital-sign pb-1"><span class="text-xs text-yellow-400">VT Expirado</span><p id="vt-value" class="text-2xl font-bold">~350</p></div>
</div>
<div>
<div><span class="text-xs font-semibold text-white ml-2">Fluxo (L/min)</span><canvas id="flowChart"></canvas></div>
<div class="mt-2"><span class="text-xs font-semibold text-white ml-2">Pressão (cmH₂O)</span><canvas id="pressureChart"></canvas></div>
<div class="mt-2"><span class="text-xs font-semibold text-white ml-2">Volume (mL)</span><canvas id="volumeChart"></canvas></div>
</div>
</div>
</div>
<div id="feedback-area" class="mt-6 bg-white p-4 rounded-lg shadow-md min-h-[50px] text-center flex items-center justify-center">
<p class="text-gray-700 italic">A simulação começará em breve. As curvas do ventilador aparecerão no monitor.</p>
</div>
</div>
<script>
window.onload = function() {
let simulationState = 'INITIAL';
let baseFR = 18;
let baseTinsp = 0.8;
const caseStatus = document.getElementById('case-status');
const actionsArea = document.getElementById('actions-area');
const feedbackArea = document.getElementById('feedback-area');
const vtValue = document.getElementById('vt-value');
// Funções para gerar dados das curvas
function getNormalWaveData(x, type) {
const period = 60 / baseFR;
const t = (x / 1000) % period;
const inspTime = baseTinsp;
if (t < inspTime) { // Inspiração
if (type === 'flow') return 60 * (1 - Math.pow(t / inspTime, 2));
if (type === 'pressure') return 10 + 18; // PEEP + Pressão Controlada
if (type === 'volume') return 350 * (t / inspTime);
} else { // Expiração
const expTime = t - inspTime;
if (type === 'flow') return -50 * Math.exp(-expTime * 2.5);
if (type === 'pressure') return 10; // PEEP
if (type === 'volume') return 350 * Math.exp(-expTime * 2.5);
}
}
function getDoubleTriggerData(x, type) {
const period = 60 / baseFR;
const t = (x / 1000) % period;
const inspTime1 = 0.8; // T-insp do ventilador
const inspTime2 = 0.6; // Duração do segundo disparo
const shortExpTime = 0.1; // Pequeno intervalo entre disparos
// Primeiro ciclo
if (t < inspTime1) {
if (type === 'flow') return 60 * (1 - Math.pow(t / inspTime1, 2));
if (type === 'pressure') return 10 + 18;
if (type === 'volume') return 350 * (t / inspTime1);
}
// Breve expiração
else if (t < inspTime1 + shortExpTime) {
const expTime = t - inspTime1;
if (type === 'flow') return -20 * Math.exp(-expTime * 5);
if (type === 'pressure') return 10 + 18 - (10 * expTime / shortExpTime);
if (type === 'volume') return 350 - (50 * expTime / shortExpTime);
}
// Segundo ciclo (Duplo Disparo)
else if (t < inspTime1 + shortExpTime + inspTime2) {
const inspTime = t - (inspTime1 + shortExpTime);
if (type === 'flow') return 50 * (1 - Math.pow(inspTime / inspTime2, 2));
if (type === 'pressure') return 10 + 18 + 12; // Pressão aumenta (stacking)
if (type === 'volume') return 300 + (300 * (inspTime / inspTime2)); // Volume aumenta (stacking)
}
// Expiração final
else {
const expTime = t - (inspTime1 + shortExpTime + inspTime2);
if (type === 'flow') return -80 * Math.exp(-expTime * 2.5);
if (type === 'pressure') return 10;
if (type === 'volume') return 600 * Math.exp(-expTime * 2.5);
}
}
function createCharts() {
const commonOptions = {
plugins: { legend: { display: false }, streaming: { duration: 10000, refresh: 80, delay: 200, onRefresh: (chart) => {
let dataFunction = simulationState === 'ASYNCHRONY' ? getDoubleTriggerData : getNormalWaveData;
chart.data.datasets.forEach(dataset => {
dataset.data.push({ x: Date.now(), y: dataFunction(Date.now(), dataset.label.toLowerCase()) });
});
}}},
scales: { x: { type: 'realtime', display: false }, y: { beginAtZero: false, ticks: { color: 'white' }, grid: { color: 'rgba(255, 255, 255, 0.2)' } } }
};
const ctxFlow = document.getElementById('flowChart').getContext('2d');
new Chart(ctxFlow, { type: 'line', data: { datasets: [{ label: 'Flow', data: [], borderColor: 'rgb(75, 192, 192)', borderWidth: 2, pointRadius: 0 }] }, options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, min: -100, max: 80 } } } });
const ctxPressure = document.getElementById('pressureChart').getContext('2d');
new Chart(ctxPressure, { type: 'line', data: { datasets: [{ label: 'Pressure', data: [], borderColor: 'rgb(255, 205, 86)', borderWidth: 2, pointRadius: 0 }] }, options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, min: 0, max: 45 } } } });
const ctxVolume = document.getElementById('volumeChart').getContext('2d');
new Chart(ctxVolume, { type: 'line', data: { datasets: [{ label: 'Volume', data: [], borderColor: 'rgb(153, 102, 255)', borderWidth: 2, pointRadius: 0 }] }, options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, min: 0, max: 700 } } } });
}
function startSimulation() {
createCharts();
feedbackArea.innerHTML = '<p class="text-gray-700 italic">Monitor a estabilizar. A aguardar evolução do paciente...</p>';
setTimeout(developAsynchrony, 10000);
}
function developAsynchrony() {
if (simulationState === 'ASYNCHRONY') return;
simulationState = 'ASYNCHRONY';
caseStatus.textContent = 'Evolução: Assincronia Detectada';
vtValue.textContent = '~600'; // VT aumenta devido ao duplo disparo
feedbackArea.innerHTML = `<p class="text-red-600 font-bold">ALERTA: O monitor agora mostra Duplo Disparo, com empilhamento de volume e aumento da pressão. Qual a sua intervenção?</p>`;
showActions();
}
function showActions() {
actionsArea.innerHTML = `
<button onclick="window.handleAction('increase_tinsp')" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition duration-200">Aumentar Tempo Inspiratório</button>
<button onclick="window.handleAction('decrease_peep')" class="w-full bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded transition duration-200">Diminuir PEEP</button>
<button onclick="window.handleAction('change_mode')" class="w-full bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded transition duration-200">Mudar para modo VCV</button>
`;
}
window.handleAction = function(action) {
if (simulationState !== 'ASYNCHRONY') return;
simulationState = 'ACTION_TAKEN';
actionsArea.innerHTML = '<p class="text-center text-gray-500 italic">Ação realizada. A observar...</p>';
if (action === 'increase_tinsp') {
feedbackArea.innerHTML = `<p class="text-green-700 font-bold">AÇÃO CORRETA: Ao aumentar o T-insp, você alinhou o tempo do ventilador com o tempo neural do paciente. A assincronia de Duplo Disparo foi resolvida.</p>`;
simulationState = 'CORRECTED';
baseTinsp = 1.2; // T-insp corrigido
vtValue.textContent = '~350';
caseStatus.textContent = 'Resolvido: Paciente Sincronizado';
} else {
let feedbackText = (action === 'decrease_peep')
? `AÇÃO INCORRETA: Diminuir a PEEP num paciente com SDRA pode levar a desrecrutamento alveolar e piorar a hipoxemia, sem corrigir a causa do Duplo Disparo.`
: `AÇÃO INCORRETA: Mudar para VCV sem ajustar o T-insp ou o fluxo não resolveria o descompasso temporal e poderia até piorar o conforto do paciente.`;
feedbackArea.innerHTML = `<p class="text-red-700 font-bold">${feedbackText}</p>`;
setTimeout(developAsynchrony, 5000);
}
}
startSimulation();
};
</script>
</body>
</html>