Introduction: Sonic Phased Array

This instructables is for an arduino sonic phased array. Visually, the sonic phased array is just a line of interconnected speakers aimed in the same direction. However, the device itself is able to direct the strength of the sound produced by these speakers by making each one send out waves at different times (phase delay). Over the course of this page, you will learn how to build, code and run your device. We have also included the math and design process that we used in building this device. Hope you enjoy building your own device as much as we enjoyed making our own.


Background Research


What is a Phased Array?

 A phased array is a group of sensors that are connected and used to produce a sensor pattern. This sensor pattern can be electronically adjusted by changing the phase of the signals to reinforce the desired direction and suppress the waves from going to the undesired direction.


Principle of Sonic Phased Arrays

Sonic phased arrays use interference to control the characteristics and direction of sound waves. By adjusting the timing of sound sources interference can be used to steer and shape sound waves.


Steering and Focusing:

Sonic phased arrays allow users to control the direction of sound propagation. By altering the phase shift applied to the system, the direction of the sound beam can be steered electronically without moving the array. Focusing techniques can be operated to concentrate sound within a specific area to lessen loss of sound over long distances.

Supplies

Components and Tools for Circuitry


Components 

  1. 1x Arduino
  2. 1x Breadboard
  3. 4x Arduino Speaker
  4. 5x 1k Potentiometer
  5. Jumper Wires


Tools 

  1. Wire Strippers and Cutters
  2. May Need Soldering Equipment


Devices/Programs for Coding


  1. Computer
  2. Arduino IDE
  3. 3d Printer Slicer Program (optional


Other


  1. Microphone with Db Output
  2. 3d Printer (optional)

Step 1: Speaker Frequency

The first step will be going over how to build the model and how to set up the code to obtain a certain frequency with one or more speakers.


Building The Array


Steps

  1. Wire/Testing speakers
  2. Speaker with Potentiometer
  3. Scale to 4 Speakers
  4. Upload code 
  5. Test phase shift


Step 1: Wire/Test Speakers



To wire the speaker, put the positive terminal to the pin that corresponds with the code, and the negative terminal to ground on the arduino.

Start by testing all your speakers. Plug in one speaker at a time and run the code below. If everything is right, the speaker will play sound. This is to make sure all speakers are working properly. Once you have tested all speakers, proceed to step two.

Speaker Testing Code: test_speaker.ino


Step 2: Speaker With Potentiometer



To wire the potentiometer, put the signal pin from the arduino to one of the outside pins on the potentiometer. Then, move the middle pin to the positive pin on the speaker and the negative pin to ground on the arduino.


The next step is to wire the speakers with a potentiometer in series. This allows you to change the volume of the speakers. Skipping this step could cause problems down the line. Again, run the code from step 1 to make sure it works. However this time, turn the potentiometer to make sure the volume is adjustable.


Step 3: Scale # of Speakers


In this step, you simply have to add more speakers. All the wiring is the same, the only difference is there is more for the additional speakers.



Code For Frequency


In order to angle the sound, the speakers must activate at different times, but they also must be the same frequency so that the result doesn’t sound horrible. How do we do this? First, it is necessary to know how to control speakers using Arduino. This turns out to be incredibly simple. A speaker pulses once every time you set its pin to one. You can then set it back to zero and repeat as fast as your period, creating a controllable frequency. Here is some pseudocode to think about if you want to try making it on your own:

loop {
set speaker pin to 1
wait half of the period
set speaker pin to 0
wait half of the period
}

If you don’t know, a period is just the inverse of a frequency. This means that if we have a target frequency of 500 Hz, the period would be 1/500 seconds. We wait half of this time between setting pins because we want a full loop to take a whole period.


The problem with this pseudocode is that if you want to do anything between setting the speaker pin, you have to write it twice. I used a little trick to make a variable fluctuate between 1 and 0 every time it calls the loop (using the NOT operator), which means I only need to write code once. This isn’t necessary, but you may do this too. Another little trick in my code is using micros() to delay the loop instead of delay(), which makes the loop slightly more accurate. Here is my code for a single speaker:

// PINS
static const int SPEAKER_PIN_0 = 10;

uint8_t write_value = 0; // This is the first little trick
float frequency = 500;
float period = 1/frequency * 1000000; // Converts to microseconds

def loop() {
unsigned long time = micros(); // This is the second little trick
write_value = ~write_value;

digitalWrite(SPEAKER_PIN_0, write_value);
while (micros() < time + period/2) { yield(); }
}

It is easy to extend this by simply adding more speaker pins and digitalWrite() calls. We will later look into making a phase shift by delaying multiple speaker writes from each other but keeping the same frequency.


Math for Frequency


Intro to Math Sections

If you want to learn the math behind all this (which I recommend as it’s very interesting) read this section, but if you don’t care or already know the content you can skip the math sections and continue building the array.

The previous code works by using digital write to switch the speaker between two modes to move the speaker’s diaphragm back and forth, creating periodic waves that create sound.

These math sections will be in a few places throughout the instructables, starting with frequency.


Frequency

The frequency created by the speakers is proportional to the time between the on-off cycles produced by the arduino. The on-off cycles produced by the arduino are determined by the delays in the code, while the arduino produces a 5v signal or 0v signal.

Step 2: Phase Shifting

The second step will be covering the math that was used to set a certain phase delay and angle, along with code that incorporates it. We will also be going over the 3d printed structure used to hold the speakers.


Math for Phase Shift


Intro to Math Used

To direct the wavefront, we need an equation that relates the desired angle, the distance between the speakers, the delay between the speakers and the speed of sound.


Wave interference

As waves overlap, their amplitudes combine. This means that when more than one source is present and the waves created overlap, there will be points at which the amplitudes combine to double, proportionally increasing intensity, (or loudness), and there will be times where the waves perfectly cancel, resulting in no audible sound. In this project, we are attempting to be able to change the trajectory of the amplified waveform.



Phase Delay

The main parameter changed to change the angle of the waveform trajectory is the phase shift, or phase delay. Phase shift is created when one speaker starts before another.


Angle-Delay Equation

To direct the wavefront, we need an equation that relates the desired angle, the distance between the speakers, and the delay between the speakers. Equation we found was θ = arcsin(radius/distance). Distance is the distance between the speakers, radius is the delay multiplied by speed of sound, and theta is the angle between the trajectory of the wavefront and speaker system.



This leaves us with our final equation θ = sin^-1 (Delay*Speed of Sound/Distance between speakers) This is proven visually in our diagram. As you can see, the wavefront and radius form a right angle triangle. Remember the wavefront is perpendicular the the trajectory of the antinode (the amplified part).

If you want to find the delay given a certain angle, some basic algebra is needed but it works out to:

t = sin(θ*π/180) * d/343

Phase Delay Code


Now that we have the math it is pretty simple to translate it into code. In code, our formula would be:

sin(angle * M_PI / 180) * 0.05 / 343 * 1000000; // Converts to microseconds

Where angle is whatever angle you want (i.e. 45) and M_PI is a built-in representation of pi.

To create a phase shift, we must delay each speaker’s digitalWrite() from the one before it. Pseudocode for that might look like this:

period = 1/500 * 1000000
_delay = sin(45 * M_PI / 180) * 0.05 / 343 * 1000000
write_value = 0

loop {
time = micros()
write_value = ~write_value

set speaker 1 pin to write_value
delay while micros() < time+_delay
set speaker 2 pin to write_value
delay while micros() < time+_delay*2
set speaker 3 pin to write_value
delay while micros() < time+_delay*3
set speaker 4 pin to write_value
delay while micros() < time+period/2
}

Now you can see why we opted to use the tricks: the first one means we only have to write all of this code once, and the second one means that the frequency will stay the same even if the delay gets big, as we wait until the same time at the end regardless. Translating this into code isn’t much harder:

// PINS
static const uint8_t SPEAKER_PIN_0 = 10;
static const uint8_t SPEAKER_PIN_1 = 11;
static const uint8_t SPEAKER_PIN_2 = 12;
static const uint8_t SPEAKER_PIN_3 = 13;

// PRECALCULATION

float frequency = 500;
float period = (1 / frequency) * 1000000;

// INITIALIZATION

uint8_t high_or_low = 0;
unsigned long time;

void setup() {
pinMode(SPEAKER_PIN_0, OUTPUT);
pinMode(SPEAKER_PIN_1, OUTPUT);
pinMode(SPEAKER_PIN_2, OUTPUT);
pinMode(SPEAKER_PIN_3, OUTPUT);
}

void loop() {
unsigned long time = micros();
float angle = 45;
float _delay = sin(angle * M_PI / 180) * 0.05 / 343 * 1000000;

high_or_low = ~high_or_low;
digitalWrite(SPEAKER_PIN_0, high_or_low);
while (micros() < time + _delay*1) { yield(); }
digitalWrite(SPEAKER_PIN_1, high_or_low);
while (micros() < time + _delay*2) { yield(); }
digitalWrite(SPEAKER_PIN_2, high_or_low);
while (micros() < time + _delay*3) { yield(); }
digitalWrite(SPEAKER_PIN_3, high_or_low);
while (micros() < time + period/2) { yield(); }
}

The only problem with this code is that if the angle is negative the delay also ends up negative. Unfortunately, we can’t activate speakers in the past, so we need to activate them backwards if the delay is negative. We can just use an if statement here:

if (angle >= 0) {
digitalWrite(SPEAKER_PIN_0, high_or_low);
while (micros() < time + _delay*1) { yield(); }
digitalWrite(SPEAKER_PIN_1, high_or_low);
while (micros() < time + _delay*2) { yield(); }
digitalWrite(SPEAKER_PIN_2, high_or_low);
while (micros() < time + _delay*3) { yield(); }
digitalWrite(SPEAKER_PIN_3, high_or_low);
while (micros() < time + period/2) { yield(); }
} else {
digitalWrite(SPEAKER_PIN_3, high_or_low);
while (micros() < time + -_delay*1) { yield(); } // Make sure to negate the delay!
digitalWrite(SPEAKER_PIN_2, high_or_low);
while (micros() < time + -_delay*2) { yield(); }
digitalWrite(SPEAKER_PIN_1, high_or_low);
while (micros() < time + -_delay*3) { yield(); }
digitalWrite(SPEAKER_PIN_0, high_or_low);
}

If you want, you can add a potentiometer to control the angle:

float pot_value = analogRead(POT_PIN);
float angle = pot_value / 1023 * 180 - 90;

And the code is done!


Building the Mount


3D Printing

To hold the speakers, we printed a bracket and braces in PLA. 3D printing gave us more precision in the distance between speakers, as well as easier adjustment of the distance between speakers. The stl files are included, but still need to be sliced in a slicing software for your particular printer and filament. If you don’t have access to a 3d printer, a mount for the speakers can be improvised, just ensure the spacing between the speakers is accurate and precise.

Step 3: Use

In this step we will show you our working device, how we tested it, and how you can test your own.


Working Video


Working Sonic Phased Array


Testing


Our team’s objective is actually only one half of the overall project. Another team set out to measure the device that we made for the sole purpose of testing. The device they made was a microphone array set up in a semi circle to be able to tell what the angle of the sound was. Although the device does not give a decibel output on each speaker, it can tell where the sound is coming from. When we set a specific angle for our device to output, we would receive the same received angle from the measurement device. Additionally to confirm that the array worked, we set up a microphone and moved it along the measurement device's semicircle. As we predicted, the microphone showed a noticeable difference between the area of our angle and everywhere else.


If you want to test your own device, we would recommend setting up a semicircle and moving a microphone around it, like we just described.