"
],
"text/plain": [
":HoloMap [Default]\n",
" :Curve [x] (y)"
]
},
"execution_count": 3,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 2151378378992
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap1 = hv.HoloMap({i: hv.Curve((x, np.real(phase * np.exp(-1j * omega * i / N * T))), \n",
" label='plane wave') for i in range(N)})\n",
"hmap1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With this simple relationship, we see a wave that propagates from left to right."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Two plane waves "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A first interesting pattern that we can obtain using this harmonic wave toolkit is what happens when two plane waves propagate in the same medium, each with the same speed, but going in opposite directions. \n",
"\n",
"The wave going in the opposite direction is defined by the following phase map:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"phase_opposite = np.exp(-1j * k * x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Which we can animate:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('2151395877832')) && !(document.getElementById('_anim_img8504ca03d80c40c68a5025083c339aa3'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Curve [x] (y)"
]
},
"execution_count": 8,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 2151396200968
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap4 = hv.HoloMap({i: hv.Curve((x, np.real((phase + phase_opposite) * np.exp(-1j * omega * i / N * T))),\n",
" label='two plane waves -x +x ') for i in range(N)})\n",
"hmap4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see a dynamical destruction and amplification of the two waves, a so-called *standing wave*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Group velocity "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The above were animated using constant phase velocity. Some of the most interesting waves are those that exist in dispersive media. This means that waves of different wavelengths can propagate at different velocities."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A simple example to understand what happens is to plot the motion of two waves going in the same direction (not opposite ones as above) but at different speeds."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here, we use a so-called dispersion relation, which relates the speed of waves at different frequencies such as the one observed for [water waves in deep waters](https://en.wikipedia.org/wiki/Dispersion_(water_waves)) (the group velocity is half the phase velocity)."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"N = 5"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"cphi = 2.\n",
"k1 = 2 * np.pi / 1.\n",
"w1 = k1 * cphi\n",
"k2 = k1 + np.pi\n",
"w2 = w1 + .5 * cphi * (k2 - k1)\n",
"\n",
"phase_k1 = np.exp(1j * k1 * x)\n",
"phase_k2 = np.exp(1j * k2 * x)\n",
"\n",
"T1 = 2 * np.pi / w1\n",
"T2 = 2 * np.pi / w2"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('2151399044432')) && !(document.getElementById('_anim_imgcd66557e3f864d5fab6d315f3792767a'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Curve [x] (y)"
]
},
"execution_count": 11,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 2151399044432
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber'\n",
"hmap5 = hv.HoloMap({i: hv.Curve((x, np.real(phase_k1 * np.exp(-1j * w1 * i / N * T1) + \\\n",
" phase_k2 * np.exp(-1j * w2 * i / N * T1))),\n",
" label='two waves travelling at different speeds') for i in range(8 * N)})\n",
"hmap5"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What is interesting here is that the shape of the resulting wave deforms in complicated way while moving from place to place. This is what is called dispersive propagation. However, there is still a way of describing this propagation in terms of things that don't change shape so much."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case, since we are summing cosine waves, we have an exact formula describing this propagation.\n",
"\n",
"\n",
"$$\n",
"\\cos(kx - \\omega t) + cos \\left( (k + \\delta k) x - (\\omega + \\delta \\omega) t \\right) = 2 \\cos \\left ( (k + \\frac{\\delta k}{2}) x - (\\omega + \\frac{\\delta \\omega}{2}) t \\right ) cos(\\frac{\\delta k}{2} x - \\frac{\\delta \\omega}{2} t) \n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the above formula, there is a wave of approximately the same propagation properties that gets multiplied by an envelope that propagates at a slower speed than the carrier frequency (again, this is naturally found in the case of water waves in deep waters)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see things more clearly, we can plot the two components as separated entities, as a *carrier* and an *envelope*."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"phase_carrier = np.exp(1j * (k1 + (k2 - k1)/2) * x)\n",
"phase_envelope = 2 * np.exp(1j * (k2 - k1)/2 * x)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('2151401565768')) && !(document.getElementById('_anim_img1fb929db0fcc4d4585a80395548cf3c3'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Overlay\n",
" .Curve.Carrier :Curve [x] (y)\n",
" .Curve.Envelope :Curve [x] (y)"
]
},
"execution_count": 13,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 2151401565768
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber' \n",
"%%opts Overlay [show_legend=False]\n",
"hmap6 = hv.HoloMap({i: hv.Curve((x, np.real(phase_carrier * np.exp(-1j * (w1 + (w2 - w1) / 2) * i / N * T1))),\n",
" label='carrier').opts(alpha=0.2) * \\\n",
" hv.Curve((x, np.real(phase_envelope * np.exp(-1j * ((w2 - w1) / 2) * i / N * T1))),\n",
" label='envelope') for i in range(8 * N)})\n",
"hmap6"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As we can see, the carrier is twice as fast as the envelope, which is the case for dispersive deep water waves."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What happens if we overlay the envelope and the carrier on top of the complicated wave that we had above?"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"// Ugly hack - see HoloViews #2574 for more information\n",
"if (!(document.getElementById('2151403251976')) && !(document.getElementById('_anim_img2fee8aa1cd2847a897b2c110f8350e92'))) {\n",
" console.log(\"Creating DOM nodes dynamically for assumed nbconvert export. To generate clean HTML output set HV_DOC_HTML as an environment variable.\")\n",
" var htmlObject = document.createElement('div');\n",
" htmlObject.innerHTML = `
"
],
"text/plain": [
":HoloMap [Default]\n",
" :Overlay\n",
" .Curve.Two_waves_travelling_at_different_speeds :Curve [x] (y)\n",
" .Curve.Carrier :Curve [x] (y)\n",
" .Curve.Envelope :Curve [x] (y)"
]
},
"execution_count": 14,
"metadata": {
"application/vnd.holoviews_exec.v0+json": {
"id": 2151403251976
}
},
"output_type": "execute_result"
}
],
"source": [
"%%output holomap='scrubber' \n",
"%%opts Overlay [show_legend=False]\n",
"hmap5 * hmap6"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The superposition lets the underlying structure of the complicated wave appear! The complicated pattern can be described by an envelope that propagates at slower speeds than the faster oscillations of the wave. This description can be very useful for many applications of dispersive waves, for instance guided waves in fiber optics, structures or at the surface of the sea. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*This post was entirely written using the IPython notebook. Its content is BSD-licensed. You can see a static view or download this notebook with the help of nbviewer at [20190204_beatsGroupVelocity.ipynb](http://nbviewer.ipython.org/urls/raw.github.com/flothesof/posts/master/20190204_beatsGroupVelocity.ipynb).*"
]
}
],
"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.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}