WaveInterference

by James Gunn: L6 Age ~16

Introduction

James has made excellent use of Wingraph and other advanced Pascal features to produce a most effective educational program. It is now available in Smart Pascal as a web preview.

You can input many sine waves with different amplitudes, offsets, and relative frequencies then the program will draw them in different colours. After the drawing is complete, you will probably want to select the console window and press RETURN to instruct the program to calculate and display the sum of all of the waves.

We used the program to construct two waves with the same frequency, a 180 degree phase difference and differing slightly in amplitude with the following input:

Input for destructive interference

Input for destructive interference

The result of adding these waves is a wave with amplitude 10, shown in white:
Destructive interference

Destructive interference

We can show summing a low frequency sine wave to a high frequency sine wave with the following input.

Input for low and high frequency waves

Input for low and high frequency waves

The resulting wave is shown in white:

Low and high frequency waves

Low and high frequency waves

Alternatively, we can instruct the program to generate random waves to obtain an output such as this.

Random output

Random output

The program uses conditional compilation to give a "verbose" option which outputs the properties of the waves on the console. (However, it is not so verbose as to indicate what the numbers represent!)

In order to run program WaveInterference, you will need to have downloaded Stefan Berinde`s wingraph.zip file as described in our Graphics tutorial. You should copy the unzipped wincrt.pas and wingraph.pas (from the src folder) into your program folder. (The compiled units are included in the zip file but you might as well have the source code available for reference). You should find these three files useful for your own graphics programs.

The Program

program WaveInterference;
{
    Copyright (c) 2011 James Gunn
    
    Licensed under the Apache License, Version 2.0 (the "License"); you may not 
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/
}

{$APPTYPE CONSOLE}{$H+}
//{$define verbose}

uses
  Classes, SysUtils, Wingraph, Wincrt, StrUtils;

const
  //Here we define how large we want the window to be.
  WIN_HEIGHT : integer = 600;
  WIN_WIDTH : integer = 600;

var
  gd, gm, i, j : smallint;
  amp : array of integer;
  offset, freq : array of real;
  colour : array of integer;
  num_waves, sumN, sumF, intInput, intErrorCode : integer;
  input : string;
  RANDOM_WAVE : boolean = false;

begin
  randomize; //so random numbers will work
  //gd and gm used later to initiate the WinGraph window
  gd := 9;
  gm := 13;

  //Ask the users if they want random waves, and keep
  //doing so until they choose 1 (yes) or 0 (no)
  repeat
    writeln('Produce random waves? [0 = False, 1 = True]');
    readln(input);
    val(input, intInput, intErrorCode);
  until (intErrorCode = 0) and ((intInput = 1) or (intInput = 0));
  //If they did choose a random wave, then we store this information
  //in a boolean variable.
  if intInput= 1 then
    RANDOM_WAVE := true;
  writeln;
  //Ask the user how many waves they are going to want
  repeat
    writeln('How many waves per run?');
    readln(input);
    val(input, intInput, intErrorCode);
  until (intErrorCode = 0) and (intInput >0 );
  //and store it in a variable.
  num_waves := intInput;
  //Extend the arrays to fit the number of waves
  //the user has specified'
  SetLength(amp, num_waves);
  SetLength(offset, num_waves);
  SetLength(colour, num_waves);
  SetLength(freq, num_waves);
  writeln;
  repeat
    //Clear the device for use.
    ClearDevice;
    //Loop through the number of waves
    for i := 0 to num_waves - 1 do
      begin
        //Now check if we are running in verbose mode. If we are then
        //we need to print out all of the wave details to the screen.
        {$ifdef verbose}
          write('Wave ', i + 1, ':');
        {$endif}

        //Generate a random amplitude for the wave between 25 and 150 if we are
        //running in random wave mode.
        //If we are running in verbose mode then output the result to the console.
        if RANDOM_WAVE then
          begin
            amp[i] := random(150) + 25;
            {$ifdef verbose}
              write(' ', Round(amp[i]));
            {$endif}
          end
        else
          //If we are not running in verbose mode then allow the user to enter
          //the wave amplitude and then validate the entry.
          begin
            repeat
              writeln;
              write('Amplitude: ');
              readln(input);
              val(input, intInput, intErrorCode);
            until (intErrorCode = 0) and (intInput > 0);
            amp[i] := intInput;
          end;

        //We now do the same for offset
        if RANDOM_WAVE then
          begin
            offset[i] := random(360);
            {$ifdef verbose}
              write(' ', Round(offset[i]));
            {$endif}
          end
        else
          begin
            repeat
              write('Offset (Degrees): ');
              readln(input);
              val(input, intInput, intErrorCode);
            until (intErrorCode = 0) and (intInput >= 0);
            offset[i]:=intInput * pi / 180;
          end;

        //and again for the frequency multiplier.
        if RANDOM_WAVE then
          begin
            freq[i]:=(random(50) / 10) + 1;
            {$ifdef verbose}
              writeln(' ', Round(freq[i]));
            {$endif}
          end
        else
          begin
            repeat
              write('Frequency Multiplier: ');
              readln(input);
              val(input, intInput, intErrorCode);
            until (intErrorCode = 0) and (intInput > 0);
            freq[i] := intInput;
          end;
        //Here the wave is given a random colour. It is fixed to give a light colour.
        colour[i]:=(random(155) + 100) + (random(155) + 100) * 256 + (random(200) + 55) * 256 * 256;
      end;
  //Now set up the window according to the constants
  //and add a title so everyone knows who created it.
  setwindowsize(WIN_WIDTH, WIN_HEIGHT);
  initgraph(gd, gm, 'Wave Adder v2.0 James Gunn');
  //Draw the axis.
  MoveTo(1, ((WIN_HEIGHT div 2) - 50));
  LineTo(WIN_WIDTH, ((WIN_HEIGHT div 2) - 50));

  //Loop through all x-values and waves to draw each wave.
  for i := 0 to WIN_WIDTH do
    begin
      //Loop through all of the waves that have been set up (could be random or user defined).
      for j := 0 to num_waves - 1 do
        begin
          //Set the colour to draw the wave as the colour generated above.
          SetColor(colour[j]);
          //Calculate the y-value of the wave at the current x-value (i) based on the
          //amplitude, frequency and offset.
          MoveTo(i, Round(Sin(((i * pi / 180) * freq[j]) + offset[j]) * amp[j]) + ((WIN_HEIGHT div 2) - 50));
          //Calculate the y-value for the next x-value and draws the line between
          //them, thereby drawing the first section of the wave.
          LineTo(i + 1, Round(Sin((((i + 1) * pi / 180) * freq[j]) + offset[j]) * amp[j]) + ((WIN_HEIGHT div 2) - 50));
        end;
      delay(5) ;
    end;
  writeln('Press enter to see the sum');
  readln;
  //Change the colour to white to make the sum stand out.
  SetColor(white);
  for i:= 0 to WIN_WIDTH do
    begin
      sumN := 0;
      sumF := 0;
      //Add up the y-value of all waves at the current x-value.
      for j := 0 to num_waves - 1 do
        sumN := sumN + Round(Sin((( i * pi / 180) * freq[j]) +  offset[j]) * amp[j]);
      //Add up the y-value of all waves at the next x-value.
      for j := 0 to num_waves-1 do
        sumF := sumF + Round(Sin((((i + 1) * pi / 180) * freq[j]) + offset[j]) * amp[j]);
      MoveTo(1, ((WIN_HEIGHT div 2) - 50));
      LineTo(WIN_WIDTH, ((WIN_HEIGHT div 2) - 50));
      //The sum is only drawn if there are 2 or more waves.
      if num_waves > 1 then
        begin
          //Using the sums calculated above, draw each section of the sum wave.
          MoveTo(i, sumN + ((WIN_HEIGHT div 2) - 50 ));
          LineTo(i + 1, sumF + ((WIN_HEIGHT div 2) - 50));
        end;
      delay(5);
    end;
  if RANDOM_WAVE = true then
    begin
      writeln('Press enter to run again');
      readln;
    end;
  until RANDOM_WAVE = false;
  writeln('Press enter to close');
  readln;
end.

Remarks

Could you write a similar program to include waves other than sine waves?

Programming - a skill for life!

Student programs to inspire you!