AvocadoSmoothie.Barista · SignatureMedian.vb · 1D Running Median 심층 분석

1D Running Median
All / Middle · Boundary · Demo

SignatureMedian 클래스의 All Median · Middle Median 모드, 4 가지 경계 처리 (Symmetric · Replicate · ZeroPad · Adaptive), Median 계산 알고리즘, 병렬화 구조를 코드 · 다이어그램 · 인터랙티브 데모로 심층 분석합니다.

Overview · Architecture

SignatureMedian 전체 구조

1D 수치 시퀀스에 Running Median 스무딩을 적용합니다. 반경 R (→ 윈도우 W = 2R + 1) 을 지정하면 각 데이터 포인트에 대해 주변 W 개 값의 중앙값을 계산합니다.

진입점 구조 - ComputeMediansByRadius → ComputeMedians

Entry
ComputeMediansByRadius()
Conversion
R → W = 2R + 1
Core
ComputeMedians()
Branch
useMiddle ?
Output
List(Of Double)
' ComputeMediansByRadius - R → W 변환 후 ComputeMedians 호출
Dim w64 As Long = CLng(kernelRadius) * 2L + 1L   ' 오버플로 방지
If w64 > Integer.MaxValue Then Throw ...
Dim w As Integer = CInt(w64)                    ' 항상 홀수 ≥ 1
Return ComputeMedians(input, useMiddle, kernelWidth:=w, ...)

🔑 핵심 분기 - useMiddle (All Median vs Middle Median)

ComputeMedians() 내부에서 useMiddle 플래그에 따라 처리 경로가 완전히 분기됩니다.

useMiddle = False → All Median

  • 전체 데이터 (0 ~ n − 1) 에 Median 적용
  • BoundaryMode 가 적용됨
  • Adaptive : 윈도우를 [0, n − 1] 내부로 슬라이드
  • Symmetric / Replicate / ZeroPad : GetValueWithBoundary() 로 범위 밖 값 합성

useMiddle = True → Middle Median

  • borderCount 만큼 양쪽 경계를 제외
  • BoundaryMode 무시 (레거시 경로)
  • 대칭 축소 (reach = min(R, i, n−1−i)) 로 위상 보정된 윈도우
  • 경계 데이터는 원본 값 그대로 유지

📊 모드 · 경계 처리 특성 비교

항목All MedianMiddle Median
처리 범위startIdx = 0, endIdx = n − 1startIdx = borderCount, endIdx = n − borderCount − 1
경계 처리BoundaryMode 4 가지 선택대칭 축소 (BoundaryMode 무시)
윈도우 크기항상 W (Adaptive 제외)가변 (경계에서 대칭 축소)
경계 데이터합성 / 반사 / 복제 / 0원본 값 그대로 보존
use case전체 시퀀스 스무딩내부 영역만 스무딩, 경계 원본 유지

🗂️ BoundaryMode 열거형

Symmetric (Mirror) Replicate (Edge Clamp) ZeroPad Adaptive (Symmetric Shrink)
Public Enum BoundaryMode
    Symmetric     '  Whole-sample 반사 : … 3, 2 | 1, 2, 3, 4, 5 | 4, 3 …
    Replicate     '  가장자리 복제    : … 1, 1, 1 | 1, 2, 3, 4, 5 | 5, 5, 5 …
    ZeroPad       '  0 패딩         : … 0, 0, 0 | 1, 2, 3, 4, 5 | 0, 0, 0 …
    Adaptive      '  대칭 축소      : reach = min(R, i, n−1−i), W = 2·reach+1
End Enum

Running Median · Concepts

Running Median - 수학적 개념과 특장점

중앙값(Median)의 정식 수학 정의, 핵심 통계 성질, 그리고 1D 스무딩 필터로서의 특장점을 체계적으로 정리합니다.

📐 중앙값(Median) - 수학적 정의

유한 크기 집합 S = {x₀, x₁, …, x_{W − 1}} 에서 중앙값은 순서 통계량 (Order Statistic) 으로 정의됩니다.

정렬 후 중앙 인덱스 선택
x(0) ≤ x(1) ≤ … ≤ x(W − 1)  →  x(k) = k 번째 순서 통계량
median(S) = {  x((W − 1) / 2)                  W 홀수
               ½ · (x(W / 2 − 1) + x(W / 2))  }  W 짝수
L₁ 최소화 관점 (동치 정의)
median(S) = argminm ∈ ℝ  Σk |xk − m|

중앙값은 집합의 모든 원소까지의 절댓값 거리 합(L₁ 노름) 을 최소화하는 값입니다. 이에 반해 평균 (Mean) 은 L₂ (제곱 거리 합) 최소화 값입니다.

Running (슬라이딩 윈도우) 적용
y[i] = median{ x[i − R], x[i − R + 1], …, x[i], …, x[i + R] }    (W = 2R + 1)

인덱스 i 를 0 부터 n − 1 까지 슬라이드하면서 매 위치마다 W 개 원소의 중앙값을 구합니다. 경계(i < R 또는 i > n − 1 − R)에서는 BoundaryMode 에 따라 창 바깥 값을 처리합니다.

🔬 핵심 통계 · 수학적 성질

📌 Breakdown Point - 50%

Breakdown Point 는 추정량이 무너지기 전까지 견딜 수 있는 이상치 비율의 상한입니다.

ε* = ⌊(W + 1) / 2⌋ / W  →  50% as W → ∞

창 내 절반 미만의 값 중 임의의 값에 이상치가 발생하더라도 중앙값은 변하지 않습니다. 평균 (Mean) 의 Breakdown Point 는 0% (단 하나의 극단값으로도 무너짐)입니다.

📌 비모수성 (Non-parametric)

중앙값은 순위 (Rank) 정보만 사용합니다. 구체적 값의 크기 (Magnitude) 가 아닌 대소 관계만이 결과에 영향을 줍니다.

  • 정규 분포 · 가우시안 가정 불필요
  • 단조 변환 (Monotone Transform) 에 불변 - f(median(S)) = median(f(S))
  • 데이터 분포가 비대칭 (Skewed) 이더라도 안정적

📌 출력이 항상 입력 집합의 원소

W 가 홀수일 때 중앙값은 반드시 창 안의 실제 데이터 값 중 하나입니다.

median(S) ∈ S   (W 홀수)

이는 스무딩 결과가 "존재했던 값" 이므로 물리적으로 의미없는 값 (예 : 음의 카운트, 범위 외 밝기) 이 출력되지 않습니다. W 짝수 시 두 중앙값의 평균이 되므로 범위 내에 있습니다.

📌 단조 선형 신호 보존 (Idempotency)

이미 단조 증가·감소하는 시퀀스에 Running Median 을 적용하면 출력이 입력과 동일합니다.

x 단조 → RunningMedian(x) = x

선형 필터 (평균 계열) 는 단조 신호도 경계에서 왜곡할 수 있지만, Median 은 이를 완전히 보존합니다.

📌 멱등성 (Idempotency under repetition)

같은 윈도우 W 로 Running Median 을 두 번 적용해도 결과가 변하지 않습니다.

M(M(x)) = M(x)   (동일 W)

평균 기반 필터를 반복 적용하면 신호가 계속 뭉개지지만, Running Median 은 수렴 후 추가 변화가 없습니다.

📌 Root Signals

Running Median 을 반복 적용했을 때 더 이상 변하지 않는 신호를 Root Signal 이라 합니다.

Root Signal 은 창 안에서 단조 구간으로만 구성되며, 수렴 보장은 Running Median 이 특정 형태의 신호 구조를 향해 안정적으로 수렴함을 증명합니다.

📈 에지 보존 - 수학적 직관

Running Median 이 경계 (급격한 계단 변화) 를 보존하는 이유를 창 내 값 분포로 설명합니다.

경계 위 창 (절반이 Low, 절반이 High)
L
L
E
H
H

창 내 Low 값과 High 값이 균등할 때, 중앙값은 에지 E 자체 또는 Low · High 의 경계값으로 수렴합니다. Moving Average 였다면 (L + L + E + H + H) / 5 로 흐릿해집니다.

경계 외부 창 (대부분 한쪽 값)
L
L
L
L
S!

단 하나의 스파이크 (S) 가 있어도 창의 대다수 값이 L이므로 중앙값 = L. 스파이크는 출력에 전혀 반영되지 않습니다.

핵심 통찰 - 중앙값은 창 안 값들의 크기 (Magnitude) 가 아닌 순위 (Rank) 로 결정됩니다. 이상치가 아무리 크더라도 순위만 최상단으로 이동할 뿐, W / 2 를 초과하지 않으면 중앙 순위에 닿지 못합니다.

⭐ Running Median 특장점 - 한눈에 정리

특장점 수학적 근거 실무 효과
이상치 강인성 Breakdown Point = 50%. L₁ 최소화는 극단값 가중치를 제한 센서 스파이크, 결측값 대체 오류 등이 출력에 전파되지 않음
에지·스텝 보존 창이 경계를 넘을 때 과반을 차지하는 다수결 (Majority) 원리로 중앙값이 한쪽으로 수렴 신호의 실제 변화 지점 위치 · 크기가 스무딩 후에도 유지됨
비모수 · 분포 독립 순위 기반 통계량. 어떤 확률 분포도 가정하지 않음 로그 스케일, 헤비테일, 이분 분포 데이터에 모두 동일하게 적용 가능
출력 범위 보장 median(S) ∈ [min(S), max(S)] - 항상 입력 범위 내 값 물리량(온도, 밝기, 카운트) 스무딩 시 범위 외 값이 절대 출력되지 않음
멱등 수렴성 M(M(x)) = M(x). Root Signal 로의 안정 수렴 보장 반복 적용 시 신호가 점점 소멸하지 않고 일정 형태를 유지
단조 신호 보존 단조 수열의 중앙값은 항상 중심 원소 = 원본과 동일 꾸준히 증가·감소하는 트렌드 구간을 왜곡 없이 통과
단일 파라미터 W(= 2R + 1) 하나로 스무딩 강도 전체 결정 튜닝 공간 최소. 윈도우를 키울수록 더 강하게 스무딩, 직관적
병렬화 친화 y[i] 는 y[j] (i ≠ j) 에 독립 - 데이터 의존성 없음 Parallel.For 로 코어 수에 비례한 선형 속도 향상 달성

Why Running Median

왜 Running Median 인가? - 필터 비교 분석

Moving Average, Binomial / Gaussian, Savitzky-Golay 등 대표적인 1D 스무딩 필터들과의 특성 비교를 통해 Running Median 의 선택 근거를 정리합니다.

📐 필터별 수식 정의

동일한 윈도우 W = 2R + 1 에서 각 필터가 출력값 y[i] 를 어떻게 결정하는지를 비교합니다.

Moving Average (SMA)
y[i] = Σk = −RR x[i + k] / W

균등 가중치. 창 안 모든 값을 동등하게 합산.

Binomial / Gaussian
y[i] = Σk = −RR w[k] · x[i + k],  Σw = 1

중심에 높은 가중치. 가우시안/이항계수 커널.

Savitzky-Golay
y[i] = Σk = −RR c[k] · x[i + k]

최소자승 다항 피팅 계수. 피크 형태 보존.

Running Median ✓
y[i] = median{ x[i − R], …, x[i], …, x[i + R] }

정렬 후 중앙값. 어떤 선형 가중합도 사용하지 않음.

📊 5개 필터 핵심 속성 비교표

속성 Moving Average Binomial / Gaussian Savitzky-Golay Running Median ✓
이상치 (Outlier) 내성 ❌ 취약
단 하나의 스파이크가 창 전체 평균을 왜곡
❌ 취약
가중 평균이므로 동일하게 영향받음
△ 보통
다항 피팅이 이상치를 완화하나 제거 불가
✅ 강력
중앙값은 이상치가 50% 미만이면 출력에 영향 無
에지 (급격한 변화) 보존 ❌ 뭉개짐
에지가 W 구간에 걸쳐 완만하게 번짐
❌ 뭉개짐
가우시안 특성상 에지 번짐이 더 심함
✅ 우수
피크·에지 형태를 다항식으로 보존
✅ 우수
에지 양측 값이 뚜렷이 다르면 중앙값이 한쪽에 수렴
스파이크 노이즈 제거 ❌ 잔류
평균화로 에너지가 분산될 뿐, 제거 아님
❌ 잔류
마찬가지로 번짐 발생
△ 부분
큰 폭의 스파이크는 피팅에 영향
✅ 완전 제거
단일 스파이크는 정렬 시 가장자리로 밀려 중앙값에서 탈락
실시간 · 스트리밍 적합성 ✅ 우수
슬라이딩 합산으로 O(1) 온라인 갱신 가능
✅ 우수
커널 고정이면 O(W) 합산
△ 보통
계수 테이블 사전 계산 후 O(W) 적용 가능하나 차수 변경 시 재계산
✅ 적합
고정 윈도우 크기 → 매 포인트마다 O(W log W) 정렬, 배치 병렬화로 실용적
매끄러움 (Smoothness) ✅ 부드러움 ✅ 매우 부드러움 ✅ 부드러움
다항 차수에 따라 조절 가능
△ 계단 현상 가능
출력이 입력값 중 하나로 고정 → 작은 W 값에서 계단식 출력
분포 가정 불필요 △ 정규분포 가정 ❌ 가우시안 가정 △ 국소 다항 가정 ✅ 가정 없음
비모수(Non-parametric). 어떠한 분포에도 동일하게 동작
파라미터 복잡도 ✅ 낮음
W 하나
✅ 낮음
W + σ
△ 중간
W + 다항 차수 (m)
✅ 낮음
W (= 2R + 1) 하나

⚡ 실시간성 · 배치 처리 관점 상세

SignatureMedian 은 사전 수집된 1D 시퀀스 전체에 대해 일괄 처리(Batch)하는 설계입니다. 이 맥락에서 Running Median 의 실시간성을 분석합니다.

⏱ 연산 복잡도 비교

  • Moving Average - O(n) : 슬라이딩 합산으로 상수 갱신
  • Gaussian / Binomial - O(n · W) : 매 포인트마다 W 개 곱셈·합산
  • Savitzky-Golay - O(n · W) : 고정 계수 테이블 적용 (계수 사전 계산 O(W³))
  • Running Median - O(n · W log W) : 매 포인트 W 개 정렬

Running Median 은 절대 속도는 평균 계열보다 느리지만, W 가 고정된 상황에서 O(n · W log W) 는 예측 가능하고 선형 확장합니다.

🚀 병렬화로 실용적 실시간성 확보

  • 각 포인트의 Median 연산은 완전 독립적 → Task 분할 용이
  • SignatureMedian 은 내부적으로 Parallel.For 로 병렬화
  • 코어 수 C 배 속도 향상 → 실측 처리 속도는 Moving Average 와 실용적으로 동등
  • SMA 의 슬라이딩 합산은 순차 의존성이 있어 병렬화 불리

Moving Average 의 O(n) 이 병렬화 한계에 부딪히는 반면, Running Median 은 O(n · W log W / C) 로 코어가 늘수록 유리해집니다.

스트리밍 온라인 환경에서 Running Median 을 O(log W) 로 갱신하려면 두 힙 (Max-Heap + Min-Heap) 구조를 사용합니다. SignatureMedian 은 배치 설계이므로 채택하지 않았으나, 실시간 단일 스트림이 필요한 경우 이 확장을 적용할 수 있습니다.

🎯 시나리오별 필터 선택 가이드

신호 특성 / 목적권장 필터이유
센서 스파이크·이상치 포함, 실제값 복원 Running Median ✓ 이상치가 출력에 영향을 주지 않는 유일한 필터
분포 가정 없는 범용 스무딩 Running Median ✓ 비모수 특성으로 어떤 데이터 분포에서도 동일하게 동작
에지·스텝 변화 보존 필요 Running Median ✓ / Savitzky-Golay 선형 필터 중 SG 가 피크 보존 최강, Median 은 에지 위치 보존
부드러운 트렌드 추출 (노이즈 ≈ 가우시안) Gaussian / Binomial 주파수 응답이 가장 매끄럽고 진동 없음
스펙트럼 분석용 미분 계수 필요 Savitzky-Golay 피팅 다항식을 미분하여 1차·2차 도함수를 직접 얻음
단순·초고속 구현, 실시간 단일 채널 Moving Average O(1) 슬라이딩 합산, 코드 최소
의료·음악·금융 데이터, 이상치 빈발 Running Median ✓ 이상치에 의한 잘못된 분석 결론 방지에 가장 효과적

✅ Running Median 적용 결정 요인 요약

1
이상치 강인성 (Robustness)

단일 스파이크나 극단값이 빈번한 1D 시계열에서 평균 계열 필터는 신뢰도가 낮습니다. Running Median 은 이상치가 창의 절반 미만인 한 출력에 전혀 영향을 주지 않습니다 - 다른 어떤 선형 필터도 제공하지 못하는 보증입니다.

2
에지 보존 (Edge Preservation)

Moving Average · Gaussian 은 신호의 급격한 변화 지점을 W 구간에 걸쳐 번지게 합니다. Running Median 은 경계 양측의 값 분포가 뚜렷이 다를 때 중앙값이 어느 한쪽으로 수렴하여 경계의 위치와 크기를 보존합니다.

3
비모수성 (Non-parametric)

Gaussian 은 노이즈가 정규분포를 따른다고 가정하고, Savitzky-Golay 는 신호가 국소적으로 저차 다항식 형태라고 가정합니다. Running Median 은 어떤 분포 가정도 하지 않아, 실제 데이터가 이 가정을 위반해도 성능이 저하되지 않습니다.

4
병렬화 친화적 배치 실시간성

매 포인트의 Median 계산은 인접 포인트와 완전히 독립적인 특성 덕분에 SignatureMedian 은 Parallel.For 로 전체 배열을 코어 수에 비례하여 분할 처리합니다. 절대 복잡도는 O(n · W log W) 이지만 병렬 실효 처리속도는 Moving Average 와 실용적으로 경쟁합니다.

5
단순한 단일 파라미터 (W 또는 R)

Savitzky-Golay 는 윈도우 크기와 다항 차수를 함께 결정해야 하고, Gaussian 은 σ 를 별도로 지정합니다. Running Median 은 반경 R (또는 W = 2R + 1) 하나만으로 전체 동작이 결정됩니다. 파라미터 탐색 공간이 작아 실무 적용이 직관적입니다.

Mode · All Median

All Median (useMiddle = False)

전체 데이터 (인덱스 0 ~ n − 1) 에 Running Median 을 적용합니다. 커널이 데이터 경계를 벗어나는 위치에서는 BoundaryMode 에 따라 범위 밖 값을 합성합니다.

🔄 처리 흐름 - 단계별 분석

1
오프셋 계산

offsetLow = (W − 1) \ 2 · offsetHigh = (W − 1) − offsetLow · W 가 홀수이면 offsetLow = offsetHigh = R

2
처리 범위 설정

startIdx = 0, endIdx = n − 1 → 전체 데이터를 순회합니다.

3
BoundaryMode 분기

Adaptive : reach = min(R, i, n−1−i) 로 윈도우를 대칭 축소하여 항상 i 중심 유지. W = 2·reach+1.
기타 모드 : 각 pos 에 대해 GetValueWithBoundary(arr, i + k, mode) 로 범위 밖 값을 합성합니다.

4
Median 계산

GetWindowMedian(win, length) → Array.Sort 후 중앙값 반환. 짝수 길이는 두 중앙값의 평균.

📐 Adaptive 모드 - 대칭 축소 (Symmetric Shrinking) 상세

Adaptive 는 합성 값을 사용하지 않고, 윈도우를 항상 i 중심으로 유지하면서 경계에서 대칭적으로 축소합니다. reach = min(R, i, n−1−i) 로 양쪽 도달 거리를 균등하게 제한하여 위상 변이 (phase shift) 를 원천 차단합니다.

' Adaptive 분기 핵심 코드 - 대칭 축소
Dim reach As Integer = Math.Min(offsetLow, Math.Min(i, n - 1 - i))
Dim W As Integer = 2 * reach + 1

For pos As Integer = 0 To W - 1
    win(pos) = arr(i - reach + pos)            ' i 중심 대칭 수집
Next
buffer(i) = GetWindowMedian(win, W)
내부 i = 5
reach = 2
win = [3, 4, 5, 6, 7]
왼쪽 경계 i = 1
reach = 1 (축소)
win = [0, 1, 2]
오른쪽 경계 i = n − 2
reach = 1 (축소)
win = [n−3, n−2, n−1]
대칭 축소 vs 기존 슬라이드 : 이전 방식은 윈도우 W 를 고정하고 start 를 좌우로 밀어 붙였습니다. 이 경우 i = 0 에서 start = 0 이면 윈도우 중심이 i 가 아니라 오른쪽으로 치우쳐져 위상 변이가 발생합니다. 대칭 축소는 항상 i 를 중심으로 양쪽 reach 를 균등하게 줄이뮼로 위상 변이가 원천적으로 불가능합니다.

🔗 기타 모드 - GetValueWithBoundary 합성 경로

' Symmetric / Replicate / ZeroPad 경로
For pos As Integer = 0 To kernelWidth - 1
    Dim k As Integer = pos - offsetLow         ' 중심 기준 오프셋
    win(pos) = GetValueWithBoundary(arr, i + k, boundaryMode)
Next
buffer(i) = GetWindowMedian(win, kernelWidth)
각 pos 에서 i + k가 범위 밖이면 mode 에 따라 반사 (Symmetric), 클램핑 (Replicate), 0.0 (ZeroPad) 을 반환합니다. Adaptive 는 이 경로를 타지 않습니다.
Mode · Middle Median

Middle Median (useMiddle = True)

borderCount 만큼 양쪽 경계를 제외한 내부 영역만 Median 을 적용합니다. BoundaryMode 는 무시되며, 경계 데이터는 원본 값 그대로 유지됩니다.

🔄 처리 흐름 - 대칭 축소 경로

1
처리 범위 축소

b = Max(0, borderCount) · startIdx = b · endIdx = n - b - 1 · 2b ≥ n 이면 처리 없이 원본 반환.

2
대칭 축소 윈도우 수집

reach = Min(offsetLow, i, n−1−i) · W = 2·reach + 1 → 경계에서 윈도우가 i 중심으로 대칭적으로 축소됩니다. 위상 변이 (phase shift) 가 발생하지 않습니다.

3
Median 계산

축소된 길이 (length) 의 윈도우로 GetWindowMedian() 호출. 짝수 길이도 처리됩니다.

📐 대칭 축소 코드 상세

' useMiddle = True 경로 - BoundaryMode 무시
' 대칭 축소: 윈도우를 항상 i 중심으로 유지,
' 경계에서 양쪽 reach 를 균등하게 줄임.
Dim reach As Integer = Math.Min(offsetLow, Math.Min(i, n - 1 - i))
Dim W As Integer = 2 * reach + 1

For k As Integer = 0 To W - 1
    win(k) = arr(i - reach + k)
Next

buffer(i) = GetWindowMedian(win, W)
대칭 축소 : 윈도우가 항상 i 를 중심으로 양쪽 동일한 거리를 커버합니다. 예: i = 1, R = 3 이면 reach = min(3, 1, n−2) = 1, W = 3 으로 축소되어 [0, 1, 2] 를 수집합니다. 이전 iMin/iMax 클램핑에서는 iMin = 0, iMax = 4, length = 5 로 비대칭 윈도우가 되어 위상 변이가 발생했습니다.

📊 borderCount 의 역할

borderCount처리 범위경계 데이터
00 ~ n − 1 (전체)대칭 축소된 윈도우로 Median 적용
R (= kernelRadius)R ~ n − R − 1원본 값 보존 (가장 일반적)
n / 2 이상처리 없음전체 원본 반환
borderCount 는 "원본 값을 보존할 양쪽 영역의 크기"를 지정합니다. 일반적으로 kernelRadius 와 같은 값을 사용하여, 커널이 완전히 데이터 내부에 있는 영역만 스무딩합니다.

📐 수학적 장단점 분석 - 다른 Boundary Mode 와의 비교

Middle Median 은 경계 문제를 다른 모드처럼 "합성"으로 해결하지 않고 "처리 대상에서 제외"하는 방식으로 접근합니다. 이 근본적인 차이에서 아래의 수학적 장단점이 도출됩니다.

✅ 수학적 장점

  • 데이터 무결성 보장 - 경계 샘플에 반사·복제·0 패딩 등 어떤 합성도 가하지 않으므로, 실제 측정값의 통계적 분포와 모멘트 (평균·분산) 가 왜곡되지 않습니다. Replicate 처럼 상수 구간이 인위적으로 생성되거나, ZeroPad 처럼 경계 에너지가 0 으로 수렴되는 편향이 없습니다.
  • Adaptive 모드가 경계 근방에서 윈도우를 대칭 축소시켜 통계적 지지가 불균등해지는 것과 대조적으로
  • 이상치 (Outlier) 반사 오염 차단 - Symmetric 모드는 경계 근방의 이상치를 거울 반사로 윈도우에 재유입시켜 스무딩 결과를 오염시킬 수 있습니다. Middle Median 은 경계 데이터를 처리 대상에서 완전히 제외하므로, 이상치가 내부 Median 계산에 영향을 미치는 경로 자체가 차단됩니다.
  • 스펙트럼 아티팩트 없음 - ZeroPad 는 불연속 점프를, Symmetric 은 인위적 주기성을 도입하여 FFT 분석 시 Gibbs 현상이나 가짜 스펙트럼 성분을 유발합니다. Middle Median 은 경계에 어떤 합성 값도 삽입하지 않으므로 이러한 스펙트럼 왜곡이 발생하지 않습니다.
  • 파라미터 단순성 및 결정론성 - BoundaryMode 를 완전히 무시하므로 모드 선택에 따른 경계 처리 결과의 가변성이 없습니다. borderCount 하나만으로 경계-내부 분할이 명확하게 결정되어 재현성과 디버깅 용이성이 향상되며, 모드 오설정으로 인한 오류 가능성도 줄어듭니다.
  • 신호 에너지 보존 - Replicate 는 경계를 상수로 연장하고 ZeroPad 는 에너지를 강제 소멸시킵니다. Middle Median 은 경계 샘플의 실제 측정 에너지를 변형 없이 유지하므로, 전체 시퀀스의 L2 노름 (에너지) 이 내부 스무딩 효과를 제외하면 경계 구간에서 정확히 보존됩니다.

⚠️ 수학적 단점

  • 유효 처리 구간 축소 - 양쪽 borderCount 개 샘플은 스무딩 대상에서 제외됩니다. 경계 부근에 이상치가 존재하더라도 보정이 이루어지지 않아, 경계 오차는 그대로 출력에 잔존합니다. 경계에서 큰 측정 오차가 발생한 상황이라면 다른 Boundary Mode 에 비해 출력 신뢰도가 상대적으로 낮을 수 있습니다.
  • 출력의 통계적 비정상성 (Non-stationarity) - 출력 시퀀스는 경계 구간 (원본, 분산 ≈ σ²) 과 내부 구간 (Median 필터 적용, 분산 ≈ σ² / W) 이 혼재합니다. 인덱스 i = b 와 i = n − b − 1 지점에서 노이즈 특성이 불연속적으로 전환되며, 이는 출력 전체에 대한 자기상관 분석이나 스펙트럼 추정을 복잡하게 만들 수 있습니다.
  • 짧은 시퀀스에서의 알고리즘 퇴화 - n ≤ 2 · borderCount 이면 처리 대상 구간이 소멸하여 스무딩 없이 원본을 반환합니다. 데이터 길이가 충분하지 않은 환경에서는 알고리즘 자체가 pass-through 로 퇴화하므로 단순한 no-op 과 수학적으로 동치가 됩니다.
  • 전환 구간의 축소된 윈도우 - borderCount < R 설정에서는 처리 구간 내 인덱스 b ~ R − 1 구간이 대칭 축소 (reach = min(R, i, n−1−i)) 로 인해 윈도우가 W 보다 작게 줄어듭니다. 해당 샘플들은 "처리된" 것으로 분류되지만 통계적 지지가 불균등하여, Adaptive 모드와 동일한 대칭 축소 동작을 수행합니다. 다만, 윈도우가 항상 i 중심이므로 위상 변이는 발생하지 않습니다.
  • 경계 노이즈의 근본 해결 부재 - Middle Median 은 경계 샘플을 건드리지 않음으로써 잘못된 보정을 방지하는 것이지, 경계 샘플 자체의 노이즈를 제거하지는 않습니다. 이는 경계 품질 문제를 수학적으로 해결 (solve) 하는 것이 아닌 회피 (avoid) 하는 방식이며, 경계 샘플의 측정 불확실도 (uncertainty) 는 그대로 잔존합니다.
💡 핵심 트레이드오프 요약 : Middle Median 은 경계를 "올바르게 합성"하는 대신 "완전히 보존"을 선택합니다. 내부 데이터의 수학적 무결성과 이상치 차단은 극대화되지만, 경계 데이터의 노이즈는 그대로 노출됩니다. 측정 데이터의 경계 신뢰도가 내부보다 낮고, 경계에서의 합성 아티팩트가 허용 불가한 응용 (예 : 센서 이상치 내성 필터링, 신호 에너지 분석) 에서 수학적으로 가장 정당화됩니다.
Shared Infrastructure · GetValueWithBoundary()

BoundaryMode - 경계 처리 4 가지

커널이 데이터 경계를 벗어날 때 범위 밖 인덱스에 어떤 값을 할당할지 결정합니다. All Median 모드 (useMiddle = False) 에서만 적용됩니다.

🔍 왜 경계 처리가 필요한가?

W = 5 (R = 2) 인 커널을 i = 1 에 적용하면 인덱스 −1 을 참조합니다. 이 범위 밖 인덱스에 대한 처리가 BoundaryMode 입니다.

경계 처리 인터랙티브 시각화
1 R = 2, 데이터 길이 = 9
원본 데이터
커널 윈도우 [i − 2 … i + 2] - 모드별 처리

GetValueWithBoundary() - 전체 코드

Private Shared Function GetValueWithBoundary(
    data As Double(), idx As Integer, mode As BoundaryMode) As Double

    Dim n As Integer = If(data Is Nothing, 0, data.Length)
    If n = 0 Then Return 0.0

    Select Case mode
        Case BoundaryMode.Symmetric
            If n = 1 Then Return data(0)
            Dim period As Long = 2L * (CLng(n) - 1L)  ' 64-bit 주기
            Dim m As Long = idx Mod period
            If m < 0 Then m += period
            Dim mapped = If(m < n, m, 2L * (n − 1L) − m)
            Return data(CInt(mapped))

        Case BoundaryMode.Replicate
            If idx < 0 Then idx = 0
            ElseIf idx >= n Then idx = n - 1
            Return data(idx)

        Case BoundaryMode.ZeroPad
            If idx < 0 OrElse idx >= n Then Return 0.0
            Return data(idx)

        Case BoundaryMode.Adaptive
            ' Symmetric 과 동일한 64-bit 주기 반사
            ...
    End Select
End Function

Symmetric  Whole-sample 반사

d  c  b
a  b  c  d  e
d  c  b

Whole-sample 반사는 경계 값을 중복하지 않고 바로 다음 값부터 반사합니다. 주기 P = 2·(N − 1) 로 64-bit Mod 를 사용해 음수 · 양수 인덱스 모두 안전하게 처리합니다. MATLAB ‘symmetric’ / NumPy ‘reflect’ / OpenCV BORDER_REFLECT_101 과 동치합니다.

인덱스 매핑 : idx = −1 → 1, idx = −2 → 2 (경계 값 중복 없이 반사)
Dim period As Long = 2L * (CLng(n) - 1L)  ' 64-bit 주기
Dim m As Long = idx Mod period
If m < 0 Then m += period
Dim mapped = If(m < n, m, 2L * (n − 1L) − m)
✦ 권장 : 일반 신호 처리 (DSP 표준 · 기본값)

Replicate  가장자리 복제

a  a  a
a  b  c  d  e
e  e  e

양 끝 값을 그대로 반복하여 경계를 채웁니다. 경계 평탄화 (Plateau) 효과가 발생하며 경계 값이 과다 반영됩니다. 구현이 가장 단순하고 빠릅니다.

인덱스 매핑 : idx < 0 → 0  ·  idx ≥ n → n − 1
If idx < 0 Then idx = 0
ElseIf idx >= n Then idx = n - 1
Return data(idx)
✦ 권장 : 경계 값을 유지하고 평탄화가 허용되는 경우

ZeroPad  0 패딩

0  0  0
a  b  c  d  e
0  0  0

범위 밖을 모두 0 으로 처리합니다. 분모 (윈도우 크기 W) 는 그대로 유지되므로 경계 근처에서 에너지 감쇠 (값 저하) 가 발생합니다. Median 에서는 0 이 중앙값을 0 방향으로 편향시킵니다.

주의 : idx < 0 || idx ≥ n → Return 0.0. 경계에서 값이 0 으로 수렴.
If idx < 0 OrElse idx >= n Then Return 0.0
Return data(idx)
✦ 권장 : 데이터 외부 = 0 인 시나리오 · 주파수 / 신호 분석

Adaptive  대칭 축소 (Symmetric Shrink)

[b c d] i=2, reach=2
[a b c] i=1, reach=1
[a] i=0, reach=0

합성 샘플을 전혀 생성하지 않습니다. 경계 근방에서 윈도우를 i 중심으로 대칭적으로 축소하여 (reach = min(R, i, n−1−i), W = 2·reach+1) 항상 진짜 데이터만 사용합니다. 위상 변이 (phase shift) 가 원천적으로 발생하지 않습니다. All Median 내에서 별도 분기로 처리됩니다.

대칭 축소 공식 : reach = Min(offsetLow, i, n − 1 − i)  →  W = 2 · reach + 1
Dim reach As Integer = Math.Min(offsetLow, Math.Min(i, n - 1 - i))
Dim W As Integer = 2 * reach + 1
' GetValueWithBoundary 를 거치지 않음
For pos = 0 To W - 1 : win(pos) = arr(i - reach + pos)
✦ 권장 : 인위적 패턴 없이 실제 데이터만 사용해야 할 때
Symmetric DSP 표준 · 자연스러운 연속성 Replicate 경계 평탄화 · 가장 단순 ZeroPad 에너지 감쇠 주의 Adaptive 대칭 축소 · 위상 변이 없음

📊 모드 선택 가이드

Mode경계 왜곡특성권장 용도
Symmetric거의 없음Whole-sample 반사, 경계 값 비중복일반 용도 (기본값)
Replicate약간 (평탄화)가장 단순, 빠름경계 평탄화 허용 시
ZeroPad있음 (감쇠)경계에서 0 방향 편향주파수 / 신호 처리
Adaptive없음대칭 축소, 위상 변이 없음합성 거부 시

🔬 Symmetric (Whole-sample) 심층 분석 - 왜 Running Median 에 최적인가?

AvocadoSmoothie 의 기본 경계 모드인 Symmetric 은 Whole-sample 반사 (경계 값 비중복) 를 채택합니다. 이것이 Running Median 알고리즘에 최적화된 방식인 수학적 · 통계적 근거를 단계별로 분석합니다.

1. Whole-sample 반사 vs Half-sample 반사 - 차이점

경계 반사에는 크게 두 가지 방식이 존재합니다. 핵심 차이는 경계 값 (Edge Value) 을 반사 구간에 한 번 더 복제하느냐 여부입니다.

✅ Whole-sample (AvocadoSmoothie 채택)

d c ba b c d ed c b
  • 경계 값 ae 가 반사 구간에 나타나지 않음
  • idx = −1 → 1 (b), idx = −2 → 2 (c)
  • 주기 P = 2 · (N − 1) = 8 (N = 5 인 경우)
  • MATLAB symmetric, NumPy reflect, OpenCV BORDER_REFLECT_101

⚠️ Half-sample (채택하지 않음)

c b aa b c d ee d c
  • 경계 값 ae 가 반사 구간에 한 번 더 나타남 (중복)
  • idx = −1 → 0 (a), idx = −2 → 1 (b)
  • 주기 P = 2 · N = 10 (N = 5 인 경우)
  • MATLAB symmetric (1-based), SciPy reflect의 일부 해석
2. Running Median 에서 Whole-sample 이 최적인 이유
🎯 핵심 원리 : Median 은 "다수결" 로 동작한다

Running Median 은 윈도우 안에서 정렬 후 가운데 값을 뽑는, 일종의 다수결 (Majority Vote) 입니다. 윈도우 안에 특정 값이 여러 번 등장하면 그 값이 중앙값으로 선택될 확률이 비례적으로 높아집니다.

A
경계 값 중복 시 Median 편향 (Half-sample 의 문제)

데이터가 [10, 20, 30, 40, 50] 이고 W = 5 일 때, i = 0 에서의 윈도우를 비교합니다.

Half-sample (i = 0)
20
10
10
20
30
정렬 : [10, 10, 20, 20, 30] → Median = 20
⚠ 10 이 2 회 등장하여 Median 이 높은 방향으로 밀림
Whole-sample (i = 0)
30
20
10
20
30
정렬 : [10, 20, 20, 30, 30] → Median = 20
✅ 어떤 값도 인위적으로 중복되지 않음. 자연스러운 분포

이 예에서는 결과가 같지만, 경계 값이 극단값 (이상치) 이거나 데이터 분포가 비대칭인 경우 Half-sample 의 중복이 Median 을 경계 값 방향으로 편향시킵니다. Whole-sample 은 경계 값을 윈도우에 1 회만 포함하므로 Median 의 다수결 중립성 (Median Neutrality) 을 보존합니다.

B
Median Neutrality (중앙값 중립성) 보존

Whole-sample 은 경계 값을 한 번만 포함하므로, 윈도우 안에서 각 값의 등장 횟수가 자연 데이터의 통계적 빈도를 왜곡하지 않습니다.

Half-sample : data[0] 이 2 회 등장 → 순위가 1 단계 밀림 → Median 이 data[0] 방향으로 편향
Whole-sample : data[0] 이 1 회만 등장 → 순위 불변 → Median 편향 없음

Running Median 은 순위 (Rank) 로만 결과가 결정되므로, 값의 등장 횟수가 인위적으로 변하면 곧 Median 이 편향됩니다. Whole-sample 은 이 등장 횟수를 보존합니다.

C
이상치가 경계에 있을 때의 강인성

센서 데이터에서 첫 샘플이 이상치 (예: 스파이크 1000) 인 경우를 생각합니다.

Half-sample (data[0] = 1000 · 스파이크)
윈도우 : [20, 1000, 1000, 20, 30]
정렬 : [20, 20, 30, 1000, 1000] → Median = 30
⚠ 스파이크가 2 개로 늘어 순위에 영향
Whole-sample (data[0] = 1000 · 스파이크)
윈도우 : [30, 20, 1000, 20, 30]
정렬 : [20, 20, 30, 30, 1000] → Median = 30
✅ 스파이크 1 개 → 중앙값에 영향 없음

이 예에서 결과가 같지만, W = 5 일 때 이상치가 2 개 (50% 미만) 이면 Half-sample 은 Breakdown Point 에 가까워지고, Whole-sample 은 여전히 안전합니다. Whole-sample 은 Running Median 의 50% Breakdown Point 를 경계에서도 완전히 보존합니다.

D
연속성 및 도함수 보존

Whole-sample 반사는 경계에서 데이터의 1 차 도함수 (기울기) 를 자연스럽게 보존합니다.

Whole-sample : data[-1] = data[1] → 기울기 = (data[1] − data[-1]) / 2 = 0 → 경계에서 대칭
Half-sample : data[-1] = data[0] → 기울기 = (data[1] − data[0]) / 2 → 경계에서 평탄화

Half-sample 은 경계 값을 반복하므로 기울기를 0 으로 수렴시킵니다 (Plateau 효과). Whole-sample 은 데이터의 자연 기울기를 반사하여 신호의 국소 트렌드를 보존합니다. 이는 Replicate 모드의 "경계 평탄화" 문제를 근본적으로 피합니다.

E
산업 표준과의 일관성

Whole-sample 반사는 신호 처리 분야의 사실상 표준 (de facto standard) 입니다.

라이브러리API 이름방식
MATLABmedfilt1(x, W)Whole-sample (기본값)
NumPy / SciPyndimage.median_filter(mode='reflect')Whole-sample
OpenCVmedianBlur(BORDER_REFLECT_101)Whole-sample
AvocadoSmoothieBoundaryMode.SymmetricWhole-sample ✓

AvocadoSmoothie 가 Whole-sample 을 채택함으로써, MATLAB · SciPy · OpenCV 의 결과와 동일한 경계 처리를 보장합니다. 라이브러리 간 결과 비교 · 검증이 직접 가능합니다.

3. 최적성 요약 - Whole-sample 이 Running Median 에 제공하는 5 가지 특장점
#특장점설명
1Median Neutrality경계 값 비중복으로 각 값의 등장 횟수 보존 → 순위 불변 → Median 편향 없음
2Breakdown Point 보존경계에서도 이상치 1 개 = 1 회 등장 → 50% Breakdown Point 완전 유지
3도함수 연속성경계 기울기를 반사하여 Plateau 효과 없이 자연 트렌드 보존
4멱등성 호환M(M(x)) = M(x) 성질이 경계에서도 성립 (인위 중복이 없으므로)
5산업 표준 호환MATLAB · SciPy · OpenCV 와 동일 경계 처리 → 교차 검증 가능
💡 결론 : Running Median 은 순위 기반 통계량이므로, 값의 등장 횟수가 곧 결과를 좌우합니다. Whole-sample 반사는 경계 값을 중복시키지 않아 Median 의 다수결 중립성, Breakdown Point, 도함수 연속성을 모두 보존합니다. 이것이 AvocadoSmoothie 가 Symmetric 모드를 Whole-sample 방식으로 구현하고, 이를 기본값으로 채택한 이유입니다.
Algorithm · GetWindowMedian

Median 계산 알고리즘

윈도우 내 값을 정렬하여 중앙값을 구합니다. Array.Sort in-place 정렬 후, 홀수 길이는 가운데 원소, 짝수 길이는 두 중앙 원소의 평균을 반환합니다.

📐 GetWindowMedian() 전체 코드

Private Shared Function GetWindowMedian(
    win() As Double, length As Integer) As Double

    Array.Sort(win, 0, length)  ' 앞 length 개만 in-place 정렬
    Dim mid = length \ 2

    If (length And 1) = 0 Then
        ' 짝수 길이 : 두 중앙값의 평균
        Return (win(mid - 1) + win(mid)) / 2.0
    Else
        ' 홀수 길이 : 정확한 가운데 원소
        Return win(mid)
    End If
End Function

📊 Median 계산 예시

윈도우정렬 후mid결과유형
[5, 2, 8, 1, 4][1, 2, 4, 5, 8]24홀수 (5)
[3, 7, 1, 9][1, 3, 7, 9]2(3 + 7) / 2 = 5짝수 (4)
[10][10]010홀수 (1)
[4, 6][4, 6]1(4 + 6) / 2 = 5짝수 (2)

⚡ R → W 변환 & 오버플로 보호

' ComputeMediansByRadius 내부
Dim w64 As Long = CLng(kernelRadius) * 2L + 1L
If w64 > Integer.MaxValue Then
    Throw New ArgumentOutOfRangeException(...)
End If
Dim w As Integer = CInt(w64)  ' 항상 홀수, ≥ 1
Long 으로 곱셈하여 Integer 오버플로를 방지합니다. R = 1,073,741,823 (Integer.MaxValue / 2) 이상이면 예외.

🔬 offsetLow / offsetHigh 계산 원리

offsetLow = (W − 1) \ 2     offsetHigh = (W − 1) − offsetLow
RW = 2R + 1offsetLowoffsetHigh윈도우 범위
1311[i − 1, i, i + 1]
2522[i − 2, i − 1, i, i + 1, i + 2]
3733[i − 3 .. i + 3]
51155[i − 5 .. i + 5]
W 가 항상 홀수 (2R + 1) 이므로 offsetLow = offsetHigh = R. 정수 나눗셈 (W − 1) \ 2 로 계산합니다.
Interactive · Visualization

Median Lab

입력 데이터 · 모드 · 경계 처리 · 반경을 설정하고 실시간으로 결과를 확인합니다. 각 인덱스별 윈도우 수집 → 정렬 → Median 과정을 단계별로 로그합니다.

2 → W = 5
입력 데이터 (쉼표 구분, 프리셋 또는 직접 편집)

입력 vs 출력 비교

INPUT
OUTPUT

📋 단계별 처리 로그

각 인덱스 i 에 대한 윈도우 수집 → 정렬 → Median 선택 과정
(실행 버튼을 클릭하세요)
Performance · Optimization

병렬화 & 성능 최적화

SignatureMedian 은 .NET 의 Parallel.For, ThreadLocal, Interlocked 등을 활용해 멀티코어에서 효율적으로 동작합니다.

1. Parallel.For - 행 단위 병렬화

Parallel.For(startIdx, endIdx + 1, Sub(i)
    ' 각 데이터 포인트 독립 처리
    ' 입력 arr 은 읽기 전용 → 경쟁 조건 없음
    ' buffer(i) 쓰기는 인덱스 i 고유 → 동기화 불필요
End Sub)
각 데이터 포인트 i 는 독립적으로 계산됩니다. 입력 arr 은 읽기 전용이고, 출력 buffer(i) 는 인덱스별 고유 접근이므로 lock 없이 완전 병렬화됩니다.

2. ThreadLocal - 스레드별 독립 버퍼

Dim localWin As New ThreadLocal(Of Double())(
    Function() New Double(kernelWidth - 1) {}
)

' Parallel.For 내부에서:
Dim win = localWin.Value  ' 스레드별 고유 배열
Parallel.For 내에서 win 배열이 필요하지만, 매 반복마다 new 하면 GC 부담이 큽니다. ThreadLocal 로 스레드당 1 회만 할당하여 재사용합니다.

3. Interlocked - 원자적 진행률 보고

Dim cnt = Interlocked.Increment(processed)
If cnt Mod reportInterval = 0 Then
    progress?.Report(Math.Min(n, cnt))
End If
reportInterval = Max(1, n \ 200) 으로 ~0.5% 간격으로만 Report() 를 호출하여 UI 스레드 부담을 최소화합니다.

4. Array.Sort in-place - GC 최적화

' GetWindowMedian - 별도 배열 할당 없음
Array.Sort(win, 0, length)  ' win 배열의 앞 length 개만 정렬
' win은 ThreadLocal 버퍼 → GC 없음, 할당 없음
이전 구현 (주석 처리된 코드) : win.Take(length).ToArray() 로 매번 새 배열을 할당했습니다. 현재는 in-place 정렬로 GC 부담을 제거했습니다.

📊 성능 특성 요약

항목상세
시간 복잡도O(n · W · log W) - 각 포인트에서 W 개 정렬
공간 복잡도O(n + W · threads) - buffer + 스레드별 win 배열
병렬화Parallel.For - 코어 수에 비례하는 속도 향상
GC 부담최소 - ThreadLocal 재사용, in-place 정렬
진행 보고~0.5% 간격 IProgress<Integer> 콜백
Resources · Downloads

다운로드 및 외부 링크

AvocadoSmoothie 핵심 애플리케이션 코드, .NET Standard 2.0 기반 Running Median 라이브러리 NuGet 패키지, 그리고 라이브러리 기능을 직접 실험해볼 수 있는 실습용 Tasting 애플리케이션을 아래 링크에서 확인하실 수 있습니다.

GitHub Repository happybono / AvocadoSmoothie

AvocadoSmoothie

AvocadoSmoothie 의 핵심 소스 코드 저장소입니다. VB.NET Windows Forms 기반으로 제작된 Running Median 노이즈 제거 애플리케이션으로, 커널 반경 (Radius) 과 경계 개수 (Border Count) 를 직접 설정하고, MiddleMedian 또는 AllMedian 방식을 선택하여 수치 시퀀스를 처리할 수 있습니다. 병렬 처리와 진행률 표시를 지원하여 대용량 데이터셋에서도 반응성 높은 UI 환경을 제공합니다.

NAMING PHILOSOPHY

AvocadoSmoothie 는 "Avocado"와 "Smoothie"의 합성어입니다. 아보카도가 단단한 겉면 안에 부드럽고 영양 가득한 속살을 품고 있듯, 노이즈가 섞인 원시 데이터를 내부적으로 부드럽게 정제하여 신뢰할 수 있는 값으로 블렌딩한다는 철학을 담고 있습니다.

VB.NET / .NET Windows Forms Running Median Noise Reduction
↗ View Source on GitHub
NuGet Package AvocadoSmoothie.Barista · v4.0.1 · .NET Standard 2.0

AvocadoSmoothie.Barista

.NET Standard 2.0 및 .NET Framework 4.8 을 기반으로 하는 고성능 Running Median 평활화 & 내보내기 툴킷 NuGet 패키지입니다. MiddleMedian 및 AllMedian 필터를 구성 가능한 윈도우 반경과 경계 보존 옵션으로 제공하며, 대용량 데이터셋을 위한 자동 파티셔닝을 갖춘 CSV 내보내기와 차트 및 문서 속성이 포함된 Excel 내보내기 (COM 자동화) 를 지원합니다. 병렬화된 평활화 처리와 진행률·취소 지원으로 배치 및 인터랙티브 시나리오 모두에 적합합니다.

VB.NET / .NET Standard 2.0 Running Median CSV · Excel Export Parallelization
$ dotnet add package AvocadoSmoothie.Barista --version 4.0.1
↗ Download on NuGet Gallery

⚡ Quick Start

' MiddleMedian - 경계 원본 보존, 내부만 스무딩
Dim result = SignatureMedian.ComputeMediansByRadius(
    data, kernelRadius:=2,
    useMiddle:=True, borderCount:=2,
    boundaryMode:=BoundaryMode.Symmetric)

' AllMedian - 전체 스무딩, Boundary Mode 적용
Dim result = SignatureMedian.ComputeMediansByRadius(
    data, kernelRadius:=2,
    useMiddle:=False, borderCount:=0,
    boundaryMode:=BoundaryMode.Symmetric)
GitHub Repository happybono / AvocadoSmoothie.Barista.Tasting

AvocadoSmoothie.Barista.Tasting

AvocadoSmoothie.Barista 라이브러리의 기능을 직접 체험하고 학습할 수 있는 실습용 동반 (companion) 애플리케이션입니다. 본격적인 프로덕션 애플리케이션을 구현하기 전에 Running Median 평활화, 경계 처리 옵션, 그리고 CSV · Excel 내보내기 워크플로우를 자유롭게 실험하고 익힐 수 있는 테이스팅 룸 (Tasting Room) 역할을 합니다.

NAMING PHILOSOPHY

AvocadoSmoothie.Barista 는 원재료 (데이터) 를 정밀하게 다듬어 완성된 스무디로 제공하는 바리스타처럼, 수치 시퀀스를 Running Median 으로 정제하는 VB.NET 라이브러리이며, AvocadoSmoothie.Barista.Tasting 은 그 라이브러리를 위한 시음 (Tasting) 공간 - 완성된 레시피에 앞서 맛을 확인하고 조율하는 실습 샘플입니다.

VB.NET / .NET Hands-on Study App Signal Processing Sample · Docs Included
↗ View on GitHub