2. Getting started
In this chapter, you will learn how to set up a simple 2-node underwater network with an acoustic link. If you already own a couple of UnetStack-compatible acoustic modems, you can certainly use them! And we’ll show you how to do that in Section 2.6 . But let us first start with a simulated 2-node underwater network, since all you need for this is a computer and the Unet simulator.
2.1. Setting up a simple simulated network
Download UnetStack community edition for your OS and untar/unzip it. Open a terminal window in the simulator’s root folder and start the simulator:
$ bin/unet samples/2-node-network.groovy 2-node network -------------- Node A: tcp://localhost:1101, http://localhost:8081/ Node B: tcp://localhost:1102, http://localhost:8082/
If you’re using Windows, you may need to use:
Open two web browser windows and key in the two http URLs shown above in each browser. This should give you a command shell for node A and node B in the two browser windows.
2.2. Making your first transmission
On the command shell for node A, type:
> tell 0, 'hello!' AGREE
Address 0 is a broadcast address, so you did not need to explicitly know the address of node B to transmit a message to it. After a short delay, you should see the message on the command shell for node B:
Congratulations!!! You have successfully transmitted your first message over the Unet.
that you see on node B is the
address (of node A). The simulator automatically allocates addresses to each node. You can easily find out the addresses of both nodes (on either node):
> host('A') 232 > host('B') 31
You can try sending a message back from node B:
> tell 232, 'hi!'
and you should see the message
on node A after just a short delay.
You could have specified the hostname instead of the address when sending the message:
2.3. Propagation delay & ranging
In the simulation, nodes A and B are placed 1 km apart. Since the speed of sound in water is about 1500 m/s (exact sound speed depends on temperature, salinity and depth), the signals take about 0.7 s to travel between the simulated nodes. This explains the short delays you see between sending the message from one node and receiving it on the other. You can also make use of this time delay to measure the distance between the nodes!
On node A, type:
> range host('B') 999.99976
You got an estimate of 1000 m for the range between the two nodes.
2.4. Sending & receiving application data
In real applications, you may want to send complex datagrams (messages) programmatically between nodes. The simplest way to do this is via the UnetSocket API ( Chapter 9 ). Let’s try it!
On node B, type:
> s = new UnetSocket(this); (1) > rx = s.receive() (2)
Open a socket on node B (
|2||Receive a datagram. This call blocks until a datagram is available.|
On node A, type:
> s = new UnetSocket(this); > s.send('hello!' as byte, 0) (1) true > s.close()
Send 6 ASCII bytes ('hello!') to address 0 (broadcast address). The
Node B will receive the bytes as a
message. You can check the data in the received datagram on the command shell for node B, and close the socket:
RxFrameNtf:INFORM[type:DATA from:232 rxTime:4134355059 (6 bytes)] > rx.data [104, 101, 108, 108, 111, 33] (1) > new String(rx.data) (2) hello! > s.close()
|1||These are the bytes representing the ASCII characters ['h', 'e', 'l', 'l', 'o', '!'].|
|2||This puts together the ASCII characters in the byte array into a String.|
While we demonstrated the use of the
2.5. Sending & receiving from a Python application
We’ll assume you have Python 3.x already installed. Let us start by installing the UnetStack Python API bindings:
$ pip install unetpy Collecting unetpy Using cached unetpy-3.1.0-py3-none-any.whl (6.9 kB) Collecting fjagepy>=1.7.0 Using cached fjagepy-1.7.0-py3-none-any.whl (12 kB) Collecting numpy>=1.11 Using cached numpy-1.18.2-cp37-cp37m-macosx_10_9_x86_64.whl (15.1 MB) Installing collected packages: numpy, fjagepy, unetpy Successfully installed fjagepy-1.7.0 numpy-1.18.2 unetpy-3.1.0
We will now write
scripts to transmit and receive a datagram respectively. We assume that you have the two-node network setup from the previous section with node A and B available on
API port 1101 and 1102 respectively.
from unetpy import UnetSocket s = UnetSocket('localhost', 1101) (1) s.send('hello!', 0) (2) s.close()
Connect to node A (
|2||Broadcast a 6-byte datagram. Address 0 is the broadcast address.|
from unetpy import UnetSocket s = UnetSocket('localhost', 1102) (1) rx = s.receive() (2) print('from node', rx.from_, ':', bytearray(rx.data).decode()) (3) s.close()
Connect to node B (
to start reception. Then, on a separate terminal window, run
to initiate transmission. You should see the received datagram printed by the
$ python rx.py from node 232 : hello!
Once you are done with your testing, it is time to shutdown the simulation. You can do that by pressing
2.6. Using acoustic modems
So far, we have worked with a simulator. While the experience is similar, it is not exactly the same. There is no real substitute for working with real modems. If you happen to have two UnetStack-compatible acoustic modems, you can use them to set up a simple 2-node network. Put them in a water body (tank, bucket, lake, sea, …), power them on, and connect each to a computer over Ethernet. The setup would look something like this:
On each computer, open a web browser and key in the IP address of the respective modem. This should give us a command shell for node A and node B on the two computers.
|If you only have one computer available, you can connect both modems to the same Ethernet switch and connect to each modem’s IP address in separate browser windows.|
When working with modems, you may need to adjust the transmit power level to a suitable level for use in the water body that you have the modems in. Too high or too low a power level will not allow the modems to communicate well. The modem transmit power can be adjusted using the
on the command shell for node A to see examples of how the command is used:
> help plvl plvl - get/set TX power level for all PHY channel types Examples: plvl // get all power levels plvl -10 // set all power to -10 dB plvl(-10) // alternative syntax plvl = -10 // alternative syntax
Assuming you have the modems in a bucket, you’ll need a fairly low transmit power. On node A, let us set the transmit power to -50 dB and try a transmission:
> plvl -50 OK > tell 0, 'hello!' AGREE
|A poor acoustic connection between modems can lead to multiple retransmits that can take many tens of seconds before successful delivery of message, or eventual delivery failure.|
If all goes well, you should see the message on node B:
Of course you’ll see a different "from" address than the one shown in the example here. It will be the actual address of your modem A. In case you don’t see the message on node B after a few seconds, you may want to adjust the power level up or down and try again.
All the other examples shown earlier in this chapter will also work with the modems. You’ll just need to replace the
2.7. Transmitting and recording arbitrary acoustic waveforms
If you have UnetStack-compatible acoustic modems that support the BASEBAND service, you can use them to transmit and record arbitrary acoustic signals. Even without access to modems, you can try this out using the Unet audio SDOAM — a fully functional modem that uses your computer’s soundcard for transmission and reception. To start Unet audio, open a terminal window in the simulator’s root folder and type:
$ bin/unet audio Modem web: http://localhost:8080/
This should start up the SDOAM and open a browser with a command shell accessing the modem. If the browser does not automatically open, just enter the modem web URL shown above in your browser. At the command shell, you can try transmitting a message:
> tell 0, 'hello!' AGREE
You should hear the transmission from your computer speaker! If you don’t, check your speaker volume and try again.
If you have 2 computers running the Unet audio SDOAM, you can receive the transmitted signal on the second computer and see the received message:
Next, try sending a simple 10 kHz tonal signal:
> bbtx cw(10000, 0.5) (1) AGREE phy >> TxFrameNtf:INFORM[txTime:4104441] (2)
|1||Request transmission of a continuous wave (cw) signal of 10 kHz and 0.5 seconds duration.|
|2||Notification that the signal was successfully transmitted.|
You should hear a 0.5 second 10 kHz tone from your computer speaker. The
command requests transmission of a baseband signal. The function
generates such a signal based on the specified frequency and duration.
To generate the baseband representation of the signal you wish to transmit, you will need to know the carrier frequency and the baseband sampling rate of the modem:
> phy.basebandRate 12000.0 > phy.carrierFrequency 12000.0
For the Unet audio SDOAM, the carrier frequency is 12 kHz and the baseband sampling rate is 12 kSa/s.
|The baseband signal is represented as a floating point array with alternate real and imaginary components in Java/Groovy. For languages that support complex numbers (e.g. Python, Julia), the signal is simply an array of complex numbers.|
You can equally easily ask the SDOAM to make an acoustic recording for you:
> bbrec 12000 (1) AGREE phy >> RxBasebandSignalNtf:INFORM[adc:1 rxTime:1911353 rssi:-61.2 fc:12000.0 fs:12000.0 (12000 baseband samples)]
|1||Request recording of 12000 baseband samples (1 second duration).|
The recording is sent to you as a
message with 12000 baseband samples in the
field. You can check the first 32 samples:
> ntf.signal[0..31] [-3.735939E-4, 6.7323225E-4, 7.94507E-4, 5.0331384E-4, 0.0012656008, -0.0010853912, -2.0923217E-4, -8.322359E-4, 1.5215082E-4, 2.417963E-4, -3.0220395E-5, -5.190366E-4, -6.904016E-4, -7.3395047E-4, 3.9846844E-5, 5.161132E-4, 0.0013477469, 6.2060537E-4, 1.00925405E-4, -3.974573E-4, -8.8431453E-4, -5.807383E-4, -5.730035E-4, -8.5867435E-4, -9.026667E-4, 2.2320295E-5, -1.7575005E-5, 0.0010946163, 7.7881676E-4, -3.7582265E-4, -9.449492E-4, -1.7722705E-4]
The values you’d see would natually be different, since the SDOAM would have recorded whatever sounds it heard using your computer’s microphone.
While we illustrated the use of the BASEBAND service using the
|<<< [Introduction]||[UnetStack basics] >>>|