[ Prev | Index | Next ]
Japanese English
Now Loading...
Download
Please download on PC (not smartphone) and extract the ZIP file. Then double-click VCSSL.bat (batch file) to execute for Microsoft® Windows®, or execute VCSSL.jar (JAR file) on the command line for Linux® and other OSes.
For details, see How to Use.
You are free to use and modify this program and material, even for educational or commercial use. » Details

Wave Interference Animation (Two Circular Waves on a Plane)

This is a simple simulator built with VCSSL that visualizes the interference of two circular waves propagating on a plane (i.e., in two dimensions).

- Table of Contents -

In the previous article, we explored the animation of a single circular wave. This article continues from there. If you're wondering "What exactly is a circular wave?", please check out the previous content first.

Here, we'll build on that and animate the interference pattern created by superimposing two circular waves.

[ Related Articles ]

Sponsored Link


How to Use

Download and Extract

At first, click the "Download" button at the above of the title of this page by your PC (not smartphone). A ZIP file will be downloaded.

If you are using Windows, right-click the ZIP file and choose "Properties" from the menu, and enable "Unblock" checkbox at the right-bottom (in the line of "Security") of the properties-window. Otherwise, when you extract the ZIP file or when you execute the software, security warning messages may pop up and the extraction/execution may fail.

Then, please extract the ZIP file. On general environment (Windows®, major Linux distributions, etc.), you can extract the ZIP file by selecting "Extract All" and so on from right-clicking menu.

» If the extraction of the downloaded ZIP file is stopped with security warning messages...

Execute this Program

Next, open the extracted folder and execute this VCSSL program.

For Windows

Double-click the following batch file to execute:

VCSSL__Double_Click_This_to_Execute.bat

For Linux, etc.

Execute "VCSSL.jar" on the command-line terminal as follows:

cd <extracted_folder>
java -jar VCSSL.jar

» If the error message about non-availability of "java" command is output...

After Launching

Upon launching the program, you'll first be asked whether to manually input the wave parameters. Unless you specifically want to set exact values (like a precise wavelength), feel free to skip this by selecting "No."

Then, a window will appear showing the circular wave interference as a 3D animation.

Window Screenshot

You can freely adjust the wave parameters -- such as wavelength, amplitude, and period -- using the sliders at the top of the window.

Closing the window will terminate the program.

Note: Smoother Wave Surface = Finer Mesh (N)

The smoothness of the wave surface depends on the mesh resolution, determined by the value of N. To adjust N, open the source code file "InterferingCircularWave.vcssl" in a text editor, and modify the value in the line around line 20:

const int N = 100;

Increasing N makes the surface smoother, but also more computationally demanding.

When editing, be careful not to remove the semicolon (;) at the end of the line.

Concept Overview

When you superimpose multiple waves, the resulting wave differs in shape and motion from either of the originals. This phenomenon is called interference.

In the article before last, we examined how two sine waves interfered along the X-axis. The combined wave had a unique form and motion, distinct from either of the original sine waves.

This time, we're taking it one dimension higher:
We'll combine two circular waves traveling across a surface and observe their interference pattern. Once again, you'll see fascinating and intricate behaviors emerge!

First, let's take a look at the two circular waves -- Wave A and Wave B -- before combining them

To begin with, let's examine the two circular waves that will be combined (referred to as Wave A and Wave B) individually. At the top of the screen, there's a slider to control the amplitude of Wave B. If you move it all the way to the left (i.e., set Wave B's amplitude to zero), Wave B disappears, and only Wave A remains, as shown below:


( Wave B amplitude set to 0, showing only Wave A )

In this animation, the red ball acts as the wave source, and circular waves spread outward in concentric rings from it. This is the form of the circular wave used in this simulation. As explained in the previous article, the cross-section of this wave that includes the wave source forms a sine wave.

Next, let's restore Wave B's amplitude to a non-zero value and set Wave A's amplitude to zero instead. This will cause Wave A to disappear and leave only Wave B visible:


( Wave A amplitude set to 0, showing only Wave B )

Here, the green ball is the wave source, and a circular wave radiates outward from it.

Unless you adjust the sliders, both waves share the same wavelength and period by default. In other words, the red and green balls -- placed slightly apart -- are emitting identical circular waves that propagate outward from each source.

Interference of Wave A and Wave B with matching amplitudes

Now let's combine the two waves -- Wave A and Wave B -- and observe their interference. When both waves have approximately the same amplitude, you'll see a distinct and fascinating interference pattern.

...That said, the program is already configured to display an ideal interference pattern immediately upon launch, so you can simply observe the default state right after starting the simulation. You'll get a result like this:


( Interference between Wave A and Wave B with matching amplitudes. The wavelength and period are also set to the same values. If you're having trouble matching the amplitudes manually, restarting the program will return to exactly this default configuration. )

What a curious pattern this is. To get a better look, let's shorten the wavelength slightly to make the shapes denser, and view the result from directly above as a static image instead of an animation:


( Wave A and Wave B are set to the same amplitude and allowed to interfere. The wavelength and amplitude are equal. If it's difficult to match the amplitudes manually, restarting the program will reset everything to exactly this configuration. )

From this top-down view, we can clearly see that there are several curved regions where the wave crests and troughs seem to mysteriously vanish. To highlight this, here's the same image with hand-drawn lines added on top (note: the lines are not mathematically exact, just roughly drawn to illustrate the idea):

Now, if we go back and review the animation, we can notice something striking: Even as the wave evolves over time, the crests and troughs consistently cancel out along these lines.

So, what exactly are these mysterious curves?

Conditions for Destructive and Constructive Interference Between Wave A and Wave B

The curved lines we saw earlier appear at locations where wave A and wave B always cancel each other out perfectly -- these points satisfy a very specific condition. More precisely, they appear at points where the distance from wave source A and the distance from wave source B differ by exactly half a wavelength.

To understand what this means, let's go back and review what happens when only wave A is present. Imagine moving away from the wave source bit by bit -- how does the wave change?

The circular waves we're dealing with here have cross-sections that form sine waves. And as we know, sine waves alternate between crests and troughs. As explained in the previous article on sine wave animation, one wavelength includes one crest and one trough.

That means that as the distance from the source increases, the wave goes crest → trough → crest → trough... at every half-wavelength interval. Whether the point directly above the wave source is at a crest or trough (or somewhere in between) depends on the time. The key idea is that crests and troughs alternate every half-wavelength.

The same thing applies to wave B.

Now let's consider what happens when we combine wave A and wave B again. In our simulator, the two sources are vibrating in perfect sync.

So, at a location equidistant from both sources, wave A and wave B will both bring a crest at the same time, or both a trough at the same time. Even at in-between times, the waves behave identically. Therefore, at such locations, wave A and wave B always reinforce each other.

Similarly, at points where the distance to the two sources differs by an integer multiple of the wavelength, the same thing happens -- the waves reinforce each other. Why? Because a full wavelength shift means the waves are offset by one crest (or one trough), so the shape remains unchanged. In short, the result is the same as if the point were equidistant from both sources.

Now we come to the main point: At points where the distance to the two sources differs by an integer multiple of the wavelength plus half a wavelength, wave A and wave B cancel each other out.

Why is that?

As we just saw, if the distance difference is an integer multiple of the wavelength, both waves arrive at the same phase -- crest aligns with crest, or trough with trough. But if we then shift by half a wavelength, we effectively move one crest ahead -- which aligns the crest of one wave with the trough of the other. So when wave A brings a crest, wave B brings a trough, and vice versa.

What about those in-between times? Well, when you combine two identical sine waves that are offset by exactly half a wavelength, they cancel each other out entirely -- the result is zero at every moment. Therefore, at locations where the distances to the two sources differ by an odd multiple of half a wavelength, the waves always cancel out, regardless of time. That's why the crests and troughs of the combined wave disappear in those regions.

What Do the Lines of Destructive and Constructive Interference Look Like?

The curved lines we observed earlier -- where the wave's surface appears unusually flat -- happen to satisfy the condition that: the difference in distance from the two wave sources A and B is exactly an integer multiple of the wavelength plus half a wavelength.

That may sound a bit complicated, but geometrically, these lines aren't so exotic -- they're simply hyperbolas, which you may remember from middle school math.

A hyperbola has an interesting property:

The difference in distances from two fixed points is constant.

In our case, those "two points" are wave source A and wave source B, and the "distance difference" is equal to an integer multiple of the wavelength plus half a wavelength. That's why the waves cancel each other out along those hyperbolic curves.

Similarly, the places where the distance difference is exactly an integer multiple of the wavelength also form hyperbolas. As explained earlier, at these locations, wave A and wave B always reinforce each other.

In fact, these constructive interference curves lie between the ones where the waves cancel out. If you look closely at those in-between regions, you'll see that the wave surface continues to vibrate, never flattening out.

The lines traced by the strongest crests and troughs -- the "ridges" of the wave -- follow hyperbolas that satisfy the condition for constructive interference.


Sponsored Link


Code

This program is written in VCSSL. Below is a brief explanation of the code. VCSSL uses a simple C-like syntax, so if you're familiar with C or similar languages, you should find it easy to follow.

If you want to change the graph range or modify various aspects of the program, you can open the script file InterferingCircularWave.vcssl in a text editor and edit it directly. Since VCSSL is a scripting language, you donft need a separate compiler -- just modify and run it.

Prerequisite Code

This program is slightly more complex than previous examples, so rather than diving in cold, it's helpful to understand a few simpler examples first.

For an understanding of how to animate circular waves and how to use GUI components like sliders to control parameters, you can refer to the previous code:

In that version, the actual animation and 3D visualization of the wave were handled by the Graph3D library, which functions like a 3D graphing tool. That allowed for a much simpler implementation, and since only one circular wave was being animated, the graph-based visualization was perfectly sufficient.

This time, however, we wanted to go a bit further -- placing sphere models for the wave sources, customizing the wave surface coloring, and so on. So instead of using a graphing tool, the drawing code is written from scratch, which adds some extra complexity.

To avoid reinventing the wheel, we use the Graphics3DFramework library -- a lightweight framework that handles much of the groundwork for rendering. As a basic example of using this framework to animate a surface, see the following:

In fact, this current program is essentially a combination of the two examples above, with a few additional features layered in. If you find the current code overwhelming at first glance, reviewing those two examples beforehand should make things clearer.

Full Code Listing

Now, let's take a look at the full source code of this program.

That's all of it. It's a bit over 400 lines in total. While the inline comments explain most of what's happening, we'll now go through the code from the top and provide some additional explanation.

That said, since covering everything in detail would get quite lengthy, we'll skim over parts that are similar to the two prerequisite examples -- Circular Wave Animation and Mesh Animation with Vertex Arrays -- and instead focus on the core elements that are unique to this program.

Variable Declarations

The variable declarations at the beginning are mostly the same as those in the previous code. The main difference is that parameters and GUI slider variables are now prepared for both Wave A and Wave B.

However, one notable change is in the format of the array used to store the vertex data of the wave surface:

In the previous program, we used three separate 2D arrays for each coordinate axis -- "waveX[N][N]", "waveY[N][N]", and "waveZ[N][N]". That format made it clearer which array held which axis, and it was easy to pass them directly to the graphing library.

In this program, however, we use VCSSL's 3D rendering functions to build and animate a custom surface model from scratch. For this purpose, the array format "[N][N][3]", which combines X, Y, and Z values into a single 3D array, is more suitable. This is because it's directly supported by the rendering functions in the framework, as shown in the diagram below (See Also: Mesh Animation with Vertex Arrays).

As the diagram shows, the last dimension of the array holds the X, Y, and Z coordinates -- index 0 for X, 1 for Y, and 2 for Z.

To make the code more readable, we define constants X, Y, and Z to represent these indices instead of using raw numbers. For example, to access the X value of the grid point at row a and column b, you can write "waveVertex[a][b][X]".

That's about all that has changed in the variable declarations. The core structure is almost the same as before.

Initialization Process at Program Startup

Next, let's look at the initialization process that takes place when the program starts running.

As mentioned earlier, this program uses the Graphics3DFramework, a lightweight framework for 3D programs. This framework automatically handles the basic setup that's common to most 3D programs -- such as creating a window and setting up a renderer (drawing engine) -- right after the program starts. Once that's done, if a function named "onStart" is defined, the framework will call it.

So, we define an "onStart" function and write in it everything we want to execute once after the program launches. In this case, the function looks like this:

At the top, it calls inputParameters() to allow the user to manually enter wave parameters if desired. This function is defined elsewhere in the same script, and it works similarly to the one in the previous code -- just doubled for wave A and wave B -- so we'll skip over the details here.

Next, setWindowSize(...) sets the size of the window, and setAmbientLightBrightness(...) adjusts the ambient lighting. These are functions provided by the framework. The camera settings -- setGraphics3DMagnification(...) and setGraphics3DDistance(...) -- come from the Graphics3D library, which handles the actual 3D rendering.

We're hardcoding some values directly into the arguments here, which isn't ideal coding practice, but it's a single-use simulation script, so hopefully you'll forgive us.

Now for the important part: the initializeCoordinate() function creates and sets up the coordinate systems, and initializeModel() creates and places the models on those coordinate systems. These functions are defined as follows:

Coordinate systems are used primarily for positioning and orienting models, as well as for moving them (see: Coordinate Systems).

Technically, we could place the wave model directly onto the global coordinate system, but depending on values like "X_MAX" or "Y_MIN", the visible area of the wave could end up off-screen or far from the origin. To avoid that, we create a base coordinate system (here called the "wave coordinate") and offset it so the wave's center aligns with the world origin. Then we place the wave model on top of that.

When creating the wave model using newModel(...), we specify "QUADRANGLE_GRID", which tells the renderer to interpret the vertex array as a grid mesh. (For more on this format, see Mesh Animation Using Vertex Arrays.)

As for the wave sources A and B, since they move over time, we also assign each of them its own base coordinate system (the "source coordinates"), mount those onto the wave coordinate, and place their sphere models on top. Later, when we want to animate their movement, we simply shift the origin of their coordinate systems, which causes their sphere models to move with them.

The last initialization step is handled by initializeGUI(), which sets up the GUI components like sliders and labels. This part is almost identical to the previous code example, just with more sliders, so we'll skip it here and move on.

Animation Process

Now let's take a look at how the wave animation is handled.

In the previous code, an animation loop was created inside the main() function, where time was advanced little by little -- like flipping through a flipbook-and slightly different wave data was passed to the graphing software for rendering. Repeating this process rapidly gave the appearance of animation.

The basic concept remains the same here. However, this time the animation loop is managed by the framework. For each iteration of the loop, the framework automatically calls the onUpdate() function.

In other words, as long as we define the onUpdate() function in our code, it will be called automatically several times per second. By updating the wave shape (and color) slightly each time within that function, the result appears animated -- easy, right?

Here's how the onUpdate() function is implemented:

The first thing it does is call updateModelVertex(), which updates the vertex coordinate array and changes the shape of the wave model. This function is defined in the same script as follows:

This function iterates through the grid points of the mesh, calculating the distance from the current point to wave sources A and B as "rA" and "rB", respectively. The distance \(r_A\) from the wave source at position \(x, y\) is calculated using the formula:

\[ r_A = \sqrt{ (x-x_A)^2 + (y-y_A)^2 } \tag{1} \]

This is implemented directly in the code using the "sqrt" (= square root) function.

Then, based on this distance, it calculates the wave values from sources A and B using the equation for a circular wave:

\[ z = A \sin 2 \pi \bigg( \frac{t}{T} - \frac{r}{\lambda} \bigg) \tag{2} \]

The results are stored in "zA" and "zB", and these are simply added together (superposition principle) and stored as the Z-value in the vertex array. Finally, the updated vertex array is passed to setModelVertex() to update the shape of the wave model. That's the end of the updateModelVertex() function.

Next, updateModelColor() is called to update the color of the wave surface. This function is also defined in the code, as follows:

This function colors the wave surface based on Z-values so that areas of greater vertical movement are easier to identify when viewed from above. Each line is explained in the comments. If you want to change the coloring, you can modify this section.

That's the end of the wave surface animation. But don't forget about the wave sources!

After the color update, the program calls updateSourceLocations(), which updates the positions of the wave sources. That function looks like this:

Since both sources are located at the origin of their respective waves, the distance \(r\) is zero, and the equation simplifies (the \(-r/\lambda\) term in eq.(2) drops out). This Z-value is then used to update the origin of the coordinate system for each source. Because the sphere models representing the wave sources are mounted onto those coordinate systems, moving the coordinate origins moves the models too.

Other Sections

That covers all the main components. The remaining parts of the code -- such as event handlers and utility functions -- are mostly the same as in the previous code and even the one before that. They handle more minor features.

That wraps up our walkthrough of the code.

License

This VCSSL/Vnano code (files with the ".vcssl" or ".vnano" extensions) is released under the CC0 license, effectively placing it in the public domain. If any sample code in C, C++, or Java is included in this article, it is also released under the same terms. You are free to use, modify, or repurpose it as you wish.

* The distribution folder also includes the VCSSL runtime environment, so you can run the program immediately after downloading. The license for the runtime is included in the gLicenseh folder.
(In short, it can be used freely for both commercial and non-commercial purposes, but the developers take no responsibility for any consequences arising from its use.) For details on the files and licenses included in the distribution folder, please refer to "ReadMe.txt".

* The Vnano runtime environment is also available as open-source, so you can embed it in other software if needed. For more information, see here.



Sponsored Link



Japanese English
[ Prev | Index | Next ]
Wave Interference Animation (Two Circular Waves on a Plane)

Interactive simulator for visualizing wave interference between two circular waves on a plane.
Circular Wave Animation

Interactive simulator for animating circular waves on a plane with adjustable parameters.
Wave Interference Animation (Two Sine Waves on a Line)

Interactive simulation of wave interference between two 1D sine waves.
Sine Wave Animation

Interactive simulator for animating sine waves with adjustable parameters.
Vnano | Solve The Lorenz Equations Numerically

Solve the Lorenz equations, and output data to plot the solution curve (well-known as the "Lorenz Attractor") on a 3D graph.
Index
[ Prev | Index | Next ]
Wave Interference Animation (Two Circular Waves on a Plane)

Interactive simulator for visualizing wave interference between two circular waves on a plane.
Circular Wave Animation

Interactive simulator for animating circular waves on a plane with adjustable parameters.
Wave Interference Animation (Two Sine Waves on a Line)

Interactive simulation of wave interference between two 1D sine waves.
Sine Wave Animation

Interactive simulator for animating sine waves with adjustable parameters.
Vnano | Solve The Lorenz Equations Numerically

Solve the Lorenz equations, and output data to plot the solution curve (well-known as the "Lorenz Attractor") on a 3D graph.
News From RINEARN
* VCSSL is developed by RINEARN.

Released: Latest Version of VCSSL with Fixes for Behavioral Changes on Java 24
2025-04-22 - VCSSL 3.4.50 released with a fix for a subtle behavioral change in absolute path resolution on network drives, introduced in Java 24. Details inside.

Released the Latest Versions of RINEARN Graph and VCSSL - Now Supporting Customizable Tick Positions and Labels!
2024-11-24 - Starting with this update, a new "MANUAL" tick mode is now supported, allowing users to freely specify the positions and labels of ticks on the graph. We'll explain the details and how to use it.

Released Exevalator 2.2: Now Compatible with TypeScript and Usable in Web Browsers
2024-10-22 - The open-source expression evaluation library, Exevalator, has been updated to version 2.2. It now supports TypeScript and can be used for evaluating expressions directly in web browsers. Explains the details.

Behind the Scenes of Creating an Assistant AI (Part 1: Fundamental Knowledge)
2024-10-07 - The first part of a series on how to create an Assistant AI. In this article, we introduce the essential knowledge you need to grasp before building an Assistant AI. What exactly is an LLM-based AI? What is RAG? And more.

Launching an Assistant AI to Support Software Usage!
2024-09-20 - We've launched an Assistant AI that answers questions about how to use RINEARN software and helps with certain tasks. Anyone with a ChatGPT account can use it for free. We'll explain how to use it.

Software Updates: Command Expansion in RINEARN Graph, and English Support in VCSSL
2024-02-05 - We updated our apps. This updates include "Enhancing the Command-Line Features of RINEARN Graph" and "Adding English Support to VCSSL." Dives into each of them!

Inside the Repetitive Execution Speedup Impremented in Vnano Ver.1.1
2024-01-17 - Delves into the update in Vnano 1.1 from a developer's viewpoint, providing detailed insights into the specific improvements made to the internal structure of the script engine.

Scripting Engine Vnano Ver.1.1 Released: Dramatic Speed Improvement for Repetitive Executions of the Same Content
2023-12-22 - Released the Vnano script engine Ver.1.1. In this version, we've made significant enhancements in processing speed by reducing the overhead of handling requests. Explains the details.