Created
January 20, 2024 19:36
-
-
Save mbutler/ff0e398ee4b40fcd8cf3d4718259669e to your computer and use it in GitHub Desktop.
Simple Frequency Shift Keying implementation for digital modulation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import wave | |
import struct | |
from scipy.signal import butter, lfilter | |
# Function to convert text to FSK and save as a WAV file | |
def text_to_fsk_wave(text, filename): | |
bit_rate = 1200 | |
freq_low = 1200 | |
freq_high = 2400 | |
sample_rate = 48000 | |
binary_data = ''.join(format(ord(char), '08b') for char in text) | |
t = np.arange(0, len(binary_data) / bit_rate, 1 / sample_rate) | |
fsk_signal = np.zeros(0) | |
for bit in binary_data: | |
freq = freq_low if bit == '0' else freq_high | |
fsk_signal = np.append(fsk_signal, np.sin(2 * np.pi * freq * t[:int(sample_rate / bit_rate)])) | |
fsk_signal = np.int16((fsk_signal / np.max(np.abs(fsk_signal))) * 32767) | |
with wave.open(filename, 'w') as wav_file: | |
wav_file.setparams((1, 2, sample_rate, 0, 'NONE', 'not compressed')) | |
for sample in fsk_signal: | |
wav_file.writeframes(struct.pack('h', sample)) | |
# Function to decode FSK WAV file back into text | |
def fsk_wave_to_text(filename): | |
bit_rate = 1200 | |
freq_low = 1200 | |
freq_high = 2400 | |
sample_rate = 48000 | |
samples_per_bit = sample_rate // bit_rate | |
with wave.open(filename, 'r') as wav_file: | |
frames = wav_file.readframes(wav_file.getnframes()) | |
fsk_signal = np.frombuffer(frames, dtype=np.int16) | |
fsk_signal = fsk_signal / np.max(np.abs(fsk_signal)) | |
fsk_signal = bandpass_filter(fsk_signal, freq_low, freq_high, sample_rate) | |
binary_data = '' | |
for i in range(0, len(fsk_signal), samples_per_bit): | |
sample = fsk_signal[i:i + samples_per_bit] | |
freq = np.fft.fftfreq(len(sample), d=1/sample_rate) | |
fft_vals = np.fft.fft(sample) | |
peak_freq = abs(freq[np.argmax(np.abs(fft_vals))]) | |
if np.isclose(peak_freq, freq_low, atol=10): | |
binary_data += '0' | |
elif np.isclose(peak_freq, freq_high, atol=10): | |
binary_data += '1' | |
text = '' | |
for i in range(0, len(binary_data), 8): | |
byte = binary_data[i:i + 8] | |
if len(byte) == 8: | |
text += chr(int(byte, 2)) | |
return text | |
# Band-pass filter for signal processing | |
def bandpass_filter(data, lowcut, highcut, fs, order=5): | |
nyq = 0.5 * fs | |
low = lowcut / nyq | |
high = highcut / nyq | |
b, a = butter(order, [low, high], btype='band') | |
y = lfilter(b, a, data) | |
return y | |
# Example usage | |
text_to_fsk_wave("Hello World", "hello_world.wav") | |
decoded_text = fsk_wave_to_text("hello_world.wav") | |
print("Decoded Text:", decoded_text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment