Back to Blog

Blog Post

이상기체 상태방정식(Ideal Gas Law)"과 "반데르발스 방정식(Van der Waals Equation)"의 실제 가스 거동 비교 분석

Published on June 24, 2026

화학공학의 "이상기체 상태방정식(Ideal Gas Law)"과 "반데르발스 방정식(Van der Waals Equation)"의 실제 가스 거동 비교 분석 문제입니다. 실험 데이터를 읽어와서 어떤 방정식이 실제 가스의 부피를 더 잘 예측하는지 NumPy로 피팅하고 Matplotlib으로 비교 시각화하는 공학적인 문제입니다.

이론 배경

이상기체 상태방정식은 실제 가스의 거동을 완전히 설명하지 못하므로, 가스 분자 자체의 부피(b)와 분자 간의 인력(a)을 보정한 반데르발스 방정식을 사용합니다.

  • 이상기체 상태방정식: P = \frac{RT}{V}

  • 반데르발스 방정식: P = \frac{RT}{V-b} - \frac{a}{V^2}

실험실에서 압력(P)에 따른 실제 이산화탄소(CO_2)의 몰부피(V) 데이터를 측정했다고 가정하고, 이를 선형 및 곡선 근사 기법을 통해 분석합니다.

수학적 수식 유도

실제 기체의 거동을 설명하는 대표적인 식 중 하나인 비리얼 상태방정식(Virial Equation of State)은 다음과 같이 압력(P)과 몰부피(V)의 관계를 전개합니다.

\frac{PV}{RT} = 1 + \frac{B}{V} + \frac{C}{V^2} + \dots

이 식의 양변을 V로 나누고, 1/V에 대한 식으로 정리를 하면 아래와 같은 구조가 됩니다. (고압 환경에서 압력 P에 따른 변화를 보기 위해 변형)

P = RT \cdot \left( \frac{1}{V} \right) + RT \cdot B \cdot \left( \frac{1}{V} \right)^2 + \dots

우리가 알고 싶은 것은 압력(P)을 넣었을 때의 부피(V)이므로, 위 식을 역으로 1/V에 대한 압력 P의 다항식 함수 형태(y = ax^2 + bx + c)로 근사화하게 됩니다.

\frac{1}{V} = a \cdot P^2 + b \cdot P + c최종적으로 나온 식을 이용하여 실험값을 대입 후, a, b, c를 구하면 부피의 역수와 압력 간의 2차 근사 함수를 구할 수 있습니다.

1. 데이터 파일 (3_data.csv)

일정한 온도(300\text{ K})에서 압력(Pressure, \text{atm})이 증가함에 따라 측정된 실제 이산화탄소 가스의 몰부피(Molar Volume, \text{L/mol}) 데이터입니다.

Pressure_atm,Molar_Vol_Lmol
1.0,24.34
5.0,4.78
10.0,2.31
20.0,1.08
40.0,0.48
60.0,0.29

2. 데이터 분석 및 시각화 코드(3_main.py)

이 코드는 실제 측정 데이터를 가져와 이상기체 공식과 비교하고, 더 정확한 예측을 위해 다항식 근사(polyfit)를 적용해 실제 가스 공식의 보정 계수를 유도하는 구조입니다.

아래 코드에서 ## 여기를 채워주세요 (두 곳)라고 씌여있는 부분을 실제 맞는 코드로 입력해 주세요. 이 후, 그래프가 출력되도록 디버깅 해 두세요.

import matplotlib.pyplot as plt
import numpy as np

class EngineeringDataReader:

    def __init__(self, file_path):
        self.file_path = file_path
        self.x = np.array([])
        self.y = np.array([])

    def load_data(self):
        temp_x = []
        temp_y = []
        try:
            with open(self.file_path, "r") as file:
                header = file.readline()
                for line in file:
                    parts = line.strip().split(",")
                    if len(parts) == 2:
                        temp_x.append(float(parts[0]))
                        temp_y.append(float(parts[1]))
            self.x = np.array(temp_x)
            self.y = np.array(temp_y)
            print(
                f"[SUCCESS] {self.file_path}에서 {len(self.x)}개의 데이터를 성공적으로 로드했습니다."
            )
        except FileNotFoundError:
            print(f"[ERROR] 파일이 존재하지 않습니다: {self.file_path}")
        return self.x, self.y


# 1. 데이터 로드 (X축: 압력 P, Y축: 실제 측정된 몰부피 V)
reader = EngineeringDataReader("3_data.csv")
pressure, real_volume = reader.load_data()

if len(pressure) > 0:
    # 기체 상수 R = 0.0821 L·atm/(mol·K), 실험 온도 T = 300 K
    R = 0.0821
    T = 300.0

    # 2. 이론적 모델 1: 이상기체 상태방정식 계산 (V = RT / P)
    ideal_volume = (R * T) / pressure

    # 3. NumPy 분석 (이론적 모델 2): 데이터 선형화 및 피팅
    # 고압 영역에서 부피의 역수(1/V)와 압력(P) 간의 비선형 관계를 보정하기 위해
    # 압력에 따른 실제 부피의 역수를 2차 다항식으로 피팅합니다.
    p_fit_a, p_fit_b, p_fit_c = np.polyfit(## 여기를 채워주세요)
    
    # 촘촘한 압력 데이터 생성 (그래프용)
    p_trend = np.linspace(1, 65, 150)
    # 이상기체 트렌드
    v_ideal_trend = (R * T) / p_trend
    # 2차 다항식으로 피팅된 실제 가스 역수 트렌드를 부피로 다시 환산
    v_fitted_trend = ## 여기를 채워주세요

    print("\n[ENCMP 100 공학 데이터 분석 결과]")
    print(f"  - 이상기체 예측 오차 (40 atm 지점): {abs(ideal_volume[4] - real_volume[4]):.3f} L/mol")
    print(f"  - 실제 데이터 기반 보정식 계수 [a, b, c]: {p_fit}")

    # 4. 예측 문제: 압력이 30.0 atm 일 때 실제 이산화탄소의 부피 예측
    target_p = 30.0
    pred_ideal = (R * T) / target_p
    pred_fitted = 1.0 / (p_fit_a*target_p**2 + p_fit_b*target_p + p_fit_c)

    print("\n[예측 문제 해결]")
    print(f"  - 질문: 압력이 {target_p} atm 일 때 예측 부피는?")
    print(f"  - 이상기체 모델 예측치: {pred_ideal:.3f} L/mol")
    print(f"  - 다항식 근사 모델 예측치 (실제 가스 근사): {pred_fitted:.3f} L/mol")

    # 5. Matplotlib 시각화 (두 모델과 실제 데이터 비교)
    plt.figure(figsize=(8, 5.5))

    # 1) 실제 실험 데이터 점
    plt.scatter(pressure, real_volume, color="black", s=60, zorder=5, label="Experimental Real $CO_2$ Data")

    # 2) 이상기체 상태방정식 곡선 (파란색 선)
    plt.plot(p_trend, v_ideal_trend, "b--", linewidth=1.5, label="Ideal Gas Law ($V = RT/P$)")

    # 3) 다항식 피팅으로 보정한 곡선 (빨간색 실선)
    plt.plot(p_trend, v_fitted_trend, "r-", linewidth=2, label="2nd-order Fitted Curve (Real Gas Model)")

    # 4) 30 atm 예측 지점 시각화 비교
    plt.scatter(target_p, pred_ideal, color="blue", marker="x", s=100, zorder=6, label="Ideal Gas Prediction at 30 atm")
    plt.scatter(target_p, pred_fitted, color="red", marker="*", s=150, zorder=6, label="Fitted Prediction at 30 atm")

    # 그래프 레이아웃 서식 설정
    plt.title("ENCMP 100: Gas Behavior Model Comparison", fontsize=14)
    plt.xlabel("Pressure $P$ (atm)", fontsize=12)
    plt.ylabel("Molar Volume $V$ (L/mol)", fontsize=12)
    plt.grid(True, linestyle=":", alpha=0.6)
    plt.yscale('log')  # 부피 변화 폭이 크므로 y축을 로그 스케일로 보면 공학적으로 훨씬 잘 보입니다.
    plt.legend(loc="upper right", fontsize=10)

    plt.show()
else:
    print("[ERROR] 데이터를 로드하지 못했습니다.")

Written by MiTornAve

Previous / Next

Previous: [3 - 2 FNN/ANFIS] 신경망에 '직관'을 이식하다: 학습하는 퍼지 시스템Next: 아레니우스 방정식(Arrhenius Equation)"을 이용한 속도 상수와 활성화 에너지() 도출 문제