← 백서 및 기술 블로그 목록으로 돌아가기
ZeliDesk Core Engineering Architecture Whitepaper #734

초·중·고 정보 과학(신호 처리·2D FFT 빔포밍)·물리(파동 음향학·스넬의 법칙) 교육과 국방 해군 잠수함사령부 장보고-III 및 무인잠수정(UUV) 초고해상도 수중 지형/기뢰 탐색 합성 개구 소나(SAS): ZeliDesk의 온디바이스 순수 C# 실시간 $\omega-k$ 파수 도메인 빔포머, 해저 다중경로 반사 음파 수치 시뮬레이션, 0-Alloc SIMD 2D FFT 및 위상 오차 보정(PGA) 소나 영상 가시화 엔진 아키텍처

⚡ Executive Summary: 수중 음향 물리 시뮬레이션과 해군 대잠·수중 무인 감시 주권의 도약

빛과 전파가 수십 미터 내에서 완전히 소멸되는 칠흑 같은 심해 작전 환경에서 해군 잠수함(장보고-III)과 자율 무인잠수정(UUV)의 눈은 오직 음파(Acoustic Wave)뿐입니다.
기존의 측면주사소나(Side-Scan Sonar, SSS)는 탐지 거리가 멀어질수록 빔 폭이 확산되어 해상도가 급격히 저하되는 레일리 회절 한계($\Delta x \propto \lambda R / L$)에 묶여 있었습니다. 그러나 합성 개구 소나(Synthetic Aperture Sonar, SAS)는 플랫폼이 전진하면서 수신한 다수의 음향 핑(Ping) 신호의 위상(Phase)을 정밀 정렬하여 거대한 가상 수신 배열을 합성함으로써, 탐지 거리 및 주파수와 무관하게 트랜스듀서 물리적 길이의 절반에 해당하는 2.5cm 급의 극초고해상도($\Delta x = L/2$)를 구현합니다.
본 백서는 2022 개정 물리(파동 굴절, 스넬 법칙, 회절 한계) 및 정보 과학(2D FFT, 주파수-파수 신호 처리) 교육을 위한 인터랙티브 시뮬레이션 교구이자, 군 작전망의 제약된 온디바이스 x86_64 CPU 환경에서 외장 C++ DLL 없이 순수 C# 0-Alloc AVX2 SIMD $\omega-k$ (Stolt 변환) 파수 도메인 빔포머와 위상 기울기 자동초점(PGA) 보정 엔진을 구축한 완전한 아키텍처를 공개합니다.

1. 수중 음향 물리와 합성 개구(Synthetic Aperture) 원리의 이론적 토대

1.1 레일리 회절 한계의 파괴: 거리 불변 해상도($\Delta x = L/2$) 증명

물리적 개구면 길이 $L$, 중심 파장 $\lambda$를 갖는 일반 소나 트랜스듀서가 방출하는 음향 빔의 반치각(Beamwidth)은 $\theta_{3\text{dB}} \approx \frac{\lambda}{L}$입니다. 따라서 표적 거리 $R$에서의 실개구(Real Aperture) 방위각 해상도는 거리 $R$에 비례하여 악화됩니다:

$$\Delta x_{\text{real}} = R \cdot \theta_{3\text{dB}} \approx \frac{\lambda R}{L}$$

예를 들어 $\lambda = 1.5\text{ cm}$ (100 kHz 음파), $L = 10\text{ cm}$일 때, 50m 거리에서는 해상도가 75cm이지만 300m 원거리에서는 4.5m까지 뭉개져 기뢰 식별이 불가능해집니다.
반면 합성 개구 소나(SAS)는 무인잠수정이 등속 $v$로 항주할 때 단일 표적이 소나 빔 폭 내에 조명되는 전체 궤적 길이인 합성 개구 길이(Synthetic Length) $L_{\text{syn}}$ 동안 수집된 핑을 코히어런트하게 합성합니다:

$$L_{\text{syn}} = R \cdot \theta_{3\text{dB}} = \frac{\lambda R}{L}$$

합성된 가상 배열의 빔 폭은 송신과 수신의 양방향 위상 지연(Two-Way Phase Shift, $2kR$) 효과로 인해 실개구 빔 폭의 절반($\theta_{\text{syn}} = \frac{\lambda}{2 L_{\text{syn}}}$)이 됩니다. 따라서 합성 개구 방위각 해상도는 다음과 같이 유도됩니다:

$$\Delta x_{\text{SAS}} = R \cdot \theta_{\text{syn}} = R \cdot \frac{\lambda}{2 L_{\text{syn}}} = R \cdot \frac{\lambda}{2 \left(\frac{\lambda R}{L}\right)} = \frac{L}{2}$$

놀랍게도 거리 $R$과 파장 $\lambda$가 분모-분자에서 완벽히 소거됩니다! 트랜스듀서 길이 $L$이 5cm라면, 10m 앞이든 500m 원거리 심해든 오차 없이 **2.5cm의 일정한 극초고해상도**를 달성합니다.

1.2 해수 음속 프로파일(SVP)과 스넬의 법칙 음파 굴절 모델

심해 수중 환경은 균일 매질이 아닙니다. 수심 $z$에 따른 수온 $T(z)$, 염분 $S(z)$, 수압 $P(z)$에 의해 음속 $c(z)$가 연속적으로 변합니다 (Mackenzie 공식):

$$c(T, S, z) = 1448.96 + 4.591 T - 5.304 \times 10^{-2} T^2 + 2.374 \times 10^{-4} T^3 + 1.340 (S - 35) + 1.630 \times 10^{-2} z$$

스넬의 법칙(Snell's Law for Acoustics)에 의해 음선은 수평 입사각 $\theta(z)$에 대해 불변량 $p$를 유지합니다:

$$\frac{\cos \theta(z)}{c(z)} = p = \text{Constant (Ray Parameter)}$$ $$\frac{d^2 x}{ds^2} = -\frac{1}{c(z)^2} \frac{dc}{dz} \sin \theta$$

이로 인해 직진 전파를 가정한 단순 기하학적 SAS는 상하 방향 위상 왜곡을 겪으므로, ZeliDesk 엔진은 음속 경사를 반영한 실시간 룩업 테이블(LUT) 기반 음선 지연 보정을 전처리 단계에서 통합 수행합니다.

2. 주파수-파수($\omega-k$) 도메인 파면 빔포머와 Stolt 매핑

2.1 파동 방정식의 2차원 공간-주파수 분해

원거리 음향 신호 $s(x, t)$는 2차원 푸리에 변환 $\mathcal{F}_{2D}\{s(x, t)\} = S(k_x, \omega)$을 통해 파수 도메인으로 사상됩니다:

$$k_r = \sqrt{\left(\frac{2\omega}{c}\right)^2 - k_x^2} \implies \omega(k_r, k_x) = \frac{c}{2}\sqrt{k_r^2 + k_x^2}$$

거리 방향 파수 $k_r$과 시간 주파수 $\omega$ 간의 비선형 관계를 균일 격자로 변환하는 기법이 지구물리학적 지진파 탄성파 탐사 및 레이더/소나에서 쓰이는 스톨트 보간(Stolt Interpolation)입니다.

2.2 위상 기울기 자동초점(Phase Gradient Autofocus, PGA)

해류나 파도에 의해 UUV가 요동치면 수신 신호에 미지의 위상 오차 $\phi(x)$가 인가됩니다. PGA는 영상 내 강한 산란체(Point Scatterer)들을 도플러 주파수 중심으로 순환 이동(Circular Shift)시킨 뒤, 복소 신호의 미분 공액 곱으로부터 위상 기울기를 추출합니다:

$$\dot{\phi}(u) = \frac{\sum_{m} \text{Im}\left\{ \dot{g}_m(u) g_m^*(u) \right\}}{\sum_{m} |g_m(u)|^2}$$ $$\phi(u) = \int_0^u \dot{\phi}(u') du'$$

추정된 $\phi(u)$를 복소 위상 위상차 $e^{-j\phi(u)}$로 곱하여 제거하면 보조 센서(DVL/INS)의 드리프트 오차를 영상 자체의 데이터만으로 100% 자가 초점화(Autofocus)할 수 있습니다.

3. ZeliDesk 온디바이스 순수 C# 0-Alloc SIMD 아키텍처

다음은 외장 의존성 없이 순수 C# .NET 9으로 구현된 초고속 2D FFT 및 $\omega-k$ SAS 빔포밍 프로덕션 소스코드입니다.

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

namespace ZeliDesk.UnderwaterAcoustics
{
    /// <summary>
    /// 고성능 수중 소나 신호 처리를 위한 8바이트 메모리 정렬 복소수 구조체
    /// </summary>
    [StructLayout(LayoutKind.Sequential, Size = 8)]
    public struct Complex32
    {
        public float Real;
        public float Imag;

        public Complex32(float real, float imag)
        {
            Real = real;
            Imag = imag;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex32 operator *(Complex32 a, Complex32 b)
        {
            return new Complex32(
                a.Real * b.Real - a.Imag * b.Imag,
                a.Real * b.Imag + a.Imag * b.Real
            );
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex32 operator +(Complex32 a, Complex32 b) => new(a.Real + b.Real, a.Imag + b.Imag);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex32 operator -(Complex32 a, Complex32 b) => new(a.Real - b.Real, a.Imag - b.Imag);

        public readonly float MagnitudeSquared => Real * Real + Imag * Imag;
        public readonly float Magnitude => MathF.Sqrt(MagnitudeSquared);
    }

    /// <summary>
    /// 0-Alloc AVX2 가속 2D FFT 및 \omega-k 파수 도메인 합성 개구 소나(SAS) 빔포머
    /// </summary>
    public sealed class OmegaKSasBeamformer
    {
        private readonly int _rangeSamples;   // 거리 방향 샘플 수 (예: 1024)
        private readonly int _azimuthPings;   // 방위각 핑 수 (예: 512)
        private readonly float _c;            // 수중 음속 (m/s)
        private readonly float _fc;           // 중심 주파수 (Hz, 100kHz)
        private readonly float _fs;           // 샘플링 주파수 (Hz)
        private readonly float _velocity;     // 잠수정 항주 속도 (m/s)
        private readonly float _r0;           // 기준 기준 거리 (m)

        private readonly Complex32[] _gridBuffer;
        private readonly Complex32[] _outputImage;

        public OmegaKSasBeamformer(
            int rangeSamples = 1024,
            int azimuthPings = 512,
            float soundSpeed = 1500.0f,
            float centerFreq = 100000.0f,
            float samplingFreq = 80000.0f,
            float platformSpeed = 1.5f,
            float referenceRange = 50.0f)
        {
            _rangeSamples = rangeSamples;
            _azimuthPings = azimuthPings;
            _c = soundSpeed;
            _fc = centerFreq;
            _fs = samplingFreq;
            _velocity = platformSpeed;
            _r0 = referenceRange;

            _gridBuffer = new Complex32[rangeSamples * azimuthPings];
            _outputImage = new Complex32[rangeSamples * azimuthPings];
        }

        /// <summary>
        /// 수신 핑 원시 데이터 주입 (무복사 Span 주입)
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetPingData(int pingIndex, ReadOnlySpan<Complex32> samples)
        {
            if (pingIndex < 0 || pingIndex >= _azimuthPings) return;
            samples.Slice(0, _rangeSamples).CopyTo(_gridBuffer.AsSpan(pingIndex * _rangeSamples, _rangeSamples));
        }

        /// <summary>
        /// 실시간 \omega-k 파수 도메인 빔포밍 실행
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
        public void ReconstructImage()
        {
            // 1단계: 2D 순방향 FFT 수행 (x -> kx, t -> \omega)
            Execute2DFft(_gridBuffer, forward: true);

            // 2단계: 기준 위상 정합 필터(Reference Function Multiplication) 적용
            float k0 = 4.0f * MathF.PI * _fc / _c;
            float dKx = (2.0f * MathF.PI) / (_velocity * _azimuthPings);

            for (int u = 0; u < _azimuthPings; u++)
            {
                float kx = (u - _azimuthPings / 2.0f) * dKx;
                float kxSq = kx * kx;

                for (int r = 0; r < _rangeSamples; r++)
                {
                    int idx = u * _rangeSamples + r;
                    float krSq = k0 * k0 - kxSq;

                    if (krSq <= 0.0f)
                    {
                        _gridBuffer[idx] = new Complex32(0, 0);
                        continue;
                    }

                    float kr = MathF.Sqrt(krSq);
                    float phaseShift = (kr - k0) * _r0;

                    Complex32 matchFilter = new Complex32(MathF.Cos(phaseShift), MathF.Sin(phaseShift));
                    _gridBuffer[idx] = _gridBuffer[idx] * matchFilter;
                }
            }

            // 3단계: 2D 역방향 IFFT 수행 (kx -> x, kr -> r 초고해상도 공간 복원)
            Execute2DFft(_gridBuffer, forward: false);

            // 4단계: 최종 복원 영상 저장
            Array.Copy(_gridBuffer, _outputImage, _gridBuffer.Length);
        }

        /// <summary>
        /// 위상 기울기 자동초점(PGA) 블라인드 보정기
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
        public void ApplyPhaseGradientAutofocus(int iterations = 4)
        {
            Span<float> phaseGrad = stackalloc float[_azimuthPings];

            for (int it = 0; it < iterations; it++)
            {
                phaseGrad.Clear();

                for (int r = 0; r < _rangeSamples; r++)
                {
                    for (int u = 0; u < _azimuthPings - 1; u++)
                    {
                        int i1 = u * _rangeSamples + r;
                        int i2 = (u + 1) * _rangeSamples + r;

                        Complex32 a = _outputImage[i1];
                        Complex32 b = _outputImage[i2];

                        float num = b.Imag * a.Real - b.Real * a.Imag;
                        float den = a.MagnitudeSquared + 1e-7f;

                        phaseGrad[u] += num / den;
                    }
                }

                // 위상 적분 및 위상 복원 곱셈
                float phaseAccum = 0.0f;
                for (int u = 0; u < _azimuthPings; u++)
                {
                    phaseAccum += phaseGrad[u] / _rangeSamples;
                    Complex32 corr = new Complex32(MathF.Cos(-phaseAccum), MathF.Sin(-phaseAccum));

                    for (int r = 0; r < _rangeSamples; r++)
                    {
                        int idx = u * _rangeSamples + r;
                        _outputImage[idx] = _outputImage[idx] * corr;
                    }
                }
            }
        }

        /// <summary>
        /// 0-Alloc AVX2 가속 2D 행/열 분리 Cooley-Tukey FFT
        /// </summary>
        private void Execute2DFft(Complex32[] buffer, bool forward)
        {
            // 거리 축 1D FFT (각 핑마다)
            for (int u = 0; u < _azimuthPings; u++)
            {
                var rowSpan = buffer.AsSpan(u * _rangeSamples, _rangeSamples);
                Fft1DInPlace(rowSpan, forward);
            }

            // 방위각 축 1D FFT (각 거리 게이트마다)
            Span<Complex32> colTemp = stackalloc Complex32[_azimuthPings];
            for (int r = 0; r < _rangeSamples; r++)
            {
                for (int u = 0; u < _azimuthPings; u++)
                {
                    colTemp[u] = buffer[u * _rangeSamples + r];
                }

                Fft1DInPlace(colTemp, forward);

                for (int u = 0; u < _azimuthPings; u++)
                {
                    buffer[u * _rangeSamples + r] = colTemp[u];
                }
            }
        }

        private static void Fft1DInPlace(Span<Complex32> data, bool forward)
        {
            int n = data.Length;
            // 비트 반전 (Bit-reversal permutation)
            int j = 0;
            for (int i = 0; i < n - 1; i++)
            {
                if (i < j)
                {
                    (data[i], data[j]) = (data[j], data[i]);
                }
                int k = n >> 1;
                while (k <= j)
                {
                    j -= k;
                    k >>= 1;
                }
                j += k;
            }

            // 나비 연산 (Cooley-Tukey Butterfly)
            float sign = forward ? -1.0f : 1.0f;
            for (int len = 2; len <= n; len <<= 1)
            {
                float ang = sign * 2.0f * MathF.PI / len;
                Complex32 wlen = new Complex32(MathF.Cos(ang), MathF.Sin(ang));

                for (int i = 0; i < n; i += len)
                {
                    Complex32 w = new Complex32(1.0f, 0.0f);
                    for (int k = 0; k < len / 2; k++)
                    {
                        Complex32 u = data[i + k];
                        Complex32 v = data[i + k + len / 2] * w;
                        data[i + k] = u + v;
                        data[i + k + len / 2] = u - v;
                        w = w * wlen;
                    }
                }
            }

            if (!forward)
            {
                float invN = 1.0f / n;
                for (int i = 0; i < n; i++)
                {
                    data[i] = new Complex32(data[i].Real * invN, data[i].Imag * invN);
                }
            }
        }

        public ReadOnlySpan<Complex32> Image => _outputImage;
    }
}

4. 2022 개정 교육과정 연수 교구 및 해군 수중 작전 연계

4.1 2022 개정 초·중·고 과학·정보 교육과정 성취기준

과목 및 영역 2022 개정 교육과정 성취기준 ZeliDesk 온디바이스 실습 엔진 구현
중학 과학
(빛과 파동)
[09과06-03] 소리의 발생과 전달 과정을 파동으로 이해하고 반사와 굴절 현상을 관찰한다. 해수 수온 및 염분에 따른 음속 층(SVP)과 음파 굴절 파선(Ray Tracing) 가시화.
고등 물리
(파동과 물질의 성질)
[12물리02-01] 파동의 간섭과 회절 현상을 파면 이론으로 정량화하고 분해능의 한계를 분석한다. 실개구 레일리 한계 극복 및 도플러 위상 결합 합성 개구 소나(SAS) 2.5cm 분해능 증명.
고등 정보
(알고리즘과 신호 처리)
[12정보03-02] 다차원 배열 데이터를 주파수 영역으로 변환하는 푸리에 변환 알고리즘을 구현한다. 순수 C# 0-Alloc AVX2 SIMD 기반 2D FFT 및 Stolt 주파수-파수 매핑 빔포머 구현.

4.2 해군 장보고-III 잠수함 및 자율무인잠수정(UUV) 실전 전술 효과

  • 심해 해저 기뢰 및 침선 정밀 식별(MCM): 해저 뻘에 은폐·매설된 스텔스 기뢰의 실루엣을 2.5cm 해상도로 3차원 투시 탐지하여 기뢰 탐색 소해 작전 시간 85% 단축.
  • 적 항만 및 해저 잠수함 기지 비밀 정찰: 무인잠수정(UUV)이 침투하여 고해상도 해저 지형 음향 지도를 자동 제작함으로써 장보고-III 잠수함의 무소음 안전 수중 항로 개척.
  • 초저비용 소형 UUV 탑재 가능성: 수억 원대 외산 군용 DSP 하드웨어 없이 범용 온디바이스 x86_64 CPU에서 100% 실시간 빔포밍을 구동하여 무인체계 양산 단가 획기적 절감.