Acoustic Location System


Hi Jason

Nice work so far (again sorry if I telling you suck eggs) most of the marinised transducers have a pretty narrow sweet spot (say ± 5-10% of the central frequency so be aware for your chrip implementation). When potting up (maybe not be an issue for experimental rigs) the resin is designed to mimic waters acoustic properties so I not sure how Plasti-Dip will go (but well worth a try). Also be careful with getting a clean smooth even final surface any "blemishes" or waviness will distort the acoustics and add a "interference" to the outcome (I've got a SSS towfish which has a scratched transducer and even after being reworked and polished and even though it still works it always has a bit of a haze of interference on that channel although reduced from what it was)

Have a look atthis

RE the peak to peak voltage more energy into the water is always better also consider a super capacitor in the circuit so you get no power droop when you fire the short bursts of sound



There is a TAB paperback "How to Build & Use Low-Cost Hydrophones" by Frank Watlington 1979 ISBN 0-8306-1079-0 that would be worth looking at if you can get it through a library. Amazon lists it for several hundred dollars which it IS NOT worth. I got mine for a buck or so at a yard sale.

The TAB book is mostly aimed at people who want to listen to fish and whales, but some of the designs could transmit as well.

For "real" transducer design I have engineering texts "Introduction to Theory and Design of Sonar Transducers" by Oscar Wilson 1988 ISBN 0-932146-22-8 and "Principles of Underwater Sound" by Robert Urick 1975 ISBN 0-07-066086-7.


Jason, just to let you know I used plastic dip on the transducers shown in the acoustic modem prototype. However that method was just for initial testing and not for prime time. I have used this method in the past to pot solenoid valves and it wasn't very effective in preventing intrusion of water under depth, and would not recommend it for more than a quick and dirty method for prototyping (probably confined to fresh water). I didn't even solder the transducers and simply compressed the ceramic ring between two long 0.100 headers and dipped it, connector and all. I'm assuming we will eventually need to find a way to make up a small batch using a proper potting compound if we get consensus on what transducer, compound, and connector to use. Bob


Thanks Bob.

I was reading some of the referenced papers and they indicated a semi-flexible potting compound with a density close to water would be best. Does that match your understanding?

Non-acid silicone would be a good density match, might try that if I can find it. I also have some Sugru I might try (density 1.68).

I need to get an amplifier working so I can use a piezo transducer instead of a microphone, which I used in air for algorithm testing, and then I can start experimenting with potting compounds. I'll probably try audible frequency discs first, since they are cheap and easy to come by, and then move on from there.


Hi Jason:

The potting compound used by Dr. Benson at USCD was EN12 from Cytec Industries. I checked into getting some a while ago. It is two part and only available in gallon quantities, can only be shipped to commercial addresses, and was quite expensive. Jim has a couple of those transducers and I believe the potting has some play in it. Maybe he can comment on that aspect specifically.




It appears that silicone caulk has similar densities to water. I think I will try a neutral-cure silicone caulk first. The acid-cure stuff will cause rapid corrosion.


It is soft, but firm. A bit like a soft pencil eraser with some toughness.

It would be nice if we can come up with something almost as good, but that is available in smaller quantities. I guess we could poll some folks from Ocean Engineering and research groups to see what they use (MBARI, WHOI, Scripps). If anyone has a contact to poll, please report back.




I am more of a nuts and bolts guy, and have worked fitting sonar and depth sounders. If it helps I used to first test for a suitable area to fit the sonar using a water filled plastic bag (no air) then pressing the sonar/depth transducer face onto it and checking for results before deciding on a pemanent fitting. Other depth transducers I have fitted that require no through hull fittings use an oil bath (castor) or silicon rubber mounted inside the hull.

The project I am working on at the moment is using pressure sensors , 2 in the vehicle and 2 on the sea floor. To get reliable depth information. As for a log (velocity) I have been using a 2 axis electro magnetic current meter made by Valeport

but have found a smaller and nice alternative made by Swoffer

I have just been using the logs without the hand held meter using a simple pulse frequency to voltage circuit (LM2917) and tuning with a pulse generator for the velocity range I am looking for (0-4mps) sea floor and (5-20mps) vehicle. The results look ok so far and good enough to use as a datum for position information along with an imu and gyro as the sensors have been putting me some where on Mars with the g forces produced up to 2 g.




I have started a git repo for the project.

Mostly testing data so far. Will put the circuits and other material in as I have time.

One addition is the results from an initial DSP algorithm for analyzing the test data (see "first test.pdf" also attached here). Work is thanks to Frikk Solberg and engineering grad student in Norway.

It looks like the envelope function gives us a way to detect the leading part of the pulse with the current SNR ratios. I will likely use a shorter pulse (half as many cycles) and send them less often (less noise in the channel). I am working on integrating the transducer and receiver into a v2.7 OpenROV unit that I just obtained (was a testing unit that was rebuilt after an implosion in Lake Tahoe). It has an IMU on board and several wires already run thru the endcaps. I will connect the transducer to the wires and add the receiver plus some type of micro-controller/DAQ that I will come up with. I am trying for 100 ksps. I tried the on-board ADCs are with the ARM cortex units I have (spark core - 72MHz ARM Cortex M3), but I also have an external ADC with a SPI interface that I can try (MCP3002 - 10 bit ADC that can run up to 200 ksps). The test program I used did 30,581 samples/sec using the analogRead() function. I also ran a Python program with a While loop (read the SPI data from the ADC) on a Raspberry Pi using a Gertboard with this ADC and was only able to get 10 ksps. The MCP3002 was running off of 3.3v. It should be capable of around 100K at 3v and 200K at 5v. More work to do here.

I will probably send a timing pulse down the tether as I transmit the acoustic pulse and we can start counting until a pulse arrives at the receiver.


124-firsttest.pdf (245 KB)


You can save yourself an awful lot of computes with a simple analog peak detector and low pass filter before digitizing.

The only time I would directly digitize the sonar signal would be for chirp processing.

An Analog Guy,




I don't disagree, what you suggest would be an effective point solution. Are you trying to spoil all of the digital and software fun :)

If it is practical (and I am exploring the limits) I would prefer to use a micro-controller along with the analog receiver/filter section that I have in place. In addition to the detection of the pulse, counting the time since it was sent, it would do the calculations for distance traveled for the pulse for various water temperatures. And possibly additional computation.

Later on I may want to experiment with phase shift detection or possibly other techniques. Since a software based system is reconfigurable, that is attractive. For final point solutions, it may be more effective to drop back to something like what you suggest. For this phase, I want to gather some empirical data on what the signal looks like. A set of points would give me that.





Would it be possible to include a Doppler meter in your design ? Wouldn't it allow for direct ROV speed measurement ?

Together with location and IMU data, the Inertial/DR navigation system, could finally be really accurate.



There is lots of interest in a DVL and an altimeter function. I am going one step at a time and once I have a proper data acquisition system going on-board, I can observe the doppler shift and work out a down facing transducer. I do want to complete the location system first -so I don't get spread too thin.

I was able to finally get my ARM micro-controller (Spark Core unit) sampling at 250Ksps and can hold 2,000 sample points in memory. I will next integrate this with the receiver/the BBB and get it on board the ROV for testing.



Hi Jim:

I can badly help on electronics. As I've said before, thats not my thing. But, once electronics working, I can help with maths modeling.

As I think I've said before too, I've worked on building mathematical models before.



More on the data acquisition results:

ADC Speed test and points collection

I was finally able to get one of my micro-controllers to run ADC samples fast enough (now sampling at >250Ksps using the on-board ADC) to support signal processing of the 40KHz acoustic signal. I used the Spark Core ( It is a nice little ARM Cortex 3 that can easily fit into the e-tube along with the receiver electronics I have put together. There are many SOM (system on module) boards available that are based on ARM Cortex 3 (and 0). It has enough memory to collect 2,000 points which can be processed by the DSP software Frikk and I have been working on. The idea would be to give the micro-controller a signal when the pulse is being transmitted. It would start counting and scanning the signal to detect the start of the pulse coming into the receiver. The Spark Core would calculate the distance of the ROV from the sender (would adjust for temp/salinity) based on the time delay. We could send this information to the BBB/Node.js app and either in the client or server code calculate possible locations (using GPS location of sender, depth, time received and possibly info from a second transmitter at another location). IMU DR info could help discriminate when multiple possible locations are found.

Test results for Spark Core (12 bit ADC) capture 2000 points in memory:

Using modified code to read ADC1 – readADC1(channel)

sps = 285,714, elapsedTime = 7 mSec

Using analogRead() to read ADC1

sps = 30,789, elapsedTime = 65mSec

Spark-core specs


  • 32-bit STM32 72MHz ARM Cortex M3
  • 128KB of Flash memory, 20KB of RAM
  • Texas Instruments SimpleLink CC3000 Wi-Fi chip
  • EEPROM (supplied by the CC3000)
  • 2MB of external flash memory

STM32F103xx reference manual (microcontroller used in Spark Core)

I wanted to thank Peter Harrison for the example fast ADC code he posted on Micromouse Online – it helped with understanding the firmware for the Spark Core/STM32.

Simple ADC use on the STM32 - Micromouse Online:

Speed of sound in water

Between 1440 and 1500 m/s depending on temp.

100 meters would be around 68msec

100ksps/.068 = 1470K samples (too many to keep in microcontroller memory)

Could scan until threshold is exceeded (other algorithms possible – moving average, envelope detection, sw peak detector)

Some test results and the ADC test program are attached. I will be adding them to the git repo

Note the tank test samples are not yet synchronized with the start of the pulse - I will be adding the capability in soon.

Test and points collection program

// ADC speed test and points collection

// with customized ADC software (faster than analogRead() )

// works on Spark Core: 32-bit STM32 72MHz ARM Cortex M3

// 128KB of Flash memory, 20KB of RAM

// see for details

// should be able to run on other ARM Cortex family processors

// may need modifications for ADC differences

// Test results: sps = 285,714, elapsedTime = 7 mSec

int ledPin = D7; // On board LED connected to digital pin D7

int triggerPin = D0; // Start points collection when D0 goes high

int iterations = 0; // iteration counter

const int maxpoints = 2000; // number of points to collect

int sps = 0;

double startTime, elapsedTime;

short points[maxpoints]; // store points here (16 bits per sample)

void setup() {

ADC_Configuration(); // set up ADC1 for single channel on-demand conversions

pinMode(ledPin, OUTPUT); // sets the pin as output

pinMode(triggerPin, INPUT_PULLDOWN); // sets the pin as input

Serial.begin(9600); // open serial over usb


void loop()


digitalWrite(ledPin, HIGH); // Turn ON the LED pin

iterations = 0;

while (digitalRead(D0) != HIGH); // Wait for signal to start points collection

startTime = millis();

while (iterations < maxpoints) { // collect samples until maxpoints is reached

points[iterations] = readADC1(0); // read the analog input channel 0 (12 bits 0-4095 0-3.3V)

// sample time is the fastest - 1.5 cycles/conversion

// and store the value in an array of points



elapsedTime = millis() - startTime;

sps = round ( (float) maxpoints * 1000.0 / (float) elapsedTime );

printPoints(); // print points to serial port

digitalWrite(ledPin, LOW); // Turn OFF the LED pin



void printPoints(void) // print points collected




Serial.print(" ADC samples in ");


Serial.print(" ms = ");


Serial.println(" samples/sec");

Serial.println("(12 bits 0-4095 0-3.3V)");

Serial.println("printing all points 10 per line");

int lines = maxpoints / 10;

int linenum = 0;

while (linenum < lines)


for (int i=0; i <10; i++) {


Serial.print(","); // comma separated





Serial.println("End of points");


// ADC code based on example by Peter Harrison: Simple ADC use on the STM32

// Micromouse Online:

u16 readADC1(u8 channel)


ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_1Cycles5);

// Start the conversion

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

// Wait until conversion completion

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

// Get the conversion value

return ADC_GetConversionValue(ADC1);


void ADC_Configuration(void)


ADC_InitTypeDef ADC_InitStructure;

/* PCLK2 is the APB2 clock */

/* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/


/* Enable ADC1 clock so that we can talk to it */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

/* Put everything back to power-on defaults */


/* ADC1 Configuration ------------------------------------------------------*/

/* ADC1 and ADC2 operate independently */

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

/* Disable the scan conversion so we do one at a time */

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

/* Don't do continuous conversions - do them on demand */

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

/* Start conversin by software, not an external trigger */

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

/* Conversions are 12 bit - put them in the lower 12 bits of the result */

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

/* Say how many channels would be used by the sequencer */

ADC_InitStructure.ADC_NbrOfChannel = 1;

/* Now do the setup */

ADC_Init(ADC1, &ADC_InitStructure);

/* Enable ADC1 */


/* Enable ADC1 reset calibration register */


/* Check the end of ADC1 reset calibration register */


/* Start ADC1 calibration */


/* Check the end of ADC1 calibration */



121-SamplesTest2Vpp40KHzSineWave.txt (6.55 KB) 122-TankTest12914.txt (8.11 KB) 123-adcspeedtest3.ino (4.75 KB)


It sounds like you have a good start on a acoustic NAV system. However one antagonizing factor you will encounter, especially in hard surfaced environments like quarries and swimming pools or near ships, is multipath. That is when there are multiple paths that the acoustic signal can take, usually involving reflections, to get from the transmitter to the receiver. In a swimming pool the signal may reflect the length or width of the pool several times and still be strong enough to register at the receiver. After you transmit the first ping you hear may be an echo of the previous transmission.

In small systems the way to combat multipath is with range gates. If you know roughly where your ROV is then you can estimate when you expect to hear the ping. Have your receiver ignore all pings that arrive impossibly early or late. Ideally you know where the ROV was from the last ping and you know its maximum velocity so you can calculate a small window or range gate where a valid ping could be expected. If no valid ping is heard you use the time_since_last_good_fix * vehicle_max_velocity to calculate a new larger range gate.

A lot of subtlety can be involved in finding the first fix and in detecting when the range gate is bracketing a reflection instead of the real ROV.


Hi Jim

Great to hear of your progress


100 meters would be around 68msec


100ksps/.068 = 1470K samples (too many to keep in microcontroller memory............... (other algorithms possible – moving average, envelope detection, sw peak detector)

Then in round figures you capture 2000 points in memory is about 130mm or 5" and assuming this memory can't readily be increased (either technology or $ either way) then

As a concept most people have 100m of cable hence for most applications this is the largest range (as a gating concept) that can be expected (more complex stuff can be done in the future but baby steps first to get a working Mark 1 system operational /functional)

We should be able to drop the resolution without any significant impact (think of the GPS having a HDOP of say 1.5m ( typical) and then this system having an accuracy of say ±200mm (8") or 4 points from 100m range/2000 points data storage) thus say ±2m with about 75% of this accounted for from the GPS.

So maybe the next step would be in determining this data storage point given a value of 100m range/2000 points = 50mm to generate 1 data point or round figures 68msec/2000 points = 0.034 msec=34 μsec time slice. Would it be best to store the average value of the time slice, the peak value of the time slice or some other weighted average??

As Douglas rightly points out multipath acoustics is a PITA but (most times in water but not always) a straight line is always the fastest route hence a need to looking for the first significant peak and his concept of last know value for use in range gating is an extremely good concept.

As usual let us know what we can do to help, try for something cheap, simple and robust as a first operational /functional system but that can be then further developed



Thanks Doug and Scott for the comments,

Yes multipath showed up right away in my shallow water tests (see attachment). Fortunately for this initial application I only need to find the first echo (leading edge). Yes I might get an old echo from a previous ping arriving early or overlapping with a new one – in addition to the delayed ones from the new pulse. These are the design problems that will be worked on.

Some of the possible ways to address multipath in this application:

Send shorter pulses (just enough cycles to reliably detect). Less chance of overlap with echo.

Send pulses less often – allows delayed echoes to die out before looking for a new pulse.

Be a bit selective about amplitude – and old echo will be attenuated and can be filtered.

If all else fails, I can try frequency hopping between pulses.

For sample collection, I now can hold 2,000 points in memory (8ms @250,000 sps)

Sound travels around 1,480 meters/sec or 11.84 meters in 8ms

This is a good next step for me since I have only tested to 4 meters. I want to see what the signal looks like further away and in open water.

Greater range can be addressed several ways:

I can sample points into a 2K ring buffer and try to process the DSP scan fast enough to keep up with the sampling

I can get a microcontroller with a bit more RAM – my Spark Core has 20KB of RAM, other ARM Cortex M3s are available with much more

I can page out the data in RAM to the 2MB of external flash memory

I can try an approach similar to what Dough suggests with “range gates”. By knowing about how far away the ROV is (using data from previous echoes) I can delay the beginning of the sampling so that the sample window brackets the time the pulse is expected.

For the next phase I will keep it simple – mostly want to see the signal


120-2Meter_20141104_172708.png (65.4 KB)


Hi Jim


Sounds good to keep it simple

I would think "Send pulses less often – allows delayed echoes to die out before looking for a new pulse", would be the best first start (so what if it is a 1 or 2 second positional update)

I'd keep "If all else fails, I can try frequency hopping between pulses" in the armoury to when there may be more location pingers for full triangulation

Tell us all what you need and I'm sure some more help can be gathered



"Send pulses less often" is the first thing to try until you have your other problems worked out. Frequency hopping is something I have never tried as my analog hardware is tuned to the carrier frequency and my digital detector is just a threshold detector.

Amplitude discrimination alone will not be reliable. As demonstrated by your 2Meter image, the longer path may have greater amplitude than the shorter direct path. Sometimes it is much greater when the direct path is blocked by seaweed or fish, or when there is a focusing curved reflector such as a bowl shaped pond bottom, boat hull curvature, or an ocean surface swell.