We make a simple sonar modem

We make a simple sonar modem


Hi, dear!


In this article, by popular demand, we will explain how to make the simplest sonar modem: some digital signal processing, some programming, some homemade printed circuit boards and a drop of practical hydrology.

All interested - welcome under the cat, in the reverberant world of underwater communication!

And here is the relevant picture, to attract attention:



"Ultimately, the point of our existence is to waste energy ... And, if possible, you know, so that it is interesting to yourself and useful to others."
(C) ABS, “Noon, XXII Century”

To save your time - summary


  • Hydroacoustic modems do not yet sell on Aliexpress
  • There is a simple and undemanding to computing resources method of detecting the tone, the frequency of which is 4 times lower than the sampling rate; Arduino is enough for implementation
  • Sample code for PC is on GitHub
  • Receiving and transmitting antennas are made from piezo-diggers for 10 p each
  • We buy (or do it ourselves) the amplifier's Taxia on the TDA2030 on Ali for 50 rubles
  • Make the LUT preamplifier, with a total cost of ~ 100 rubles
  • Connect and go to the pond
  • Rejoice

Motivational Prelude


Now you can buy almost anything on Aliexpress or eBay. Especially a lot of different for self-manufacturing of something electronic based on Arduino. You can make (if you just buy uninteresting) a millenn-stop meteorological station with an Internet connection, an automatic cat feeder, a home brewery controller, but you still cannot buy a sonar modem, a designer for its manufacture, or at least a module for adruino. Well and good! And do not - now we will tell you how to do it, and also tell you how it works.

We all thought for a long time what could be offered to lovers for self-production. Something very simple, which can be collected by a schoolchild from sticks and ropes of what everyone has at hand, but at the same time necessarily representing at least the minimum practical or educational value.

Something that promises a long and exciting improvement, something that can be transferred even to arduino , be it amiss .

If we approach the question materialistically, we would like to offer a detailed tutorial for the manufacture of some simple device that would be more or less able to transmit data in a shallow water reservoir (a shallow hydroacoustic channel is the most complex), would mean the maximum production of a printed circuit board using LUT, with a total cost not exceeding two or three hundred rubles on the mini ball.

What are we going to do today?


  • remember how to make a suitable sonar antenna and make a couple;
  • connect one of the antennas to the PC via an amplifier with a TDA for ~ 50 rubles and get a transmitter;
  • for the second we will do with the help of LUT a preamplifier for ~ 100 rubles;
  • write (I’ve already written and put everything on Git) with a simple C # modem and we’ll try everything in the nearest reservoir;

What do we need for this?


  • two piezoelectric elements. For example, hours or from greeting ;
  • RG-174/U cable (or equivalent) ~ 5 meters;
  • zero-seals;
  • water resistant varnish;
  • foil textolite, a total of about 100x200 mm;
  • amplifier on the TDA2030 (for example, accessories for the preamp

How does it work?


The whole idea of ​​the simplest modem is built on, again, the simplest (coincidence?) Detector of a certain tone, about which, to my shame, I did not hear. He told me about him quite by chance andrey_9999a . By the way, he made a preamp charge.

In this regard, I recalled a quote from the book by Leonard Susskind “The Battle of a Black Hole”:
“As a wine connoisseur, I’m more or less sure that even with my eyes closed I can tell red from white. Even more reliably I distinguish wine from beer. But then the taste will fail me. "
I can say to myself that, as a real electronics engineer, I am more or less sure that I can solder two thick wires for sure. Even more reliably, I distinguish a hot soldering iron from a cold one even with eyes closed, but then further the skill will let me down. Therefore, all that concerns the development and manufacture of boards is the work of my friends and colleagues andrey_9999a and StDmitriev .

So back to the detector. It is a simplified special case of calculating the Fourier integral:

$ \ int_0 ^ Tf (x) sin (\ omega t) dt $


In the case of a digital signal, to calculate the amplitude of an arbitrary harmonic, you need to perform a discrete Fourier transform, for Arduina it is rather heavy, but the trick is that if you take Fc as a carrier frequency, it will be exactly 4 times less than the sampling rate Fs , then the amplitude of this harmonic can be calculated demonically simpler.

In this case, dt = 2π * (Fs/4)/Fs = π/2 , and there are only 4 samples per carrier period:



If everything is shifted to π/4 then the samples will take only two values: √2/2 and -√2/2, for simplicity, we leave only the signs - "+" and "-" .

The essence of the method is that we represent the sinus phase as a sequence of characters "+" "+" "-" "-" , and cosine as "+" "-" "-" "+" .

Let the input signal be in the buffer sn , we have two annular averaging buffers for the sine and cosine phases - bs and bc of size N They have common head and tail pointers - bH and bT . At the initial moment of time bH = N-1, bT = 0 . Averaging cycle counter C = 0 .

We take 4 samples from the input buffer and fold them according to the sequences of characters.

Example code
a = sn (i)
bs (bH) = a
bc (bH) = a
s1 = s1 + a - bs (bT)
s2 = s2 + a - bc (bT)
bH = (bH + 1)% N
bT = (bT + 1)% N

a = sn (i + 1)
bs (bH) = a
bc (bH) = -a
s1 = s1 + a - bs (bT)
s2 = s2 - a - bc (bT)
bH = (bH + 1)% N
bT = (bT + 1)% N

a = sn (i + 2)
bs (bH) = -a
bc (bH) = -a
s1 = s1 - a - bs (bT)
s2 = s2 - a - bc (bT)
bH = (bH + 1)% N
bT = (bT + 1)% N

a = sn (i + 3)
bs (bH) = -a
bc (bH) = a
s1 = s1 - a - bs (bT)
s2 = s2 + a - bc (bT)
bH = (bH + 1)% N
bT = (bT + 1)% N


After each processed four samples, we check the averaging cycle counter and if it has passed for N , then we calculate the amplitude of the cA carrier:

  if ++ cycle & gt; = N
  cA = sqrt (s1 * s1 + s2 * s2)
  cycle = 0
 end  

This is what a perfect signal looks like:



The signal itself is shown in blue, the carrier amplitude is shown in red (everything is reduced to a range of -1..1). In this case, N = 2 because there is no noise and everything works fine anyway.

Now add some white noise and see how our detector reacts to this:



I added white noise so that the signal-to-noise ratio was 0 dB. In the figure above, blue shows a noisy signal, green shows the source signal, and red shows the amplitude value. In this case, with N = 2 , the detector did not detect anything, and the minimum N at which it regularly works is 32. That is, the size of the processing window in the samples was 32 * 4 = 128 samples.

That is, now we can analyze the input signal and estimate a parameter that quantifies the presence of frequency, four times less than the sampling rate. If we set a certain threshold value for this parameter, then everything can be binarized, and to put it simply, we can answer the question: is there a given tone in the input signal or not?

This is very good, but we need to pass bits, and the bits can take two values.

Implement a system with two signal states using one so-so idea, so we will not encode one of the states of silence (pause). This would have made the detection more difficult: it would have been necessary to somehow single out the beginning of the premise, think up how to arrange its end, etc.

Instead, "1" and "0" we will encode pulses of different lengths, between the bits there is a so-called. the guard interval - because we still need to deal with multipath propagation and reverberation. In simple terms, the guard interval is the place (time) where all reflections of the previous bit, all sounds and echoes will fade.

Looking ahead, we note that with such a signal structure, the algorithm of the receiver operation is greatly simplified: waiting for the tone to appear, detecting the beginning, waiting for the tone to disappear, and detecting the time again - if the received time is more similar in length to “1”, we probably took a bit with a value of "1", if it looks more like a "0" - then apparently we took a bit, with a value of "0".

In general, we can say that this is a kind of Morsechian.

Soft part of the modem


For the impatient, the example is on GitHub . Written in haste in C # (because I write on a PC on it and it’s just easier and faster for me).

To play and capture audio from the microphone input, use the wonderful NAudio library .

All modem logic is in the class SUAModem (Simple Underwater Acoustic Modem).

The following parameters are passed to the constructor:

double sRateHz is the sampling rate in Hertz;
int wSize - the size of the processing window in the samples;
int oneMultiplier - how many "windows" lasts a bit with a value of "1"
int zeroMultiplier - how many “windows” the bit with the value “0” lasts
double eThreshold - the threshold, let's say about it later

To generate a signal from the byte array, there is the ModulateData (byte [] data) method, which returns an array of 16-bit signed samples.

public short [] ModulateData (byte [] data)
   public short [] ModulateData (byte [] data)
 {
  double alpha = 0;
  double phase = 0;

  List & lt; short & gt;  samples = new List & lt; short & gt; ();
  BitArray bits = new BitArray (data);

  for (int i = 0; i & lt; bits.Length; i ++)
  {
  int sLim = (bits [i])?  oneDurationSmp: zeroDurationSmp;
  alpha = 0;
  phase = 0;
 
  for (int sIdx = 0; sIdx & lt; = sLim; sIdx ++)
  {
  alpha = Math.Sin (phase);
  phase + = delta;
  if (phase & gt; = alimit)
  phase - = alimit;
  samples.Add (Convert.ToInt16 (alpha * short.MaxValue));
  }
  samples.AddRange (new short [defenseIntervalSmp]);
  }
  return samples.ToArray ();
 }
  


In the main loop, the samples list is filled in by the transmitted bits. Depending on the current transmitted bit, the length of the sLim signal generated in the samples is set. A guard interval is added after each bit.

Of course ...
Many may notice that when generating a signal it would have been possible to do without the sine function, but This example allows, by changing the value of delta, to change the frequency of the generated tone.

To generate a tone with a frequency of $ F_n $ for a given sample rate  $ F_s $ corresponding value  $ \ delta $ is calculated simply:

$ \ delta = 2 \ pi F_n/F_s $



To generate and emit a signal, there is the TransmitData (byte [] data) method, which internally calls ModulateData:

public double TransmitData (byte [] data)
  public double  TransmitData (byte [] data)
 {
  var samples = ModulateData (data);
  double txTime = ((double) samples.Length)/SampleRateHz;

  var rawBytes = new byte [samples.Length * 2];
  for (int i = 0; i & lt; samples.Length; i ++)
  {
  var bts = BitConverter.GetBytes (samples [i]);
  rawBytes [i * 2] = bts [0];
  rawBytes [i * 2 + 1] = bts [1];
  }

  using (var ms = new MemoryStream (rawBytes))
  {
  using (var rs = new RawSourceWaveStream (ms, new WaveFormat (Convert.ToInt32 (SampleRateHz), 16, 1)))
  {
  using (var wo = new WaveOutEvent ())
  {
  wo.Init (rs);
  wo.Play ();
  while (wo.PlaybackState == PlaybackState.Playing)
  {
  Thread.SpinWait (1);
  }
  }

  rs.Close ();
  }
  ms.Close ();
  }
  return txTime;
 }
  


The SUAModem class reports the acceptance of the next byte using the DataReceivedEventHandler event.

Input samples are acquired using the ProcessInputSignal (short [] data) method, where they are written to the ring ring buffer.The analysis takes place in a separate thread, in the Receiver method.

And the receiver itself lives in the Receive method:

private void Receive ()
  private void Receive ()
 int a;
  while (rCnt & gt; = 4)
  {
  a = ring [rRPos];
  rRPos = (rRPos + 1)% rSize;
  rCnt--;
  dRing1 [rHead] = a;
  dRing2 [rHead] = a;
  s1 + = a - dRing1 [rTail];
  s2 + = a - dRing2 [rTail];
  rHead = (rHead + 1)% windowSize;
  rTail = (rTail + 1)% windowSize;

  a = ring [rRPos];
  rRPos = (rRPos + 1)% rSize;
  rCnt--;
  dRing1 [rHead] = a;
  dRing2 [rHead] = -a;
  s1 + = a - dRing1 [rTail];
  s2 + = -a - dRing2 [rTail];
  rHead = (rHead + 1)% windowSize;
  rTail = (rTail + 1)% windowSize;

  a = ring [rRPos];
  rRPos = (rRPos + 1)% rSize;
  rCnt--;
  dRing1 [rHead] = -a;
  dRing2 [rHead] = -a;
  s1 + = -a - dRing1 [rTail];
  s2 + = -a - dRing2 [rTail];
  rHead = (rHead + 1)% windowSize;
  rTail = (rTail + 1)% windowSize;

  a = ring [rRPos];
  rRPos = (rRPos + 1)% rSize;
  rCnt--;
  dRing1 [rHead] = -a;
  dRing2 [rHead] = a;
  s1 + = -a - dRing1 [rTail];
  s2 + = a - dRing2 [rTail];
  rHead = (rHead + 1)% windowSize;
  rTail = (rTail + 1)% windowSize;

  if (++ cycle & gt; = windowSize)
  {
  cycle = 0;

  currentEnergy = Math.Sqrt (s1 * s1 + s2 * s2)/windowSize;
  double de = currentEnergy - prevEnergy;

  #region analysis

  if (skip> 0)
  skip - = windowSize * 4;
  else
  {
  if (isRise)
  {
  if (de & gt; -Threshold)
  {
  riseSmp + = windowSize * 4;
  }
  else
  {
//analyze symbol
  isRise = false;

  double oneDiff = Math.Abs ​​(oneDurationSmp - riseSmp);
  double zeroDiff = Math.Abs ​​(zeroDurationSmp - riseSmp);

  if (oneDiff & gt; zeroDiff)
  {
//Mostly likely "0"
  AddBit (false);
  }
  else
  {
//Mostly likely "1"
  AddBit (true);
  }

  samplesSinceLastBit = 0;
  skip = defenseIntervalSmp/2;
  }
  }
  else
  {
  if (de> threshold)
  {
  isRise = true;
  riseSmp = windowSize * 4;
  }
  }
  }

  #endregion

  prevEnergy = currentEnergy;

  if (bPos & gt; 0)
  {
  samplesSinceLastBit + = 4 * windowSize;
  if (samplesSinceLastBit & gt; = defenseIntervalSmp * 2 + zeroDurationSmp + oneDurationSmp)
  {
  DiscardBits ();
  }
  }
  }
  }
  }
  


From the code it is clear that the analysis is carried out on 4 samples, if you wish, you can save the state and carry out processing and one sample each, which will be useful when transferring to some weak MC. As data is received, the value of the amplitude s is calculated at the frequency sRateHz/4. The difference between the previous and current amplitude value is calculated and then compared with a predetermined threshold selected experimentally. The example allows in real time to change this threshold.

A sharp increase in amplitude indicates the beginning of a "bit", a sharp (somewhat less sharp - due to reverberation) decline - the end of a "bit".

After receiving the next bit, we work out the guard interval - we skip the specified number of samples - there are all sorts of echoes in them, they will only interfere with us.

The iron part of the modem


So, with the structure of the signal, everything is clear, how to take it is also clear. Things are easy - learn how to radiate a signal into the water and take it out of the water.

If you don’t have any hydroacoustic antennas, then it’s time to make them our previous tutorial .

I’ve got them from that time, so I’m missing this step.

We connect that antenna for transmission to



In the photo above, on the screen there is a small spoiler of the next article. Next time, on the same glands, we will again try to transmit the “video” sound through the water, but in a completely different way than last time
.

With the receiving antenna is somewhat more complicated. Although piezo squeezers are very sensitive, this is not enough. We will have to collect a preamp board with a filter for the 5-35 kHz band.
Gain we take 1000.

The circuitry, the PCB design, and the list of preamp components are on our GitHub: , the tracks are top layer and bottom layer , in > BOM .

LUT technology was discussed 100 times a hundred times, but give the same we do our bit.

Process photo
So, we take the appropriate magazine, we have only this one at hand:



We take from there a couple of pages and print layers on them using a laser printer.



Combine with needles and glue along one side, as shown in the photo:



We wet the toner with isopropyl alcohol before using the iron:



Iron through folded A4 sheet:



Soak it with warm water under the tap:



And laundered leftover paper. After that we get a billet ready for pickling:



Cut off the excess with the help of scissors for metal or to whom the more convenient.

We poison in ferric chloride. Especially for the article, we bred fresh, it turned out to be so intensive that from the future board there are active bubbles:



As a result, after etching and washing the toner we get the following semi-finished product:





After the components are soldered and washed, the board looks like this.



And this is what the receiving part of the assembly looks like. Power is supplied from the same lead battery 12 volts:



A small disclaimer about the filter
If the reader wants to change the band, we suggest recalculating the 8th order filter compiled on TL084C, the cheapest 4-channel opamp (DA2 at
Just in case, here is the frequency response of the current implementation of the filter:



And here's another
project for this filter, created in the Qucs

Experiments and Testing


To connect to a laptop, we use the usual Jack 3.5 mm, the very tip is a signal, the middle one is not connected, the ground is dust to dust . All amplifications and any microphone effects need to be turned off, and the volume will have to be played to reach the optimal level. The hobbling should occur when the antenna connected to the preamplifier is touched with a finger and lightly stroked.

If you simply put one piezo on another without an amplifier and a preamp and connect them to the audio input and output, then everything works perfectly. Below is a segment of the signal and you can even see where the values ​​of bits are:



The signal itself is shown in blue, the difference between the current and previous amplitude values ​​(front) is shown in red, the difference between the previous and current values ​​(decrease) is in green. You can easily “demodulate” this part of the premise: 1 0 0 0 1 1 0. Our zero is twice as long as one, and the guard interval is equal to the duration of zero.

Further, also without an amplifier and a preamplifier, we lower our antennas into a metal tank, measuring 3x1.5x1.5. We have this in the laboratory, and we made a rule for ourselves that we are not engaged in any communication if it is somehow unable to work in this tank. The fact is that in such a closed volume of energy there is no particular place to go - the sound is wonderfully and repeatedly reflected from the metal walls and porridge is obtained at the point of reception. And given the fact that we usually check ready devices with energy, designed for thousands of meters, you can imagine what is happening there.

For example, our two modems RedLINE work stably in this tank only at a distance no more than two meters, and two uWAVE -a work steadily at about 1 meter. While the first in open water runs up to 8000 meters, and the second - kilometer .
Of course, all commercial products do not use such primitive modulation schemes, which are discussed in the article, and are much more complicated, but now it is important for us to understand the basics and usefully do something with our hands.

In general, we lower the antennas into the tank at a distance of about 50 centimeters and get something far less beautiful than with the direct contact of the antennas:



Although a much longer guard interval is used here, it is still evident that the echo goes almost to the next bit, the fronts and especially the recessions are very blurred. But you can still determine the content of the message: 1 0 0 0 1 1 0

In both cases, I transmitted the message "123" and these seven bits belong to the unit symbol.
It looked like this, then the interface was slightly redone



From the screenshot above, it is clear that with those settings, sending the message “Hello, habr !!!:-) ”consisting of 19 bytes takes 9.132 seconds, that is, the transmission rate was 16.6 bit/s. By the way, in order for the modem to work in our tank, we had to increase the guard interval so that the transmission rate dropped to ~ 3 bps.

We checked the homemade products in the swimming pool, where she earned steady on 10 meters.


We also indulged in homemade products on the pond. I used an active hydrophone very similar in construction to the one proposed in the article, only instead of a piezo snapper, a sensor from a parking sensor was used there, the battery was mounted in a coil on which a cable was wound:





The receiver and transmitter antennas descended directly from the shore, the depth there dramatically decreases from 0.5 to 2 meters. In the experience shown in the photo above, oddly enough, the worst conditions, the distance there was only about 5 meters - this was the initial setting in general. Of the 20 messages sent, 3 bytes each, in six of them one byte was beaten.

Then, when we connected the receiver to the second laptop and moved to the other side of the pond (distance of about 30 meters), the transmission went much better - there were only a couple of errors in 40 messages ranging in size from 3 to 13 bytes.


The following photo shows the places where the antennas were located.



Conclusion and further research


As promised, for a few rubles, we collected a working device. Although its practical value is doubtful, the process of manufacturing and setting up on the pond itself will be very useful for beginners. On the described carrier detection method, it is quite possible to come up with various simple navigation systems for amateur use, and what is especially nice, the computational complexity allows implementing the method on a simple microcontroller.

Not to be unsubstantiated regarding the construction of navigation systems on simple signals, take a look at uWAVE modems , what they even tried to make a video . It will be very interesting to hear your opinions on this matter - it is very important to have confirmation that you are not doing something in vain.

However, returning to the main topic, we note that it could be improved in the proposed scheme:

  • make threshold calculation adaptive
  • analyze the width of the signals automatically
  • Try using different lengths for different bit combinations.
  • screw the clash robust coding
  • transfer all this to arduino
  • the volume and threshold have to be long and tedious to pick up, so it would be good to add an AGC preamplifier

At this meeting, I will declare closed, and if you are interested in the topic, here is a list of our previous articles:
Underwater GPS from scratch in a year
Underwater GPS on an underwater robot: experience of use
We made the world's smallest sonar modem
To the issue of the effect of cyanobacteria on the speech functions of the president
Making a simple sonar antenna out of garbage
A video session of sound transmission through water with disclosure
Underwater GPS on two transceivers
Navigation under water: pelenguy not pelenguy - you are doomed to success
Underwater GPS: continued

P.S.


  As always, we are pleased to hear comments and suggestions, valid criticism and approving shouts)

P.P.S.


Don't remove the pieces of iron - next time we will again transmit the “video” through the water with them.

Source text: We make a simple sonar modem