Simuladores do curso de UTI do Dr Yuri
<title>Ver UTI - Simulação: Duplo Disparo em SDRA</title> <script src="https://cdn.tailwindcss.com"></script> <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> <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><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>