음향 통신 동기화 완성 - 시작과 끝 감지
시연 동영상 링크
https://youtu.be/lI-I8FzTY5U
주제
Send Unicode via MFSK
주요 목표
송수신 기능 완성
#1 송신
- send_data 함수는 사용자가 입력한 텍스트를 소리로 바꾸어 재생한다.
- MFSK 인코딩을 해야하므로,
- text → hex
- start 주파수 전송 (2 unit)
- 데이터 주파수 전송 (1 unit씩)
- end 주파수 전송 (2 unit)
- pyaudio로 재생
#2 수신
- 오디오 스트림 열기
- 녹음에 필요한 여러 상수 정의
- 오디오 데이터 수신
- Noise Threshold 처리 (RMS 사용)
- 데이터 안에 포함된 주파수 성분 분석 위해 FFT(푸리에 변환) 적용
- 정리 후 결과 출력
- main은 강의자료의 코드를 그대로 사용했다.

세부 목표
목표1) 소음에 대한 처리
[ 데이터 도착할 때부터 연산: Current Data 출력 ] (#2 수신 - 4,5번 참고)

- START Signal 받기 전에도 소음이 들어온다. 그러나 이것까지 FFT돌리고 주파수를 찾는 것은 의미 없는 낭비가 되므로, RMS값을 이용하여 noise threshold처리를 해줬다. THRESHOLD보다 작은 rms값은 noise로 판단하고 별다른 처리를 하지 않는다.
- 코드 실행 환경에 따라 THRESHOLD를 다르게 설정해야했는데, 이에 소음에 대한 rms값이 현재 어떤지 확인하며 실시간으로 디버깅해야했다.
- 이때 강의자료에서는 기준으로 표준편차를 사용했으나, 디버깅 시 변화량을 보는 것이 직관적이지 않아 나는 RMS(Root Mean Square)를 이용했다. 이는 에너지의 크기 측정하는 방법인데, 수식을 보면 표준편차와 거의 linear관계이고 사인파의 평균값이 0 근처이므로 대체 가능했다.
- 이 if문 다음에 푸리에 연산이 오는데, THRESHOLD보다 작은 값(데이터가 아닌 노이즈)이면 다른 연산 없이 다시 while문의 처음으로 돌아가므로 데이터가 도착할 때부터 연산을 시작할 수 있다.
- 또한 Current Data는 5번의 해당 코드를 통해 출력된다. (Detected: data, data는 주파수에 매핑된 데이터). START / END / HEX(0~F) / “” 값을 갖는다.
print(f"[{status}] | [RMS: {rms:.2f}] | Detected: {data} | Freq: {top_freq:.1f} Hz | Text Hex: {text_hex}")
목표2) 데이터가 언제 시작하는지 알아내기 (동기화)
[ START Signal 처리 방법 ] (#2 수신 - 5번 참고)

- 앞서 START 주파수를 rules 딕셔너리에 정의해둔 바 있다. padding에 의해 512±5Hz의 값이 들어오면 딕셔너리 매핑을 통해 판단, 데이터 수신을 시작한다. is_receiving 변수로 받아야 할 데이터의 시작 전후 상태를 구분한다.
- is_receiving은 ’NONE(필요없는 데이터)’과 ‘DATA(변환해야 할 데이터)’ 상태 구분을 위해 도입한 변수이다.
- 이때 과제의 출력조건을 만족시키기 위해, 로그에 [START]가 찍히도록 들어갈 status를 문자열로 정의해준다.
- 노이즈로 인해 end_count가 변했을 수도 있어, 이후 정확히 END조건을 판단할 수 있게 0으로 초기화해준다.
- 처리가 끝나면 continue로 while의 처음으로 돌아와 다음 데이터를 받고, 이제 .
목표3) 데이터가 언제 끝나는지 알아내기 (동기화)
[ END Signal 처리 방법 ] (#2 수신 - 5번 참고)

- 앞서 END 주파수를 rules 딕셔너리에 정의해둔 바 있다. padding에 의해 2944±5Hz의 값이 들어오면 딕셔너리 매핑을 통해 판단, 데이터 수신을 종료한다. (2944 = 512 + 128 + 128 * 16 + 128 * 2)
- 이때 주파수가 수신되더라도 end_count를 세며 이게 2 이상일 때만 종료하는데, 노이즈에 의해 순간 END주파수가 들어오는 상황을 처리하기 위함이다.
Leave a comment