{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "KqfSrMPzw_o-" }, "source": [ "# ECE113 Lab2 - Time Frequency\n", " \n", " Spectrogram part was originally designed by John Pauly, modified...

1 answer below »
Follow instructions in 2 python files (part 1 nd part 2)


{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "KqfSrMPzw_o-" }, "source": [ "# ECE113 Lab2 - Time Frequency\n", " \n", "Spectrogram part was originally designed by John Pauly, modified and extended to include SDR and FM processing by Michael Lustig, Translated to python by Frank Ong and Michael Lustig. Updated for UCLA ECE113, Spring 2021\n", "\n", "In this lab, we will look at the processing and spectrum of time-varying signals. In the first part of the lab we will look at the Short-Time Fourier Transform and spectrograms. We will use this to analyze audio signals and broadcast FM." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 12719, "status": "ok", "timestamp": 1618980033503, "user": { "displayName": "SIYOU PEI", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjPLYDIo6KrkLnX_geUHBpWjnScNQGOFD5SCR_5=s64", "userId": "12952600159186734542" }, "user_tz": 420 }, "id": "a0mLNCdcuXFn", "outputId": "5a4759fb-c3df-4872-9d51-cacad34b9753" }, "outputs": [], "source": [ "!conda install -c conda-forge python-sounddevice" ] }, { "cell_type": "markdown", "metadata": { "id": "KqfSrMPzw_o-" }, "source": [ "If you have problems importing sounddevice, please shut down jupyter notebook, open anaconda prompt, run 'conda install -c conda-forge python-sounddevice', open jupyter notebook and try to import it one more time" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "executionInfo": { "elapsed": 356, "status": "ok", "timestamp": 1618980042710, "user": { "displayName": "SIYOU PEI", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjPLYDIo6KrkLnX_geUHBpWjnScNQGOFD5SCR_5=s64", "userId": "12952600159186734542" }, "user_tz": 420 }, "id": "h-Yasfluw_pG" }, "outputs": [], "source": [ "# Import functions and libraries\n", "import numpy as np, matplotlib.pyplot as plt\n", "from numpy import *\n", "from numpy.fft import *\n", "import scipy.io.wavfile as wavfile\n", "import scipy.signal as signal\n", "from matplotlib.pyplot import *\n", "import sounddevice as sd" ] }, { "cell_type": "markdown", "metadata": { "id": "KFqr0k4Vw_pI" }, "source": [ "## Part I: Spectrograms\n", "In class we used the DFT to estimate the frequency of a segment of a signal. When we do this, we are implicitly assuming that the frequency is constant over that interval. This is a reasonable assumption for some signals, especially for a very short time windows. \n", " \n", "There are many times when we'd like analyze signals whose frequency is changing over time. In fact, most signals aren't interesting unless they do change! There are many examples, including speech, music, and the sounds that surround you in daily life. In this lab we will learn how to process these signals to determine how their spectrum changes with time.\n", "\n", "The basic problem is that we have long segment of a signal $x[n]$, where $n=0, ... ,N-1$. We want to know what its frequency is as a function of time. There are two basic approaches. One is to pass the signal through a bank of bandpass filters, and plot the outputs of the filters as a function of time. \n", "\n", "The second approach is based on the short-time Fourier transform (STFT) and is to break the signal up into short segments, and compute the spectrum of each of these separately. This is the approach we will use in this lab.\n", "\n", "To obtain these, possibly overlaping, segments, the signal is multiplied by a sliding window. One key design parameter here is the window length which determines both time and frequency resolutions of STFT. The wider the window is, the higher frequency resolution we will have (think about the sharper/narrower sinc in the frequency domain) but our time resolution will be lower. In contrast, the narrower the window is, there will be less variation in the time-domain characteristics of the signal within the widnow duration. In other words, with narrower window, we will have better time resolution but our frequency resolution would get worse. This is why, with STFT, we cannot improve both time and frequency resolution simultaneously! This is sometimes known as the uncertainly principle with the Fourier analysis. " ] }, { "cell_type": "markdown", "metadata": { "id": "FP954obKw_pI" }, "source": [ "A sample signal is shown in Figure 1. Obviously you can tell that the amplitude is changing as a function of time. When you examine the signal closely, you can also tell that the frequency is changing.\n", "Since the frequency is changing, we want to break the signal into segments over which the frequency is relatively constant. Then we will analyze each segment using the DFT. The result of analyzing the first 256 samples, and another block of 256 samples that is 1024 samples later is shown in Figure 2. As is the convention with the DFT, zero frequency is the first sample, and the Nyquist rate corresponds to the middle sample. The sampling rate in this example was 8192Hz, so the maximum frequency is 4096Hz. Note that the frequency has dropped about 300 Hz between the first and second block." ] }, { "cell_type": "markdown", "metadata": { "id": "Jechn48Tw_pJ" }, "source": [ "

\
\n", "
Figure 1: A segment of a sampled bird song.
" ] }, { "cell_type": "markdown", "metadata": { "id": "hzoGDuWJw_pJ" }, "source": [ "For a long signal, there would be a tremendous number of plots that would have to be examined, and this doesn't convey the information very effectively. Instead, the most common presentation is to display the information in an image format, with frequency on the vertical axis, time on the horizontal axis, and the value of a particular pixel being the magnitude of the spectra at that time and frequency. Remember that STFT is essentially a function of two variables: time and frequency. So spectrograms are typically shown as heatmap diagrams where the color at each point on the time-frequency grid would show the STFT magnitude at that point. \n", "\n", "For the first 4 tasks, we are assuming that the signal is real and the magnitude of the spectrum is symmetric about the origin. We therefore need only display the positive frequencies. Later, in task 5 where we acquire data using the SDR the signal is going to be complex and we will need to display both positive and negative frequencies. This presentation is known as a spectrogram." ] }, { "cell_type": "markdown", "metadata": { "id": "57UYKlZsw_pK" }, "source": [ "

\
\n", "
Figure 2: The spectra from two 256 sample blocks of the signal from Fig. 1
" ] }, { "cell_type": "markdown", "metadata": { "id": "iY0aiGiEw_pK" }, "source": [ "An example of this type of plot for the signal that Fig. 1 was taken from is shown in Fig. 3:\n", "

\
\n", "
Figure 3: A segment of a sampled bird song.
" ] }, { "cell_type": "markdown", "metadata": { "id": "fljwf_E9w_pL" }, "source": [ "A function that takes a two-dimensional array y and makes an image of the log-magnitude is given below:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "executionInfo": { "elapsed": 355, "status": "ok", "timestamp": 1618980056531, "user": { "displayName": "SIYOU PEI", "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14GjPLYDIo6KrkLnX_geUHBpWjnScNQGOFD5SCR_5=s64", "userId": "12952600159186734542" }, "user_tz": 420 }, "id": "2v6RKwzcw_pL" }, "outputs": [], "source": [ "# Plot an image of the spectrogram y, with the axis labeled with time tl,\n",
Answered 4 days AfterJun 03, 2021

Answer To: { "cells": [ { "cell_type": "markdown", "metadata": { "id": "KqfSrMPzw_o-" }, "source": [ "# ECE113...

Joice G answered on Jun 07 2021
152 Votes
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "signal_spectro_hann_overlap.ipynb",
"provenance": [],
"collapsed_sections": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 274
},
"id": "Ac5ac442hAtG",
"outputId": "5b493581-4577-4a4e-9b14-fe64bcf086e3"
},
"source": [
"import numpy as np\n",
"from scipy import signal\n",
"from
scipy.fft import fftshift\n",
"import scipy.io.wavfile as wavfile\n",
"import matplotlib.pyplot as plt\n",
"#import sounddevice as sd\n",
"\n",
"# Spectrogram plot\n",
"def sg_plot (t_range, f_range , y ,dbf=60,fig =None) :\n",
"\n",
" eps = 10.0**(-dbf/20.0)\n",
" # minimum signal\n",
" # find maximum \n",
" y_max = abs(y).max()\n",
" # compute 20*log magnitude, scaled to the max\n",
" y_log = 20.0*np.log10((abs(y)/y_max)*(1-eps)+eps)\n",
"\n",
" # rescale image intensity to 256\n",
" img =256*(y_log+dbf)/dbf - 1\n",
"\n",
" fig = plt.figure(figsize =(16,6))\n",
"\n",
" plt.imshow(np.flipud(64.0*(y_log + dbf )/dbf), extent = t_range + f_range)\n",
" plt.xlabel('Time, s')\n",
" plt.ylabel('Frequency, Hz')\n",
" plt.tight_layout()\n",
" return fig\n",
"\n",
"#Spectrogram with overlapping hanning windows\n",
"def mySpectrogram_hann_overlap(data_s1,fs_s1,m):\n",
" \n",
" zro_padd = 0;\n",
" tot_len = len(data_s1);\n",
" print('The total length is ' +str(tot_len))\n",
" print('The m is ' +str(m))\n",
"\n",
" if ((tot_len % m) != 0 ):\n",
" zro_padd = m-(tot_len % m); \n",
"\n",
" data_s1_fin = np.concatenate([data_s1, np.zeros(zro_padd)])\n",
" col_size = len(data_s1_fin)//m;\n",
"\n",
" print('The column size is ' +str(col_size))\n",
"\n",
" data_s1_fin = np.array(data_s1_fin)\n",
" print(col_size)\n",
" print('The final data length is '+str(len(data_s1_fin)))\n",
"\n",
" XX=[]\n",
" leng = col_size;\n",
" diff = leng-128;\n",
" for mm in range(0,len(data_s1_fin)):\n",
" if leng+(diff*mm) <= len(data_s1_fin):\n",
" x= data_s1_fin[(diff*mm):leng+(diff*mm)]\n",
" else:\n",
" break\n",
" \n",
" XX.append(x)\n",
"\n",
" XXm=np.array(XX).transpose()\n",
" print(XXm.shape)\n",
"\n",
" #Xm = np.reshape(data_s1_fin, (m,col_size), order = 'F' )\n",
" Xmw=XXm * np.hanning(len(XXm))[:,None]\n",
" t_range = [0.0, 1*tot_len]\n",
" f_range = [0.0, fs_s1 / 2.0] \n",
" Xmf = np.fft.fft(Xmw,len(Xmw),axis=0)\n",
" fig=sg_plot(t_range,f_range,Xmf[0:m//2,:])\n",
" #print(Xm.shape)\n",
" print('Hnning overlap Over')\n",
"\n",
"#Spectrogram with hanning windows\n",
"def mySpectrogram_hann(data_s1,fs_s1,m):\n",
" \n",
" zro_padd = 0;\n",
" tot_len = len(data_s1);\n",
" print('The total length is ' +str(tot_len))\n",
" print('The m is ' +str(m))\n",
"\n",
" if ((tot_len % m) != 0 ):\n",
" zro_padd = m-(tot_len % m); \n",
"\n",
" data_s1_fin = np.concatenate([data_s1, np.zeros(zro_padd)])\n",
" col_size = len(data_s1_fin)//m;\n",
"\n",
" print('The column size is ' +str(col_size))\n",
"\n",
" data_s1_fin = np.array(data_s1_fin)\n",
" print(col_size)\n",
" print('The final data length is '+str(len(data_s1_fin)))\n",
"\n",
" \n",
" Xm = np.reshape(data_s1_fin, (m,col_size), order = 'F' )\n",
" Xmw=Xm * np.hanning(len(Xm))[:,None]\n",
" t_range = [0.0, 1*tot_len]\n",
" f_range = [0.0, fs_s1 / 2.0] \n",
" Xmf = np.fft.fft(Xmw,len(Xmw),axis=0)\n",
" fig=sg_plot(t_range,f_range,Xmf[0:m//2,:])\n",
" #print(Xm.shape)\n",
" print('Hanning Over')\n",
"\n",
"#Spectrogram with rectangular windows\n",
"def mySpectrogram(data_s1,fs_s1,m):\n",
" \n",
" zro_padd = 0;\n",
" tot_len = len(data_s1);\n",
" print('The total length is ' +str(tot_len))\n",
" print('The m is ' +str(m))\n",
"\n",
" if ((tot_len % m) != 0 ):\n",
" zro_padd = m-(tot_len % m); \n",
"\n",
" data_s1_fin = np.concatenate([data_s1, np.zeros(zro_padd)])\n",
" col_size = len(data_s1_fin)//m;\n",
"\n",
" print('The column size is ' +str(col_size))\n",
"\n",
" data_s1_fin = np.array(data_s1_fin)\n",
" print(col_size)\n",
" print('The final data length is '+str(len(data_s1_fin)))\n",
"\n",
" \n",
" Xm = np.reshape(data_s1_fin, (m,col_size), order = 'F' )\n",
" Xmw=Xm;\n",
" t_range = [0.0, 1*tot_len]\n",
" f_range = [0.0, fs_s1 / 2.0] \n",
" Xmf = np.fft.fft(Xmw,len(Xmw),axis=0)\n",
" fig=sg_plot(t_range,f_range,Xmf[0:m//2,:])\n",
" #print(Xm.shape)\n",
" print('Rectangular Over')\n",
"\n",
"\n",
"# Reading the wave files\n",
"###Change the path while using from your machine\n",
"#(fs, data) = wavfile.read('/content/drive/MyDrive/python_works/spectrogram_asssign/s1.wav')\n",
"(fs, data) = wavfile.read('/content/drive/MyDrive/python_works/spectrogram_asssign/s2.wav')\n",
"#(fs, data) = wavfile.read('/content/drive/MyDrive/python_works/spectrogram_asssign/s3.wav')\n",
"#(fs, data) = wavfile.read('/content/drive/MyDrive/python_works/spectrogram_asssign/s4.wav')\n",
"#(fs, data) = wavfile.read('/content/drive/MyDrive/python_works/spectrogram_asssign/s5.wav')\n",
"\n",
"m_block = 256;\n",
"#mySpectrogram(data,fs, m_block)\n",
"#mySpectrogram_hann(data,fs, m_block)\n",
"mySpectrogram_hann_overlap(data,fs, m_block)"
],
"execution_count": 1,
"outputs": [
{
"output_type": "stream",
"text": [
"The total length is 199587\n",
"The m is 256\n",
"The column size is 780\n",
"780\n",
"The final data length is 199680\n",
"(780, 306)\n",
"Hnning overlap Over\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"image/png":...
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here