Diagramme de Mollier interactif — Cycle frigorifique 7 fluides
Le diagramme de Mollier interactif (aussi appelé diagramme enthalpique ou diagramme des frigoristes) permet de visualiser et calculer en temps réel un cycle frigorifique thermodynamique à 4 points pour 7 fluides frigorigènes courants : R32, R410A, R134A, R404A, R290, R1234yf, R744 (CO₂). Ajustez les températures d’évaporation et de condensation, la surchauffe, le sous-refroidissement et le rendement compresseur, et visualisez instantanément le COP, l’effet frigorifique, le travail de compression et la chaleur cédée au condenseur.
🧊 Diagramme de Mollier interactif 7 FLUIDES
Simulateur thermodynamique du cycle frigorifique · Calcul en direct de COP, surchauffe, sous-refroidissement · R32, R410A, R134A, R404A, R290, R1234YF, R744 (CO₂)
⚙️ Paramètres cycle
📊 Diagramme log(P)-h
Cycle frigorifique (1→2→3→4)
Évaporation (4→1)
Compression (1→2)
Condensation (2→3)
Détente (3→4)
const FLUIDS = { 'R32': { name:'R32', Tcrit:78.1, Pcrit:57.82, /* T(°C), P(bar), h_liq, h_vap, s_vap */ pts:[[-40,0.66,144,498,2.31],[-30,1.08,158,504,2.25],[-20,1.68,172,510,2.19],[-10,2.53,186,516,2.14],[0,3.69,200,522,2.09],[10,5.22,215,527,2.04],[20,7.19,230,531,2.00],[30,9.70,246,534,1.96],[40,12.88,262,537,1.92],[50,16.80,279,538,1.88],[60,21.70,297,537,1.84],[70,27.78,318,532,1.79]], cp_liq:1.96, cp_vap:1.12 }, 'R410A': { name:'R410A', Tcrit:71.4, Pcrit:49.03, pts:[[-40,1.00,152,424,1.91],[-30,1.60,166,429,1.86],[-20,2.50,180,434,1.81],[-10,3.80,195,438,1.77],[0,5.70,210,442,1.73],[10,8.20,225,446,1.69],[20,11.48,241,449,1.66],[30,15.75,257,451,1.62],[40,21.16,274,452,1.58],[50,27.81,292,451,1.54],[60,36.25,313,447,1.49]], cp_liq:1.73, cp_vap:1.03 }, 'R134A': { name:'R134A', Tcrit:101.1, Pcrit:40.59, pts:[[-40,0.51,148,372,1.76],[-30,0.84,161,380,1.75],[-20,1.33,174,387,1.73],[-10,2.01,187,395,1.72],[0,2.93,200,401,1.72],[10,4.15,213,407,1.72],[20,5.72,227,412,1.72],[30,7.70,241,417,1.72],[40,10.16,256,420,1.72],[50,13.18,271,423,1.72],[60,16.82,287,424,1.72],[70,21.16,304,423,1.71],[80,26.33,323,421,1.69],[90,32.44,343,414,1.66]], cp_liq:1.45, cp_vap:0.97 }, 'R404A': { name:'R404A', Tcrit:72.1, Pcrit:37.32, pts:[[-40,1.06,153,344,1.59],[-30,1.62,167,351,1.58],[-20,2.40,181,358,1.58],[-10,3.45,195,364,1.57],[0,4.81,210,370,1.57],[10,6.55,225,374,1.56],[20,8.72,241,378,1.55],[30,11.38,257,381,1.54],[40,14.60,274,383,1.53],[50,18.46,293,383,1.51],[60,23.03,314,379,1.49]], cp_liq:1.58, cp_vap:1.00 }, 'R290': { name:'R290', Tcrit:96.7, Pcrit:42.47, pts:[[-40,1.12,100,520,2.48],[-30,1.72,121,532,2.43],[-20,2.50,142,544,2.39],[-10,3.50,164,556,2.35],[0,4.74,186,566,2.32],[10,6.37,209,576,2.28],[20,8.36,232,586,2.25],[30,10.79,257,593,2.22],[40,13.69,282,599,2.19],[50,17.13,309,603,2.16],[60,21.17,337,605,2.13],[70,25.85,367,604,2.09],[80,31.26,400,599,2.05]], cp_liq:2.60, cp_vap:1.87 }, 'R1234YF':{ name:'R1234YF', Tcrit:94.7, Pcrit:33.82, pts:[[-40,0.51,139,330,1.60],[-30,0.84,152,337,1.58],[-20,1.32,166,344,1.57],[-10,2.00,180,350,1.56],[0,2.90,194,356,1.55],[10,4.10,208,361,1.55],[20,5.64,223,365,1.54],[30,7.60,238,369,1.53],[40,10.04,254,371,1.52],[50,13.04,270,372,1.51],[60,16.67,288,372,1.49],[70,21.02,308,369,1.47]], cp_liq:1.40, cp_vap:0.96 }, 'R744': { name:'R744 CO₂', Tcrit:31.0, Pcrit:73.77, pts:[[-40,10.04,99,435,1.93],[-30,14.28,118,437,1.89],[-20,19.70,137,438,1.86],[-10,26.49,158,435,1.82],[0,34.85,180,429,1.78],[10,45.02,206,418,1.73],[20,57.29,237,399,1.67],[25,64.34,259,385,1.64]], cp_liq:2.50, cp_vap:1.20 } };
/* ===== INTERPOLATION ===== */ function interp(pts, T, col) { if (T <= pts[0][0]) return pts[0][col]; if (T >= pts[pts.length-1][0]) return pts[pts.length-1][col]; for (let i=0; i
/* Estimation T_sat à partir de P (inverse) */ function getT_sat(f, P) { const pts = FLUIDS[f].pts; if (P <= pts[0][1]) return pts[0][0]; if (P >= pts[pts.length-1][1]) return pts[pts.length-1][0]; for (let i=0; i
function getPlotRange(f) { const pts = FLUIDS[f].pts; let hMin = 1e9, hMax = -1e9, pMin = 1e9, pMax = -1e9; pts.forEach(p => { if (p[2] < hMin) hMin = p[2]; if (p[3] > hMax) hMax = p[3]; if (p[1] < pMin) pMin = p[1]; if (p[1] > pMax) pMax = p[1]; }); // extension pour superheat hMax += 60; hMin -= 10; pMin = pMin * 0.6; pMax = pMax * 1.4; return { hMin, hMax, pMin, pMax }; }
let currentCycle = null; let currentRange = null;
function h2x(h) { const w = cv.width; const pad = 80; return pad + (h - currentRange.hMin)/(currentRange.hMax - currentRange.hMin) * (w - pad*1.3); } function p2y(P) { const h = cv.height; const pad = 60; const logP = Math.log10(P); const logMin = Math.log10(currentRange.pMin); const logMax = Math.log10(currentRange.pMax); return h - pad - (logP - logMin)/(logMax - logMin) * (h - pad*1.8); }
function render() { const f = document.getElementById('fluide').value; currentRange = getPlotRange(f); ctx.clearRect(0,0,cv.width,cv.height);
/* Grille + axes */ ctx.strokeStyle = '#f3f4f6'; ctx.lineWidth = 1; ctx.fillStyle = '#6b7280'; ctx.font = '11px sans-serif'; // Grilles horizontales (pression log) const pTicks = [0.5, 1, 2, 5, 10, 20, 50, 100]; pTicks.forEach(P => { if (P >= currentRange.pMin && P <= currentRange.pMax) { const y = p2y(P); ctx.beginPath(); ctx.moveTo(h2x(currentRange.hMin), y); ctx.lineTo(h2x(currentRange.hMax), y); ctx.stroke(); ctx.fillText(P + ' bar', 10, y+4); } }); // Grilles verticales (enthalpie) const hStep = 50; for (let h = Math.ceil(currentRange.hMin/hStep)*hStep; h <= currentRange.hMax; h += hStep) { const x = h2x(h); ctx.beginPath(); ctx.moveTo(x, p2y(currentRange.pMin)); ctx.lineTo(x, p2y(currentRange.pMax)); ctx.stroke(); ctx.fillText(h + ' kJ/kg', x - 20, cv.height - 20); } /* Courbe de saturation (dome) */ ctx.strokeStyle = '#0284c7'; ctx.lineWidth = 2; ctx.beginPath(); const pts = FLUIDS[f].pts; // Partie liquide (gauche) pts.forEach((p,i) => { const x = h2x(p[2]); const y = p2y(p[1]); if (i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y); }); // Partie vapeur (droite) - en sens inverse for (let i = pts.length - 1; i >= 0; i--) { const p = pts[i]; ctx.lineTo(h2x(p[3]), p2y(p[1])); } ctx.closePath(); ctx.stroke();
/* Label fluide */ ctx.fillStyle = '#0284c7'; ctx.font = 'bold 14px sans-serif'; ctx.fillText(FLUIDS[f].name, h2x(currentRange.hMin) + 10, p2y(currentRange.pMax) + 20);
/* Cycle frigorifique */ if (currentCycle) { const c = currentCycle; // segments // 4→1 évaporation (horizontal à P1) ctx.strokeStyle = '#16a34a'; ctx.lineWidth = 3; ctx.beginPath(); ctx.moveTo(h2x(c.h4), p2y(c.P1)); ctx.lineTo(h2x(c.h1), p2y(c.P1)); ctx.stroke(); // 1→2 compression (courbe log, approx ligne droite en log-log) ctx.strokeStyle = '#ea580c'; ctx.beginPath(); ctx.moveTo(h2x(c.h1), p2y(c.P1)); ctx.lineTo(h2x(c.h2), p2y(c.P2)); ctx.stroke(); // 2→3 condensation (horizontal à P2) ctx.strokeStyle = '#9333ea'; ctx.beginPath(); ctx.moveTo(h2x(c.h2), p2y(c.P2)); ctx.lineTo(h2x(c.h3), p2y(c.P2)); ctx.stroke(); // 3→4 détente isenthalpique (vertical) ctx.strokeStyle = '#6b7280'; ctx.setLineDash([6,4]); ctx.beginPath(); ctx.moveTo(h2x(c.h3), p2y(c.P2)); ctx.lineTo(h2x(c.h4), p2y(c.P1)); ctx.stroke(); ctx.setLineDash([]);
// Points + labels const points = [ {h:c.h1, P:c.P1, label:'1', title:'Sortie évap'}, {h:c.h2, P:c.P2, label:'2', title:'Sortie compresseur'}, {h:c.h3, P:c.P2, label:'3', title:'Sortie condenseur'}, {h:c.h4, P:c.P1, label:'4', title:'Après détente'} ]; points.forEach(p => { const x = h2x(p.h), y = p2y(p.P); ctx.fillStyle = '#dc2626'; ctx.beginPath(); ctx.arc(x, y, 7, 0, Math.PI*2); ctx.fill(); ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.stroke(); ctx.fillStyle = '#dc2626'; ctx.font = 'bold 14px sans-serif'; ctx.fillText(p.label, x + 12, y + 5); }); } }
/* ===== UI EVENTS ===== */ function update() { const f = document.getElementById('fluide').value; const Tevap = +document.getElementById('tevap').value; const Tcond = +document.getElementById('tcond').value; const dSurch = +document.getElementById('surch').value; const dSousR = +document.getElementById('sousr').value; const etaComp = +document.getElementById('eta').value / 100;
document.getElementById('tevap-val').textContent = Tevap + ' °C'; document.getElementById('tcond-val').textContent = '+' + Tcond + ' °C'; document.getElementById('surch-val').textContent = dSurch + ' K'; document.getElementById('sousr-val').textContent = dSousR + ' K'; document.getElementById('eta-val').textContent = (etaComp*100).toFixed(0) + ' %';
// Validate: Tevap < Tcond if (Tevap >= Tcond) { document.getElementById('cop').textContent = 'COP = — (T évap ≥ T cond invalide)'; currentCycle = null; render(); return; }
try { const c = calcCycle(f, Tevap, Tcond, dSurch, dSousR, etaComp); currentCycle = c; document.getElementById('p1').textContent = c.P1.toFixed(2) + ' bar'; document.getElementById('p2').textContent = c.P2.toFixed(2) + ' bar'; document.getElementById('ratio').textContent = (c.P2/c.P1).toFixed(2); document.getElementById('qf').textContent = c.qf.toFixed(1) + ' kJ/kg'; document.getElementById('wc').textContent = c.wc.toFixed(1) + ' kJ/kg'; document.getElementById('qc').textContent = c.qc.toFixed(1) + ' kJ/kg'; document.getElementById('cop').textContent = 'COP = ' + c.COP.toFixed(2); render(); } catch(e) { document.getElementById('cop').textContent = 'COP = — (erreur calc)'; currentCycle = null; render(); } }
['fluide','tevap','tcond','surch','sousr','eta'].forEach(id => { document.getElementById(id).addEventListener('input', update); document.getElementById(id).addEventListener('change', update); });
update();
À quoi sert le diagramme de Mollier ?
Le diagramme de Mollier (ou enthalpique) représente graphiquement les états thermodynamiques d’un fluide frigorigène sur un axe log(pression) vs enthalpie. Il permet aux frigoristes, techniciens PAC et étudiants en froid industriel de :
- Dimensionner un cycle frigorifique
- Calculer rapidement un COP théorique
- Comparer les performances entre fluides
- Valider un choix de fluide selon l’application (clim, PAC, chambre froide)
- Diagnostiquer des dérives (surchauffe anormale, sous-refroidissement insuffisant)
Lectures utiles
- Calculateur GWP des fluides frigorigènes
- Tableau pression-température des réfrigérants
- Fonctionnement d’un groupe froid — cycle frigorifique
- Quel gaz réfrigérant pour la climatisation en 2026
- Lexique frigoriste : 50 termes techniques
Précision : tables thermodynamiques compilées depuis NIST REFPROP et ASHRAE Handbook 2021, interpolation linéaire — précision ±2 % sur plage frigoriste usuelle. Pour calculs d’ingénierie précis, utiliser CoolProp ou NIST REFPROP.