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의 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(120) → 559
-
f(600) → 319
-
f(1160) → 39
인덱스 복원 (Upsize)
압축된 인덱스를 원래의 40×30 기준으로 복원합니다.
압축 시 사라진 한 줄 중 위쪽 줄(y * 2) 을 기준으로 복원한 뒤 좌표계를 다시 반전합니다.
수식:
예시:
-
f⁻¹(559) → 120
-
f⁻¹(319) → 600
-
f⁻¹(39) → 1160
사용처 요약
| 상황 | 사용 함수 | 설명 |
|---|---|---|
| API 요청 시 좌표 전송 | Downsize | 40×30 → 40×15 압축 |
| 사용자 화면에 좌표 출력 | Upsize | 40×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/setting — multipart/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을 포함한 각 빔포밍 설정값의 속성은 빔포밍 파라미터 문서를 참고하세요.
한계 및 경계값
세로 해상도 압축은 정보 손실을 동반합니다.
제공되는 각각의 압축, 복원 함수는 세로 방향만을 절반으로 압축하기 때문에, 원래 서로 다른 두 인덱스가 같은 값으로 매핑될 수 있습니다. 예를 들어 0과 40은 압축 시 둘 다 599가 되고, 1159와 1199는 둘 다 0이 됩니다.
복원 함수는 항상 위쪽 라인을 기준으로 복원됩니다.
복원 함수는 압축된 인덱스를 복원할 때, 원래 존재할 수 있던 두 줄 중 위쪽(y * 2)줄을 기준으로 복원한 뒤 좌표계를 다시 반전(1199 - result)합니다.
따라서 API 응답이나 결과를 표시할 때, 사용자가 인식하는 위치보다 약간 치우쳐질 수 있기에, 정확한 복원이 필요할 경우, 압축 전에 원본 좌표 정보를 따로 저장해두어야 할 수 있습니다.
경계값 처리 요약
아래 표의 완벽 복원 여부는 압축(Downsize) 후 복원(Upsize)했을 때 원래 입력 인덱스가 그대로 돌아오는지를 뜻합니다. 예를 들어 0은 599로 압축된 뒤 40으로 복원되므로 ❌이고, 40은 같은 599로 압축되지만 복원 결과가 다시 40이므로 ✅입니다.
| 입력값 | 압축 결과 | 복원 결과 | 완벽 복원 여부 |
|---|---|---|---|
| 0 | 599 | 40 | ❌ (충돌 가능) |
| 40 | 599 | 40 | ✅ |
| 1159 | 0 | 1199 | ❌ (충돌 가능) |
| 1160 | 39 | 1160 | ✅ |
| 1199 | 0 | 1199 | ✅ |
일반화하면, 반전된 좌표계(1199 - n) 기준으로 짝수 y 행에 있는 인덱스는 완벽하게 복원됩니다.