요구사항 명세(SR) 학습 노트 목차

05. Predictive Climate — 하나의 Fan을 네 기능이 나눠 쓰는 법

출처: SR §6.4.2 (1. 목표 온도 기반 자동 공조 / 2. 실내 공기 순환 / 3. Predictive Pre-conditioning / 4. Fan 제어 기능 간 전환 / 5. Window 기반 자동 환기 / 6. Fan 동작 및 상태 확인 / 7. 오류 및 안전 동작) 관련 TBD: TBD-012a(목표 온도 범위 및 Fan 출력 전환 기준), TBD-012b(Window 기반 자동 환기 시작·종료 온습도 기준 및 최대 수행 시간), TBD-018(Predictive Climate Fan 제어 기준), TBD-010(자동 환기 기반 윈도우 닫힘 정책) 담당 노드: S32K144 Function Controller(공조 출력 장치 직접 제어) + Power Window Controller(환기용 윈도우 구동) + Sensing Controller(온·습도) + Vision(탑승자)


0. 이 절의 구조적 특징 — 자원 경합

§6.4.2가 다른 절과 근본적으로 다른 점이 있다. 하나의 물리 자원(Fan)을 여러 논리 기능이 공유한다.

다이어그램 로딩 중…

Fan은 하나뿐인데 이걸 요구하는 기능이 셋이다. 그래서 §6.4.2에는 **"4. Fan 제어 기능 간 전환"**이라는 소절이 통째로 존재한다. 다른 절에는 이런 게 없다.

그리고 네 번째 기능인 Window 기반 자동 환기는 Fan이 아니라 창문을 쓴다 — 즉 02편의 Power Window와 자원을 공유한다. 자원 경합이 절 경계를 넘어간다.


1. 목표 온도 기반 자동 공조

  • 사용자는 차량 내 HMI 및 모바일 인터페이스를 통해 목표 온도 기반 자동 공조 기능의 사용 여부를 설정할 수 있어야 한다.
  • 사용자는 차량 내 HMI 및 모바일 인터페이스를 통해 목표 온도를 설정할 수 있어야 한다.
  • 시스템은 목표 온도 기반 자동 공조 기능이 활성화된 경우 유효한 현재 실내 환경 정보와 설정된 목표 온도를 공조 판단에 반영해야 한다.
  • 시스템은 현재 실내 온도와 목표 온도의 차이에 따라 필요한 Fan 출력 수준을 결정해야 한다.
  • 시스템은 자동 공조에 사용되는 Fan 출력 수준을 OFF, LOW, MEDIUM, HIGH 로 구분해야 한다.
  • 시스템은 현재 실내 환경 또는 목표 온도가 변경된 경우 변경된 정보를 이후의 자동 공조 판단에 반영해야 한다.
  • 시스템은 목표 온도 기반 자동 공조 기능이 비활성화된 경우 해당 기능에 의한 자동 Fan 제어를 수행하지 않아야 한다.
  • 시스템은 목표 온도 기반 자동 공조 기능의 활성화 상태와 현재 실내 온도를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.

1-1. Fan 출력이 4단계 이산값이다

"시스템은 자동 공조에 사용되는 Fan 출력 수준을 OFF, LOW, MEDIUM, HIGH 로 구분해야 한다."

연속 PWM이 아니라 4단계 이산값으로 못 박았다. 왜?

이산 4단계연속 PWM
상태를 HMI에 표시하기 쉽다 (§6.4.2 "출력 수준을 차량 내 HMI에서 확인")"37 %"를 보여줘야 하나?
요구 출력과 실제 출력의 일치 판정이 명확하다 (§6.4.2 오류 조건)오차 허용 범위를 정의해야 함
전환이 이산적이라 사용자가 변화를 인지한다서서히 변하면 인지 못 함
상태 기계가 단순제어 루프 튜닝 필요

§6.4.2의 7번(오류 및 안전 동작)에 이런 요구사항이 있다.

"시스템은 요구된 Fan 출력 수준과 실제 Fan 상태가 일치하지 않는 경우 오류 상태로 처리해야 한다."

이 비교가 성립하려면 출력이 이산값이어야 한다. 연속 PWM이면 "37 % 요구, 35 % 실제"가 오류인지 아닌지 판정 기준을 따로 정해야 한다. 4단계면 requested == actual 한 줄로 끝난다.

1-2. 온도차 → Fan 출력 매핑

"시스템은 현재 실내 온도와 목표 온도의 차이에 따라 필요한 Fan 출력 수준을 결정해야 한다."

TBD-012a: "Predictive Climate 목표 온도 범위 및 Fan 출력 전환 기준 — 6.4 Function Controller 요구사항 기준으로 확정"

전환 기준에도 히스테리시스가 필요하다. 03편의 조도 판정과 같은 이유 — 경계에서 채터링하면 Fan이 LOW↔MEDIUM을 반복하며 소음이 거슬린다.

/* §6.4.2 — 온도차 기반 Fan 출력 결정 (TBD-012a) */
typedef enum { FAN_OFF = 0, FAN_LOW, FAN_MED, FAN_HIGH } fan_level_t;

/* 단계별 진입/이탈 임계 (0.1 °C 단위) — 히스테리시스 밴드 */
static const struct { int16_t up; int16_t down; } TH[] = {
    /* FAN_OFF  → LOW  */ { .up =  10, .down =   5 },   /* 1.0 °C 초과 시 LOW, 0.5 °C 미만 시 OFF */
    /* FAN_LOW  → MED  */ { .up =  30, .down =  20 },
    /* FAN_MED  → HIGH */ { .up =  60, .down =  45 },
};

static fan_level_t g_fan_req = FAN_OFF;

static fan_level_t decide_fan(int16_t cur_c10, int16_t target_c10, bool env_valid)
{
    /* §6.4.2 — 유효한 정보만 판단에 반영 */
    if (!env_valid) return g_fan_req;      /* 새 판단을 하지 않고 현 상태 유지 */

    int16_t diff = (int16_t)abs(cur_c10 - target_c10);

    /* 위로 올라갈 때는 up 임계, 내려올 때는 down 임계 */
    fan_level_t lv = g_fan_req;
    if (lv < FAN_HIGH && diff > TH[lv].up)          lv = (fan_level_t)(lv + 1);
    else if (lv > FAN_OFF && diff < TH[lv - 1].down) lv = (fan_level_t)(lv - 1);

    g_fan_req = lv;
    return lv;
}

한 번에 한 단계씩만 이동하는 게 포인트다. OFF에서 갑자기 HIGH로 뛰면 소음이 급격히 커져 놀란다. 그리고 단계별 히스테리시스가 각각 걸려 있어야 각 경계에서 안정적이다.

1-3. 활성화 상태가 판단 자체를 게이트한다

활성화된 경우  → 유효한 환경 정보와 목표 온도를 판단에 반영
비활성화된 경우 → 해당 기능에 의한 자동 Fan 제어를 수행하지 않는다

"해당 기능에 의한"이 중요하다. 자동 공조가 꺼져 있어도 Pre-conditioning이나 사용자 직접 조작에 의한 Fan 동작은 계속될 수 있다. 기능별로 게이트가 독립적이다.

이게 00편 패턴 B(freedom from interference)의 변형이다 — 오류가 아니라 사용자 설정에 의한 격리.


2. 실내 공기 순환

  • 사용자는 차량 내 HMI 를 통해 실내 공기 순환 Fan 의 출력 수준을 OFF, LOW, MEDIUM, HIGH 중에서 선택할 수 있어야 한다.
  • 시스템은 사용자가 선택한 유효한 Fan 출력 수준을 실내 공기 순환 동작에 반영해야 한다.
  • 시스템은 실내 공기 순환 중 사용자가 Fan 출력 수준을 변경한 경우 변경된 수준을 반영해야 한다.
  • 시스템은 사용자가 OFF 를 선택한 경우 실내 공기 순환에 의한 Fan 출력을 중지해야 한다.
  • 시스템은 현재 실내 공기 순환 Fan 출력 수준을 차량 내 HMI 에서 사용자가 확인할 수 있도록 해야 한다.

2-1. 이 기능만 "차량 내 HMI"로 한정된다

목표 온도 설정은 **"차량 내 HMI 및 모바일 인터페이스"**인데, 공기 순환 Fan 선택은 **"차량 내 HMI"**만이다.

왜? 공기 순환은 지금 차 안에 있는 사람을 위한 기능이기 때문이다. 원격으로 "지금 팬을 MEDIUM으로"는 의미가 없다. 반면 목표 온도는 미리 설정해 두면 도착했을 때 쾌적하므로 원격이 유용하다.

요구사항의 주어와 인터페이스 지정만으로 기능의 성격을 읽을 수 있다. SR을 읽을 때 이런 미세한 차이를 놓치지 않아야 한다.

2-2. 직접 제어와 자동 제어의 관계

이 기능은 사용자가 Fan 출력을 직접 지정한다. 자동 공조는 시스템이 결정한다. 둘이 동시에 Fan을 원하면? — 4절(Fan 제어 기능 간 전환)이 답한다.


3. Predictive Pre-conditioning

  • 시스템은 반복되는 차량 이용 정보를 기반으로 예상 탑승 시점을 판단해야 한다.
  • 시스템은 예상 탑승 시점과 유효한 현재 실내 환경 정보를 Predictive Pre-conditioning 필요 여부 판단에 사용해야 한다.
  • 시스템은 예상 탑승 시점 이전에 공조가 필요하다고 판단한 경우 Predictive Pre-conditioning 을 시작해야 한다.
  • 시스템은 Predictive Pre-conditioning 수행 중 현재 실내 환경과 설정된 목표 온도를 이용하여 필요한 Fan 출력 수준을 결정해야 한다.
  • 시스템은 Predictive Pre-conditioning 수행 중 실내 환경이 변경되어 변경된 정보를 이후의 공조 판단에 반영해야 한다.
  • 사용자는 차량 내 HMI 및 모바일 인터페이스를 통해 수행 중인 Predictive Pre-conditioning 을 정지할 수 있어야 한다.
  • 시스템은 사용자의 유효한 정지 요청이 확인된 경우 Predictive Pre-conditioning 에 의한 Fan 제어를 종료해야 한다.
  • 시스템은 Predictive Pre-conditioning 의 수행 상태를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.

3-1. "반복되는 차량 이용 정보"가 이 기능의 전부다

"시스템은 반복되는 차량 이용 정보를 기반으로 예상 탑승 시점을 판단해야 한다."

패턴 학습이다. 매일 아침 8시에 차를 타는 사용자면, 7시 50분에 미리 공조를 시작한다.

무엇을 기록해야 하는가?

/* 요일 × 시간대 히스토그램 — 가장 단순하고 견고한 방법 */
#define SLOT_MIN   15u                       /* 15분 단위 */
#define SLOTS_PER_DAY (24u * 60u / SLOT_MIN) /* 96 슬롯 */

typedef struct {
    uint8_t count[7][SLOTS_PER_DAY];   /* 요일별·슬롯별 탑승 횟수 */
    uint8_t weeks_observed;
} usage_hist_t;

/* 탑승 이벤트 기록 — 도어 열림 + 시동 등으로 판정 */
static void usage_record(usage_hist_t *h, uint8_t dow, uint16_t minute_of_day)
{
    uint8_t slot = (uint8_t)(minute_of_day / SLOT_MIN);
    if (h->count[dow][slot] < 255u) h->count[dow][slot]++;
}

/* 예상 탑승 시점 판단 — 임계 횟수 이상 반복된 슬롯 */
static bool usage_predicts(const usage_hist_t *h, uint8_t dow, uint8_t slot)
{
    return h->count[dow][slot] >= PREDICT_MIN_COUNT;   /* 예: 3주 연속 */
}

요일을 분리하는 게 중요하다. 평일 8시와 주말 8시는 완전히 다른 패턴이다. 요일 없이 시간만 보면 주말 아침마다 헛되이 공조를 돌린다.

함정 — 학습 데이터가 없을 때 차를 처음 산 사용자는 히스토그램이 비어 있다. 이때 Pre-conditioning동작하지 않아야 한다. 근거 없는 예측으로 배터리를 쓰면 안 된다. 위 코드의 PREDICT_MIN_COUNT가 그 방어다. 그리고 사용 패턴이 바뀌면(이직, 이사) 오래된 데이터가 방해한다. 실무에서는 지수 감쇠(exponential decay)를 넣어 최근 데이터에 가중치를 준다.

3-2. 사용자 정지가 명시적 요구사항이다

사용자는 … 수행 중인 Predictive Pre-conditioning 을 정지할 수 있어야 한다.
시스템은 사용자의 유효한 정지 요청이 확인된 경우 … Fan 제어를 종료해야 한다.

시스템이 스스로 시작한 동작은 사용자가 멈출 수 있어야 한다. 이건 자율 동작을 갖는 모든 기능의 기본 원칙이다.

Pre-conditioning은 사용자가 차 밖에 있을 때 시작된다. 배터리를 쓰고 소음을 낸다. 사용자가 "오늘은 안 탈 건데"라고 판단하면 멈출 수 있어야 한다.


4. Fan 제어 기능 간 전환 — 이 절의 핵심

  • 시스템은 Fan 을 사용하는 기능이 수행 중인 상태에서 다른 Fan 제어 기능의 새로운 유효한 사용자 요청이 확인된 경우 기존 Fan 제어 동작을 종료하고 새로운 사용자 요청을 반영해야 한다.
  • 시스템은 사용자의 새로운 유효한 Fan 제어 요청을 수행 중인 Predictive Pre-conditioning 보다 우선하여 처리해야 한다.
  • 시스템은 새로운 Fan 제어 기능으로 전환된 이후 이전 기능의 Fan 출력을 자동으로 재개하지 않아야 한다.

4-1. 세 문장이 만드는 규칙

다이어그램 로딩 중…

**소유권 모델(ownership model)**이다. 어느 순간 Fan의 소유자는 정확히 하나다.

typedef enum {
    FAN_OWNER_NONE = 0,
    FAN_OWNER_AUTO_CLIMATE,   /* 목표 온도 기반 자동 공조 */
    FAN_OWNER_MANUAL,         /* 실내 공기 순환 — 사용자 직접 */
    FAN_OWNER_PRECOND,        /* Predictive Pre-conditioning */
} fan_owner_t;

static fan_owner_t g_fan_owner = FAN_OWNER_NONE;
static fan_level_t g_fan_level = FAN_OFF;

/* §6.4.2 — Fan 제어 기능 간 전환 */
static bool fan_claim(fan_owner_t who, fan_level_t lv, bool is_user_request)
{
    /* 사용자 요청은 Pre-conditioning 보다 우선 */
    if (g_fan_owner == FAN_OWNER_PRECOND && is_user_request) {
        precond_terminate();              /* 기존 기능을 종료 — 일시정지가 아니다 */
    }
    else if (g_fan_owner != FAN_OWNER_NONE && g_fan_owner != who) {
        if (!is_user_request) return false;   /* 비사용자 요청은 기존 소유자를 못 뺏는다 */
        fan_owner_terminate(g_fan_owner);
    }

    g_fan_owner = who;
    g_fan_level = lv;
    fan_output_apply(lv);
    return true;
}

4-2. "종료"이지 "일시정지"가 아니다

세 번째 문장이 이걸 못 박는다.

"시스템은 새로운 Fan 제어 기능으로 전환된 이후 이전 기능의 Fan 출력을 자동으로 재개하지 않아야 한다."

00편 패턴 C다. 구현상 이건 이전 기능의 상태를 저장해 두지 말라는 뜻이다.

/* ✗ 이렇게 하면 요구사항 위반 */
static fan_level_t g_saved_level;
static fan_owner_t g_saved_owner;

void fan_release(void) {
    g_fan_owner = g_saved_owner;      /* 자동 재개 — 금지 */
    fan_output_apply(g_saved_level);
}

/* ✓ 종료는 종료다 */
static void fan_owner_terminate(fan_owner_t who) {
    switch (who) {
    case FAN_OWNER_PRECOND:      precond_state = PRECOND_ENDED; break;
    case FAN_OWNER_AUTO_CLIMATE: /* 기능은 켜져 있지만 이번 판단 사이클은 끝 */ break;
    case FAN_OWNER_MANUAL:       manual_level = FAN_OFF;        break;
    default: break;
    }
}

단, 자동 공조는 미묘하다. 사용자가 수동으로 Fan을 조작해서 자동 공조가 종료됐다. 그런데 자동 공조 기능 자체는 여전히 "활성화" 상태다. 다음 판단 사이클에서 다시 Fan을 요구할 것인가?

SR 문장만으로는 확정할 수 없다. "자동 재개하지 않는다"를 어디까지 적용하는가가 설계 문의 대상이다. 합리적 해석은:

  • 사용자 수동 조작은 명시적 의도이므로, 자동 공조가 그걸 즉시 덮어쓰면 안 된다
  • 따라서 사용자 조작 이후에는 자동 공조를 비활성화하거나, 최소한 상당 시간 억제해야 한다
  • 이게 실제 차량 공조 UX와도 일치한다 (AUTO 버튼을 눌러야 자동으로 돌아온다)

5. Window 기반 자동 환기

  • 사용자는 차량 내 HMI 를 통해 Window 기반 자동 환기 기능의 사용 여부를 설정할 수 있어야 한다.
  • 시스템은 Window 기반 자동 환기 기능이 비활성화된 경우 새로운 자동 환기 필요 여부 판단을 수행하지 않아야 한다.
  • 시스템은 유효한 실내 온도 및 습도 정보를 Window 기반 자동 환기 필요 여부 판단에 사용해야 한다.
  • 시스템은 유효한 탑승자 정보를 확인하고, 실내 탑승자가 없는 경우에만 Window 기반 자동 환기 필요 여부를 판단해야 한다.
  • 시스템은 자동 환기 판단에 필요한 실내 환경 정보 또는 탑승자 정보를 신뢰할 수 없는 경우 해당 정보에 기반한 새로운 자동 환기 판단을 수행하지 않아야 한다.
  • 시스템은 정의된 자동 환기 시작 조건이 충족된 경우 Power Window 기능에 정의된 환기 위치를 목표로 하는 열림 동작을 요청해야 한다.
  • 시스템은 정의된 자동 환기 종료 조건이 충족된 경우 Power Window 기능에 Window 닫힘 동작을 요청해야 한다.
  • 시스템은 Window 기반 자동 환기 수행 중 자동 환기 허용 조건이 더 이상 충족되지 않는 경우 자동 환기 동작을 종료해야 한다.
  • 시스템은 전용 윈도우 스위치, 정지 요청 또는 Anti-pinch 보호 동작에 의해 자동 환기 기반 윈도우 동작이 중단된 경우 해당 자동 환기 동작을 종료해야 한다.
  • 시스템은 중단된 Window 기반 자동 환기 동작을 새로운 유효한 자동 환기 판단 없이 자동으로 재개하지 않아야 한다.
  • 시스템은 Window 기반 자동 환기 기능의 활성화 상태와 현재 동작 상태를 차량 내 HMI 에서 사용자가 확인할 수 있도록 해야 한다.
  • 시스템은 자동 환기 종료를 위한 Window 닫힘 동작이 Power Window 기능의 안전 조건 또는 닫힘 허용 조건에 의해 수행되지 않은 경우 해당 자동 환기를 정상 완료로 처리하지 않아야 한다.

5-1. "탑승자가 없는 경우에만"

"시스템은 유효한 탑승자 정보를 확인하고, 실내 탑승자가 없는 경우에만 Window 기반 자동 환기 필요 여부를 판단해야 한다."

사람이 타고 있으면 창문을 자동으로 열지 않는다. 이유:

  1. 탑승자가 있으면 공조(Fan)를 쓰면 된다. 창문을 여는 건 사람이 없을 때의 대안이다.
  2. 주행 중 창문이 저절로 열리면 위험하고 놀란다.
  3. 탑승자의 의사를 무시하는 동작이다.

이건 03편에서 본 **"실내 고온 + 탑승자 부재 = 실내 환경 개선 필요"**의 구현이다. 부재 조건이 두 절에 걸쳐 일관되게 유지된다.

5-2. 요청과 실행이 분리돼 있다

자동 환기 시작 조건 충족  →  Power Window 기능에 "정의된 환기 위치를 목표로 하는 열림 동작을 요청"
자동 환기 종료 조건 충족  →  Power Window 기능에 "Window 닫힘 동작을 요청"

**"수행해야 한다"가 아니라 "요청해야 한다"**이다. Predictive Climate는 창문을 직접 움직일 권한이 없다 — §7.2의 "Window Motor 는 Power Window Controller 만 직접 제어한다"가 여기서 문장 형태로 나타난다.

그리고 02편의 §6.2.1 우선순위에서 자동 환기가 최하위였다. 요청해도 거부될 수 있다.

5-3. 마지막 요구사항이 이 절에서 가장 정교하다

"시스템은 자동 환기 종료를 위한 Window 닫힘 동작이 Power Window 기능의 안전 조건 또는 닫힘 허용 조건에 의해 수행되지 않은 경우 해당 자동 환기를 정상 완료로 처리하지 않아야 한다."

시나리오를 그려 보자.

다이어그램 로딩 중…

창문이 열린 채로 남았는데 "환기 완료"라고 표시하면 사용자는 차가 잠겨 있다고 믿는다. 비가 오거나 도난당한다.

이 요구사항은 분산 시스템에서 하위 기능의 실패를 상위 기능이 흡수하지 않고 정직하게 전파하라는 요구다. 소프트웨어 공학 일반 원칙(실패를 삼키지 마라)이 안전 요구사항으로 표현된 사례.

TBD-010이 여기 걸려 있다: "원격·원터치·자동 환기 기반 윈도우 닫힘 정책 — 적용 법규 및 데모 안전 조건 기준 확정. 참조 절: §6.2.2, §6.4.2".

두 절을 동시에 참조하는 유일한 TBD다. 즉 이 정책은 Power Window와 Predictive Climate 양쪽 요구사항을 함께 확정해야 한다.

5-4. 중단 → 종료 → 재개 금지의 3단 논리

전용 윈도우 스위치 / 정지 요청 / Anti-pinch 에 의해 윈도우 동작 중단
  → 자동 환기 동작을 종료한다                        (기능 레벨 종료)
  → 새로운 유효한 자동 환기 판단 없이 자동 재개하지 않는다  (재시작 금지)

창문만 멈추는 게 아니라 상위 기능이 꺼진다. 이게 02편 꼬리질문 6번의 답이다.

왜 이렇게 강한가? 사용자가 스위치로 창문을 닫았다는 건 **"환기하지 마"**라는 의사 표현이다. 창문만 멈추고 자동 환기 기능이 살아 있으면, 잠시 후 다시 창문이 열린다. 사용자와 시스템이 싸우게 된다.

TBD-012b: "Window 기반 자동 환기 시작·종료 온습도 기준 및 최대 수행 시간 — Predictive Climate 의 Window 기반 자동 환기 요구사항 기준으로 확정".

**"최대 수행 시간"**이 있다는 게 중요하다. 온도가 안 떨어지면 창문이 무한히 열려 있게 되므로, 상한이 필요하다.


6. Fan 동작 및 상태 확인

  • 시스템은 현재 활성화된 Predictive Climate 기능에서 결정된 유효한 Fan 출력 수준을 실제 Fan 동작에 반영해야 한다.
  • 시스템은 실제 Fan 동작 상태를 OFF, LOW, MEDIUM, HIGH 로 구분하여 관리해야 한다.
  • 시스템은 실제 Fan 동작 상태를 확인할 수 있어야 한다.
  • 시스템은 현재 Fan 동작 상태와 출력 수준을 차량 내 HMI 에서 사용자가 확인할 수 있도록 해야 한다.

6-1. "요구 출력"과 "실제 상태"가 별도 변수다

결정된 유효한 Fan 출력 수준  ← 요구 (requested)
실제 Fan 동작 상태            ← 실측 (actual)

이 둘을 분리해야 §6.4.2의 7번 오류 조건이 성립한다.

"시스템은 요구된 Fan 출력 수준과 실제 Fan 상태가 일치하지 않는 경우 오류 상태로 처리해야 한다."

typedef struct {
    fan_level_t requested;      /* 기능이 요구한 수준 */
    fan_level_t actual;         /* 실측된 수준 */
    bool        actual_trusted; /* 실측 가능한가 */
    uint32_t    mismatch_since_ms;
} fan_status_t;

/* §6.4.2 — 요구와 실제의 불일치 감시 */
#define FAN_MISMATCH_TOLERANCE_MS  1500u   /* 전환 과도 구간 허용 */

static bool fan_fault(fan_status_t *s)
{
    if (!s->actual_trusted) return true;    /* 실제 상태를 확인 못 함 → 정상 처리 금지 */

    if (s->requested == s->actual) { s->mismatch_since_ms = 0; return false; }

    /* 전환 직후 짧은 불일치는 정상 — 팬이 가속/감속하는 시간 */
    if (s->mismatch_since_ms == 0) { s->mismatch_since_ms = hal_now_ms(); return false; }
    return (hal_now_ms() - s->mismatch_since_ms) > FAN_MISMATCH_TOLERANCE_MS;
}

허용 시간(tolerance)이 필요한 이유: 요구를 OFF→HIGH로 바꾼 순간 실제 팬은 아직 정지 상태다. 회전수가 올라가는 데 시간이 걸린다. 즉시 불일치로 판정하면 매 전환마다 오류가 뜬다.

6-2. 실제 Fan 상태를 어떻게 아는가

방법원리특징
전류 측정팬 부하 전류가 출력 수준에 비례추가 부품 적음. 팬 개체차·전압 변동에 영향받음
회전수 신호(tach)팬 내장 홀 센서의 펄스정확. 팬이 tach 출력을 지원해야 함
역기전력PWM OFF 구간의 BEMF 측정부품 없음. 회로·타이밍 까다로움

TBD-018이 "Predictive Climate Fan 제어 기준 — OFF/LOW/MEDIUM/HIGH 전환 조건 및 실제 출력 기준 확정"으로 남겨 뒀다. **"실제 출력 기준"**이라는 표현이 이 측정 방식 결정을 포함한다.


7. 하드웨어 구현 — 온도 장치와 실측

⚠️ 이 절은 SR 에 없다. §6.4.2 는 Fan 출력 수준만 정의하고 가열·냉각 소자를 정의하지 않는다. 그런데 팬은 공기를 순환시킬 뿐이라 목표 온도에 도달시키지 못한다 — 실제로 구현하려면 필연적으로 필요한 부품이고, 여기에 그 설계를 정리한다.

7-1. 히터인가 펠티어인가

히터 (저항)펠티어 (TEC)
할 수 있는 것가열만가열 + 냉각
원리전류를 흘리면 열이 난다전류 방향에 따라 한쪽이 차가워지고 반대쪽이 뜨거워진다
필요한 회로MOSFET 1개H-브리지 (스위치 4개)
PWM 채널1개2개 (양방향)
전류설계하기 나름크다 (TEC1-12706 이 12 V 6 A)
추가 부품없음방열판 + 방열팬 필수

펠티어를 택하면 §6.4.2-1 의 목표 온도 자동 공조를 온전히 구현할 수 있다. 히터만이면 목표보다 추울 때만 대응 가능해 반쪽이 된다.

7-2. 방열이 1순위다

펠티어열을 없애지 않고 옮긴다.

뜨거운 면이 버려야 할 열 = 차가운 면에서 퍼낸 열 + 소자가 소비한 전력
        Qh              =          Qc           +         P

12 V × 6 A = 72 W 를 먹으면서 30 W 를 냉각하면, 뜨거운 면에서 100 W 이상을 빼내야 한다. 데스크탑 CPU 쿨러급이다.

구성열저항100 W 버릴 때 온도 상승
방열판 + 자연 대류약 1~2 ℃/W100~200 ℃ → 소자 사망
방열판 + 팬약 0.1~0.3 ℃/W20~30 ℃

방열이 부족하면 뜨거운 면 온도가 올라 유지 가능한 온도차가 소진되고, 차가운 면도 안 차가워진다. 최악의 경우 내부 납땜이 녹아(130~140 ℃ 대) 소자가 영구 파괴된다.

시연 구성도 여기서 결정된다 — 모사 캐빈 안쪽에 차가운 면, 바깥에 뜨거운 면 + 방열팬. 닫힌 상자 안에 다 넣으면 전체 온도만 올라간다.

7-3. 방열팬은 공조 팬과 별개다

공조 팬방열팬
위치모사 캐빈 안펠티어 뜨거운 면 (캐빈 밖)
SR 근거§6.4.2 에 있음없음 — 펠티어 때문에 생긴 부품
제어OFF/LOW/MED/HIGH, 사용자 설정펠티어가 켜지면 무조건 최대

둘을 같은 팬으로 쓰면 소자가 죽는다. §6.4.2 는 Fan 출력에 OFF 를 포함하므로, 사용자가 OFF 를 선택하는 순간 방열이 끊기는데 펠티어는 목표 온도를 향해 계속 돌고 있다.

if (!fan_heatsink_running()) { tec_stop(FAULT_TEC_NO_HEATSINK_FAN); return; }

안전 메커니즘의 가용성이 기능의 전제 조건이라는 점에서, §6.2.2 의 "Anti-pinch 를 사용할 수 없는 경우 닫힘 동작을 시작하지 않아야 한다"와 똑같은 구조다.

7-4. H-브리지와 데드타임

극성을 바꾸려면 H-브리지가 필요하고, 위·아래 스위치가 순간이라도 동시에 켜지면 전원이 GND 로 직결(shoot-through)되어 MOSFET 이 즉시 탄다. 그 사이에 두는 짧은 공백이 **데드타임**이다.

S32K144 의 FTM 이 하드웨어로 넣어 준다.

FTM2->COMBINE = FTM_COMBINE_COMBINE0_MASK    /* 채널쌍 결합 */
              | FTM_COMBINE_COMP0_MASK       /* 상보 출력 */
              | FTM_COMBINE_DTEN0_MASK       /* 데드타임 삽입 */
              | FTM_COMBINE_SYNCEN0_MASK;

/* DTPS = ÷4 → 1카운트 = 50 ns, DTVAL = 20 → 1 µs */
FTM2->DEADTIME = FTM_DEADTIME_DTPS(0b10) | FTM_DEADTIME_DTVAL(20);

소프트웨어로 만들면 안 된다 — 지연이 인터럽트에 밀리면 그 순간 관통 전류가 흐른다. 그리고 1 µs 는 출발점일 뿐이고 오실로스코프로 게이트 파형이 겹치지 않는지 확인해야 한다.

구동 방식은 Sign-magnitude 로 간다.

정방향(냉각)  S1 상시 ON, S4 에 PWM
역방향(가열)  S2 상시 ON, S3 에 PWM

Locked anti-phase 는 출력 0 일 때도 전류가 좌우로 흐르며 줄열만 낸다 — 냉각은 안 되고 열만 나는 최악의 상태다.

7-5. PWM 구동은 효율을 떨어뜨린다

냉각 능력 ∝ I,   줄열(손실) ∝ I²

PWM(듀티 D):  냉각 ∝ D·I,  줄열 ∝ D·I²
DC  (듀티 D):  냉각 ∝ D·I,  줄열 ∝ (D·I)² = D²·I²   ← PWM 보다 D 배 작다

듀티 50 % 면 PWM 이 DC 보다 줄열을 2배 낸다. 같은 냉각에 열이 두 배 나오니 효율이 절반이다. 인덕터로 평활하면(사실상 벅 컨버터) 개선되지만 프로토타입에서는 감수하고 문서화하는 게 현실적이다.

다만 주파수를 1 Hz 급으로 낮추면 안 된다 — 소자 내부에 열 사이클링이 걸려 수명이 깎인다. 1~5 kHz 가 무난하다.

7-6. PWM 동기 ADC — 요구-실제 대조의 실제 구현

§6.4.2-6 의 "실제 Fan 동작 상태를 확인할 수 있어야 한다"를 구현하려면 전류를 재야 하는데, PWM 구동에서는 아무 때나 찍으면 안 된다.

PWM  ─┐    ┌────┐    ┌────┐
      └────┘    └────┘    └──
전류  ─┐    ┌────┐    ┌────┐      ← ON 구간에만 흐른다
      └────┘    └────┘    └──
샘플        ↑         ↑            ← ON 구간 중앙, 스위칭 노이즈 회피

S32K144 에는 이걸 위한 하드웨어 경로가 있다.

FTM 카운터가 지정 값 도달
      ↓ 하드웨어 트리거
   TRGMUX          트리거 라우팅
      ↓
    PDB            프로그래머블 지연 — ON 구간 중앙까지
      ↓
    ADC            변환 시작

소프트웨어가 전혀 개입하지 않는다. 폴링으로 맞추려 하면 인터럽트 지연 때문에 지터가 생겨 값이 흔들린다.

듀티가 5 % 미만이면 25 kHz 기준 ON 구간이 2.5 µs 뿐이라 링잉이 안 죽은 상태에서 샘플링된다. 값을 못 믿으므로 판정에서 제외해야 하고, 이건 §6-1 의 "전환 과도 구간 허용"과 같은 처리다.

7-7. 채널 배분 (S32K144)

FTM0  CH0~2   RGB LED          12비트 @ 19.5 kHz
FTM1  CH0     공조 팬           @ 25 kHz (4선 팬 — 가청대 위로)
FTM2  CH0/1   펠티어 H-브리지    @ 2 kHz, 데드타임 1 µs, 상보
FTM3  CH0     공조 팬 tach 입력 캡처
      CH1     방열팬

주파수가 부하마다 다르므로 FTM 을 나눠야 한다 — 같은 모듈의 채널은 카운터와 주기를 공유한다. 특히 4선 팬의 PWM 입력은 21~28 kHz 를 전제로 설계돼 있어, 그 아래로 내리면 코일에서 가청 소음이 난다.


8. 오류 및 안전 동작

  • 시스템은 목표 온도 기반 자동 공조에 필요한 실내 환경 정보를 신뢰할 수 없는 경우 해당 정보에 기반한 새로운 자동 공조 판단을 수행하지 않아야 한다.
  • 시스템은 Predictive Pre-conditioning 에 필요한 정보를 신뢰할 수 없는 경우 해당 정보에 기반한 새로운 Predictive Pre-conditioning 을 시작하지 않아야 한다.
  • 시스템은 Predictive Climate 기능에 필요한 통신 정보를 신뢰할 수 없는 경우 해당 정보에 기반한 새로운 자동 공조 동작을 시작하지 않아야 한다.
  • 시스템은 실제 Fan 동작 상태를 정상적으로 확인할 수 없는 경우 해당 Fan 동작을 정상 상태로 처리하지 않아야 한다.
  • 시스템은 요구된 Fan 출력 수준과 실제 Fan 상태가 일치하지 않는 경우 오류 상태로 처리해야 한다.
  • 시스템은 Fan 제어 중 오류가 발생한 경우 의도하지 않은 Fan 출력의 지속을 방지해야 한다.
  • 시스템은 Predictive Climate 관련 오류 상태를 차량 내 HMI 및 모바일 인터페이스를 통해 사용자가 확인할 수 있도록 해야 한다.

7-1. "의도하지 않은 Fan 출력의 지속을 방지"

04편의 도어락 액추에이터 요구사항과 같은 문형이다.

§6.4.1 "시스템은 도어 제어 중 오류가 발생한 경우 의도하지 않은 도어락 액추에이터의 지속 동작을 방지해야 한다." §6.4.2 "시스템은 Fan 제어 중 오류가 발생한 경우 의도하지 않은 Fan 출력의 지속을 방지해야 한다."

Fan의 경우 위험은 다르다. 도어락은 과열이지만, Fan은 배터리 방전이 주다. 주차된 차에서 Fan이 계속 돌면 며칠 만에 시동이 안 걸린다.

Pre-conditioning은 원래 차가 꺼진 상태에서 도는 기능이므로 이 위험이 실재한다.

/* Fan 지속 동작 방지 — 최대 연속 동작 시간 + 배터리 전압 감시 */
#define FAN_MAX_CONTINUOUS_MS   (20u * 60u * 1000u)   /* 20분 */
#define BATT_CUTOFF_MV          11800                  /* 이하면 중단 */

void fan_safety_tick(void)
{
    if (g_fan_level == FAN_OFF) { g_fan_on_since = 0; return; }
    if (g_fan_on_since == 0) g_fan_on_since = hal_now_ms();

    /* ① 최대 연속 동작 시간 */
    if ((hal_now_ms() - g_fan_on_since) > FAN_MAX_CONTINUOUS_MS) {
        fan_force_off(FAULT_FAN_MAX_TIME);
        return;
    }
    /* ② 배터리 보호 — Pre-conditioning 은 시동이 꺼진 상태에서 돈다 */
    if (g_fan_owner == FAN_OWNER_PRECOND && batt_mv() < BATT_CUTOFF_MV) {
        fan_force_off(FAULT_FAN_LOW_BATT);
        return;
    }
    /* ③ 요구-실제 불일치 */
    if (fan_fault(&g_fan_status)) fan_force_off(FAULT_FAN_MISMATCH);
}

②가 SR에 명시돼 있지 않다는 점에 주목. SR은 "의도하지 않은 지속을 방지"라고만 하고 방법을 정하지 않는다. 배터리 컷오프는 설계 문서의 몫이다 — §9의 "세부 중재 및 실행 메커니즘은 SysRS 또는 설계 문서에서 정의한다"에 해당한다.


9. 공통 오류 원칙 (§6.4.4) 적용

§6.4.4는 Smart Access·Predictive Climate·Ambient Lighting 셋에 공통으로 적용된다.

  • 시스템은 Smart Access, Predictive Climate 또는 Ambient Lighting 중 특정 기능에 오류가 발생하더라도 독립적으로 안전하게 수행할 수 있는 다른 기능을 불필요하게 중단하지 않아야 한다.
  • 시스템은 통신 오류 복구 시, 이전에 수신한 마지막 정상 정보를 근거로 새로운 자동 기능을 수행하지 않아야 한다.
  • 시스템은 기능 오류가 복구된 경우 최신 입력 정보와 관련 기능 상태를 다시 평가해야 한다.
  • 시스템은 오류로 중단된 자동 기능을 오류 복구만을 근거로 자동 재개하지 않아야 한다.
  • 시스템은 오류 복구 후 최신 조건이 유효한 경우에만 새로운 자동 동작을 수행해야 한다.

8-1. 복구 후의 정확한 순서

다이어그램 로딩 중…

"복구했으니 하던 걸 계속"이 아니라 "복구했으니 처음부터 다시 판단"이다.

Predictive Climate에 적용하면:

static void climate_on_error_recovered(void)
{
    /* ✗ 금지 — 마지막 정상 정보 재사용 */
    /* fan_claim(g_last_owner, g_last_level, false); */

    /* ✓ 재평가 */
    cabin_env_t env = sensing_read_fresh();          /* 최신 입력 */
    if (!env.temp_valid || !env.humid_valid) return; /* 최신 조건 무효 → 동작 없음 */

    bool occupant = vision_occupant_present_fresh();
    if (!auto_climate_enabled()) return;             /* 관련 기능 상태 재평가 */

    fan_level_t lv = decide_fan(env.temp_c10, g_target_c10, true);
    if (lv != FAN_OFF) fan_claim(FAN_OWNER_AUTO_CLIMATE, lv, false);
}

10. 한 줄 요약

항목한 줄
목표 온도 자동 공조Fan 4단계 이산값(요구-실제 비교를 위해). 온도차 → 단계, 히스테리시스로 채터링 방지
실내 공기 순환사용자 직접 선택. 차량 내 HMI만 — 지금 차 안 사람을 위한 기능
Pre-conditioning반복 이용 패턴 학습 → 예상 탑승 시점 전 공조 시작. 사용자가 정지 가능
Fan 전환Fan 소유자는 언제나 하나. 사용자 요청이 Pre-conditioning보다 우선. 전환 후 자동 재개 없음
Window 자동 환기탑승자 없을 때만. Power Window에 요청만 한다. 닫힘이 거부되면 정상 완료 아님
Fan 상태요구와 실제를 별도 관리. 불일치는 오류(단, 전환 과도 구간 허용)
오류·안전Fan 지속 동작 방지. 복구는 재평가 후 새 동작 — 마지막 정상 정보 재사용 금지

설계 판단 체크포인트

구현에 들어가기 전에 팀이 답을 갖고 있어야 하는 것들이다. 답이 안 나오면 그 자리가 곧 설계 문의 또는 TBD 후보다.

  1. Fan 출력을 연속 PWM(0~100 %)으로 구현하면 어떤 요구사항이 깨지나? §6.4.2의 "요구된 Fan 출력 수준과 실제 Fan 상태가 일치하지 않는 경우 오류 상태로 처리해야 한다"의 판정 기준이 사라진다. 이산 4단계에서는 requested == actual이 명확하지만, 연속값에서는 허용 오차를 별도로 정의해야 하고 그 값이 SR에 없다. 또 HMI 표시("OFF/LOW/MEDIUM/HIGH로 구분하여 관리")도 요구사항 위반이 된다.

  2. 자동 환기로 창문이 열려 있는데 갑자기 탑승자가 감지됐다. 무슨 일이 일어나야 하나? §6.4.2는 "자동 환기 허용 조건이 더 이상 충족되지 않는 경우 자동 환기 동작을 종료해야 한다"고 한다. 탑승자 부재는 허용 조건이므로 종료 대상이다. 종료 시 Power Window에 닫힘을 요청하고, 그 요청이 §6.2.2 조건에 걸려 거부되면 정상 완료로 처리하지 않고 HMI에 노출한다.

  3. Pre-conditioning 중에 사용자가 HMI에서 Fan을 MEDIUM으로 선택했다. Pre-conditioning은 일시정지인가 종료인가? 종료다. §6.4.2는 "사용자의 새로운 유효한 Fan 제어 요청을 수행 중인 Predictive Pre-conditioning 보다 우선하여 처리해야 한다"와 "새로운 Fan 제어 기능으로 전환된 이후 이전 기능의 Fan 출력을 자동으로 재개하지 않아야 한다"를 둘 다 갖고 있다. 사용자가 Fan을 OFF로 바꿔도 Pre-conditioning이 되살아나면 안 된다.

  4. 자동 환기의 "최대 수행 시간"(TBD-012b)이 왜 필요한가? 온도가 예상대로 떨어지지 않으면 종료 조건이 영영 충족되지 않고 창문이 계속 열려 있다. 비·도난·배터리(HMI 상태 갱신) 문제가 생긴다. 최대 시간은 종료 조건의 안전망이다. 시간 초과로 종료할 때도 닫힘 요청이 거부될 수 있으므로, 그 경우 역시 정상 완료가 아니다.

  5. 요구 Fan 수준과 실제 상태의 불일치에 허용 시간을 두지 않으면? OFF→HIGH 전환 순간 실제 팬은 아직 회전수가 낮아 매 전환마다 오류가 뜬다. 오류가 잦으면 사용자가 무시하게 되고(alarm fatigue), 진짜 고장을 놓친다. 허용 시간은 팬의 물리적 기동/정지 시간보다 길고, 실제 고장을 놓칠 만큼 길지는 않게 잡아야 한다 — TBD-018의 "실제 출력 기준"에 포함될 값이다.

  6. §6.4.4는 "오류 복구만을 근거로 자동 재개하지 않는다"고 한다. 그럼 Pre-conditioning은 복구 후 어떻게 다시 시작되나? 복구 자체로는 시작되지 않는다. 다음 판단 사이클에서 "예상 탑승 시점 + 유효한 실내 환경 정보"로 Pre-conditioning 필요 여부를 새로 판단하고, 조건이 성립하면 그때 시작된다. 즉 복구는 "다시 판단할 수 있는 상태"로 돌려놓을 뿐이고, 판단은 별개의 사건이다.

Smart Access — Digital Key·근접 판단·도어 상태 정합성Ambient Lighting — 표시 우선순위·식별 가능성·조도 조절