# Haar 웨이블릿을 이용한 기본 변환 예제

Haar 웨이블릿 변환은 가장 단순하고 기본적인 형태의 이산 웨이블릿 변환(DWT)으로, 데이터의 압축과 신호 분석에 자주 사용된다. 이 변환은 간단한 수학적 연산을 통해 신호를 저주파 성분(평균)과 고주파 성분(차이)으로 나누는 방식으로 동작한다. 여기에서는 1차원 신호를 대상으로 Haar 웨이블릿을 적용하는 과정을 단계별로 설명한다.

#### Haar 웨이블릿의 정의

Haar 웨이블릿 함수는 단순하지만 강력한 특징을 가지고 있으며, 다음과 같은 두 가지 필터로 표현된다.

1. **스케일링 함수** $\phi(t)$:

$$
\phi(t) = \begin{cases} 1 & \text{if } 0 \leq t < 1 \ 0 & \text{otherwise} \end{cases}
$$

2. **웨이블릿 함수** $\psi(t)$:

$$
\psi(t) = \begin{cases} 1 & \text{if } 0 \leq t < 0.5 \ -1 & \text{if } 0.5 \leq t < 1 \ 0 & \text{otherwise} \end{cases}
$$

이러한 정의를 기반으로, Haar 웨이블릿 변환은 입력 신호를 간단한 연산을 통해 평균과 차이를 계산하는 방식으로 동작한다.

#### 변환 과정

Haar 웨이블릿 변환은 신호의 길이가 $2^n$인 경우에 효과적이며, 변환 과정은 다음의 단계로 이루어진다.

**1. 입력 신호 예시**

예를 들어, 다음과 같은 8개의 샘플을 가진 신호 $\mathbf{x}$가 있다고 가정하자:

$$
\mathbf{x} = \[4, 6, 10, 12, 14, 16, 18, 20]
$$

**2. 1단계 변환**

1단계 변환에서는 인접한 두 샘플의 평균과 차이를 계산한다. 이때, 평균은 저주파 성분(스케일링 계수), 차이는 고주파 성분(디테일 계수)을 나타낸다.

평균과 차이를 구하는 식은 다음과 같다:

$$
\text{평균} = \frac{x\_{2i} + x\_{2i+1}}{2}, \quad \text{차이} = \frac{x\_{2i} - x\_{2i+1}}{2}
$$

적용하면:

$$
\mathbf{c}^{(1)} = \[5, 11, 15, 19], \quad \mathbf{d}^{(1)} = \[-1, -1, -1, -1]
$$

여기서 $\mathbf{c}^{(1)}$는 1단계의 스케일링 계수 벡터이며, $\mathbf{d}^{(1)}$는 1단계의 디테일 계수 벡터이다.

**3. 2단계 변환**

1단계에서 구한 스케일링 계수 $\mathbf{c}^{(1)}$에 대해 다시 동일한 변환을 적용한다. 즉, $\mathbf{c}^{(1)}$의 평균과 차이를 계산한다:

$$
\mathbf{c}^{(2)} = \[8, 17], \quad \mathbf{d}^{(2)} = \[-3, -2]
$$

**4. 3단계 변환**

마지막으로 $\mathbf{c}^{(2)}$에 대해 같은 연산을 적용한다:

$$
\mathbf{c}^{(3)} = \[12.5], \quad \mathbf{d}^{(3)} = \[-4.5]
$$

따라서 최종적으로 Haar 웨이블릿 변환의 결과는 아래와 같다:

$$
\mathbf{c}^{(3)}, \mathbf{d}^{(3)}, \mathbf{d}^{(2)}, \mathbf{d}^{(1)} = \[12.5, -4.5, -3, -2, -1, -1, -1, -1]
$$

#### Haar 웨이블릿 변환의 역변환

Haar 웨이블릿 변환은 역변환을 통해 원래 신호를 재구성할 수 있다. 역변환은 변환 과정의 반대 방향으로 진행되며, 각 단계에서 평균과 차이를 사용하여 원래의 샘플을 복원한다.

**1. 역변환의 개념**

역변환은 다음의 공식을 기반으로 진행된다. 주어진 평균 $a$와 차이 $d$가 있을 때, 원래의 두 샘플 $x\_1$과 $x\_2$는 다음과 같이 복원된다:

$$
x\_1 = a + d, \quad x\_2 = a - d
$$

이 공식을 단계별로 적용하여 원래의 신호를 복원한다.

**2. 단계별 역변환 과정**

**(a) 3단계 복원**

3단계 변환의 결과는 $\mathbf{c}^{(3)} = \[12.5]$와 $\mathbf{d}^{(3)} = \[-4.5]$이다. 이를 이용해 2단계의 스케일링 계수를 복원한다:

$$
c^{(2)}\_1 = 12.5 + (-4.5) = 8, \quad c^{(2)}\_2 = 12.5 - (-4.5) = 17
$$

따라서, $\mathbf{c}^{(2)} = \[8, 17]$.

**(b) 2단계 복원**

이제 $\mathbf{c}^{(2)} = \[8, 17]$과 $\mathbf{d}^{(2)} = \[-3, -2]$를 사용하여 1단계의 스케일링 계수를 복원한다:

$$
c^{(1)}\_1 = 8 + (-3) = 5, \quad c^{(1)}\_2 = 8 - (-3) = 11
$$

$$
c^{(1)}\_3 = 17 + (-2) = 15, \quad c^{(1)}\_4 = 17 - (-2) = 19
$$

따라서, $\mathbf{c}^{(1)} = \[5, 11, 15, 19]$.

**(c) 1단계 복원**

마지막으로, $\mathbf{c}^{(1)} = \[5, 11, 15, 19]$과 $\mathbf{d}^{(1)} = \[-1, -1, -1, -1]$을 이용하여 원래의 샘플을 복원한다:

$$
x\_1 = 5 + (-1) = 4, \quad x\_2 = 5 - (-1) = 6
$$

$$
x\_3 = 11 + (-1) = 10, \quad x\_4 = 11 - (-1) = 12
$$

$$
x\_5 = 15 + (-1) = 14, \quad x\_6 = 15 - (-1) = 16
$$

$$
x\_7 = 19 + (-1) = 18, \quad x\_8 = 19 - (-1) = 20
$$

따라서 원래의 신호는 $\mathbf{x} = \[4, 6, 10, 12, 14, 16, 18, 20]$로 정확하게 복원된다.

#### C++ 코드 예제

아래의 C++ 코드는 위의 Haar 웨이블릿 변환 및 역변환 과정을 구현한 예제이다. 코드에서는 1차원 배열을 입력으로 받아서 변환과 역변환을 수행한다.

```cpp
#include <iostream>
#include <vector>

void haarTransform(std::vector<double>& data) {
    int n = data.size();
    std::vector<double> temp(n);
    while (n > 1) {
        n /= 2;
        for (int i = 0; i < n; i++) {
            temp[i] = (data[2 * i] + data[2 * i + 1]) / 2;
            temp[n + i] = (data[2 * i] - data[2 * i + 1]) / 2;
        }
        for (int i = 0; i < 2 * n; i++) {
            data[i] = temp[i];
        }
    }
}

void inverseHaarTransform(std::vector<double>& data) {
    int n = 1;
    std::vector<double> temp(data.size());
    while (n < data.size()) {
        for (int i = 0; i < n; i++) {
            temp[2 * i] = data[i] + data[n + i];
            temp[2 * i + 1] = data[i] - data[n + i];
        }
        for (int i = 0; i < 2 * n; i++) {
            data[i] = temp[i];
        }
        n *= 2;
    }
}

int main() {
    std::vector<double> data = {4, 6, 10, 12, 14, 16, 18, 20};
    haarTransform(data);
    
    std::cout << "Haar Transform: ";
    for (double d : data) std::cout << d << " ";
    std::cout << std::endl;

    inverseHaarTransform(data);
    
    std::cout << "Inverse Haar Transform: ";
    for (double d : data) std::cout << d << " ";
    std::cout << std::endl;

    return 0;
}
```

이 예제 코드에서 `haarTransform` 함수는 입력 데이터를 변환하여 Haar 계수를 계산하고, `inverseHaarTransform` 함수는 이를 기반으로 역변환을 수행한다. 코드 실행 결과는 Haar 변환된 계수와 원래 신호의 복원 결과를 출력한다.
