{
"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
}