[아두이노] 가변저항 튜너 + 저항 형태의 온도센서와 보정 필요성에 대한 이해


아두이노와 NTC 서미스터를 이용해 생육 챔버나 스마트팜용 온도계를 만들 때,
단순히 전압을 읽어 map() 함수로 변환하면 반드시 실패합니다. 우리의 목표는 온도->전압 함수의 정확한 역함수(전압->온도)를 구하는 것입니다.

정밀한 제어를 위해서는 다음 3단계 공정이 필요합니다:

하드웨어(가변저항) → 수학(로그) → 보정(투 포인트)

이 과정을
👉 "세상에 하나뿐인 나만의 정밀 자(Scale)를 만드는 과정"
으로 비유해 보겠습니다.


1️⃣ 가변저항: 눈금을 진하고 촘촘하게 (Resolution 확보)

가변저항을 조절하는 것은
👉 내가 보고 싶은 온도 구간에서 데이터 밀도를 높이는 작업입니다.

✔️ 엔지니어링 포인트

서미스터는 저항이 변하는 소자이므로 전압 분배 회로를 사용합니다.

Vout = Vcc × (R_thermistor / (R_fixed + R_thermistor))

이때,

  • R_fixed (가변저항)을 조절하면

  • 특정 온도 구간에서 전압 변화 폭이 달라집니다

👉 핵심 전략:

관심 온도 (예: 25°C)에서 ADC 값이 "중간값(≈512)" 근처가 되도록 조정

이렇게 하면:

  • 1°C당 더 많은 ADC 값을 사용하게 됨

  • 해상도(Resolution) 최대화


✔️ 비유

자 위의 눈금이 흐릿하면 측정 자체가 불가능합니다.

가변저항 조정은
👉 희미한 눈금을 진하고 촘촘하게 다시 그리는 작업

이 단계에서 우리는
👉 좋은 "생데이터"를 확보합니다.


2️⃣ 로그 보정: 휘어진 막대기를 반듯하게 (Linearization)

데이터를 촘촘하게 모았다고 끝이 아닙니다.

서미스터는 본질적으로 비선형 소자입니다.

👉 온도 vs 저항 관계:

R ∝ e^(1/T)

즉,

  • 온도가 올라갈수록 저항은 지수적으로 감소

  • 전압은 곡선 형태로 변화


✔️ 문제

  • 저온 영역 → 변화 큼

  • 고온 영역 → 변화 작음

👉 결과:

같은 1°C라도 구간마다 민감도가 다름


✔️ 해결 방법: 로그(Log) 변환

대표 공식: Steinhart-Hart Equation

1/T = A + B·ln(R) + C·(ln(R))^3

또는 단순화된 Beta 모델:

1/T = 1/T0 + (1/B)·ln(R/R0)

👉 로그를 취하면:

  • 지수 곡선 → 직선에 가까워짐

  • 전체 구간에서 균일한 감도 확보


✔️ 비유

자의 막대기 자체가 활처럼 휘어 있음

로그 보정은
👉 휘어진 막대를 일직선으로 펴는 작업

이제:

  • 형태는 완벽한 직선

  • 하지만 아직 "온도 값"은 없음


3️⃣ 투 포인트 보정: 숫자를 정확히 찍기 (Calibration)

수식이 완벽해도 실제 부품은 오차가 존재합니다.

👉 이유:

  • 제조 편차

  • B값 오차

  • ADC 오차


✔️ 해결 방법: 2점 보정 (Two-Point Calibration)

두 개의 기준점을 실제로 측정합니다.

기준점예시
저온 (T1)얼음물 (0°C)
고온 (T2)기준 온도계 (예: 40°C)

✔️ 보정 수식

선형 보정:

T_corrected = a × T_raw + b

계수 계산:

a = (T2 - T1) / (Raw2 - Raw1)
b = T1 - a × Raw1

✔️ 비유

이제 반듯한 막대기를 들고 표준 온도계 옆에 선다

그리고:

  • 0°C 위치에 "0" 표시

  • 40°C 위치에 "40" 표시

👉 이 과정이 바로 캘리브레이션


🎯 결론: 왜 이 3단계가 모두 필요한가?

이 중 하나라도 빠지면 실패합니다.


❌ 가변저항이 없으면

  • 데이터가 듬성듬성

  • 온도가 계단처럼 변함

👉 저해상도


❌ 로그 보정이 없으면

  • 중간 온도에서 오차 발생

👉 비선형 오차


❌ 투 포인트 보정이 없으면

  • 값이 실제 온도와 다름

👉 정확도 부족


✅ 핵심 요약

✔ 가변저항 → 밀도 확보
✔ 로그 → 형태 교정
✔ 보정 → 값 확정

👉 이 3단계를 거쳐야
진짜 "정밀 온도계"가 완성됩니다


💡 Tip (실전 구현)

#include <math.h>

// 캘리브레이션 데이터
const float T1 = 0.0;
const float T2 = 40.0;
const float Raw1 = 320.0;
const float Raw2 = 580.0;

float calibrate(float raw) {
  float a = (T2 - T1) / (Raw2 - Raw1);
  float b = T1 - a * Raw1;
  return a * raw + b;
}

👉 팁:

  • 캘리브레이션 값은 코드 상단에 상수로 관리

  • 유지보수 / 재보정이 매우 쉬워짐



🧪 [실험 코드] 서미스터 비선형 vs 로그 보정 비교

앞서 설명한 내용을 실제로 눈으로 확인해보기 위해
👉 NTC 서미스터의 비선형성과 로그 보정 효과를 시뮬레이션해보겠습니다.

이 코드는 다음 두 가지를 비교합니다:

  • ❌ 단순 선형 보정 (map 방식)

  • ✅ 로그 기반 보정 (Steinhart-Hart)


📌 전체 코드

import numpy as np
import matplotlib.pyplot as plt

# 1. 설정값 (NTC 서미스터 및 전압 분배 회로)
B_CONSTANT = 3950        # 서미스터 특성 계수 (B-constant)
R_NOMINAL = 10000        # 25도에서의 저항 (10kΩ)
T_NOMINAL = 25 + 273.15  # 기준 온도 (Kelvin)
R_FIXED = 1000           # 가변저항 설정 (비선형성 강조를 위해 낮게 설정)
V_IN = 5.0               # 입력 전압 (5V)

# 2. 온도 범위 설정 (0도 ~ 50도) → "실제 온도"
true_celsius = np.linspace(0, 50, 100)
true_kelvin = true_celsius + 273.15

# 3. 물리적 현상 시뮬레이션
# (온도 → 저항 → 전압)

# 서미스터 저항 (지수 함수)
r_sensor = R_NOMINAL * np.exp(
    B_CONSTANT * (1/true_kelvin - 1/T_NOMINAL)
)

# 전압 분배 (아두이노 A0 입력값)
v_out = V_IN * (r_sensor / (R_FIXED + r_sensor))


# 4. ❌ 보정 방식 A: 단순 선형 해석 (map 방식)

# 0도와 50도 기준으로 직선 매핑
v_start = v_out[0]   # 0°C 전압
v_end = v_out[-1]    # 50°C 전압

temp_linear = (v_out - v_start) * (50 - 0) / (v_end - v_start) + 0


# 5. ✅ 보정 방식 B: 로그 보정 (Steinhart-Hart / Beta 모델)

# 전압 → 저항 역산
r_calc = R_FIXED * (v_out / (V_IN - v_out))

# 로그 적용
inv_t = (1/T_NOMINAL) + (1/B_CONSTANT) * np.log(r_calc / R_NOMINAL)

# Kelvin → Celsius 변환
temp_log = (1/inv_t) - 273.15


# --- 그래프 시각화 ---
plt.figure(figsize=(14, 6))

# [왼쪽] 센서 자체의 비선형 출력
plt.subplot(1, 2, 1)
plt.plot(true_celsius, v_out, linewidth=2.5, label='Actual Sensor Output')

plt.title('Step 1: Sensor Output (Non-linear)')
plt.xlabel('Real Temperature (°C)')
plt.ylabel('Voltage (V)')
plt.grid(True, linestyle='--')
plt.legend()


# [오른쪽] 해석 방식 비교
plt.subplot(1, 2, 2)

# 로그 보정 (정확)
plt.plot(v_out, temp_log, linewidth=2.5,
         label='Logarithmic Calibration (Accurate)')

# 선형 보정 (오차 발생)
plt.plot(v_out, temp_linear, linestyle='--',
         linewidth=2,
         label='Simple Linear Mapping (Inaccurate)')

plt.title('Step 2: Linear vs Log Interpretation')
plt.xlabel('Input Voltage (V)')
plt.ylabel('Calculated Temperature (°C)')
plt.legend()
plt.grid(True, linestyle='--')

plt.tight_layout()
plt.show()

🔍 코드 해설 (핵심만)

1️⃣ 물리 모델

r_sensor = R_NOMINAL * np.exp(...)

👉 서미스터는 지수 함수 형태로 동작


2️⃣ 전압 변환

v_out = V_IN * (r_sensor / (R_FIXED + r_sensor))

👉 아두이노는 "전압"만 읽을 수 있기 때문에
👉 반드시 전압 분배 회로 필요


3️⃣ 선형 방식 (실패 사례)

temp_linear = ...

👉 map()과 동일한 방식
👉 양 끝은 맞지만 중간에서 틀어짐


4️⃣ 로그 방식 (정답)

np.log(...)

👉 지수 → 로그로 변환
👉 곡선을 직선으로 펴는 핵심 단계


📊 결과 해석

✔️ 왼쪽 그래프

👉 온도 vs 전압

  • 완벽한 직선 ❌

  • 곡선 형태 (비선형)


✔️ 오른쪽 그래프

👉 전압 → 온도 변환 결과

🔵 로그 보정

  • 실제 온도와 거의 일치

  • 전 구간 정확

🟢 선형 보정

  • 양 끝은 맞음

  • 중간 구간 오차 발생


🎯 핵심 결론

이 실험이 보여주는 것:

❌ map() → 틀린 온도계
✅ log() → 진짜 온도계


💡 실무에서 중요한 포인트

이 코드에서 일부러:

R_FIXED = 1000

👉 이렇게 낮게 설정한 이유:

  • 비선형을 더 극적으로 드러내기 위함

실제 설계에서는:

  • 측정 범위에 맞게 저항값 튜닝 필요


🚀 한 줄 요약

서미스터는 "전압 → 온도"가 아니라
"전압 → 저항 → 로그 → 온도" 순서로 풀어야 한다


끝.

댓글

이 블로그의 인기 게시물

공압 속도 제어: 미터인 vs 미터아웃

[PLC] 센서 NPN, PNP 출력 타입별 결선방법 (OMRON E2E-X 시리즈 3선식 배선)

NPN, PNP 트랜지스터 차이점

[주식] 한국거래소(KRX) 데이터 API 입문 가이드

[농사] 천연 식물성 살충제 종류 및 제조법

[PLC] PLC 아날로그 입출력 기본

[투자] ETF 투자 가이드 : 카테고리별 ETF 선택 전략

[농사] 토마토 수경재배 : 모종 이식 & 재배 간격

사각형의 넓이 공식의 증명

[전기 기초] 전력공식 P=VI 유도