'Audio Frequency Separation In Python
I'm working on a nerd project for fun. The project is analog video recorded onto an audio cassette. The challenge lies in the very limited bandwidth. I have a method to record color video at 24fps along with mono audio. I got the video stuff working but need some help with the audio. Here is the signal I have to work with:
Note: using YUV color space
Left channel: Sync Pulses & Y (luma) data
Right channel: U & V (chroma) data mixed with Mono audio (Amplitude Modulated at 14kHz)
I'm not sure how to separate the color data from the audio. I've looked into FFT with numpy a bit but am not fully understanding it.
Basically what I need is a band filter to separate 13990Hz - 14010Hz (to account for wow and flutter)
Solution 1:[1]
Ok here is a little test code that shows how this works.
import matplotlib.pyplot as plt
import numpy as np
import math as mt
from scipy.signal import butter, sosfilt, lfilter
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
sos = butter(order, [low, high], analog=False, btype='band', output='sos')
return sos
def bandpass(data, lowcut, highcut, fs, order=5):
sos = butter_bandpass(lowcut, highcut, fs, order=order)
y = sosfilt(sos, data)
return y
def bandstop(data, lowcut, highcut, fs, order):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
i, u = butter(order, [low, high], btype='bandstop')
y = lfilter(i, u, data)
return y
# Modulation & Bandpass Test
# note that the data is just test data and isn't actual audio or color data
Fs = 192000 # rate
f = 14000 # carrier frequency (Hz)
sample = 192000 # total length
x = np.arange(sample)
signal = (np.sin(2 * np.pi * 1000 * x / Fs)) # audio
noise = 0.5*(np.sin(2 * np.pi * 10000 * x / Fs)) # color data
y = [] # combined AM audio and color data
for t in range(0, sample, 1):
amp = (signal[t] + 1) / 2
sine = amp * (mt.sin(2*mt.pi * f * t / Fs))
y.append((sine+noise[t])/2)
# y is raw signal
w = bandpass(y, 1600, 1800, 24000, order=1) # only AM audio signal
v = bandstop(y, 1450, 1950, 24000, order=6) # Rest of the signal
# Note: lowered the sample rate input for the filters (and frequencies accordingly)
# since it didn't like 192khz
# The color data does get impacted by the bandstop filter but this is
# mostly not noticable as the YUV color space is used meaning
# the color resolution can be reduced drastically without noticable effect
plt.plot(y)
plt.plot(w)
plt.plot(v)
plt.xlabel('sample')
plt.ylabel('amplitude')
plt.show()
If you want to check out the full code along with a wav of the signal and an example video of the output here's a link: https://drive.google.com/drive/folders/18ogpK4n43d_Q0tjdmlm2uIRZBIrRu01y?usp=sharing
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jake A |
