Tool 활용법/Sionna 활용법

Blender 기반 도시 모델에서 물리 채널 생성하기 (CIR, CFR, Radio Map)

gksyb4235 2026. 2. 11. 23:15

대학교 3D 모델을 활용한 MIMO 채널 분석 및 공간 커버리지 시각화 실험


앞 단계에서 PathSolver를 통해 다중 전파 경로(Paths)를 계산했다면,

이제 이 물리 경로를 통신 시스템이 실제로 사용하는 채널 표현으로 변환해야 한다.

Sionna RT는 Paths 객체를 통해 다음을 직접 생성할 수 있다.

  • 연속시간 등가 기저대역 채널 임펄스 응답 (CIR)
  • 채널 주파수 응답 (CFR)
  • 이산 복소 기저대역 채널 탭 (taps)
  • 공간 기반 Radio Map

 

 

직접 생성한 Scene에 Tx, Rx 배치하기


여기서는 test_scene 폴더 안에 있는 test_scene.xml 파일을 로드한다.

 

scene = load_scene("test_scene/kyunghee.xml")

 

이 XML 파일에는 Blender에서 생성한 건물, 지면, 그리고 각 객체에 할당한 radio material 정보가 포함되어 있다.

Sionna는 이를 기반으로 전파 시뮬레이션을 수행할 수 있는 내부 구조로 변환한다.

 

아래는 XML 파일의 형태이다.

우리가 설정한 Materials와 건물 정보가 잘 들어가 있다.

 

모듈 import, Scene Load 후 scene.preview를 통해 제대로 로드되었는지 확인한다.

 

 

 

뒤에서는 송신기(Transmitter)와 수신기(Receiver)를 배치하고,

Sionna RT를 사용해 통신 시스템이 실제로 사용하는 채널 표현으로 변환한다.

 

 

 

Transmitter와 Receiver 인스턴스 생성


다음으로 실제 무선 장치를 생성하는 방법은 다음과 같다.

tx = Transmitter("tx", [0, 0, 0], [0.0, 0.0, 0.0])
scene.add(tx)

rx = Receiver("rx", [0, 0, 0], [0.0, 0.0, 0.0])
scene.add(rx)

 

이때 tx와 rx의 인자의 의미는 다음과 같다.

  1. 장치 이름
  2. 위치 좌표 (x, y, z)
  3. 방향 (orientation)

 

이때 내가 생성할 좌표를 얻기 위해 Blender를 활용할 수 있다.
Blender에서 Cursor Tool → View 탭 → Location을 사용하면 Scene 내 원하는 위치의 정확한 좌표를 확인할 수 있다.

이 과정을 통해 3D 모델과 RF 시뮬레이션 좌표계를 정확히 일치시킬 수 있다.

기지국의 위치는 전자정보대학교 옥상에 설치했다.

 

수신자는 도서관으로 향하고 있는 학생으로 한다.

 

 

이를 통해 최종 설정한 좌표는 아래와 같다. (사람이 들고 있는 핸드폰의 위치는 1.5m로 설정)

이때 look_at을 통해 tx는 rx를 향하도록 한다.

scene.tx_array = PlanarArray(num_rows=4,
                             num_cols=4,
                             vertical_spacing=0.5,
                             horizontal_spacing=0.5,
                             pattern="tr38901",
                             polarization = "V")

scene.rx_array = PlanarArray(num_rows=1,
                             num_cols=1,
                             vertical_spacing=0.5,
                             horizontal_spacing=0.5,
                             pattern='iso',
                             polarization = "V")

tx = Transmitter("tx", [132.4, -27.36, 16.83], [0.0, 0.0, 0.0])
scene.add(tx)

rx = Receiver("rx", [-36.81, 18.67, 1.5], [0.0, 0.0, 0.0])
scene.add(rx)

tx.look_at(rx) # Transmitter points towards receiver

 

이제 제대로 배치되었는지 확인해보자.

# Instantiate a path solver
# The same path solver can be used with multiple scenes
p_solver  = PathSolver()

# Compute propagation paths
paths = p_solver(scene=scene,
                 max_depth=5,
                 los=True,
                 specular_reflection=True,
                 diffuse_reflection=False,
                 refraction=True,
                 synthetic_array=False,
                 seed=41)
                 
scene.preview(paths=paths, clip_at=20)

 

 

확실히 건물이 밀집되지 않은 탁 트인 환경이라 산란이나 반사가 잘 일어나지 않음을 확인할 수 있다.

 

 

 

 

CIR·CFR·Radio Map 계산하기


앞 단계에서 PathSolver를 통해 다중 전파 경로(Paths)를 계산했다면,
이제 이 물리 경로를 통신 시스템이 실제로 사용하는 채널 표현으로 변환해야 한다.

Sionna RT는 Paths 객체를 통해 다음을 직접 생성할 수 있다.

  • 연속시간 등가 기저대역 채널 임펄스 응답 (CIR)
  • 이산 복소 기저대역 채널 탭 (taps)
  • 채널 주파수 응답 (CFR)
  • 시간 변화 채널 (Doppler 기반)
  • 공간 기반 Radio Map

 

Paths → CIR (Channel Impulse Response)


CIR은 다음과 오른쪽과 같이 표현된다.

 

  • : p번째 경로의 복소 계수
  • τ_p: 경로 지연
  • P: 경로 수

Sionna RT에서는 다음 한 줄로 생성된다.

 

a, tau = paths.cir(normalize_delays=True, out_type="numpy")

 

이때 반환되는 tensor의 구조는 다음과 같다.

 

 

이는 아래와 같은 형태이다.

 

  • a shape: [num_rx, num_rx_ant, num_tx, num_tx_ant, num_paths, num_time_steps]
  • tau shape: [num_rx, num_rx_ant, num_tx, num_tx_ant, num_paths]

 

a.shape는 다음과 같다.

차원 의미
num_rx 수신기 개수 1
num_rx_ant 수신 안테나 개수 2
num_tx 송신기 개수 1
num_tx_ant 송신 안테나 개수 16
num_paths 경로 개수 14
num_time_steps 시간 샘플 수 1

 

송신 안테나가 16개인데, 이는 Tx 배열을 4 × 4 PlanarArray로 설정했기 때문이다.

즉 현재 채널은, 16 × 2 MIMO 채널이다.

수신 안테나가 2개인 이유는 RX 쪽에 dual polarization이 설정되었기 때문이다.

 

경로 수 14개는 LoS + 반사 + 굴절 등을 포함하여 총 14개의 경로가 검출되었다는 뜻이다.

max_depth, 도시 구조, synthetic_array 여부에 따라 달라짐

 

시간 차원 = 1이라는 뜻은 velocity를 설정하지 않았거나 cir() 호출 시 num_time_steps를 지정하지 않았기 때문이다.

즉, 현재 채널은 정적 채널(static channel) 상태다.

 

정리하면 TX 안테나 16개 / RX 안테나 2개 / 각 링크마다 14개의 multipath / 시간 변화 없음

이는 완전한 MIMO 물리 채널을 나타낸다.

 

 

채널 임펄스 응답(Channel Impulse Response, CIR) 시각화


t = tau[0,0,0,0,:]/1e-9 # Scale to ns
a_abs = np.abs(a)[0,0,0,0,:,0]
a_max = np.max(a_abs)

# And plot the CIR
plt.figure()
plt.title("Channel impulse response")
plt.stem(t, a_abs)
plt.xlabel(r"$\tau$ [ns]")
plt.ylabel(r"$|a|$");

 

 

왼쪽은 실제 경희대 모델처럼 장애물도 없고 탁 트인 환경에서의 CIR 결과이다.

이 경우 송신기와 수신기 사이에 장애물이 거의 없는 구조로 반사 조건을 만족하는 표면도 없고, 난반사도 활성화되지 않았기 때문에 다중 경로가 거의 생성되지 않아 실제로 계산된 propagation paths가 LoS(Line-of-Sight) 중심으로 형성되었다.

따라서 CIR에는 강한 LoS 성분 하나만 지배적으로 나타나고, 다른 경로들은 존재하지 않거나 매우 미약하게 나타난다.

특히, 첫 번째 도달 경로 지연은 기본적으로 0으로 정규화되기 때문에 왼쪽 그림에 나타난 것처럼 단일 스파이크에 가까운 형태는 오류가 아니라 해당 환경의 물리적 특성을 제대로 반영한 결과다.

 

반면 오른쪽 그림은 앞서 Munich 환경과 같이 건물과 구조물이 복잡하게 배치된 도시 환경에서 계산된 결과로,
전파가 여러 표면에서 반사·굴절되며 다중 경로가 풍부하게 형성된 경우다.

이 경우 CIR에는 다양한 지연 구간에 걸쳐 여러 개의 경로 성분이 분포하며, 전형적인 다중 경로 채널 특성이 나타난다.

 

 

 

 

Paths → CFR (Channel Frequency Response)


OFDM 시스템에서는 주파수 응답이 필요하다.

CFR(Channel Frequency Response)는 CIR을 주파수 영역으로 변환한 형태이며,
오른쪽과 같이 표현할 수 있다.

 

여기서

  • a_p: p번째 경로의 복소 계수
  • τ_p: 경로 지연
  • P: 경로 수

각 서브캐리어 주파수에서 모든 경로 성분이 위상 회전을 거쳐 합산된 값이 CFR이다.

즉, CFR은 각 서브캐리어 주파수에서의 채널 응답을 계산한다.

이는 실제 5G NR 물리계층 시뮬레이션과 직접 연결할 수 있다.

 

// OFDM 파라미터 설정
num_subcarriers = 1024
subcarrier_spacing = 30e3

frequencies = subcarrier_frequencies(num_subcarriers, subcarrier_spacing)
# Compute channel frequency response
h_freq = paths.cfr(frequencies=frequencies,
                   normalize=True, # Normalize energy
                   normalize_delays=True,
                   out_type="numpy")

# Shape: [num_rx, num_rx_ant, num_tx, num_tx_ant, num_time_steps, num_subcarriers]
print("Shape of h_freq: ", h_freq.shape)

 

이때 반환되는 tensor 구조는 다음과 같다.

h_freq shape: [num_rx, num_rx_ant, num_tx, num_tx_ant, num_time_steps, num_subcarriers]
 

이를 차원별로 해석하면 다음과 같다.

차원 의미
num_rx 수신기 개수 1
num_rx_ant 수신 안테나 개수 2
num_tx 송신기 개수 1
num_tx_ant 송신 안테나 개수 16
num_time_steps 시간 샘플 수 1
num_subcarriers 서브캐리어 개수 1024

송신 안테나가 16개인 이유는 TX 배열을 4 × 4 PlanarArray로 설정했기 때문이다.
수신 안테나가 2개인 이유는 RX 쪽에 dual polarization이 설정되었기 때문이다.

따라서 각 서브캐리어마다 16 × 2 MIMO 채널 행렬이 존재한다.

 

 

채널 주파수 응답(Channel Frequency Response, CFR) 시각화


# Plot absolute value
plt.figure()
plt.plot(np.abs(h_freq)[0,0,0,0,0,:]);
plt.xlabel("Subcarrier index");
plt.ylabel(r"|$h_\text{freq}$|");
plt.title("Channel frequency response");

 

첫 번째 그림은 경희대처럼 장애물이 거의 없는 개방 환경에서의 CFR로, LoS 성분이 지배적인 채널 특성을 그대로 반영한다.

CIR 분석에서 확인했듯이 다중 경로가 거의 존재하지 않으면 지연 확산(delay spread)이 매우 작고, 그 결과 주파수 영역에서도 채널 이득이 거의 일정하게 유지된다.

이는 주파수 선택성이 거의 없는 평탄 페이딩(flat fading)에 가까운 형태이며, 모든 서브캐리어가 유사한 채널 이득을 갖는다.

즉, 시간 영역에서 단일 스파이크에 가까운 CIR은 주파수 영역에서 거의 일정한 CFR로 대응된다.

 

반면 오른쪽은 뮌헨과 같은 복잡한 도시 환경에서의 CFR로, 다수의 반사·굴절 경로가 형성된 다중 경로 채널의 전형적인 모습이다.

CIR에서 여러 지연 성분이 분포하면, 각 경로가 서로 다른 위상 회전을 거쳐 합산되면서 서브캐리어별로 간섭 패턴이 발생한다.

그 결과 특정 주파수에서는 이득이 크게 감소하고(딥 페이딩), 다른 주파수에서는 강화되는 주파수 선택적 페이딩이 나타난다.

즉, 시간 영역에서의 넓은 지연 확산은 주파수 영역에서의 큰 진폭 변동으로 이어지며, 이는 복잡한 도시 환경 채널의 핵심 특성이다.

 

 

 

 

Discrete Channel Taps: 시간 영역 링크 레벨 모델로 확장하기


앞에서 CIR(연속시간)과 CFR(주파수 영역)을 구했다면, 이제 실제 링크 레벨 시뮬레이션에 직접 투입 가능한 이산 시간 채널 모델(channel taps)과 이동성(mobility)까지 확장하는 단계다.

이 부분은 CIR/CFR의 응용 단계에 해당하며, 특히 OFDM 또는 단일 반송파 시간영역 시뮬레이션에서 핵심적이다.

 

 

Discrete Channel Taps: 연속 CIR → 이산 채널


링크 레벨 시뮬레이션에서는 연속 시간의 δ-함수 형태 CIR 대신, 샘플링된 이산 채널 계수 h[ℓ]이 필요하다.

이산 채널은 다음 과정을 통해 얻어진다.

  1. CIR을 원하는 대역폭으로 저역통과 필터링
  2. 샘플링 주파수에서 샘플링
  3. 무한 길이 sinc 응답 → 유한 구간으로 truncation
taps = paths.taps(bandwidth=100e6, # Bandwidth to which the channel is low-pass filtered
                  l_min=-6,        # Smallest time lag
                  l_max=100,       # Largest time lag
                  sampling_frequency=None, # Sampling at Nyquist rate, i.e., 1/bandwidth
                  normalize=True,  # Normalize energy
                  normalize_delays=True,
                  out_type="numpy")

print("Shape of taps: ", taps.shape)
>>>
(1, 2, 1, 1, 1, 107)

 

 

  • bandwidth : 채널을 저역통과 필터링할 대역폭 (예: 100 MHz 시스템)
  • sampling_frequency=None : 기본적으로 Nyquist rate에서 샘플링
    → fs=1/bandwidthf_s = 1/\text{bandwidth}
  • l_min, l_max : tap index 범위
    → sinc 필터는 무한 길이를 가지므로 반드시 자른다.

 

이때 출력 Tensor의 구조는 다음과 같다.

[num_rx,
 num_rx_ant,
 num_tx,
 num_tx_ant,
 num_time_steps,
 num_taps]

 

 

즉, 총 107개의 tap을 가짐을 의미한다.

 

 

Discrete Channel Taps 시각화하기


plt.figure()
plt.stem(np.arange(-6, 101), np.abs(taps)[0,0,0,0,0]);
plt.xlabel(r"Tap index $\ell$");
plt.ylabel(r"|$h[\ell]|$");
plt.title("Discrete channel taps");

 

 

이 그래프는 실제 통신 시스템에서 사용하는 FIR 채널 계수를 보여준다.

 

왼쪽 그림은 경희대처럼 탁 트인 공간에서의 Discrete Channel Taps 결과로, 사실상 LoS 성분만 존재하는 채널에 가까운 형태다.

이처럼 Los Dominant 환경에서는 tap이 거의 1~2개에 집중되며,  대부분의 tap 인덱스에서 계수가 거의 0에 수렴한다.

이는 CIR에서 확인한 것처럼 지연 확산(delay spread)이 극히 작고, 다중 경로가 거의 형성되지 않았기 때문이다.

결과적으로 시간 영역에서 채널은 거의 단일 경로 FIR 필터에 가까우며, ISI(Inter-Symbol Interference) 영향도 매우 제한적이다. 이런 환경에서는 채널이 거의 flat fading 특성을 보이게 된다.

 

반면 오른쪽 그림은 뮌헨과 같은 복잡한 도시 환경에서의 결과로, 여러 tap 인덱스에 걸쳐 유의미한 에너지가 분포하고 있다.

첫 번째 tap(LoS)이 가장 크지만, 이후 20~90 인덱스 구간에 다수의 반사 및 산란 경로 성분이 존재한다.

이는 CIR에서 나타난 다중 지연 성분이 이산 시간 영역에서 여러 tap으로 확산된 결과다.

즉, 지연 확산이 크고 다중 경로가 풍부한 채널이며, 시간 영역에서 긴 FIR 구조를 형성한다.

이러한 채널은 주파수 영역에서는 강한 주파수 선택적 페이딩을 유발하며, 등화(equalization) 설계와 CP 길이 설정에 중요한 영향을 미친다.

 

 

 

 

Radio Map: 공간 전체에서의 채널 품질 시각화


앞에서는 특정 TX–RX 쌍에 대해 전파 경로를 계산했다면,

Radio Map은 관점을 바꿔서 “공간 전체에서 이 송신기의 신호가 어떻게 분포하는가”를 계산하는 기능이다.

즉, 하나의 수신기 위치가 아니라, 평면 위의 모든 점을 가상의 수신기 위치로 가정하여 채널 지표를 계산한다.

 

 

Radio Map의 개념


Radio Map은 다음과 같은 값을 공간 좌표 (x,y)마다 계산한다.

  • Path Gain (채널 이득)
  • RSS (Received Signal Strength)
  • SINR (Signal-to-Interference-plus-Noise Ratio)

즉, 특정 송신기에 대해, 공간상의 모든 위치에서 관측될 신호 품질을 지도 형태로 표현한 것이라고 볼 수 있다.

 

이 기능은 다음과 같은 연구에 매우 유용하다.

  • 기지국 배치 최적화 / 커버리지 분석 / 빔포밍 설계 / Digital Twin 기반 네트워크 계획 / 6G 자율 네트워크 시뮬레이션

 

 

RadioMapSolver 생성 및 계산


Path 계산에 PathSolver가 필요했듯이, Radio Map 계산에는 RadioMapSolver가 필요하다.

 

rm_solver = RadioMapSolver()

 

이 객체는 공간을 격자로 나눈 뒤, 각 격자점에서 전파 경로를 계산하여 원하는 지표를 생성한다.

이후 Radio Map을 계산한다. 

 

rm = rm_solver(
    scene=scene,
    max_depth=5,
    cell_size=[1,1],
    samples_per_tx=10**6
)

 

주요 파라미터는 아래와 같다.

  • scene : 전파 환경 (건물, 재료, TX 위치 포함)
  • max_depth : 반사·굴절 최대 횟수 (높을수록 다중 경로 효과 반영 ↑, 계산량 ↑)
  • cell_size=[1,1] : Radio Map의 공간 해상도 (1m × 1m 격자)
  • samples_per_tx=10⁶ : Monte Carlo 샘플 수 (난반사 포함 시 샘플링 정밀도에 영향)

해상도를 줄이면 계산 속도는 빨라지지만 공간 분해능은 떨어진다.

다음으로 결과를 시각화한다.

 

scene.preview(radio_map=rm)