사인파로 16000Hz PCM를 만들기 위해서는 다음과 같은 단계를 거칩니다.
- 샘플링 주파수와 신호 주파수를 정합니다.
- 이 경우, 샘플링 주파수는 16000Hz, 신호 주파수는 1000Hz로 가정합니다.
- 사인파를 생성합니다.
- 이 경우, 1초간의 사인파를 생성합니다.
- 사인파의 식은 다음과 같습니다.
- y(t) = A sin(2πft)
- A는 진폭을 나타냅니다. 이 경우, 1로 가정합니다.
- f는 주파수를 나타냅니다. 이 경우, 1000Hz로 가정합니다.
- t는 시간을 나타냅니다. 이 경우, 0부터 1초까지 1/16000초 간격으로 생성합니다.
- y(t) = A sin(2πft)
- 생성된 사인파를 샘플링합니다.
- 이 경우, 1초간의 사인파를 16000개의 샘플링으로 나눕니다.
- 샘플링 된 사인파를 16-bit PCM 데이터로 변환합니다.
- 16-bit PCM 데이터는 -32768부터 32767까지의 값을 가집니다.
16000Hz 사인파 PCM 생성 코드
import wave
import math
# 샘플링 주파수와 진폭을 설정합니다.
sampling_freq = 16000 # 샘플링 주파수
amplitude = 32000 # 진폭
# PCM 파일의 프레임 수와 기간을 계산합니다.
num_frames = sampling_freq * 1 # 1초
duration = 1 # 1초
# 사인 파를 생성합니다.
freq = 4400 # 주파수
sine_wave = [0.7 * amplitude * math.sin(2 * math.pi * freq * (x / sampling_freq)) for x in range(num_frames)]
# PCM 파일을 생성합니다.
file = wave.open('sine_wave_pcm2.wav', 'wb')
file.setnchannels(1) # 모노 채널
file.setsampwidth(2) # 샘플링 폭 (2바이트)
file.setframerate(sampling_freq) # 샘플링 주파수
for s in sine_wave:
file.writeframesraw(int(s).to_bytes(2, byteorder='little', signed=True))
file.close()

이제, 생성된 16000Hz PCM 데이터를 48000Hz PCM 데이터로 변환하는 과정을 설명하겠습니다.
- 업샘플링을 수행합니다.
- 업샘플링은 샘플링 주파수를 증가시키는 과정입니다.
- 이 경우, 16000Hz에서 48000Hz로 샘플링 주파수를 증가시킵니다.
- 업샘플링에는 여러 방법이 있지만, 이 경우 선형 보간법을 사용합니다.
- 선형 보간법은 인접한 두 샘플링 값 사이의 값을 선형적으로 계산하여 업샘플링하는 방법입니다.
- 샘플링 레이트 컨버터를 사용하여 업샘플링된 데이터를 필터링합니다.
- 샘플링 레이트 컨버터는 샘플링 주파수를 변환하는 과정에서 발생하는 에일리어싱을 방지하기 위해 필터링을 수행합니다.
- 이 경우, FIR 필터를 사용하여 필터링을 수행합니다.
- FIR 필터는 유한한 시간 동안만 반응하는 필터입니다.
- 필터링된 데이터를 다시 16-bit PCM 데이터로 변환합니다.
16000Hz 사인파 PCM을 입력으로 받아 48000Hz PCM으로 변환하는 코드
import wave
import math
# 입력 파일의 정보를 가져옵니다.
with wave.open('sine_wave_pcm.wav', 'rb') as input_file:
num_channels = input_file.getnchannels() # 채널 수
sample_width = input_file.getsampwidth() # 샘플링 폭 (바이트)
input_sampling_freq = input_file.getframerate() # 입력 파일의 샘플링 주파수
input_num_frames = input_file.getnframes() # 입력 파일의 프레임 수
input_duration = input_num_frames / float(input_sampling_freq) # 입력 파일의 재생 시간
# 출력 파일의 정보를 설정합니다.
output_sampling_freq = 48000 # 출력 파일의 샘플링 주파수
output_num_frames = int(input_num_frames * output_sampling_freq / float(input_sampling_freq)) # 출력 파일의 프레임 수
output_duration = input_duration # 출력 파일의 재생 시간
# 입력 파일의 PCM 데이터를 읽어옵니다.
with wave.open('sine_wave_pcm.wav', 'rb') as input_file:
pcm_data = input_file.readframes(input_num_frames)
# 48000 Hz의 샘플링 주파수로 변환합니다.
sine_wave = []
for i in range(output_num_frames):
t = float(i) / output_sampling_freq
idx = int(t * input_sampling_freq)
if idx >= input_num_frames:
break
s = int.from_bytes(pcm_data[idx * sample_width:(idx + 1) * sample_width], byteorder='little', signed=True)
sine_wave.append(s)
# 출력 파일을 생성합니다.
with wave.open('sine_wave_pcm_48000.wav', 'wb') as output_file:
output_file.setnchannels(num_channels) # 채널 수
output_file.setsampwidth(sample_width) # 샘플링 폭 (바이트)
output_file.setframerate(output_sampling_freq) # 샘플링 주파수
for s in sine_wave:
output_file.writeframesraw(s.to_bytes(sample_width, byteorder='little', signed=True))

이렇게 생성된 48000Hz PCM 데이터는 원래의 16000Hz PCM 데이터보다 더 많은 샘플링 주파수를 가지므로 더욱 높은 해상도와 더욱 부드러운 음질을 가지게 됩니다.
하지만 업샘플링 과정에서 필터링을 수행하므로 일부 정보 손실이 발생할 수 있습니다. 이를 방지하기 위해서는 더욱 복잡한 필터링 기술이 필요합니다.
또한, 원래의 16000Hz PCM 데이터와 48000Hz PCM 데이터는 주파수 스펙트럼이 다르므로 이를 고려하여 음성 및 오디오 신호를 처리해야 합니다. 예를 들어, 음성 인식이나 음악 분석 등에서는 주파수 변화를 감지하여 적절한 처리를 수행해야 합니다.
이처럼 샘플링은 디지털 신호 처리에서 매우 중요한 과정입니다. 적절한 샘플링 주파수와 샘플링 기술을 선택하여 음성 및 오디오 신호를 처리함으로써 높은 해상도와 부드러운 음질을 구현할 수 있습니다.