|
138 | 138 | "The continuous wavelet transforms in PyWavelets returns two values:\n",
|
139 | 139 | "\n",
|
140 | 140 | "- coefficents: collection of complex number outputs for wavelet coefficients\n",
|
141 |
| - "- frequencies: collection of frequencies, if the sampling period are in seconds then frequencies are in hertz otherwise a sampling period of 1 is assumed\n", |
| 141 | + "- frequencies: collection of frequencies (if the sampling period are in seconds then frequencies are in hertz otherwise a sampling period of 1 is assumed)\n", |
142 | 142 | "\n",
|
143 | 143 | "The final size of coefficients depends on the length of the input data and the length of the given scales."
|
144 | 144 | ]
|
|
152 | 152 | "\n",
|
153 | 153 | "The range of scales are a combination of the smallest scale (s0), spacing between discrete scales (dj), and the maximum scale (jtot). \n",
|
154 | 154 | "\n",
|
155 |
| - "For the purpose of this exercise, the musical range of frequencies range from 261 - 494 Hz\n", |
| 155 | + "For the purpose of this exercise, the musical range of frequencies range from 261 - 494 Hz.\n", |
156 | 156 | "\n",
|
157 | 157 | "| Note | Freq |\n",
|
158 | 158 | "|--------|--------|\n",
|
|
164 | 164 | "| F note | 350 hz |\n",
|
165 | 165 | "| G note | 392 hz |\n",
|
166 | 166 | "\n",
|
| 167 | + "\n", |
| 168 | + "_Note: Musical note frequencies can vary, these frequencies are taken from [here](https://mixbutton.com/mixing-articles/music-note-to-frequency-chart/)_\n", |
| 169 | + "\n", |
167 | 170 | "It is good practice to include a range greater than precisely needed. This will make the bands for each frequency in the wavelets clearer.\n",
|
168 | 171 | "\n",
|
169 |
| - "For example, scales from 1 to 40 represent a frequency range from 8125 - 208.33 Hz\n", |
| 172 | + "Scales will change the shape of the wavelet to have it match a specific frequency. For example, scalings from 1 to 40 represent a frequency range from 8125 - 208.33 Hz.\n", |
170 | 173 | "\n",
|
171 | 174 | "```\n",
|
172 | 175 | "sample_rate, signal_data = wavfile.read('jingle_bells.wav')\n",
|
|
180 | 183 | "metadata": {},
|
181 | 184 | "source": [
|
182 | 185 | "## Extract audio .wav file\n",
|
183 |
| - "The .wav input file contains information about the amplitude at every time step (in seconds) in the file. The frequency of the note will determine which chord each part of the piece represents." |
| 186 | + "The .wav input file contains information about the amplitude at every time step (in seconds) in the file. The frequency will determine which note each part of the piece represents." |
184 | 187 | ]
|
185 | 188 | },
|
186 | 189 | {
|
|
205 | 208 | "source": [
|
206 | 209 | "## Let's Give the Data a Look!\n",
|
207 | 210 | "\n",
|
208 |
| - "It is always good practice to view the data that we have collected. First, let's organize the data into a `pandas` dataframe to organize the amplitude and time stamps" |
| 211 | + "It is always good practice to view the data that we have collected. First, let's organize the data into a `pandas` dataframe to organize the amplitude and time stamps." |
209 | 212 | ]
|
210 | 213 | },
|
211 | 214 | {
|
|
224 | 227 | "source": [
|
225 | 228 | "### Plot a Small Sample of the .wav File\n",
|
226 | 229 | "\n",
|
227 |
| - "Plot a small subsample of the .wav to visualize the input data" |
| 230 | + "Plot a small subsample of the .wav to visualize the input data." |
228 | 231 | ]
|
229 | 232 | },
|
230 | 233 | {
|
|
253 | 256 | "cell_type": "markdown",
|
254 | 257 | "metadata": {},
|
255 | 258 | "source": [
|
256 |
| - "`wavelet_coeffs` is a complex number with a real and an imaginary part (1 + 2i). The power spectrum plots the real component of the complex number. The real component represents the magntiude of the wavelet coefficient displayed as the absolute value of the coefficients squared" |
| 259 | + "`wavelet_coeffs` is a complex number with a real and an imaginary part (1 + 2i). The power spectrum plots the real component of the complex number. The real component represents the magnitude of the wavelet coefficient displayed as the absolute value of the coefficients squared." |
257 | 260 | ]
|
258 | 261 | },
|
259 | 262 | {
|
|
280 | 283 | "source": [
|
281 | 284 | "### A Note on Choosing the Right Scales\n",
|
282 | 285 | "\n",
|
283 |
| - "`freqs` is normalized frequencies, so needs to be multiplied by these sampling frequency to turn back into frequencies which means that you need to multiply them by your sampling frequency (500Hz) to turn them into actual frequencies" |
| 286 | + "`freqs` is normalized frequencies, so it needs to be multiplied by this sampling frequency to turn it back into frequencies which means that you need to multiply them by your sampling frequency (500Hz) to turn them into actual frequencies." |
284 | 287 | ]
|
285 | 288 | },
|
286 | 289 | {
|
|
325 | 328 | "outputs": [],
|
326 | 329 | "source": [
|
327 | 330 | "fig, ax = plt.subplots(figsize=(8, 8))\n",
|
328 |
| - "data = np.log2(np.square(abs(wavelet_coeffs))) # compare the magntiude\n", |
| 331 | + "data = np.log2(np.square(abs(wavelet_coeffs))) # compare the magnitude\n", |
329 | 332 | "plt.xlabel(\"Time Steps\")\n",
|
330 | 333 | "plt.ylabel(\"Scale Sensitivity\")\n",
|
331 | 334 | "plt.imshow(data, \n",
|
|
341 | 344 | "source": [
|
342 | 345 | "## Overlay Possible Frequencies\n",
|
343 | 346 | "\n",
|
344 |
| - "To overlay these frequencies with the wavelet scaologram:\n", |
| 347 | + "To overlay these frequencies with the wavelet scalogram:\n", |
345 | 348 | "<div class=\"admonition alert alert-info\">\n",
|
346 | 349 | " <p class=\"admonition-title\" style=\"font-weight:bold\">Important Note</p>\n",
|
347 | 350 | " To convert HZ frequency to a <code>scale = hz *.0001</code> (where 0.01 is 100 Hz sampling) then apply <code>frequency2scale()</code> PyWavelets function\n",
|
|
356 | 359 | "source": [
|
357 | 360 | "fig, ax = plt.subplots(figsize=(8, 8))\n",
|
358 | 361 | "\n",
|
359 |
| - "# Overlay frequency of chords as dotted lines\n", |
| 362 | + "# Overlay frequency of notes as dotted lines\n", |
360 | 363 | "sample_rate = 1/sampleRate\n",
|
361 | 364 | "a_freq = pywt.frequency2scale(wavelet_mother, 440*sample_rate)\n",
|
362 | 365 | "plt.axhline(y=a_freq, color='lightpink', linestyle='--', label='A') # A note: 440 hz\n",
|
|
391 | 394 | "source": [
|
392 | 395 | "## Determining Which Frequencies to Overlay\n",
|
393 | 396 | "\n",
|
394 |
| - "For this example, we know that the input data is \"Jingle Bells\" so known which chords are going to be used\n", |
| 397 | + "For this example, we know that the input data is \"Jingle Bells\" so we know which notes are going to be used.\n", |
395 | 398 | "\n",
|
396 | 399 | "```\n",
|
397 | 400 | "\"Jingle Bells, Jingle Bells, Jingle All the Way\" as EEE EEE EGCDE\n",
|
398 | 401 | "```\n",
|
399 | 402 | "\n",
|
400 |
| - "However, let's imagine that we aren't sure. Wavelets gain information about _when_ a frequency occurs, but at a lower resolution to an exact frequency. To determine which chords are a best fit, you can make use of FFT to determinine which chords to include. Without FFT, the larger possible ranges of frequency can make it possible to confuse nearby chords." |
| 403 | + "However, let's imagine that we aren't sure. Wavelets gain information about _when_ a frequency occurs, but at a lower resolution to an exact frequency. To determine which notes are a best fit, you can make use of FFT to determinine which notes to include. Without FFT, the larger possible ranges of frequency can make it possible to confuse nearby notes." |
401 | 404 | ]
|
402 | 405 | },
|
403 | 406 | {
|
|
441 | 444 | "cell_type": "markdown",
|
442 | 445 | "metadata": {},
|
443 | 446 | "source": [
|
444 |
| - "## Overlay Frequency of Chords\n", |
445 |
| - "Using FFT we can now say that there are four clear frequencies that are associated with four chords for CDEG" |
| 447 | + "## Overlay Frequency of Notes\n", |
| 448 | + "Using FFT we can now say that there are four clear frequencies that are associated with four notes for CDEG." |
446 | 449 | ]
|
447 | 450 | },
|
448 | 451 | {
|
|
467 | 470 | "source": [
|
468 | 471 | "fig, ax = plt.subplots(figsize=(8, 8))\n",
|
469 | 472 | "\n",
|
470 |
| - "# Overlay frequency of chords as dotted lines\n", |
| 473 | + "# Overlay frequency of notes as dotted lines\n", |
471 | 474 | "sample_rate = 1/sampleRate\n",
|
472 | 475 | "c_freq = pywt.frequency2scale(wavelet_mother, 261*sample_rate)\n",
|
473 | 476 | "plt.axhline(y=c_freq, color='red', linestyle='--', label='C') # C Note: 261 hz\n",
|
|
494 | 497 | "cell_type": "markdown",
|
495 | 498 | "metadata": {},
|
496 | 499 | "source": [
|
497 |
| - "## Four Chords!\n", |
| 500 | + "## Four Notes!\n", |
498 | 501 | "\n",
|
499 |
| - "The darkest color correlates with the frequency at each time stamp. Rather than appearing as distinct peaks like Fourier Transform, wavelets return a gradient of frequencies. This is the loss in precision due to Heisenberg's Uncertainty Principle. While the frequencies can still be determined, there is some level of uncertainty in the exact frequencies. This is where combining wavelets with a Fourier Transform can be useful. We now know that this piece has four notes `CDEG`. The vertical bands represent where the note ends before the next note begins. This piece of music has a deliberate start and stop so this band will not always be as obvious in other pieces of music.\n", |
| 502 | + "The darkest color correlates with the frequency at each time stamp. Rather than appearing as distinct peaks like a Fourier Transform, wavelets return a gradient of frequencies. This is the loss in precision due to Heisenberg's Uncertainty Principle. While the frequencies can still be determined, there is some level of uncertainty in the exact frequencies. This is where combining wavelets with a Fourier Transform can be useful. We now know that this piece has four notes `CDEG`. The vertical bands represent where the note ends before the next note begins. This piece of music has a deliberate start and stop so this band will not always be as obvious in other pieces of music.\n", |
500 | 503 | "\n",
|
501 | 504 | "We can read this wavelet analysis by finding what note corresponds with the darkest band. \n",
|
502 | 505 | "\n",
|
|
0 commit comments