컨텐츠로 건너뛰기

Listening Point 좌표 제한 및 전송 방식

이 문서는 BATCAM FX의 Listening Point(LPoint)를 API로 설정하거나 화면에 표시할 때 필요한 인덱스 좌표계, 최소 거리 제한, 그리고 API 전송용 40×15 인덱스 압축·복원 규칙을 설명합니다. LPoint 인덱스를 다루는 코드는 모두 이 문서의 좌표계 규칙(우하단 원점)을 전제로 작성해야 합니다.

BATCAM FX 에서 전달되는 Beamforming 이벤트의 BF Map은 40x30 의 구조로 이루어져 있으며, 전송 시 1x1200 구조의 Array로 전달됩니다.

BATCAM FX RTSP 영상에 BF Map을 가시화한 예시 화면. 녹색 부분이 예시로 설정된 Listening Point

BATCAM FX RTSP 영상에 BF Map 을 가시화하는 경우를 가정한 사진. 녹색 부분은 예시로 설정됐다고 가정한 Listening Point.

BATCAM FX의 LPoint 기능은 3개까지 지정 가능하며, 지정한 위치에서 빔포밍된 오디오 신호가 LPointAudio 메시지(ROS 토픽 /fx_{hardware_id}/lpoint_audio, 채널 lpoint0~lpoint2)를 통해 전송됩니다. 메시지 구조는 ROS 연동 문서를 참고하세요.

인덱스 좌표계

LPoint는 40×30 크기의 2D 그리드를 1차원 인덱스(0~1199)로 표현합니다.

⚠️ 좌표계 주의: BATCAM FX의 BF Map 인덱스는 우하단이 0, 좌상단이 1199입니다. 일반적인 좌상단 원점(0) 좌표계와 반대이므로, 압축/복원 시 반드시 1199 - n 변환이 필요합니다. 이 변환 없이 직접 n % 40, n / 40으로 계산하면 잘못된 결과가 나옵니다.

인덱스는 우하단(0)에서 시작해 왼쪽으로 증가하며, 한 행(40칸)이 끝나면 한 줄 위로 올라갑니다. 즉 그리드 좌표를 x = n mod 40, y = ⌊n / 40⌋ 으로 계산하면 x는 오른쪽에서 왼쪽으로, y는 아래에서 위로 증가합니다. 네 모서리의 인덱스는 다음과 같습니다.

위치인덱스
우하단0
좌하단39
우상단1160
좌상단1199

제한사항

Listening Point를 설정할 때, 두 지점 간의 거리가 너무 가까우면 안 됩니다.

현재 BATCAM FX의 LPoint 설정에서는 다음과 같은 최소 거리 제한이 설정되어 있습니다:

  • 가로 방향: 최소 ±2 칸 이상

  • 세로 방향: 최소 ±2 칸 이상

즉, 하나의 Listening Point가 지정되면, 그로부터 가로·세로로 2칸 이내의 모든 영역은 다른 Listening Point로 사용할 수 없습니다.

예를 들어, 다음과 같은 Listening Point를 지정했다고 가정하는 경우(아래 x·y는 x = n mod 40, y = ⌊n / 40⌋ 으로 계산한 그리드 좌표 — 우하단 원점 기준):

  • Listening Point A: 인덱스 20 (x=20, y=0)

  • Listening Point B: 인덱스 580 (x=20, y=14)

해당 두 Listening Point 주변에는 다음과 같은 제한 영역이 설정됩니다:

  • A를 기준으로: 18 ≤ x ≤ 22, 0 ≤ y ≤ 2 (y의 음수 방향은 그리드 밖이므로 0에서 잘립니다)

  • B를 기준으로: 18 ≤ x ≤ 22, 12 ≤ y ≤ 16

이 범위 안에 추가 Listening Point를 설정하면 안 됩니다.

API에서 사용하기 위한 LPoint 인덱스 압축 및 복원

API 요청 시에는 세로 방향 해상도를 절반으로 줄인 40×15 형태(인덱스 0599)로 변환하여 인덱스를 전송해야 합니다. 펌웨어 v1.0.2d부터 빔포밍 설정 API의 lpoint 인덱스 허용 범위가 01199에서 0~599로 변경되었습니다 (펌웨어 릴리즈 노트 참고).

이를 위해 다음의 공식들을 사용하여 압축(Downsize) 및 복원(Upsize)을 수행합니다.

💡 참고: 압축은 세로 해상도를 절반으로 줄이므로 정보가 손실될 수 있습니다. 좌표 정밀도가 필요한 경우 압축 전 원본 인덱스를 별도로 보존하세요. 손실·복원 규칙의 상세 내용은 아래 한계 및 경계값 섹션을 참고하세요.

인덱스 압축 (Downsize)

1차원 인덱스 n(0~1199)을 40×15 그리드 기준으로 변환합니다.

좌표계를 반전(1199 - n)한 뒤 세로 해상도를 절반으로 줄여 y 좌표를 압축합니다.

수식:

f(n)=401199n402+((1199n)mod40)f(n) = 40 \cdot \left\lfloor \frac{\left\lfloor \frac{1199 - n}{40} \right\rfloor}{2} \right\rfloor + ((1199 - n) \bmod 40)

예시:

  • f(120) → 559

  • f(600) → 319

  • f(1160) → 39

인덱스 복원 (Upsize)

압축된 인덱스를 원래의 40×30 기준으로 복원합니다.

압축 시 사라진 한 줄 중 위쪽 줄(y * 2) 을 기준으로 복원한 뒤 좌표계를 다시 반전합니다.

수식:

f1(n)=1199(40(2n40)+(nmod40))f^{-1}(n) = 1199 - \left(40 \cdot (2 \cdot \left\lfloor \frac{n}{40} \right\rfloor) + (n \bmod 40)\right)

예시:

  • f⁻¹(559) → 120

  • f⁻¹(319) → 600

  • f⁻¹(39) → 1160

사용처 요약

상황사용 함수설명
API 요청 시 좌표 전송Downsize40×30 → 40×15 압축
사용자 화면에 좌표 출력Upsize40×15 → 40×30 복원

이를 각 언어에 대응되는 코드로 표현하면 다음과 같습니다.

Swift

extension Int {
func lPointDownSized() -> Int {
let value = 1199 - self
let x = value % 40
let y = value / 40
let downY = y / 2
return downY * 40 + x
}
func lPointUpSized() -> Int {
let x = self % 40
let y = self / 40
let upY = y * 2
return 1199 - (upY * 40 + x)
}
}

Python

def l_point_down_sized(n: int) -> int:
value = 1199 - n
x = value % 40
y = value // 40
down_y = y // 2
return down_y * 40 + x
def l_point_up_sized(n: int) -> int:
x = n % 40
y = n // 40
up_y = y * 2
return 1199 - (up_y * 40 + x)

C#

public static class LPointExtensions
{
public static int LPointDownSized(this int n)
{
int value = 1199 - n;
int x = value % 40;
int y = value / 40;
int downY = y / 2;
return downY * 40 + x;
}
public static int LPointUpSized(this int n)
{
int x = n % 40;
int y = n / 40;
int upY = y * 2;
return 1199 - (upY * 40 + x);
}
}

C++

int lPointDownSized(int n) {
int value = 1199 - n;
int x = value % 40;
int y = value / 40;
int downY = y / 2;
return downY * 40 + x;
}
int lPointUpSized(int n) {
int x = n % 40;
int y = n / 40;
int upY = y * 2;
return 1199 - (upY * 40 + x);
}

API 전송 방식

변환한 LPoint 인덱스는 빔포밍 설정 API의 index_l 파라미터로 전송합니다. BATCAM FX 장비가 API를 직접 서빙하며(기본 URL http://{device_ip}), 인증은 Basic 인증을 사용합니다.

항목내용
설정 조회GET /beamforming/setting — 현재 빔포밍 설정값을 반환하며, 응답의 index_l은 정수 3개의 배열입니다.
설정 변경PATCH /beamforming/settingmultipart/form-data 형식으로 전송합니다.
index_l 요청 형식쉼표로 구분된 3개의 L point 문자열 (예: 20,510,579)
주의부분 설정은 반영되지 않으므로 전체 값을 전송해야 합니다. 먼저 GET으로 현재 설정을 가져온 뒤, index_l만 수정하여 전체를 다시 전송하세요.
오류 응답잘못된 lpoint 파라미터 전달 시 400 응답(error: 1, message: lpoint parameter error)이 반환됩니다.

성공 시 응답은 봉투 구조로 반환됩니다:

{
"error": 0,
"result": {
"autogain": true,
"gain": 100,
"x_cal": -0.06,
"y_cal": 0,
"distance": 1,
"high_cut": 45000,
"low_cut": 2000,
"index_l": [20, 510, 579]
}
}

요청/응답의 전체 스키마와 실제 호출 테스트는 FX API 플레이그라운드의 beamforming 그룹에서 확인할 수 있습니다. index_l을 포함한 각 빔포밍 설정값의 속성은 빔포밍 파라미터 문서를 참고하세요.

한계 및 경계값

세로 해상도 압축은 정보 손실을 동반합니다. 제공되는 각각의 압축, 복원 함수는 세로 방향만을 절반으로 압축하기 때문에, 원래 서로 다른 두 인덱스가 같은 값으로 매핑될 수 있습니다. 예를 들어 040은 압축 시 둘 다 599가 되고, 11591199는 둘 다 0이 됩니다.

복원 함수는 항상 위쪽 라인을 기준으로 복원됩니다. 복원 함수는 압축된 인덱스를 복원할 때, 원래 존재할 수 있던 두 줄 중 위쪽(y * 2)줄을 기준으로 복원한 뒤 좌표계를 다시 반전(1199 - result)합니다.

따라서 API 응답이나 결과를 표시할 때, 사용자가 인식하는 위치보다 약간 치우쳐질 수 있기에, 정확한 복원이 필요할 경우, 압축 전에 원본 좌표 정보를 따로 저장해두어야 할 수 있습니다.

경계값 처리 요약

아래 표의 완벽 복원 여부는 압축(Downsize) 후 복원(Upsize)했을 때 원래 입력 인덱스가 그대로 돌아오는지를 뜻합니다. 예를 들어 0599로 압축된 뒤 40으로 복원되므로 ❌이고, 40은 같은 599로 압축되지만 복원 결과가 다시 40이므로 ✅입니다.

입력값압축 결과복원 결과완벽 복원 여부
059940❌ (충돌 가능)
4059940
115901199❌ (충돌 가능)
1160391160
119901199

일반화하면, 반전된 좌표계(1199 - n) 기준으로 짝수 y 행에 있는 인덱스는 완벽하게 복원됩니다.