{ "cells": [ { "cell_type": "markdown", "id": "8bf0c3d7", "metadata": {}, "source": [ "# Fourier decomposition\n", "\n", "This example uses the `show()`, `morph()`, `translate()` and `hide()` animations to animate `plot` plot objects to show how we can reconstruct a signal with a Fourier Transform." ] }, { "cell_type": "code", "execution_count": null, "id": "b8ecc773", "metadata": {}, "outputs": [], "source": [ "import diplotocus as dpl\n", "import numpy as np\n", "\n", "#We create our timeline and define a global easing\n", "tl = dpl.Timeline(xlim=(-5,5),ylim=(-0.25,1.5),easing=dpl.easeInCubic())\n", "\n", "#We create the signal we want to Fourier decompose\n", "x = np.linspace(-5,5,100)\n", "y = np.exp(-x**2)\n", "\n", "#Plot the real signal\n", "tl.ax.plot(x, y, c='k', ls='--', alpha=0.5)\n", "\n", "#Get its Fourier power spectrum\n", "freq = np.fft.fftfreq(len(x),x[1]-x[0])\n", "sp = np.fft.fft(y)\n", "\n", "#Add a plot object for our reconstructed signal\n", "p_total = dpl.plot(x,np.zeros_like(x),c='green',lw=3)\n", "p_total.plot(duration=30)\n", "\n", "#We create a list to store all the plotObjects we will animate\n", "plot_objects = [p_total]\n", "\n", "#Loop over the first 8 frequencies\n", "for i in range(8):\n", " amp = np.abs(sp[i])/len(x)\n", " phase = np.angle(sp[i])\n", " if i > 0:\n", " amp *= 2#We need to double the amplitude of doubled modes\n", "\n", " x0 = np.linspace(-5,5,500,endpoint=False)\n", " y0 = 0.25*np.cos(x0*2*np.pi*freq[i]) + 1.25\n", " y1 = amp*np.cos((x0-x[0])*2*np.pi*freq[i] + phase) + 1.25\n", "\n", " #We first create a cosine wave of the current frequency\n", " p = dpl.plot(x0,y0)\n", "\n", " #We delay each mode so they appear sequentially\n", " base_delay = 50*i\n", " #We fade the plot in\n", " p.show(duration=10,delay=base_delay)\n", " #Morph it into the right cosine wave given the power spectrum\n", " p.morph(new_x=x0,new_y=y1,duration=20,delay=base_delay + 10)\n", " #Move it down\n", " p.translate(start_pos=(0,0),end_pos=(0,-1.25),duration=20,delay=base_delay + 30)\n", " #Hide it\n", " p.hide(duration=10,delay=base_delay + 40)\n", " plot_objects.append(p)\n", "\n", " #We compute the reconstructed signal from modes <= i\n", " sp_total = np.where(np.abs(freq) > freq[i],0,sp)\n", " y_total = np.fft.ifft(sp_total,n=len(x))\n", " #We update our reconstructed signal\n", " p_total.morph(new_x=x,new_y=y_total,duration=20,delay=base_delay + 30)\n", "\n", "tl.animate(plot_objects)\n", "tl.save_video('../../_static/examples/fourier.mp4')" ] }, { "cell_type": "code", "execution_count": 58, "id": "f5077e4e", "metadata": { "tags": [ "remove-input" ] }, "outputs": [ { "data": { "text/html": [ "\n", " \n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import HTML, display\n", "display(HTML(\"\"\"\n", " \n", "\"\"\"))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.3" } }, "nbformat": 4, "nbformat_minor": 5 }