euphony 라이브러리 0.8.0 버전의 FSK 코드 분석 #101
Replies: 8 comments 5 replies
-
좋은 글 감사합니다 ㅎㅎ |
Beta Was this translation helpful? Give feedback.
-
친절한 설명 감사드립니다 :) |
Beta Was this translation helpful? Give feedback.
-
헤매고 있었는데 설명 감사합니다! 👍 |
Beta Was this translation helpful? Give feedback.
-
좋은 내용 감사합니다! 👍 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
정리 정말 잘하시네용 ..!! 이해쏙쏙!! 감사합니다 ㅎㅎㅎ👍👍👍 |
Beta Was this translation helpful? Give feedback.
-
정리 깔끔하게 잘 하셨네요!! 😄 좋은 내용 감사합니다! |
Beta Was this translation helpful? Give feedback.
-
저도 저 나름대로 FSK model을 분석해 보았고, 앞으로 구현될 ASK 모델 개발을 어떤 방향으로 해 나가야 할지 작성해 보았습니다. 읽다보면 @jopopcorn FSK Feature 분석@kuro11pow2 님이 정리해 주신 자료를 보면 ASK 와 FSK의 차이가 분명하게 보입니다. 일단 첫번째로 알아야 할 것은 파동 입니다. 다들 아시겠지만, 정말 간단하게 이야기 하자면 파동의 모습입니다. 여기서 알 수 있는 것은 WaveList FSK::modulate(string code) {
vector<shared_ptr<Wave>> result;
for (char c : code ) {
switch(c) {
case 'S':
result.push_back(
Wave::create()
.vibratesAt(kStartSignalFrequency)
.setSize(kBufferSize)
.setCrossfade(BOTH)
.build()
);
break;
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9':
result.push_back(
Wave::create()
.vibratesAt(kStandardFrequency + ((c - '0') * kFrequencyInterval))
.setSize(kBufferSize)
.setCrossfade(BOTH)
.build()
);
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
result.push_back(
Wave::create()
.vibratesAt(kStandardFrequency + ((c - 'a' + 10) * kFrequencyInterval))
.setSize(kBufferSize)
.setCrossfade(BOTH)
.build()
);
break;
default:
throw Base16Exception();
}
}
return result;
} 코드를 보셔도 그리고 string 내부의 각각의 char 마다 적절한 주파수를 계산해서 ex) 1 ⇒ kStandardFrequency + ((c - '0') * kFrequencyInterval) ⇒ 18001 + (1 * (44100/512)) = 18087.132.... 정도로 나옵니다.
지웅님께서 적은 2019 기술 동향 보고서에 참고 하시면 될 것 같습니다. 우리가 발생한 음파가 사람 귀에 들리면 안되기 때문에 가청 주파수를 피해 그 위 주파수를 씁니다. FSK feature를 통해서 우리가 개발해나가야 할 부분Wave::create()
.vibratesAt(kStandardFrequency + ((c - '0') * kFrequencyInterval)) FSK feature에서 vibrateAt이라는 함수를 살펴 보면 //WaveBuilder.cpp
WaveBuilder& WaveBuilder::vibratesAt(int hz) {
wave.setHz(hz);
return *this;
} //Wave.cpp
void Euphony::Wave::setHz(int hz) {
mHz = hz;
this->updatePhaseIncrement(hz);
} //Wave.h
std::atomic<double> mPhaseIncrement{0.0}; atomic 형에 대한 설명은 아래에 링크를 보시면 자세하게 나와 있습니다. https://en.cppreference.com/w/cpp/atomic/atomic 대충 설명하자면, 하나의 오브젝트를 하나의 쓰레드가 read나 write를 하고 있을 때 접근해서 생길 수 있는 문제점들을 atomic 객체를 통해 예방 할 수 있습니다. 원래는 뮤텍스 객체를 만들어 lock과 unlock을 해 줘서 그걸 방지해줘야 하지만, atomic을 통해서 쉽게 할 수있다고 합니다. (C++, 운영체제 고수분들 이부분 설명이 맞나요??..ㅎㅎ) 그래고 atomic 객체는 더하기 빼기 밖에 안되기 때문에 위에 코드를 보시면 //Wave.h
//
// Created by designe on 20. 9. 16.
//
#ifndef EUPHONY_WAVE_H
#define EUPHONY_WAVE_H
#include <vector>
namespace Euphony {
class WaveBuilder;
enum CrossfadeType {
FRONT,END,BOTH,NONE
};
class Wave {
public:
Wave();
Wave(int hz, int bufferSize);
Wave(const float* src, int bufferSize);
explicit Wave(const Wave& copy);
static WaveBuilder create();
void oscillate();
void oscillate(int hz, int size);
void setCrossfade(CrossfadeType crossfadeType);
int getHz() const;
void setHz(int hz);
int getSize() const;
void setSize(int size);
std::vector<float> getSource() const;
void setSource(const std::vector<float> &source);
std::vector<int16_t> getInt16Source();
static int16_t convertFloat2Int16(float source);
private:
friend class WaveBuilder;
int mHz;
int mSize;
CrossfadeType crossfadeType;
std::vector<float> mSource;
float mPhase = 0.0;
std::atomic<double> mPhaseIncrement{0.0};
void updatePhaseIncrement(int hz);
};
}
#endif //EUPHONY_WAVE_H
|
Beta Was this translation helpful? Give feedback.
-
ASK 피처 개발을 위해 우선 FSK 코드를 분석하고 있는데요.
저도 완벽하게 이해하진 못했지만 FSK의 전반적인 흐름을 이해하기 좋을 것 같아 따로 디스커션 올립니다!
FSK
FSK는 디지털 변조 방식 중의 하나이며, 주파수를 기준으로 데이터를 구분할 수 있습니다.
FSK를 쉽게 이해하기 위해 예시를 들자면 0과 1을 표현할 때 1초 동안의 주파수가 크다면 1, 적으면 0으로 표현할 수 있습니다.
FSK 헤더 파일에는 다음과 같이 정의되어 있습니다.
'Modem이 디지털 변조 방식이다'라고 생각하면 좋을 것 같고, FSK가 그러한 디지털 변조 방식 중 하나입니다.
modulate
함수는 두가지인데, 아래 빨간색 동그라미로 표시한 버튼을 누르면 내부 코드를 따라가 확인할 수 있습니다.버튼을 누르면
FSK.cpp
파일에서의modulate
구현체를 볼 수 있습니다. 참고로 제가 사용 중인 ide는 안드로이드 스튜디오입니다!modulate (변조)
19라인의
WaveList FSK::modulate(string code)
함수의 코드를 먼저 보면, Base16 기반으로 문자를 아날로그(음파)로 만들어줍니다.0부터 f까지의 문자를 각각의 음파로 변조해서 생성합니다. 그런데 25라인에는 S라는 문자도 케이스에 포함되어 있어서 뭐지?! 했습니다.
Packet.h
파일을 열어보면toString()
함수가 있는데, 위의 사진에 표시한 버튼과 마찬가지로 toString() 라인의 왼쪽 버튼을 클릭하면 코드 구현체가 나옵니다. 그냥Packet.cpp
파일 들어가서 바로 확인해도 상관 없지만, 저는 보통 아래에 첨부한 사진에서 보이는 Edit Source라는 메뉴의 커맨드를 사용해서 내부 코드를 확인하는 편이라서 이런 흐름으로 본다는 것을 참고로 작성합니다!어쨌든 패킷을 String으로 바꿔줄 때 result 값에 S라는 문자를 추가하고 그 뒤에 페이로드와 체크섬, 패리티 코드를 뒤이어 붙이는 것을 확인했습니다. 다시
modulate
함수 코드를 살펴보면, S라는 문자가 시작을 의미하는 주파수(kStartSignalFrequency
) 음파를 만들어낸다고 해석할 수 있습니다.멘토님이 올려주신 v0.8 변경사항을 보니 Packet 클래스는 음파 통신의 데이터 패킷을 의미한다고 합니다.
예상하는 시나리오로는 디지털 신호를 패킷으로 받아 String으로 변환하고, 각 문자에 맞는 음파로 변조하는 것 같습니다!
demodulate (복조)
이제
demodulate
함수를 보려고 합니다! WaveList라는 Wave를 저장한 벡터의 사이즈 만큼 HexVector 변수를 생성해줍니다.v0.8 변경사항 설명에 따르자면, 기본적으로 모든 Base는 HexVector를 가지고 각각의 진법으로 변환하여 사용한다고 합니다.
HexVector의 생성자 내부 코드를 보면 문자를 다시 16진법으로 변환하는 것으로 추측됩니다.
HexVector은 중요한 자료 구조라고 하니, 자세히 이해하신 분이 계신다면 추가로 코멘트 남겨주시면 감사하겠습니다!
for문에서는 WaveList를 순회하여 각 웨이브를 int형으로 전환한 후 스펙트럼을 만들어 HexVector 변수에 push 해줍니다.
이러한 HexVector를 패킷으로 바꾸어서 반환하는 것이 복조입니다.
있는 그대로의 코드를 당연하게 설명한 것 뿐이긴 하지만, FSK 코드를 읽어보지 않으신 분들은 참고하시길 바랍니다!
FFT에 관한 지식을 습득하고 난 뒤에 더 자세히 코드를 뜯어서 분석해보려고 합니다. FFT와 HexVector을 이해하신 분이 있다면 공유해주시면 좋을 것 같아요! 😸
제 해석이 정확하진 않으므로 정정할 부분은 꼭 말씀해주세요 😹
Beta Was this translation helpful? Give feedback.
All reactions