센서 캘리브레이션, 왜 이렇게 시간이 걸리나

센서 캘리브레이션, 왜 이렇게 시간이 걸리나

센서 캘리브레이션, 왜 이렇게 시간이 걸리나

시작은 단순했다

프로젝트 킥오프 때 PM이 말했다. “온도 센서 하나 달고, 가속도 센서 하나 달면 되죠?” 그때 난 고개를 끄덕였다. 센서 데이터시트 보고 I2C 연결하면 끝이라고 생각했다. 2주면 충분하다고 보고했다.

지금 6주째다.

회의실에서 시연할 때였다. 온도를 보여주는데 25.3도가 나왔다. 실제 온도계는 23.1도. “2도 차이는 오차 범위 아닌가요?” PM이 물었다. 나는 대답했다. “데이터시트상 오차는 ±0.5도입니다.”

그날부터 캘리브레이션 지옥이 시작됐다.

데이터시트는 거짓말을 하지 않는다

데이터시트를 다시 읽었다. “Typical accuracy ±0.5°C”라고 적혀 있다. Typical이란 단어가 눈에 들어왔다. 각주를 봤다. “at 25°C, in ideal conditions”.

이상적 조건.

우리 제품은 영하 10도에서 영상 50도까지 써야 한다. 보드 위에는 MCU가 있고, 전원 IC가 있고, 다 발열한다. 센서 옆에 파워 LED가 있다. 켜지면 0.3도가 올라간다.

이상적이지 않다.

HW팀에 물었다. “센서 위치 옮길 수 있나요?” 답은 “레이아웃 다시 그려야 하는데요”였다. 양산 2달 남았다. 레이아웃 변경은 불가능하다.

결국 소프트웨어로 해결해야 한다. 캘리브레이션이다.

첫 번째 시도: 오프셋 보정

간단하게 생각했다. 실제값 - 측정값 = 오프셋. 이걸 빼주면 되지 않나.

항온 챔버를 빌렸다. 25도로 맞췄다. 센서는 27.2도를 가리킨다. 오프셋 -2.2도. 코드에 넣었다.

float get_calibrated_temp(void) {
    float raw = read_temp_sensor();
    return raw - 2.2;
}

다시 측정했다. 25.0도. 완벽하다.

PM에게 보여줬다. “이제 됩니다.” 다음 날 HW팀이 왔다. “0도에서 측정해봤는데 1.5도 차이 납니다.”

챔버를 0도로 맞췄다. 센서는 1.2도. 보정하면 -1.0도. 실제는 0도. 1도 차이다.

오프셋이 온도마다 다르다.

두 번째 시도: 선형 보정

고등학교 수학이 떠올랐다. 일차 함수. y = ax + b.

두 점을 측정했다. (0도, 1.2도), (25도, 27.2도). 기울기를 구했다. a = (27.2 - 1.2) / (25 - 0) = 1.04. 센서가 1.04배씩 틀린다.

float get_calibrated_temp(void) {
    float raw = read_temp_sensor();
    return (raw - 1.2) / 1.04;
}

0도에서 테스트. 0.0도. 25도에서 테스트. 25.1도. 완벽하다.

“이제 정말 됩니다.” PM에게 보고했다.

다음 주 HW팀이 또 왔다. “50도에서 측정해봤는데 2도 차이 납니다.”

챔버를 50도로 맞췄다. 센서는 52.8도. 보정하면 49.6도. 실제는 50도. 0.4도 차이.

선형이 아니다.

세 번째 시도: 다항식 보정

이차 함수를 써야 한다. y = ax² + bx + c.

세 점이 필요하다. 0도, 25도, 50도. 각각 측정했다. 연립방정식을 풀었다. 대학교 선형대수 교재를 꺼냈다. 행렬 계산기를 돌렸다.

계수가 나왔다. a = 0.00012, b = 1.038, c = -1.15.

float get_calibrated_temp(void) {
    float raw = read_temp_sensor();
    float corrected = 0.00012 * raw * raw + 1.038 * raw - 1.15;
    return corrected;
}

전 구간을 측정했다. 오차가 ±0.3도 이내다. 데이터시트보다 좋다.

성공했다고 생각했다.

문제는 개체차

양산 시제품이 왔다. 10개. 모두 측정했다.

1번: 0.2도 오차 2번: 0.8도 오차 3번: 1.3도 오차 … 10번: 0.5도 오차

센서마다 특성이 다르다. 당연하다. 반도체 공정은 완벽하지 않다. 같은 웨이퍼에서 나와도 다르다.

PM이 물었다. “양산할 때마다 캘리브레이션 하면 되지 않나요?”

양산 계획은 월 1만 개다. 하나당 3개 온도에서 10분씩 측정해야 한다. 30분 × 10,000개 = 5,000시간. 불가능하다.

“자동화하면요?” PM이 또 물었다.

챔버가 100만원이다. 10대 사면 1억. 공간도 필요하다. 인건비도 필요하다. 제품 원가가 3만원인데.

불가능하다.

네 번째 시도: 원포인트 캘리브레이션

다른 방법을 생각했다. 한 점만 측정하면 어떨까.

25도에서만 측정한다. 그 오차를 저장한다. 부팅할 때 불러온다. 전체 구간에 적용한다.

“25도는 어떻게 만드나요?” HW팀이 물었다.

에어컨 튼 사무실. 온도계 옆에 보드를 놓는다. 30분 기다린다. 25도 ±1도 정도는 된다. 정밀하진 않지만 대량 생산에선 현실적이다.

void factory_calibration(void) {
    float raw = read_temp_sensor();
    float offset = 25.0 - raw;  // 25도 기준
    write_flash(OFFSET_ADDR, &offset, sizeof(float));
}

float get_calibrated_temp(void) {
    float offset;
    read_flash(OFFSET_ADDR, &offset, sizeof(float));
    float raw = read_temp_sensor();
    return raw + offset;
}

10개 시제품에 적용했다. 전 구간 오차가 ±1도 이내다. 데이터시트보다 나쁘지만 스펙은 만족한다.

PM이 승인했다. 생산팀에 전달했다.

2주 후 생산팀에서 연락 왔다. “25도를 어떻게 확인하나요?”

가속도계는 더 복잡하다

온도 센서는 그나마 나았다. 가속도계는 차원이 다르다.

3축이다. X, Y, Z. 각각 오프셋이 있다. 각각 감도가 다르다. 축 간 크로스토크도 있다.

데이터시트를 봤다. “Factory calibrated”. 공장에서 보정했다고 한다. 믿었다.

보드를 평평하게 놓았다. Z축은 1g를 가리켜야 한다. 중력이니까.

측정값: 0.97g.

보드를 세웠다. X축이 1g를 가리켜야 한다.

측정값: 1.03g.

Factory calibrated라더니.

6면 캘리브레이션

방법을 찾았다. 보드를 6방향으로 놓는다. +X, -X, +Y, -Y, +Z, -Z. 각각 ±1g가 나와야 한다.

실제로 측정했다.

  • +X: 1.03g
  • -X: -0.98g
  • +Y: 1.01g
  • -Y: -0.99g
  • +Z: 0.97g
  • -Z: -1.02g

평균을 구했다. 오프셋을 구했다. 스케일을 구했다.

typedef struct {
    float offset_x, offset_y, offset_z;
    float scale_x, scale_y, scale_z;
} accel_calib_t;

void six_point_calibration(accel_calib_t *calib) {
    // 각 면에서 측정
    // 오프셋 = (max + min) / 2
    // 스케일 = 2.0 / (max - min)
    // 복잡한 계산...
}

한 개 보정하는데 10분 걸렸다. 각 면에서 안정화를 기다려야 한다. 정확히 수평을 맞춰야 한다.

양산은 불가능하다.

결국 타협

PM과 회의했다. “가속도계 정확도를 낮추면 안 될까요?”

스펙 문서를 다시 봤다. “가속도 정확도 ±5%”. 현재 오차는 ±3%. 스펙은 만족한다.

“그럼 캘리브레이션 안 해도 되는 거 아닌가요?” PM이 물었다.

“지금은 그렇습니다. 근데 센서 로트 바뀌면 또 모릅니다.”

“그럼요?”

“그때 다시 보겠습니다.”

엔지니어링의 현실이다. 완벽한 해답은 없다. 시간과 비용과 정확도의 균형이다.

배운 것들

6주간 배운 걸 정리했다.

  1. 데이터시트의 ‘Typical’은 ‘최선의 경우’다
  2. 센서마다 특성이 다르다
  3. 온도는 비선형이다
  4. 개체차는 피할 수 없다
  5. 양산성을 고려해야 한다
  6. 완벽한 캘리브레이션은 불가능하다
  7. 스펙을 만족하면 충분하다

책상 서랍에 노트를 넣었다. 온도 보정 공식, 측정 데이터, 시행착오가 빼곡하다. 다음 프로젝트에서 또 쓸 것이다.

센서는 항상 틀린다. 그걸 보정하는 게 내 일이다. 완벽할 순 없다. 하지만 쓸 만하게는 만들 수 있다.

그게 펌웨어 엔지니어가 하는 일이다.

다음 프로젝트

오늘 새 프로젝트 킥오프가 있었다. PM이 말했다. “이번엔 압력 센서도 들어갑니다.”

나는 데이터시트를 펼쳤다. “Typical accuracy ±2%“라고 적혀 있다.

각주를 봤다. “at 25°C, 1atm, in ideal conditions”.

한숨이 나왔다.

“캘리브레이션 일정 좀 넉넉히 잡아주세요.” 내가 말했다.

“얼마나요?” PM이 물었다.

“4주요.”

“2주면 안 될까요?”

또 시작이다.


센서는 거짓말쟁이다. 근데 우린 그걸 믿어야 한다. 보정하고, 측정하고, 또 보정한다. 결국 경험만 쌓인다.