본문 바로가기
Sensor/압력센서(Pressure)

고해상도 압력 센서 온도 보상 알고리즘 설계 및 구현

by linuxgo 2025. 8. 31.

1. 개요

본 문의 목적은 ADS124S08 고해상도 24-bit ΔΣ ADC와 STM32L432KC MCU를 기반으로 압력 센서의 출력 특성을 정확히 보정하는 데 있다. 압력 센서는 온도 변화에 따른 게인 및 오프셋 드리프트 현상을 나타내며, 이는 측정 정확도를 저하시킨다. 이를 해결하기 위해 본 문서에서는 ADS124S08 내장 온도 센서를 활용하여 추가 하드웨어 없이 온도를 동시에 측정하고, 정규화(Normalization) 및 다항식 모델링을 적용하여 온도 보정을 수행한다.

정규화 과정은 원시 ADC 데이터(\( V_{\text{raw}}, T_{\text{raw}} \))를 \([0, 1]\) 범위로 변환함으로써 수치적 안정성을 확보하고, Levenberg-Marquardt (LM) 알고리즘 기반의 계수 피팅 과정에서 효율적인 수렴을 가능하게 한다. 또한, STM32L432KC의 32-bit 부동소수점 연산 환경에서 계산 오차를 최소화하는 효과가 있다.

보정 모델은 2차 및 3차 다항식으로 제안되며, 2차 모델은 ±0.2~0.5% FSO 수준의 정확도를 제공하여 저전력·실시간 응용에 적합하고, 3차 모델은 ±0.1% FSO의 정밀도를 확보하여 고정밀 계측 응용에 적합하다. 본 문서에서는 -40°C ~ 125°C, 0 ~ 100 kPa 범위에서 15포인트(5 압력 × 3 온도) 데이터를 수집하고, 이를 기반으로 보정 계수를 도출하였다.

Keywords: Pressure Sensor (압력 센서), High-Resolution Measurement (고해상도 측정), Temperature Compensation (온도 보상), Polynomial Calibration (다항식 보정), Normalization (정규화), ADS124S08, STM32L432KC, Sensor Calibration Algorithm (센서 보정 알고리즘), Low-Power Embedded System (저전력 임베디드 시스템), High-Precision Measurement (고정밀 측정)

2. 데이터 정규화

입력 데이터(\( V_{\text{raw}}, T_{\text{raw}} \))는 24-bit ADC 값(0~16777215)으로, 큰 스케일로 인해 다항식 계산에서 수치적 오차 가능성이 있습니다. Min-Max 정규화를 적용하여 [0, 1] 범위로 변환:

\[ V_{\text{norm}} = \frac{V_{\text{raw}} - V_{\text{min}}}{V_{\text{max}} - V_{\text{min}}} \]

\[ T_{\text{norm}} = \frac{T_{\text{raw}} - T_{\text{min}}}{T_{\text{max}} - T_{\text{min}}} \]

  • \( V_{\text{min}}, V_{\text{max}} \): 압력 ADC 값의 최소/최대 (예: 838860, 6039797).
  • \( T_{\text{min}}, T_{\text{max}} \): 온도 ADC 값의 최소/최대 (예: 1677722, 3355444).
  • 출력(\( P_{\text{calibrated}}, T_{\text{calibrated}} \))은 물리 단위(kPa, °C) 유지.

 정규화

  • 수치적 안정성: \( V_{\text{raw}}^3 \approx 10^{21} \) 같은 큰 값은 부동소수점 오차 유발 가능. 정규화로 입력을 [0, 1]로 줄여 오차 감소.
  • 피팅 안정성: LM 알고리즘의 수렴 속도와 안정성 향상.
  • STM32L432KC: 32-bit float 연산에서 정밀도 개선.

3. 보정 모델

3.1. 온도 보정 (2차 다항식)

정규화된 온도 데이터(\( T_{\text{norm}} \))로 실제 온도(\( T_{\text{calibrated}} \)) 계산:

\[ T_{\text{calibrated}} = b_2 \cdot T_{\text{norm}}^2 + b_1 \cdot T_{\text{norm}} + b_0 \]

변수 설명

  • \( T_{\text{norm}} \): 정규화된 온도 ADC 값 ([0, 1]).
  • \( T_{\text{calibrated}} \): 보정된 온도 (°C).
  • \( T_{\text{ref}} \): 기준 온도 (25°C).
  • \( b_2, b_1, b_0 \): 계수 (정규화 후 스케일 조정).

ADS124S08 내장 온도 센서: 내부 다이오드 전압 변화, \( V_{\text{REF}} = 2.5V \), 24-bit ADC 출력. -40°C~125°C에서 약간의 비선형성(±0.5°C) 보상.

2차 다항식: 온도 센서의 비선형성은 2차로 충분히 모델링(±0.1°C 정확도).

정규화 효과: \( T_{\text{raw}} \approx 10^6 \) 대신 \( T_{\text{norm}} \in [0, 1] \)로, 계수 크기 균일화(예: \( b_2 \approx 10^2 \)).

예상 계수: \( b_2 \approx 10^2 \), \( b_1 \approx 10^2 \), \( b_0 \approx -40 \).

3.2. 압력 보정  (2차 및 3차 다항식)

정규화된 압력 데이터(\( V_{\text{norm}} \))와 보정된 온도(\( T \))로 압력(\( P_{\text{calibrated}} \)) 계산:

2차 다항식

\[ P_{\text{calibrated}} = a_2 \cdot V_{\text{norm}}^2 + a_1 \cdot V_{\text{norm}} + a_0 + [\text{Tcg}_2 \cdot (T - T_{\text{ref}})^2 + \text{Tcg}_1 \cdot (T - T_{\text{ref}})] \cdot V_{\text{norm}} + [\text{Tco}_2 \cdot (T - T_{\text{ref}})^2 + \text{Tco}_1 \cdot (T - T_{\text{ref}})] \]

3차 다항식

\[ P_{\text{calibrated}} = a_3 \cdot V_{\text{norm}}^3 + a_2 \cdot V_{\text{norm}}^2 + a_1 \cdot V_{\text{norm}} + a_0 + [\text{Tcg}_2 \cdot (T - T_{\text{ref}})^2 + \text{Tcg}_1 \cdot (T - T_{\text{ref}})] \cdot V_{\text{norm}} + [\text{Tco}_2 \cdot (T - T_{\text{ref}})^2 + \text{Tco}_1 \cdot (T - T_{\text{ref}})] \]

변수 설명

  • \( V_{\text{norm}} \): 정규화된 압력 ADC 값 ([0, 1]).
  • \( T \): 보정된 온도 (°C).
  • \( T_{\text{ref}} \): 기준 온도 (25°C).
  • \( P_{\text{calibrated}} \): 보정된 압력 (kPa).
  • \( a_3, a_2, a_1, a_0 \): 다항식 계수 (3차: \( a_3 \) 포함).
  • \( \text{Tcg}_2, \text{Tcg}_1 \): 게인 보상 계수.
  • \( \text{Tco}_2, \text{Tco}_1 \): 오프셋 보상 계수.

정규화: \( V_{\text{norm}} \in [0, 1] \)로, \( V_{\text{norm}}^3 \approx 1 \)이 되어 수치적 오차 감소. 계수 크기 균일화(예: \( a_3 \approx 10^2 \)).

2차 vs. 3차:

  • 2차: 0~100 kPa에서 ±0.2~0.5% FSO, 계산 단순, STM32L432KC 적합.
  • 3차: 고압력 비선형성 정밀 보상(±0.1% FSO), 고정밀 응용.

예상 계수:

  • 2차: \( a_2 \approx 10^2 \), \( a_1 \approx 10^2 \), \( a_0 \approx 0 \), \( \text{Tcg}_2, \text{Tcg}_1 \approx 10^{-1} \), \( \text{Tco}_2, \text{Tco}_1 \approx 10^0 \).
  • 3차: \( a_3 \approx 10^2 \), \( a_2, a_1, a_0, \text{Tcg}, \text{Tco} \) 유사.

4. 온도 보상 절차

4.1. 준비 단계

  • 하드웨어: ADS124S08 (24-bit, SPI, \( V_{\text{REF}} = 2.5V \)), STM32L432KC, Uncalibrated Pressure Sensor, 온도 챔버.
  • 소프트웨어: Python (NumPy, SciPy), STM32CubeIDE (HAL).
  • 인터페이스: SPI1 (PA4=CS, PA5=SCK, PA6=MISO, PA7=MOSI).

4.2. 캘리브레이션 데이터 수집

  • 압력: 0, 25, 50, 75, 100 kPa.
  • 온도: -40°C, 25°C, 125°C.
  • ADS124S08 설정: Sinc3 필터, 20 SPS, PGA=1, 내부 2.5V 참조.
  • 노이즈 처리: 100 샘플 평균화.

데이터 수집 코드 (STM32L432KC, ADS124S08):

#include "stm32l4xx_hal.h"

SPI_HandleTypeDef hspi1;

/* ADS124S08 레지스터 쓰기 */
void ads124s08_write_reg(uint8_t reg_addr, uint8_t data) {
    uint8_t tx_data[3] = {0x40 | (reg_addr & 0x1F), 0x00, data};
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, tx_data, 3, HAL_MAX_DELAY);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}

/* ADS124S08 레지스터 읽기 */
uint8_t ads124s08_read_reg(uint8_t reg_addr) {
    uint8_t tx_data[3] = {0x20 | (reg_addr & 0x1F), 0x00, 0x00};
    uint8_t rx_data[3];
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 3, HAL_MAX_DELAY);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    return rx_data[2];
}

/* ADS124S08 초기화 */
void ads124s08_init(void) {
    uint8_t reset_cmd[1] = {0x06};
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, reset_cmd, 1, HAL_MAX_DELAY);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    HAL_Delay(1);

    ads124s08_write_reg(0x02, 0x01); // INPMUX: AIN0/AIN1
    ads124s08_write_reg(0x03, 0x00); // PGA: Gain=1
    ads124s08_write_reg(0x04, 0x04); // DATARATE: 20 SPS, Sinc3
    ads124s08_write_reg(0x05, 0x20); // REF: 내부 2.5V
    ads124s08_write_reg(0x0A, 0x10); // SYS: 온도 센서 활성화
}

/* ADS124S08 데이터 읽기 */
uint32_t ads124s08_read_data(void) {
    uint8_t tx_data[3] = {0x12, 0x00, 0x00};
    uint8_t rx_data[3];
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 3, HAL_MAX_DELAY);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    return (rx_data[0] << 16) | (rx_data[1] << 8) | rx_data[2];
}

/* 압력 센서 데이터 수집 */
uint32_t read_pressure(void) {
    ads124s08_write_reg(0x02, 0x01);
    uint64_t sum = 0;
    uint32_t samples = 100;
    for (uint32_t i = 0; i < samples; i++) {
        while (!(ads124s08_read_reg(0x00) & 0x80));
        sum += ads124s08_read_data();
        HAL_Delay(50);
    }
    return (uint32_t)(sum / samples);
}

/* 온도 센서 데이터 수집 */
uint32_t read_temperature(void) {
    ads124s08_write_reg(0x02, 0xFF);
    ads124s08_write_reg(0x0A, 0x10);
    uint64_t sum = 0;
    uint32_t samples = 100;
    for (uint32_t i = 0; i < samples; i++) {
        while (!(ads124s08_read_reg(0x00) & 0x80));
        sum += ads124s08_read_data();
        HAL_Delay(50);
    }
    return (uint32_t)(sum / samples);
}
    

예시 데이터:

import numpy as np

data = np.array([
    [0,   -40,   838860,  1677722,   0, -40],
    [0,    25,   872415,  2516583,   0,  25],
    [0,   125,   905969,  3355444,   0, 125],
    [25,  -40,  2097152, 1677722,  25, -40],
    [25,   25,  2139095, 2516583,  25,  25],
    [25,  125,  2181038, 3355444,  25, 125],
    [50,  -40,  3355443, 1677722,  50, -40],
    [50,   25,  3439329, 2516583,  50,  25],
    [50,  125,  3523215, 3355444,  50, 125],
    [75,  -40,  4613734, 1677722,  75, -40],
    [75,   25,  4697620, 2516583,  75,  25],
    [75,  125,  4781506, 3355444,  75, 125],
    [100, -40,  5872025, 1677722, 100, -40],
    [100,  25,  5955911, 2516583, 100,  25],
    [100, 125,  6039797, 3355444, 100, 125]
])
V_raw = data[:, 2]
T_raw = data[:, 3]
P_ref = data[:, 4]
T_ref = data[:, 5]

# 정규화 파라미터
V_min, V_max = V_raw.min(), V_raw.max()
T_min, T_max = T_raw.min(), T_raw.max()
V_norm = (V_raw - V_min) / (V_max - V_min)
T_norm = (T_raw - T_min) / (T_max - T_min)
    

4.3. 온도 보정 계수 추출

공식: \( T_{\text{calibrated}} = b_2 \cdot T_{\text{norm}}^2 + b_1 \cdot T_{\text{norm}} + b_0 \).

방법: LM 알고리즘으로 \( T_{\text{norm}}, T_{\text{ref}} \) 피팅.

4.4. 압력 보정 계수 추출

공식: 2차/3차 다항식, \( V_{\text{norm}}, T_{\text{calibrated}} \).

방법: LM 알고리즘으로 피팅.

4.5. 계수 및 정규화 파라미터 MCU Flash 저장

#include "stm32l4xx_hal.h"

/* 정규화 파라미터 */
float norm_params[4] = {838860.0f, 6039797.0f, 1677722.0f, 3355444.0f}; // V_min, V_max, T_min, T_max
/* 계수 배열 */
float coeffs_2nd[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
float coeffs_3rd[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};

/* Flash에 저장 */
void save_coefficients(uint32_t address, float* data, uint8_t size) {
    HAL_FLASH_Unlock();
    for (int i = 0; i < size; i++) {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address + i*4, *(uint32_t*)&data[i]);
    }
    HAL_FLASH_Lock();
}
    

4.6. MCU 런타임 보정

#define T_REF 25.0f

/* 정규화 함수 */
float normalize(float x, float x_min, float x_max) {
    return (x - x_min) / (x_max - x_min);
}

/* 온도 보정 */
float correct_temperature(uint32_t T_raw) {
    float T_norm = normalize((float)T_raw, norm_params[2], norm_params[3]);
    float b2 = 100.0f; // 예시 계수
    float b1 = 165.0f;
    float b0 = -40.0f;
    return b2 * T_norm * T_norm + b1 * T_norm + b0;
}

/* 압력 보정: 2차 */
float correct_pressure_2nd(uint32_t V_raw, float T) {
    float V_norm = normalize((float)V_raw, norm_params[0], norm_params[1]);
    float a2 = coeffs_2nd[0];
    float a1 = coeffs_2nd[1];
    float a0 = coeffs_2nd[2];
    float Tcg2 = coeffs_2nd[3];
    float Tcg1 = coeffs_2nd[4];
    float Tco2 = coeffs_2nd[5];
    float Tco1 = coeffs_2nd[6];
    float T_diff = T - T_REF;
    return (a2 * V_norm * V_norm + a1 * V_norm + a0 +
            (Tcg2 * T_diff * T_diff + Tcg1 * T_diff) * V_norm +
            (Tco2 * T_diff * T_diff + Tco1 * T_diff));
}

/* 압력 보정: 3차 */
float correct_pressure_3rd(uint32_t V_raw, float T) {
    float V_norm = normalize((float)V_raw, norm_params[0], norm_params[1]);
    float a3 = coeffs_3rd[0];
    float a2 = coeffs_3rd[1];
    float a1 = coeffs_3rd[2];
    float a0 = coeffs_3rd[3];
    float Tcg2 = coeffs_3rd[4];
    float Tcg1 = coeffs_3rd[5];
    float Tco2 = coeffs_3rd[6];
    float Tco1 = coeffs_3rd[7];
    float T_diff = T - T_REF;
    return (a3 * V_norm * V_norm * V_norm + a2 * V_norm * V_norm + a1 * V_norm + a0 +
            (Tcg2 * T_diff * T_diff + Tcg1 * T_diff) * V_norm +
            (Tco2 * T_diff * T_diff + Tco1 * T_diff));
}
    

4.7. 검증

기준: 온도 ±0.1°C, 압력 2차(±0.2~0.5 kPa), 3차(±0.1 kPa).

4.8. 노이즈 관리

Sinc3 필터, 100 샘플 평균화, IIR 필터 (alpha=0.05).

float iir_filter(float new_sample, float prev_output, float alpha) {
    return alpha * new_sample + (1.0f - alpha) * prev_output;
}
    

5. 보정 계수 추출 파이썬 구현 코드

15포인트 데이터를 사용하여 온도 보정(2차)과 압력 보정(2차/3차)을 수행하고, 보상 전/후 검증

# 필요한 라이브러리 임포트
import numpy as np  # 배열 연산 및 수치 계산을 위한 라이브러리
from scipy.optimize import curve_fit  # LM 알고리즘을 사용한 계수 피팅
import matplotlib.pyplot as plt  # 그래프 생성을 위한 라이브러리

# 캘리브레이션 데이터: [P_ref, T_ref, V_raw, T_raw, P_ref, T_ref]
# 열: 참조 압력(kPa), 참조 온도(°C), 원시 압력 ADC, 원시 온도 ADC, 참조 압력, 참조 온도
data = np.array([
    [0,   -40,   838860,  1677722,   0, -40],
    [0,    25,   872415,  2516583,   0,  25],
    [0,   125,   905969,  3355444,   0, 125],
    [25,  -40,  2097152, 1677722,  25, -40],
    [25,   25,  2139095, 2516583,  25,  25],
    [25,  125,  2181038, 3355444,  25, 125],
    [50,  -40,  3355443, 1677722,  50, -40],
    [50,   25,  3439329, 2516583,  50,  25],
    [50,  125,  3523215, 3355444,  50, 125],
    [75,  -40,  4613734, 1677722,  75, -40],
    [75,   25,  4697620, 2516583,  75,  25],
    [75,  125,  4781506, 3355444,  75, 125],
    [100, -40,  5872025, 1677722, 100, -40],
    [100,  25,  5955911, 2516583, 100,  25],
    [100, 125,  6039797, 3355444, 100, 125]
])

# 데이터에서 필요한 열 추출
V_raw = data[:, 2]  # 원시 압력 ADC 값
T_raw = data[:, 3]  # 원시 온도 ADC 값
P_ref = data[:, 4]  # 참조 압력 (kPa)
T_ref = data[:, 5]  # 참조 온도 (°C)

# Min-Max 정규화: ADC 값을 [0, 1] 범위로 변환
V_min, V_max = V_raw.min(), V_raw.max()  # 압력 ADC 최소/최대
T_min, T_max = T_raw.min(), T_raw.max()  # 온도 ADC 최소/최대
V_norm = (V_raw - V_min) / (V_max - V_min)  # 정규화된 압력 데이터
T_norm = (T_raw - T_min) / (T_max - T_min)  # 정규화된 온도 데이터

# 기준 온도 상수 정의
T_REF = 25.0  # 기준 온도 (°C)

# 온도 보정 함수: 2차 다항식
# 입력: T_norm (정규화된 온도), 출력: T_calibrated (°C)
def temp_correction(T_norm, b2, b1, b0):
    return b2 * T_norm**2 + b1 * T_norm + b0

# 압력 보정 함수: 2차 다항식
# 입력: (V_norm, T), 출력: P_calibrated (kPa)
def sensor_correction_2nd(x, a2, a1, a0, Tcg2, Tcg1, Tco2, Tco1):
    V_norm, T = x  # 정규화된 압력과 보정된 온도
    T_diff = T - T_REF  # 기준 온도와의 차이
    return (a2 * V_norm**2 + a1 * V_norm + a0 +
            (Tcg2 * T_diff**2 + Tcg1 * T_diff) * V_norm +
            (Tco2 * T_diff**2 + Tco1 * T_diff))

# 압력 보정 함수: 3차 다항식
# 입력: (V_norm, T), 출력: P_calibrated (kPa)
def sensor_correction_3rd(x, a3, a2, a1, a0, Tcg2, Tcg1, Tco2, Tco1):
    V_norm, T = x  # 정규화된 압력과 보정된 온도
    T_diff = T - T_REF  # 기준 온도와의 차이
    return (a3 * V_norm**3 + a2 * V_norm**2 + a1 * V_norm + a0 +
            (Tcg2 * T_diff**2 + Tcg1 * T_diff) * V_norm +
            (Tco2 * T_diff**2 + Tco1 * T_diff))

# 온도 계수 피팅: LM 알고리즘으로 2차 다항식 계수 추출
popt_T, _ = curve_fit(temp_correction, T_norm, T_ref, p0=[0, 100, -40], method='lm')
b2, b1, b0 = popt_T  # 추출된 계수: b2, b1, b0
print("Temperature Coefficients (Normalized):")
print(f"b2: {b2:.6e}, b1: {b1:.6e}, b0: {b0:.6e}")

# 압력 계수 피팅: 2차 및 3차 다항식 계수 추출
popt_S2, _ = curve_fit(sensor_correction_2nd, (V_norm, T_ref), P_ref, p0=[0, 100, 0, 0, 0, 0, 0], method='lm')
popt_S3, _ = curve_fit(sensor_correction_3rd, (V_norm, T_ref), P_ref, p0=[0, 0, 100, 0, 0, 0, 0, 0], method='lm')
print("\n2nd Order Pressure Coefficients:", popt_S2)
print("3rd Order Pressure Coefficients:", popt_S3)

# 보정 결과 계산
T_pred = temp_correction(T_norm, *popt_T)  # 보정된 온도
P_pred_2nd = sensor_correction_2nd((V_norm, T_pred), *popt_S2)  # 2차 보정 압력
P_pred_3rd = sensor_correction_3rd((V_norm, T_pred), *popt_S3)  # 3차 보정 압력

# 보정 오차 출력
print("\nCalibration Errors:")
print("Temperature Error (°C):", np.abs(T_pred - T_ref))
print("2nd Order Pressure Error (kPa):", np.abs(P_pred_2nd - P_ref))
print("3rd Order Pressure Error (kPa):", np.abs(P_pred_3rd - P_ref))

# 원시 데이터 스케일링: 그래프를 위해 물리 단위로 변환
V_raw_scaled = (V_raw - V_min) / (V_max - V_min) * 100  # 0~100 kPa로 스케일링
T_raw_scaled = (T_raw - T_min) / (T_max - T_min) * 165 - 40  # -40~125°C로 스케일링

# 데이터 정렬: 그래프 가독성을 위해 T_ref와 P_ref 오름차순 정렬
sort_idx = np.argsort(T_ref)  # T_ref 기준 정렬 인덱스
T_ref_sorted = T_ref[sort_idx]
T_raw_scaled_sorted = T_raw_scaled[sort_idx]
T_pred_sorted = T_pred[sort_idx]

# 온도 보상 그래프 생성
plt.figure(figsize=(10, 6))  # 그래프 크기 설정 (10x6 인치)
plt.scatter(T_ref_sorted, T_raw_scaled_sorted, label='Raw Temperature (Scaled)', color='red', marker='x')
plt.scatter(T_ref_sorted, T_pred_sorted, label='Calibrated Temperature', color='blue', marker='o')
plt.plot(T_ref_sorted, T_ref_sorted, label='Reference Temperature', color='green', linestyle='--')
plt.xlabel('Reference Temperature (°C)')  # X축 라벨
plt.ylabel('Temperature (°C)')  # Y축 라벨
plt.title('Temperature Compensation')  # 그래프 제목
plt.legend()  # 범례 표시
plt.grid(True)  # 그리드 추가
plt.savefig('temperature_compensation.png')  # PNG 파일로 저장
plt.close()  # 메모리 정리

# 압력 보상 그래프 생성
plt.figure(figsize=(10, 6))  # 그래프 크기 설정
colors = {-40: 'blue', 25: 'green', 125: 'red'}  # 온도별 색상 정의
for temp in [-40, 25, 125]:
    idx = np.where(T_ref == temp)[0]  # 특정 온도에 해당하는 인덱스
    # P_ref 기준으로 정렬
    sort_idx = np.argsort(P_ref[idx])
    P_ref_sorted = P_ref[idx][sort_idx]
    V_raw_scaled_temp = V_raw_scaled[idx][sort_idx]
    P_pred_2nd_temp = P_pred_2nd[idx][sort_idx]
    P_pred_3rd_temp = P_pred_3rd[idx][sort_idx]
    plt.scatter(P_ref_sorted, V_raw_scaled_temp, label=f'Raw Pressure (T={temp}°C, Scaled)', marker='x', color=colors[temp])
    plt.scatter(P_ref_sorted, P_pred_2nd_temp, label=f'2nd Order Calibrated (T={temp}°C)', marker='o', color=colors[temp], alpha=0.6)
    plt.scatter(P_ref_sorted, P_pred_3rd_temp, label=f'3rd Order Calibrated (T={temp}°C)', marker='^', color=colors[temp], alpha=0.3)
plt.plot(P_ref, P_ref, label='Reference Pressure', color='black', linestyle='--')  # 참조 압력 기준선
plt.xlabel('Reference Pressure (kPa)')  # X축 라벨
plt.ylabel('Pressure (kPa)')  # Y축 라벨
plt.title('Pressure Compensation (2nd vs. 3rd Order)')  # 그래프 제목
plt.legend()  # 범례 표시
plt.grid(True)  # 그리드 추가
plt.savefig('pressure_compensation.png')  # PNG 파일로 저장
plt.close()  # 메모리 정리
    

그래프 설명:

  • Temperature Compensation:
    • X축: Reference Temperature (°C) (-40, 25, 125°C).
    • Y축: Temperature (°C).
    • 데이터: Raw Temperature (scaled), Calibrated Temperature, Reference Temperature.
    • 목적: 보정 후 \( T_{\text{calibrated}} \)가 \( T_{\text{ref}} \)와 일치하는지 확인.

  • Pressure Compensation :
    • X축: Reference Pressure (kPa) (0, 25, 50, 75, 100 kPa).
    • Y축: Pressure (kPa).
    • 데이터: Raw Pressure (scaled), Calibrated Pressure (2nd/3rd order), Reference Pressure.
    • 색상: -40°C (blue), 25°C (green), 125°C (red).
    • 목적: 2차/3차 다항식의 보정 정확도 비교, 온도별 드리프트 확인.

Pressure Sensor Calibraion

6. 결론

본 문서에서는 ADS124S08 내장 온도 센서와 STM32L432KC MCU를 이용하여 압력 센서의 온도 보상 방법을 제안하였다. 정규화를 통해 대규모 ADC 원시 데이터를 안정적으로 처리하였으며, LM 알고리즘 기반 계수 추출로 보정 모델을 구축하였다.

  • 정규화 효과: 입력 데이터를 [0, 1] 범위로 변환하여 수치적 안정성과 피팅 효율성을 크게 향상시켰다.
  • 온도 보상 성능: 2차 다항식 모델만으로도 ±0.1°C 수준의 보정이 가능하였다.
  • 압력 보상 성능:
    • 2차 다항식 모델은 ±0.2~0.5% FSO 수준의 정확도를 제공하여 저전력 및 일반 산업용 응용에 적합하였다.
    • 3차 다항식 모델은 ±0.1% FSO 이하의 정확도를 달성하여 정밀 계측 및 고신뢰성 응용에 적합함을 확인하였다.
  • 구현 용이성: STM32L432KC의 연산 능력으로 실시간 보정이 가능하며, Flash에 정규화 파라미터 및 계수를 저장하여 임베디드 환경에서도 안정적인 동작이 가능하다.

따라서 제안된 방법은 저전력·고정밀 압력 계측 시스템에 효과적으로 적용할 수 있으며, 향후에는 더 많은 캘리브레이션 포인트 확장, 비선형 머신러닝 모델 적용, 온도 히스테리시스 보상 등을 통해 성능을 한층 개선할 수 있을 것이다.

Keywords: Pressure Sensor (압력 센서), High-Resolution Measurement (고해상도 측정), Temperature Compensation (온도 보상), Polynomial Calibration (다항식 보정), Normalization (정규화), ADS124S08, STM32L432KC, Sensor Calibration Algorithm (센서 보정 알고리즘), Low-Power Embedded System (저전력 임베디드 시스템), High-Precision Measurement (고정밀 측정)