<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Unet</title>
        <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
        <link>blog.unetstack.net/</link>
        <description></description>
        <pubDate>Wed, 22 Apr 2026 02:58:40 +0000</pubDate>
        
        <item>
            <title>Turning a Multi-Receiver Modem into a USBL Transceiver</title>
            <link>/turning-a-multi-receiver-modem-into-a-usbl-transceiver</link>
            <guid isPermaLink="true">/turning-a-multi-receiver-modem-into-a-usbl-transceiver</guid>
            <description>&lt;p&gt;Picture this: You are running a mission with a mobile underwater node. You have a multi-receiver acoustic system on your surface vessel ensuring a robust, high-speed communication link. But as the autonomous underwater vehicle (AUV) navigates the mission, you also need to know exactly where it is. What if you didn’t need to deploy a completely separate tracking system for this? What if the exact same hardware you are using to talk to your AUV could also be used to track it?&lt;/p&gt;

&lt;p&gt;Space, weight, and budget are always at a premium in subsea deployments. If you are using a multi-receiver communication system running UnetStack, it is highly likely that you have access to the raw acoustic data and the timing information from all your receiving channels. Because UnetStack natively supports these multi-receiver architectures, it is possible to use your existing communication hardware for the localization and tracking of targets too.&lt;/p&gt;

&lt;p&gt;Take the &lt;a href=&quot;https://subnero.com/products/wnc/gen4x/accessories/multi-receiver.html&quot; target=&quot;\_blank&quot;&gt;Subnero multi-receiver modem&lt;/a&gt; as a practical example. We are frequently asked if this system can be used as a USBL transceiver. The short answer is yes. While the primary purpose of its multi-receiver architecture is to enhance communication performance through spatial diversity, the hardware requirements for localization are almost identical. Therefore, converting it into an Ultra-Short Baseline (USBL) transceiver is remarkably straightforward.&lt;/p&gt;

&lt;p&gt;The resulting setup is basically a modern USBL system approached “from the other side.” Most traditional USBL systems available today provide some basic communication capability in addition to their primary tracking functions. Conversely, a UnetStack-powered multi-receiver modem allows you to add tracking capabilities on top of the communication link.&lt;/p&gt;

&lt;p&gt;In this blog post, we will demonstrate how two minor modifications, some rigid scaffolding for the modem’s hydrophones and a script run on your laptop, are all that stand between you and a fully functional USBL system. Specifically, we will first walk you through the concrete steps required to configure a multi-receiver modem as a transceiver, and then we will peek under the hood to explain in detail how this system works. But before all that, let us begin with a quick refresher on USBL systems.&lt;/p&gt;

&lt;div style=&quot;width: 100%; display: flex; flex-direction: row; gap: 0.5rem 2rem; justify-content: center; align-items: start; flex-wrap: wrap; font-style: italic; text-align: center;&quot;&gt;
&lt;div&gt;
&lt;img src=&quot;../assets/img/usbl/transceiver.jpg&quot; style=&quot;padding: 0px&quot; /&gt;
&lt;p&gt;USBL transceiver ready to be lowered onto the seabed.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;img src=&quot;../assets/img/usbl/transponder.jpg&quot; style=&quot;padding: 0px&quot; /&gt;
&lt;p&gt;USBL transponder attached to a diver tank.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;usbl-basics&quot;&gt;USBL Basics&lt;/h2&gt;

&lt;p&gt;The basic working principle of a USBL system is that a transceiver sends out an interrogation signal and waits for a response from a transponder unit attached to the tracking target. The overall delay between the interrogation and its response then informs the tracker about the range to the target, and the small differences in arrival times across an array of hydrophones on the transceiver allow it to estimate the bearing. Together, these two pieces of information pinpoint a unique target location in three-dimensional space.&lt;/p&gt;

&lt;div style=&quot;width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 0rem 2rem; flex-wrap: wrap;&quot;&gt;
&lt;img src=&quot;../assets/img/usbl/usbl_range.svg&quot; style=&quot;padding: 0px&quot; /&gt;
+
&lt;img src=&quot;../assets/img/usbl/usbl_bearing.svg&quot; style=&quot;padding: 0px&quot; /&gt;
=
&lt;img src=&quot;../assets/img/usbl/usbl_location.svg&quot; style=&quot;padding: 0px&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;installing-the-dependencies&quot;&gt;Installing the Dependencies&lt;/h2&gt;

&lt;p&gt;Our goal in this post is to replicate such a USBL system using a pair of UnetStack modems and a few &lt;a href=&quot;https://julialang.org/&quot; target=&quot;\_blank&quot;&gt;Julia&lt;/a&gt; scripts available from the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/usbl&quot; target=&quot;\_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-contrib&lt;/code&gt; GitHub repository&lt;/a&gt;. Therefore, as a first step please download the repository and then run the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./install&lt;/code&gt; script to install a Julia runtime plus a few Julia packages. Note that your modems must be running UnetStack v5 or later for the following scripts to work.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-multi-receiver-modem&quot;&gt;Setting Up the Multi-Receiver Modem&lt;/h2&gt;

&lt;p&gt;To convert arrival times into arrival direction, the USBL modem must know the precise arrangement of its receiving elements. Therefore, its transducer and the three hydrophones must be attached to some rigid structure (e.g. a frame, a boat or an AUV) and then their precise locations must be made available to the USBL software. When attaching the hydrophones, care should be taken not to obstruct the main bulb of the hydrophones, and the overall geometry should be close to tetrahedral with a side length as large as possible but at least 15 cm (6 inches) for a modem with a center frequency of 24kHz.&lt;/p&gt;

&lt;div style=&quot;text-align: center; font-style: italic;&quot;&gt;
&lt;img src=&quot;../assets/img/usbl/usbl-frame.jpg&quot; /&gt;
&lt;p&gt;Subnero multi-receiver modem with a 3D-printed frame to secure the hydrophones.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The provided script performs localization in the body frame of reference given by the receiver geometry. Therefore, if your transceiver setup is mobile then you may have to attach an attitude heading reference system (AHRS) sensor to your transceiver to support conversion from the body reference frame to an East-North-Up coordinate system. Subnero modems can be equipped with an internal AHRS sensor as an optional upgrade.&lt;/p&gt;

&lt;p&gt;If your focus is more on software development rather than hardware and real-world tracking, then the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-contrib&lt;/code&gt; repository also contains a turnkey script to deploy your modems in a virtual acoustic ocean. Please see the appendix at the end of this post for details. Regardless of which path you choose, we will assume for the remainder of this post that you now have a setup equivalent to the following.&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img src=&quot;../assets/img/usbl/setup.png&quot; style=&quot;width: 900px&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;launching-the-usbl-script&quot;&gt;Launching the USBL Script&lt;/h2&gt;

&lt;p&gt;With the hardware now in place, the final step on our journey towards a USBL transceiver is to launch a helper script that does the USBL computation. To this end, please write the receiver geometry into a text file, starting with one line containing the whitespace-separated (x,y,z) coordinates of the transducer followed by three analogous lines for each hydrophone in the order of the labels on their cables.&lt;/p&gt;

&lt;div class=&quot;language-julia highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# Example geometry file for a tetrahedron with a side length of 15cm&lt;/span&gt;
  &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;         &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;     &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;        &lt;span class=&quot;c&quot;&gt;# Transducer&lt;/span&gt;
  &lt;span class=&quot;mf&quot;&gt;0.0866025&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.122474&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# Hydrophone 1&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0433013&lt;/span&gt;   &lt;span class=&quot;mf&quot;&gt;0.075&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.122474&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# Hydrophone 2&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0433013&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.075&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.122474&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# Hydrophone 3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the geometry file is ready, we can then launch the USBL script using the following command.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# Abstract command&lt;/span&gt;
./usbl &amp;lt;transceiver IP address&amp;gt; &amp;lt;geometry file&amp;gt;
&lt;span class=&quot;c&quot;&gt;# Concrete example&lt;/span&gt;
./usbl 192.168.42.123 geometry.txt
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we can exercise the USBL functionality by running the following commands on the Unet shell.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;subscribe&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ranging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;subscribe&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bearings&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;subscribe&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;locations&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transponder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Unet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/usbl/screenshot-usbl.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that depending on your setup, you may have to increase the power level on both the transceiver and transponder modem for the ranging to be successful; the default power level of -42 is very weak and will not be detectable except at very short ranges. We recommend a power level of -10 as a safe default, and 0 if you need to communicate over long distances. You can change the power level using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl &amp;lt;new power level&amp;gt;&lt;/code&gt;, and you can make the new setting persistent across reboots by adding this command to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startup.groovy&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;If you have managed to follow along until here, then congratulations: you have just successfully located the transponder modem using nothing but sound! As the above screenshot shows, your modem now reports three pieces of location information.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;For each incoming signal, it shows a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BearingNtf&lt;/code&gt; reporting in degrees the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;azimuth&lt;/code&gt; (horizontal direction, 0° is positive x-axis and 90° is positive y-axis) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elevation&lt;/code&gt; (vertical direction, 90° is positive z-axis).&lt;/p&gt;

    &lt;div style=&quot;width: 100%; display: flex; flex-direction: row; justify-content: center; gap: 4rem; flex-wrap: wrap; margin-bottom: 2rem;&quot;&gt;
&lt;img src=&quot;../assets/img/usbl/azimuth.svg&quot; style=&quot;padding: 0px&quot; /&gt;
&lt;img src=&quot;../assets/img/usbl/elevation.svg&quot; style=&quot;padding: 0px&quot; /&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;For each execution of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt;, it shows a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RangeNtf&lt;/code&gt; reporting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt; in meters to node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Whenever we have both a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bearing&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RangeNtf&lt;/code&gt;, the modem also shows a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PeerLocationNtf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can selectively toggle each of these notifications using the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;subscribe&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsubscribe&lt;/code&gt; commands. Also, remember that bearing and peer location are reported in the body frame of reference given by the geometry file and that an AHRS sensor may be needed to convert these quantities to world coordinates.&lt;/p&gt;

&lt;h2 id=&quot;usbl-ui&quot;&gt;USBL UI&lt;/h2&gt;

&lt;p&gt;To make it easier to interpret the USBL output, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-contrib&lt;/code&gt; repo provides a UI extension that visualizes the ranges, bearings and location estimates.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/usbl/ui.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To activate this UI, please proceed as follows.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Upload &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/usbl/ui/dist/USBL.html&quot; target=&quot;\_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ui/dist/USBL.html&lt;/code&gt;&lt;/a&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/&lt;/code&gt; folder of your modem.&lt;/li&gt;
  &lt;li&gt;Refresh the UI, then go to Dashboards &amp;gt; USBL.html&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;how-does-this-work&quot;&gt;How Does This Work?&lt;/h2&gt;

&lt;p&gt;Now that we have a working USBL transceiver, let us take a closer look at how it actually works. As you may have noticed, there are two topics that require further explanation.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;How do we trigger the transponder modem to send us a signal, and how do we use this signal to measure the range?&lt;/li&gt;
  &lt;li&gt;How do we estimate the bearing of the incoming signal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The remainder of this post will answer these two questions.&lt;/p&gt;

&lt;h2 id=&quot;estimating-the-range&quot;&gt;Estimating the Range&lt;/h2&gt;

&lt;p&gt;UnetStack modems constantly monitor the input audio stream for special signals called preambles, and upon detecting a preamble they emit a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DetectionNtf&lt;/code&gt; that lets other software components know about and react to this situation. This setup makes it very easy to measure the distance between two modems.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;On the transponder side, we set up a script to listen for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DetectionNtf&lt;/code&gt; and then reply with a matching response signal after some predefined delay \(\Delta T &amp;gt; 0\).&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On the transceiver side, we emit an interrogation signal at time \(T_1\), then wait for a matching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DetectionNtf&lt;/code&gt; and read from it the time of arrival \(T_2\). The range between the transceiver and transponder is then given by&lt;/p&gt;

\[r = \tfrac{c}{2} \, (T_2 - T_1 - \Delta T)\]

    &lt;p&gt;where \(c\) is the speed of sound in water.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This logic is built into UnetStack in the form of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range()&lt;/code&gt; command. Therefore, no additional code is required to realize the ranging part of our USBL system.&lt;/p&gt;

&lt;h2 id=&quot;estimating-the-bearing&quot;&gt;Estimating the Bearing&lt;/h2&gt;

&lt;p&gt;Slightly more work is required to get the bearing estimation up and running. At a high level, the algorithm for doing so consists of two steps.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Upon receiving a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DetectionNtf&lt;/code&gt;, we determine the precise arrival times \(t_i\) on each channel \(i \in \{0,1,2,3\}\).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Given these arrival times and the known receiver positions \(x_i \in \mathbb{R}^3\), we can then compute a corresponding direction of arrival \(u \in \mathbb{R}^3\).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second of these steps is quite straightforward. In fact, all it takes to convert arrival times \(t_i\) into a bearing estimate \(u\) is to evaluate&lt;/p&gt;

\[u = - \frac{\Delta x^{-T} \Delta t}{\| \Delta x^{-T} \Delta t \|_2}\]

&lt;p&gt;where&lt;/p&gt;

\[\Delta x
=
\big[\, \Delta x_1 \,\,\, \Delta x_2 \,\,\, \Delta x_3 \, \big]
\qquad\text{with}\qquad
\Delta x_i = x_i - x_0\]

&lt;p&gt;is a square matrix with the spatial offsets \(\Delta x_i\) between the hydrophones and the transducer as its columns, and similarly&lt;/p&gt;

\[\Delta t
=
\big[\, \Delta t_1 \,\,\, \Delta t_2 \,\,\, \Delta t_3 \bigr]^T
\qquad\text{with}\qquad
\Delta t_i = t_i - t_0\]

&lt;p&gt;is a vector consisting of the differences in arrival times \(\Delta t_i\).&lt;/p&gt;

&lt;p&gt;The above formula is derived from the observation that the time it takes for the wavefront to move from a hydrophone to the transducer is given by&lt;/p&gt;

&lt;div style=&quot;width: 100%; display: flex; justify-content: center; gap: 1rem; align-items: center; flex-wrap: wrap;&quot;&gt;

$$
\Delta t_i
=
- \frac{\Delta x_i^T \, u}{c}
.
$$

&lt;img src=&quot;../assets/img/usbl/arrival_vector_equation.svg&quot; style=&quot;padding: 0px&quot; /&gt;

&lt;/div&gt;

&lt;p&gt;The suggested formula is then obtained by collecting these individual equations into a combined system, solving for \(u\) and finally normalising the result to eliminate the dependence on the sound speed \(c\).&lt;/p&gt;

&lt;h2 id=&quot;estimating-the-arrival-times&quot;&gt;Estimating the Arrival Times&lt;/h2&gt;

&lt;p&gt;The last remaining piece in our USBL puzzle is to devise an algorithm for estimating the precise arrival times from the recorded audio signals. Mathematically, this amounts to finding offsets \(o_i\) such that the signal \(r_i\) recorded on channel \(i \in \{0,1,2,3\}\) shifted by the offset \(o_i\) matches the expected preamble \(p\), i.e.&lt;/p&gt;

\[r_i[o_i + k] \approx p[k]
\qquad \text{for all} \qquad
k \in \{0, \ldots, N-1\}
,\]

&lt;p&gt;where \(N\) denotes the length of the preamble. A standard way to tackle this problem is to determine the offsets \(o_i\) by maximising the absolute value of the cross-correlation,&lt;/p&gt;

\[o_i = \argmax \, \bigl| c[o] \bigr|
\qquad \text{where} \qquad
c[o]
=
\sum_{k=0}^{N-1} r_i[o + k] \, \overline{p[k]}
.\]

&lt;p&gt;(We assume here that \(r_i\) and \(p\) represent complex-valued baseband samples and hence apply complex conjugation \(x \mapsto \overline{x}\) to one of the factors when evaluating the cross-correlation.)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/usbl/correlation_maximisation.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our USBL code is based on this correlation maximization idea but applies two further refinements.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Rather than looking for the strongest arrival, our algorithm looks for the earliest arrival by locating the earliest peak that reaches at least half of the maximum correlation. This modification makes the algorithm more robust against echoes from nearby reflectors.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;../assets/img/usbl/earliest_arrival.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We subsample the correlation signal by a factor eight to increase the precision of the estimated arrival times.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;../assets/img/usbl/subsampling.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it! With these modifications, we now have a complete set of algorithms for tracking a target underwater. If you’d like to know more about how to implement these algorithms, then we encourage you to take a look at the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/tree/master/contrib/usbl/usbl-julia&quot; target=&quot;\_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usbl-julia&lt;/code&gt; folder&lt;/a&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-contrib&lt;/code&gt;. As you will see, UnetStack’s open architecture makes it very easy to extend a modem’s functionality using just a few lines of code!&lt;/p&gt;

&lt;h2 id=&quot;appendix-setting-up-a-virtualacousticocean-test-environment&quot;&gt;Appendix: Setting Up a VirtualAcousticOcean Test Environment&lt;/h2&gt;

&lt;p&gt;Setting up a USBL mount and deploying it in a body of water large enough to support USBL testing can be logistically challenging. To facilitate testing in a lab, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-contrib&lt;/code&gt; repository contains a script that allows you to deploy your modems in a &lt;a href=&quot;https://github.com/org-arl/VirtualAcousticOcean.jl&quot; target=&quot;\_blank&quot;&gt;VirtualAcousticOcean&lt;/a&gt; simulation environment. This script reconfigures the very lowest layers of the modems’ networking stacks such that rather than transmitting and receiving signals via the attached physical hardware, they instead communicate via a simulator that imitates the distortions that would have been observed if the modems had been deployed in a real ocean. All that is needed to activate this environment is to run the following command.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# Abstract command&lt;/span&gt;
./vao &amp;lt;transceiver IP address&amp;gt; &amp;lt;transponder IP address&amp;gt;
&lt;span class=&quot;c&quot;&gt;# Concrete example&lt;/span&gt;
./vao 192.168.42.123 192.168.42.45
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Among other things, this command will reboot your modems. Once they are back online, you can test that everything is set up correctly by running the following commands on the Unet shell of one modem and verifying that the other modem receives the message.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;plvl&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tell&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Unet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;hello world&apos;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/usbl/screenshot-tell.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Please note that after activating a VirtualAcousticOcean configuration, the modems will remain in this configuration until it is actively removed. You can return the modems to transmitting and receiving via their onboard hardware by deleting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modem.toml&lt;/code&gt; files in their respective &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/&lt;/code&gt; folders.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/usbl/screenshot-modem-toml.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Please also see our &lt;a href=&quot;https://blog.unetstack.net/running-hardware-in-the-loop-simulations-using-unetstack-modems&quot;&gt;earlier blog post&lt;/a&gt; for more information on using UnetStack modems with VirtualAcousticOcean.&lt;/p&gt;
</description>
            <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Acoustic Communication and Navigation for Subsea Robotics — Part 2</title>
            <link>/acoustic-communication-and-navigation-for-subsea-robotics-part2</link>
            <guid isPermaLink="true">/acoustic-communication-and-navigation-for-subsea-robotics-part2</guid>
            <description>&lt;p&gt;In part 1, we discussed the first three levels, technology choices, integration hygiene, and deployment planning. Those alone get you most of the way to confident connectivity. In this post, we’ll describe the last two levels, where systems adapt in real time and missions flex slightly to help communication.&lt;/p&gt;

&lt;h2 id=&quot;level-4-adaptive-communication-links&quot;&gt;Level 4: Adaptive communication links&lt;/h2&gt;

&lt;p&gt;Once a vehicle is in the water, the ocean reveals its true character. Conditions change with depth, movement, and even the passing of ships. Instead of locking parameters before deployment, we can let the modem adapt in real time. Adaptive modulation schemes allow the system to step down to more robust modes when multipath or Doppler is high, and step up again when the channel clears to deliver higher throughput. Similarly, error control coding can be tuned dynamically: adding more redundancy when losses rise, and trimming it back to recover data rate when the link is clean. Erasure codes are particularly useful underwater; they let us transmit a little extra upfront, so the receiver can reconstruct the message even if several frames are lost, without the delay of waiting for acknowledgements. Together, these adaptive techniques turn a static link into one that bends with the ocean instead of breaking against it.&lt;/p&gt;

&lt;p&gt;Adaptivity is not only about modulation; it’s also about choosing the right link at the right time. Most vehicles today carry more than one communication interface, Wi-Fi or 4G when surfaced, satellite on a mothership or shore station, optics for short range underwater, and acoustics for longer ranges. A smart stack can switch among these automatically, routing different types of data to the most suitable link. For instance, video streams can go over Wi-Fi when the vehicle is near the surface, low-rate telemetry can flow over acoustics while submerged, and large files can transfer over optical when in close range. By declaring the content type, time-to-live, and priority of each data stream, operators can leave the decision-making to the stack instead of micromanaging links. UnetStack, for example, allows this kind of policy-based routing, so vehicles can focus on their mission while the communication system quietly optimizes delivery.&lt;/p&gt;

&lt;p&gt;All of these adaptive behaviours—whether changing modulation and coding in real time, dynamically routing across multiple links, or delivering content based on link availability—are already supported in UnetStack. In this article, we’ve focused on the why and what of adaptive communication, but in future blogs, we’ll dive into the how: demonstrating how these ideas are implemented in UnetStack.&lt;/p&gt;

&lt;h2 id=&quot;level-5-adaptive-command-and-control&quot;&gt;Level 5: Adaptive command and control&lt;/h2&gt;

&lt;p&gt;The highest level of confidence comes when vehicles themselves adapt their missions based on feedback from the communication system. Instead of treating comms as an independent subsystem, we can use information about link quality to make small but meaningful changes in behaviour. For example, if the modem detects that the channel is degrading, the vehicle might pause bulk transfers, climb or dive a few metres to escape a dead zone, or slightly adjust its course to maintain better connectivity. These interactions are illustrated in Figure 1, which shows how different onboard agents—command and control (C2), network, and sensing—communicate with each other to adjust plans dynamically. By keeping this feedback loop lightweight and local, vehicles can preserve their mission goals while still giving the communication system a chance to perform optimally. This idea of adaptive mission execution moves connectivity from being a fragile dependency to becoming an active part of mission planning.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms-arch.png&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 1: Schematic of adaptive mission execution. The C2 agent manages node placement and motion planning, the sensor agent handles data acquisition and processing, and the network agent oversees inter-node communication. Feedback from the network agent informs the C2 agent about link quality, prompting small plan adjustments that keep missions robust without human intervention. From M. Chitre, “A holistic approach to underwater sensor network design,” in Proceedings of Naval Technology Seminar (NTS) 2011, May 2011. (Invited).&lt;/p&gt;

&lt;p&gt;Recent work (&lt;a href=&quot;https://arl.nus.edu.sg/wp-content/uploads/2022/09/Chitre_Physics-informed_UComms-2022.pdf&quot;&gt;&lt;em&gt;M. Chitre and K. Li, “Physics-informed Data-driven Communication Performance Prediction for Underwater Vehicles,” in The 6th Underwater Communications Networking (UComms 2022), (Lerici, Italy), 2022.&lt;/em&gt;&lt;/a&gt;) has shown that we can go even further by predicting what lies ahead using lightweight, physics-informed, data-driven models. The idea is simple but powerful: as an autonomous vehicle moves, it measures acoustic signal strength along its path and uses those observations to predict what the field will look like in the region just ahead. Rather than relying purely on machine learning, which struggles to extrapolate beyond the data it has seen, this method embeds the underlying physics of acoustic propagation directly into the learning process. Each measurement is treated as a combination of rays arriving from different directions, and a sparse optimization algorithm estimates which ray angles and amplitudes are most likely to explain the observed field. By constraining the learning to the acoustic wave equation, the algorithm can make physically realistic predictions even with very little data.&lt;/p&gt;

&lt;p&gt;In the study, a simulated AUV travelled along a 100 m segment at a depth of 100 m, taking signal-strength readings every metre while communicating with a surface ship 2 km away (Figure 2). Using only those 100 measurements as input, the model then predicted the acoustic field across a 250 m × 50 m region in front of the vehicle. The ground-truth field computed with the BELLHOP propagation model is shown in Figure 3, while Figure 4 shows the model’s predictions using the physics-informed approach. The resemblance between the two fields is striking: even fine-scale interference patterns and “dark zones” of low signal strength are reproduced well enough to guide adaptive path-planning. Because the model learns from multiple frequencies simultaneously and enforces sparsity across ray arrivals, it generalizes far better than traditional data-driven methods. In practice, this means a vehicle can predict where the link will hold and where it will fade, and adjust its trajectory before the connection is lost—all in real time and with modest onboard computing resources.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms03.png&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 2: Simulation setup&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms04.png&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 3: Ground truth signal strength integrated over the 9–14 kHz band, as obtained from BELLHOP over the region of interest. The AUV path is shown in blue, with solid dots showing the measurement locations. The white rectangle shows a region marked for closer inspection.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms05.png&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 4: Predicted signal strength integrated over the 9– 14 kHz band, over the region of interest. The AUV path is shown in blue, with solid dots showing the measurement locations. The white rectangle shows a region marked for closer inspection&lt;/p&gt;

&lt;p&gt;This work demonstrates how data and physics can come together to make underwater communication systems proactive rather than reactive. Instead of waiting for a link to fail and then compensating, vehicles can now anticipate when and where communication will degrade, and adjust before it happens. These predictions close the loop between perception and control—turning what was once a static channel model into a living part of the mission logic. Combined with the adaptive mission behaviours discussed earlier, such models make it possible for underwater vehicles to plan smarter routes, schedule transfers more intelligently, and ultimately operate with a level of confidence that was previously out of reach.&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h1&gt;

&lt;p&gt;When you add adaptation to the first three levels, the operating picture changes. Operators declare intent and monitor goodput, not tweak knobs. Vehicles help themselves with minor depth or timing shifts. Multi-link stacks exploit whatever the environment offers. Most importantly, the link stops being an unreliable afterthought, and starts being trusted.&lt;/p&gt;

&lt;p&gt;The message is simple, physics still sets the limits, but if we respect it, plan for it, and adapt intelligently, those limits work for us. Once we have that confidence, we can design missions and systems that rely on the link instead of avoiding it.&lt;/p&gt;
</description>
            <pubDate>Wed, 17 Dec 2025 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Acoustic Communication and Navigation for Subsea Robotics — Part 1</title>
            <link>/acoustic-communication-and-navigation-for-subsea-robotics-part1</link>
            <guid isPermaLink="true">/acoustic-communication-and-navigation-for-subsea-robotics-part1</guid>
            <description>&lt;p&gt;&lt;em&gt;This two-part article is based on the talk “Connectivity with Confidence: Acoustic Communication and Navigation in Practice,” delivered by Professor Mandar Chitre (National University of Singapore). The blog was written to distill the key ideas from that presentation into a written form for a wider audience.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When we ask a room of subsea robotics developers and users how many have used underwater acoustic communications, we often see a good number of hands. But when we follow up and ask how many feel confident that, when they put a vehicle in the water, the acoustic link will “just work,” the show of hands drops dramatically. That gap is what we want to address in this two-part series. It’s time to move from treating communication as a nice-to-have, something added reluctantly and not relied upon, to building connectivity with confidence.&lt;/p&gt;

&lt;p&gt;For a long time, skepticism about acoustic links was justified. They were fragile, unreliable, and unpredictable. But technology has evolved. With the right choices and a bit of discipline, it is now possible to achieve robust, dependable connectivity that not only supports communication but also navigation. In fact, when we use the word connectivity, we mean both. Acoustics underpins them together. Aerial drones exploded in use partly because of easy communication and GPS navigation. Underwater vehicles, by contrast, have been held back because we lacked the same level of confidence in connectivity. We believe that can change.&lt;/p&gt;

&lt;h1 id=&quot;the-basics&quot;&gt;The Basics&lt;/h1&gt;

&lt;h2 id=&quot;why-acoustics&quot;&gt;Why Acoustics?&lt;/h2&gt;

&lt;p&gt;Radio and most light simply don’t travel well underwater. Even visible light in clear water only gets you tens of meters; in turbid coastal waters like Singapore, it is even less. Acoustics, on the other hand, propagate hundreds of meters, to tens of kilometers. Frames typically contain a preamble, data modulated onto a carrier, error correction, and checksums. Robust incoherent modulation schemes work well for commands and telemetry, while coherent modulation schemes are needed for images and high-rate data. Forward Error Correction (FEC) and erasure codes add robustness without long feedback cycles. This is critical because sound travels so much slower than light.&lt;/p&gt;

&lt;h2 id=&quot;acoustic-communication&quot;&gt;Acoustic communication&lt;/h2&gt;

&lt;p&gt;When we talk about frames and packets underwater, it is useful to be precise. A packet is a unit of data, but modems often fragment it into smaller frames for transmission. Each frame has its own preamble, data, and error check. On the receiving side, fragments are reassembled into the original packet. Because underwater channels lose frames more often, we need mechanisms to deal with the loss. Automatic Repeat Request (ARQ) is one approach: the receiver asks for specific lost fragments to be re-sent. But given the long propagation delays, this can waste valuable time. Erasure correction coding provides another option: by adding some extra parity frames at the start, the receiver can reconstruct the whole packet as long as it collects enough of the transmitted frames, even if a few are missing. This avoids the need to wait for a round-trip of acknowledgements, which can often take long underwater.&lt;/p&gt;

&lt;p&gt;Next, there are also some terms that we need to define clearly. Robustness refers to the chance that a packet crosses cleanly the first time, without errors. Reliability, on the other hand, is the end-to-end guarantee that comes from feedback and retransmission if needed. Both are useful, but they come with different costs. Similarly, we care not about raw link rate, which is the number printed in the datasheet, but about throughput or “goodput”: the actual amount of useful data delivered correctly. A link claiming tens of kilobits per second may in practice give you only a fraction of that once protocol overheads and frame loss are accounted for. Understanding these distinctions avoids confusion when comparing modems or planning missions.&lt;/p&gt;

&lt;h2 id=&quot;acoustic-navigation&quot;&gt;Acoustic navigation&lt;/h2&gt;

&lt;p&gt;Navigation is built on the same acoustic signals. The simplest method is two-way travel time ranging: one device transmits, the other responds, and the round-trip time divided by two gives you a range. With synchronized clocks, we can also do one-way travel time ranging, which halves the time taken for ranging, and reduces energy usage (but requires very stable oscillators). Using several surface nodes with GPS, we can build long-baseline (LBL) systems, where either the topside knows the vehicle’s location or the vehicle computes it itself in “inverse LBL.” With a single beacon, compact Ultra-Short Baseline (USBL) systems estimate bearing and range together, and again, they can be configured in normal or inverse modes depending on where you want the computation to happen. These methods are mature and well-proven in underwater systems, but they still face practical challenges in real deployments—from multipath and synchronization drift to environmental variability—so it’s important to account for these factors early in your system design.&lt;/p&gt;

&lt;h1 id=&quot;why-doesnt-it-just-work&quot;&gt;Why doesn’t it “just work”?&lt;/h1&gt;

&lt;p&gt;Many people are surprised when an underwater modem doesn’t “just work.” The reason is that the ocean is an entirely different medium from the air or fiber networks we are used to. Bandwidth is scarce, signals bounce off the surface and seabed creating echoes, vehicle motion causes Doppler, and noise from ships or even snapping shrimp can overwhelm weak signals. On top of this, sound travels 200,000 times slower than light, so protocols designed for the Internet break down. Unless these realities are accounted for, what looks good on paper quickly fails at sea.&lt;/p&gt;

&lt;p&gt;One of the most useful ways we have found to explain the pitfalls is through a simple list of don’ts and do’s. The don’ts are the traps that catch many first-time users—but each of them has a simple alternative. Don’t assume you can simply replace a tether with modems and expect the same reliability; acoustic networks require new ways of thinking about timing and robustness. Don’t use internet protocols blindly, because the assumptions of fast feedback and low loss don’t hold underwater; purpose-built protocols handle this far better. Don’t ignore the physics of bandwidth, absorption, and Doppler; knowing these limits helps you plan within what the ocean can actually support. Don’t overload the channel by pushing it to its theoretical maximum; leave headroom for retries and environmental fluctuations. Don’t reinvent decades of work already built into frameworks like UnetStack; start with proven foundations and tune from there. And finally, don’t try to optimize everything before you have a stable link—get it working robustly first, then improve it. We’ll come back to how each of these “do’s” map into the five levels of confidence that follow.&lt;/p&gt;

&lt;p&gt;These are practical steps starting from the technology choices you make, through integration and planning, and extending into advanced adaptive techniques that, if followed, can transform underwater communication from a gamble into something you can rely on.&lt;/p&gt;

&lt;h1 id=&quot;the-five-levels-of-confidence&quot;&gt;The five levels of confidence&lt;/h1&gt;

&lt;p&gt;These five levels capture the progression from basic design decisions to advanced adaptive techniques that push performance further. The first three are essential; the last two are advanced. In this first part, we’ll cover the first three.&lt;/p&gt;

&lt;h2 id=&quot;level-1-technology-choices&quot;&gt;Level 1: Technology choices&lt;/h2&gt;

&lt;p&gt;Before you even build or buy, the technology choices you make set the upper bound for what your system can achieve. The first and most important is the frequency band. Higher frequencies in the hundreds of kiloHertz give you short-range but high-rate links, suitable for a few hundred meters and applications like image or file transfer. Mid-range frequencies in the tens of kiloHertz are the workhorse for kilometre-scale missions. At the other end, only a few kiloHertz will carry over tens of kilometres, but at the cost of data rate. Every choice is a trade-off between absorption, ambient noise, and usable bandwidth, so you need to pick the sweet spot that matches your mission profile. As shown in Figure 1, sound attenuation in warm shallow waters increases steeply with frequency. This relationship is what drives the trade-off between range and data rate when selecting an operating band.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms01.png&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 1: Sound attenuation in warm shallow waters&lt;/p&gt;

&lt;p&gt;Transmit source levels are another key decision. These are not just about the hardware spec sheet. They are limited by environmental regulations on noise, by cavitation thresholds when operating shallow or with small vehicles, and by whether your power system can actually supply the transient peaks that the transducer draws. Directivity is equally important. Omnidirectional transducers are simple to deploy, but if you know the geometry of your mission, directional transducers can make the most of your energy. On the receiver side, adding spatial diversity is often an overlooked but powerful option. Just as Wi-Fi access points benefit from multiple antennas, a small array of hydrophones can significantly improve robustness, and it is usually inexpensive to add on a surface platform or larger vehicle.
Finally, consider modulation and coding. It is tempting to chase the highest bit rates, but robustness almost always matters more. Choose the lowest rate that still meets your data needs, and use forward error correction or erasure coding to carry you through challenging conditions. Navigation is also part of the early design stage. Decide whether you will rely on simple two-way ranging, or if your system can support synchronized clocks for one-way measurements. Think about whether your setup favours long baseline (LBL), inverted LBL, Ultra-Short Baseline (USBL), or inverted USBL. These are not afterthoughts, they fundamentally shape what your system can deliver once it is in the water.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/auvcomms02.webp&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Figure 2:  &lt;em&gt;The typical sound levels of ocean background noises at different frequencies, as measured by Wenz (1962). This graph is therefore also referred to as the Wenz curves. The sound levels are given in underwater dB summed over 1 Hz wide frequency bands, which is often written as dB re 1 µPa2/Hz. &lt;a href=&quot;https://dosits.org/science/sounds-in-the-sea/what-are-common-underwater-sounds/&quot;&gt;Adapted (after National Research Council, 2003) from Wenz, G. M. (1962). Acoustic ambient noise in the ocean: Spectra and sources. The Journal of the Acoustical Society of America, 34(12), 1936–1956.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Beyond frequency, power, and modulation, there are also important choices in how multiple users share the channel and how higher-level data is handled. Medium access control (MAC) is a prime example: if you can synchronize your devices, a time-division scheme (TDMA) often provides the most predictable performance; if traffic is bursty or unpredictable, random-access approaches like CSMA or MACA may be better, though they come with higher overhead. At higher layers, think about how your system expresses priorities and deadlines. Some data is time-sensitive (like vehicle position), while other data may be large but delay-tolerant. A modem or stack that allows you to configure quality of service, set time-to-live values, and even declare content types (e.g. image, telemetry, audio) can make smarter transmission decisions on your behalf. The overall configurability of the technology is therefore not just a “nice-to-have”, it is a core part of making sure the link adapts to your mission requirements instead of forcing your mission to adapt to the link.&lt;/p&gt;

&lt;p&gt;And if navigation is part of your mission, you also need to decide upfront whether the system should support ranging and localization, whether it can provide synchronized time across nodes, and how stable the clocks are in practice. These capabilities determine not just how you communicate, but how you localize vehicles underwater, so they must be considered at the same stage as frequency bands and modulation schemes.&lt;/p&gt;

&lt;h2 id=&quot;level-2-integration-hygiene&quot;&gt;Level 2: Integration hygiene&lt;/h2&gt;

&lt;p&gt;When it comes to mechanical integration, factors such as the placement of the transducer plays an important role. Simply mounting it wherever there is space on a vehicle rarely works well. Thrusters generate noise and, more critically, microbubbles that persist in the water and scatter sound, destroying coherent links even when SNR looks good. Flow noise from fast-moving vehicles, vibrations from mechanical structures, and even the rigidity of the mounting bracket all contribute to degraded performance. We have seen vehicles that lost their link whenever they moved away from the ship, only to recover it as soon as they turned slightly, simply because their thruster wake sat directly in the acoustic path. The wake was filled with microbubbles that scattered and distorted the sound waves, severely degrading the signal even though the signal-to-noise ratio appeared good. Paying attention to transducer location and characterizing flow and thruster noise early in the integration process prevents many of these headaches. Ambient noise in the operating environment can also vary dramatically, shipping lanes, construction sites, and even biological sources like snapping shrimp can raise the noise floor and reduce performance. On top of this, interference from other acoustic systems, whether they are echo sounders, sonars, or other modems, can overlap with your own signals if frequencies are not coordinated. Factoring these acoustic neighbours into integration and deployment decisions is critical.&lt;/p&gt;

&lt;p&gt;Electrical integration is just as critical. Modems draw sharp bursts of current during transmission, and if the power bus is noisy or poorly filtered, that noise couples back into the receiver front end. Clean power supplies and proper filtering are essential to ensure consistent source levels and avoid self-interference. Once integrated, it is important to measure actual source levels in situ, because cabling, mounts, or limited current draw from a vehicle’s battery system may reduce output below specification. Shallow-water operation at high source levels can also cause cavitation, producing bubbles that not only damage transducers but also severely degrade signals. Regularly checking for cavitation thresholds and logging ambient noise levels in your deployment area helps ensure that electrical and acoustic integration issues do not compromise the system. Beyond hardware, it is equally important to evaluate communication performance after integration: measure diagnostics such as packet delivery ratios, latency, and ranging accuracy in realistic conditions. These checks often reveal integration flaws that would otherwise remain hidden until deployment. Synchronization and ranging performance must also be verified, since even small timing errors can undermine both communication and navigation functions if not properly accounted for.&lt;/p&gt;

&lt;p&gt;Software integration is the third pillar of hygiene. Too often, teams treat the modem as a transparent pipe and push raw bytes across. This wastes much of what modern stacks can offer. In UnetStack, for example, applications can attach metadata such as robustness level, reliability, time-to-live, priority, and MIME type to each message, allowing the modem to make smarter delivery decisions. A short snippet shows how this works:&lt;/p&gt;

&lt;p&gt;Example AUV code snippet:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnetSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;192.168.0.42&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;TOPSIDE&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ttl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TTL_MAILBOX&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mailbox&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;STATUS&apos;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mimeType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;application/json+auvstatus&apos;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// facilitate application-specific compression&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toJson&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example TOPSIDE code snippet:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnetSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;192.168.0.27&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;rx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;receive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ui&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;showStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By tagging data this way, we give the modem the context it needs to adapt to current conditions, compressing an image if bandwidth is poor, discarding stale telemetry instead of wasting airtime, or prioritizing urgent commands. This transforms software integration from a simple “pipe” to a smarter, adaptive communication framework that supports confident operation in real-world deployments.&lt;/p&gt;

&lt;h2 id=&quot;level-3-deployment-planning&quot;&gt;Level 3: Deployment planning&lt;/h2&gt;

&lt;p&gt;Deployment planning is where theory meets the ocean, and it makes a huge difference to communication performance. Many users ask a simple question: what range will I get with this modem? Unfortunately, the answer is never a single number. Communication performance depends on much more than just distance. It is shaped by depth, bottom type, water column properties, and geometry. Acoustic energy refracts, reflects, and cancels in ways that create “hot spots” and “dark zones.” A link that looks strong at 500 meters might vanish entirely at 800 meters, only to return at 1,200 meters. Planning missions without considering this variability often leads to surprises in the field.&lt;/p&gt;

&lt;p&gt;One of the most effective ways to plan is through propagation modeling. Physics-based models, if you have good knowledge of the environment (sound speed profile, seabed composition, depth, and bathymetry), can predict where signals will carry well and where they will fail. Even with limited data, these tools can produce maps of expected signal-to-noise ratio that guide decisions such as when to run telemetry updates or attempt bulk transfers. If modeling or measurements are not possible, rules of thumb can still be applied to avoid known traps, like the Lloyd mirror effect.&lt;/p&gt;

&lt;p&gt;The Lloyd mirror is a particularly important phenomenon to account for. Near the surface, acoustic signals arrive via both a direct path and a surface-reflected path. The reflection undergoes a 180° phase shift, so when the two signals overlap, they can cancel each other out and create a dark band of poor reception. This effect shows up consistently in field tests and models alike. The solution is simple: increase the combined depth of the transmitter and receiver. That could mean mounting the transducer deeper on a vehicle, or placing the surface modem further below the waterline. Small changes in depth can move the system out of destructive interference zones and into regions of strong signal, dramatically improving reliability. Planning missions with this in mind, whether through detailed modeling, in-situ measurements, or rules of thumb, turns deployment from guesswork into an informed exercise.&lt;/p&gt;

&lt;p&gt;Do these three levels well, and you are already far ahead. You will have a link you trust for commands and telemetry, predictable windows for heavier data, and navigation updates at the cadence you need. In part 2, we’ll explore levels four and five, adaptive links and adaptive missions, where the system and the vehicle adjust in real time.&lt;/p&gt;
</description>
            <pubDate>Wed, 17 Dec 2025 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Running Hardware-in-the-Loop Simulations Using UnetStack Modems</title>
            <link>/running-hardware-in-the-loop-simulations-using-unetstack-modems</link>
            <guid isPermaLink="true">/running-hardware-in-the-loop-simulations-using-unetstack-modems</guid>
            <description>&lt;p&gt;Underwater wireless communication is difficult to design, test, and deploy. The ocean is an unforgiving test environment, with dynamic and often unpredictable propagation characteristics. Access to vessels, dive teams, and favorable weather windows often restrict testing frequency, making rapid iteration nearly impossible.&lt;/p&gt;

&lt;p&gt;For researchers, engineers, and system integrators working on underwater networks, simulation is an essential first step. It enables protocol design and debugging, visualizes network behavior, and allows performance evaluation under varying conditions. Most importantly, simulation helps reduce risk before committing to expensive deployments.&lt;/p&gt;

&lt;h2 id=&quot;why-hardware-in-the-loop-hil&quot;&gt;Why Hardware-in-the-Loop (HIL)?&lt;/h2&gt;

&lt;p&gt;While pure software simulation (where all nodes run on a single computer) is useful, it falls short in certain cases, particularly when real-time behavior, hardware driver integration, and system compatibility are important.&lt;/p&gt;

&lt;p&gt;Imagine you are a researcher developing a large scale underwater network. You want to validate not only your algorithms but also the performance of the modems you plan to use in the field. Before investing time and money into an offshore campaign, you want confidence that your system behaves correctly, both in logic and in timing. You also want to try out multiple configurations quickly.&lt;/p&gt;

&lt;p&gt;This is where HIL simulations shine. By keeping your real hardware in the loop, you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Test the actual modem hardware, drivers, and firmware.&lt;/li&gt;
  &lt;li&gt;Verify timing behavior and interface compatibility of your algorithms in the modems.&lt;/li&gt;
  &lt;li&gt;Run real world network software with simulated acoustic links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your modem is software-defined and open-architecture, such as Subnero’s modems, HIL offers a development experience that closely mirrors actual deployment.&lt;/p&gt;

&lt;h2 id=&quot;the-foundation-unetstack-v5--virtual-acoustic-ocean&quot;&gt;The Foundation: UnetStack v5 + Virtual Acoustic Ocean&lt;/h2&gt;

&lt;p&gt;Modems running UnetStack v5 — such as those offered by Subnero — are fully software-defined and follow an open architecture. This enables users to customize physical and network layers, extend built-in components, and use the exact same software stack in both simulated and real-world deployments.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/org-arl/VirtualAcousticOcean.jl&quot;&gt;Virtual Acoustic Ocean (VAO)&lt;/a&gt; is an open-source acoustic channel simulator. It supports standard propagation models, and allows users to define node positions, protocol stack parameters, and environmental conditions. Simulations can be run in interactive mode, making VAO suitable for everything from basic tests to complex protocol validation.&lt;/p&gt;

&lt;p&gt;With a modem running UnetStack v5 and VAO, users are now able to unlock scalable, reproducible HIL simulations that can closely mirror real-world underwater communication scenarios while enabling rapid, repeatable testing without going to sea.&lt;/p&gt;

&lt;h2 id=&quot;typical-use-cases&quot;&gt;Typical Use Cases&lt;/h2&gt;

&lt;p&gt;This simulation setup supports a variety of scenarios. Researchers can use it to develop and validate new communication algorithms such as those at the physical or network layers, under realistic acoustic conditions. Commercial teams can evaluate performance for AUV-based data harvesting or remote sensing missions before heading to the field. Defense teams can rehearse complex mission scenarios virtually, especially in environments where access or testing is restricted.&lt;/p&gt;

&lt;h2 id=&quot;step-by-step-guide-to-hil-simulation&quot;&gt;Step-by-Step Guide to HIL Simulation&lt;/h2&gt;

&lt;p&gt;Before beginning the simulation, ensure you have the following setup:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Two Subnero M25M series modems running UnetStack v5.&lt;/li&gt;
  &lt;li&gt;A laptop or mini-PC with Julia installed, capable of running the Virtual Acoustic Ocean (VAO) simulator.&lt;/li&gt;
  &lt;li&gt;An Ethernet switch to connect all devices to the same network.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/vao-setup.jpg&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;All components — modems and the VAO-running machine — should be on the same subnet to be able to reach each other using their IP address.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; Use an isolated network switch (without internet access) to avoid interference from unrelated network traffic during simulation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: This example uses Subnero M25M (MF-band) modems, but the same steps apply to Subnero’s LF and HF modems. The simulation script provided is just one example — please refer to the VAO GitHub repository for the latest examples, which may differ. This guide shows how to connect two Subnero modems, but more nodes can be added by extending the script with additional addnode! lines.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;1-install-vao-and-packages&quot;&gt;1. Install VAO and Packages&lt;/h3&gt;

&lt;p&gt;At a Julia terminal:&lt;/p&gt;

&lt;div class=&quot;language-julia highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pkg&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;VirtualAcousticOcean&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0.8.1&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;UnderwaterAcoustics&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Sockets&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;2-add-example-scenario&quot;&gt;2. Add Example Scenario&lt;/h3&gt;

&lt;p&gt;Copy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2-node-network.jl&lt;/code&gt; file from the &lt;a href=&quot;https://github.com/org-arl/VirtualAcousticOcean.jl&quot;&gt;GitHub repo&lt;/a&gt; examples folder to your working directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example content:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-julia highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VirtualAcousticOcean&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnderwaterAcoustics&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Sockets&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnderwaterEnvironment&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seabed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SandyClay&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bathymetry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;40.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PekerisRayTracer&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Simulation&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;24000.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;addnode!&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UASP2&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9809&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;addnode!&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1000.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UASP2&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9819&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Simulation running with these nodes:&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nodes&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;  - Node &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(idx) &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;at position &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;(node.pos) receiving on UDP port &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;(node.conn.port)&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: The example shown here is representative. The version available in the &lt;a href=&quot;https://github.com/org-arl/VirtualAcousticOcean.jl&quot;&gt;VAO GitHub repository&lt;/a&gt; may differ slightly depending on updates or version changes.
&lt;strong&gt;Run it from the terminal:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; julia &lt;span class=&quot;nt&quot;&gt;--threads&lt;/span&gt; auto 2-node-network.jl
Simulation running with these nodes:
  - Node 1 at position &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0.0, 0.0, &lt;span class=&quot;nt&quot;&gt;-10&lt;/span&gt;.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; receiving on UDP port 9809
  - Node 2 at position &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1000.0, 0.0, &lt;span class=&quot;nt&quot;&gt;-10&lt;/span&gt;.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; receiving on UDP port 9819
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;3-configure-subnero-modems&quot;&gt;3. Configure Subnero Modems&lt;/h3&gt;

&lt;p&gt;Each modem needs to be configured to redirect its baseband interface to VAO. Access each modem’s web UI and upload this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modem.toml&lt;/code&gt; to the Scripts folder:&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nn&quot;&gt;[input]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;analoginterface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UASP2DAQ&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;192.168.42.10&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9809&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[output]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;analoginterface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;UASP2DAQ&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ensure this matches the VAO machine’s IP and each modem uses the correct port (e.g. 9809). Additionally, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[output]&lt;/code&gt; section is optional and typically used when configuring a physical modem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Verify the setup via modem shell:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;bb
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; bb
« Baseband »

Baseband service for UASP2DAQ.AnalogInterface
...
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also check modem logs for an entry similar to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;1750584190212	INFO	UASP2DAQ@27:UASP2DAQ@1:57	Connecting to UASP2 DAQ at 192.168.42.10:9809...
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Now you have 2 nodes deployed 1 km apart and connected through VAO. With the nodes now connected via VAO and properly configured, you can begin interactive testing and messaging between the modems.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;4-set-transmit-power&quot;&gt;4. Set Transmit Power&lt;/h3&gt;

&lt;p&gt;Since the modems are deployed 1 km apart, set full transmit power:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;plvl 0
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;5-test-the-link&quot;&gt;5. Test the Link&lt;/h3&gt;

&lt;p&gt;Send a test message from either of the modem’s shell:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;tell 0, &lt;span class=&quot;s2&quot;&gt;&quot;Hello Sea&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see the message on the receiving modem’s shell, confirming that the simulated link is working.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;unetcube-unetstack-oem-edition--vao&quot;&gt;UnetCube (UnetStack OEM Edition) + VAO&lt;/h2&gt;

&lt;p&gt;If you do not have Subnero modems, you can still simulate the system using UnetCube (UnetStack OEM Edition) on single-board computers (e.g., Jetson Orin Nano). The simulation behavior will be the same, enabling rapid prototyping.&lt;/p&gt;

&lt;figure&gt; &lt;img width=&quot;70%&quot; src=&quot;../assets/img/unetcube.jpg&quot; /&gt;&lt;/figure&gt;

&lt;p&gt;Contact &lt;a href=&quot;mailto:info@subnero.com&quot;&gt;info@subnero.com&lt;/a&gt; for more information.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/org-arl/VirtualAcousticOcean.jl&quot;&gt;VAO GitHub Repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://unetstack.net&quot;&gt;UnetStack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://subnero.com&quot;&gt;Subnero&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Wed, 11 Jun 2025 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Running Unet audio on Apple silicon</title>
            <link>/running-unet-audio-on-apple-silicon</link>
            <guid isPermaLink="true">/running-unet-audio-on-apple-silicon</guid>
            <description>&lt;p&gt;&lt;a href=&quot;https://unetstack.net/handbook/unet-handbook.html#_transmitting_and_recording_arbitrary_acoustic_waveforms&quot;&gt;Unet audio&lt;/a&gt; is a great educational tool for using and testing Unet implementations using UnetStack. Unet audio uses your computer’s sound card as an acoustic modem. Almost the entire functionality of UnetStack is available in Unet audio, so you can easily &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook.html#_developing_your_own_agents&quot;&gt;develop and test Unet Agents&lt;/a&gt;, try out &lt;a href=&quot;https://blog.unetstack.net/custom-phy&quot;&gt;communications algorithms&lt;/a&gt;, and even test your scripts and programs written to interact with UnetStack without needing any extra hardware.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/unetaudio.png&quot; alt=&quot;Unet audio&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unet audio binds to your computer’s operating system and uses the built-in audio services to send and receive audio from the sound card. This means that some of the libraries used by Unet audio need to be compiled for the specific operating system and architecture.&lt;/p&gt;

&lt;p&gt;Until UnetStack 3 Community release v3.4.3, Unet audio was only supported on Linux and macOS on the Intel &lt;strong&gt;x86&lt;/strong&gt; architecture. However, with the release of Apple Silicon, and the popularity of Mac computers with the M1/2/3 chips, we have been working to make Unet audio available on the &lt;strong&gt;ARM&lt;/strong&gt; architecture.&lt;/p&gt;

&lt;p&gt;We are happy to announce that Unet audio is now available on macOS running on Apple Silicon, from &lt;a href=&quot;https://unetstack.net/#downloads&quot;&gt;Unet Community v3.4.4&lt;/a&gt; onwards.&lt;/p&gt;

&lt;h2 id=&quot;setup-unet-audio-on-macs-with-apple-silicon&quot;&gt;Setup Unet audio on Macs with Apple Silicon&lt;/h2&gt;

&lt;p&gt;Unet audio comes as a part of UnetStack 3 Community releases. You can download the latest release from the &lt;a href=&quot;https://unetstack.net/#downloads&quot;&gt;UnetStack 3 downloads section&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;

&lt;p&gt;UnetStack 3 requires Java 8 to be installed on your computer. With the macOS on Apple Silicon, you can run Java 8 compiled for x86 architecture using &lt;a href=&quot;https://support.apple.com/en-sg/HT211861&quot;&gt;Rosetta 2&lt;/a&gt; or run Java 8 compiled for ARM (aarch64) architecture natively.&lt;/p&gt;

&lt;p&gt;Unet audio additionally requires &lt;a href=&quot;https://www.portaudio.com/&quot;&gt;portaudio&lt;/a&gt; to be installed on your computer. &lt;a href=&quot;https://https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; is a great package manager for macOS, and you can use it to install portaudio.&lt;/p&gt;

&lt;p&gt;The architecture of Java 8 that you have installed on your computer will determine which version of portaudio you need to use. The following table shows the compatibility between the architecture of the Mac, Java 8, and portaudio:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Computer CPU&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Java 8 Architecture&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Portaudio Architecture&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Intel x86&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Apple Silicon (aarch64)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;aarch64&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;aarch64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Apple Silicon (Rosetta)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We recommend using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aarch64&lt;/code&gt; version of Java 8 and other dependencies on your Apple Silicon Mac. &lt;a href=&quot;https://www.azul.com/&quot;&gt;Azul Systems&lt;/a&gt; provides a great build of Java 8 for ARM, and you can download it from &lt;a href=&quot;https://www.azul.com/downloads/zulu-community/?os=macos&amp;amp;architecture=arm-64-bit&amp;amp;package=jdk&quot;&gt;here&lt;/a&gt;. If you use the &lt;a href=&quot;https://sdkman.io/&quot;&gt;sdkman&lt;/a&gt; tool, you can install the ARM version of Java 8 using the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;sdk &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;java 8.0.322-zulu
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To check which version of Java 8 you are using, you can run the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; java &lt;span class=&quot;nt&quot;&gt;-version&lt;/span&gt;
openjdk version &lt;span class=&quot;s2&quot;&gt;&quot;1.8.0_&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;XXX&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
OpenJDK Runtime Environment &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Zulu 8.&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;A&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;.&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;B&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;.&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;C&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-CA-macos-aarch64&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Homebrew and Portaudio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The version of portaudio installed by Homebrew will depend on the version of Homebrew that was installed on your computer. By default, Homebrew installs the native (ARM) version, but it is possible to have an x86 version of Homebrew installed (with Rosetta 2). Check which version of Homebrew you are using by running the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; which brew
/opt/homebrew/bin/brew
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An x86 version of Homebrew will return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/brew&lt;/code&gt; instead. If you are running an x86 version of Homebrew, we recommend that you switch to the native version of Homebrew.&lt;/p&gt;

&lt;p&gt;Once you are using the native version of Homebrew, you can install portaudio using the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;portaudio
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can ensure that the correct version of portaudio is installed by running the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file /opt/homebrew/lib/libportaudio.dylib
/opt/homebrew/lib/libportaudio.dylib: Mach-O 64-bit dynamically linked shared library arm64
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt; in the output.&lt;/p&gt;

&lt;h3 id=&quot;running-unet-audio&quot;&gt;Running Unet audio&lt;/h3&gt;

&lt;p&gt;Once you have installed the correct version of Java 8 and portaudio, you can run Unet audio by unzipping the UnetStack 3 Community release and running the following command in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-v3.4.4&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;bin/unet audio
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;accepting-security-permissions-on-macos-for-running-unet-audio&quot;&gt;Accepting Security Permissions on macOS for running Unet audio&lt;/h2&gt;

&lt;p&gt;When you run Unet audio for the first time, macOS will flag the dynamic libraries that Unet audio uses as being from an unidentified developer.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/unetaudio-security.png&quot; alt=&quot;Unet audio Security&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You will need to permit running these libraries. You can do this by going to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System Preferences&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Security &amp;amp; Privacy&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;General&lt;/code&gt; and clicking on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Allow Anyway&lt;/code&gt; next to the message that says that the libraries were blocked from running.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/unetaudio-security-allow.png&quot; alt=&quot;Unet audio Security&quot; width=&quot;70%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When you run Unet audio again, you will be prompted to permit running the libraries. Click on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Open&lt;/code&gt; to permit running the libraries.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/unetaudio-security-open.png&quot; alt=&quot;Unet audio Security&quot; width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You might have to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin/unet audio&lt;/code&gt; command again after permitting the libraries to run. You should only have to do this once, and Unet audio will run without any issues after that.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;small&gt; Photo by &lt;a href=&quot;https://unsplash.com/@alesnesetril?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Ales Nesetril&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/gray-and-black-laptop-computer-on-surface-Im7lZjxeLhg?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt; &lt;small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/p&gt;

</description>
            <pubDate>Wed, 14 Feb 2024 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>A Step-by-Step Guide to Deploying and Operating an Acoustic Modem running UnetStack to Achieve the Best Performance</title>
            <link>/A-Step-by-Step-Guide-to-Deploying-and-Operating-an-Acoustic-Modem-running-UnetStack-to-Achieve-the-Best-Performance</link>
            <guid isPermaLink="true">/A-Step-by-Step-Guide-to-Deploying-and-Operating-an-Acoustic-Modem-running-UnetStack-to-Achieve-the-Best-Performance</guid>
            <description>&lt;p&gt;Deploying and configuring an acoustic modem during a field deployment to achieve the best performance can be a challenging task, especially for those who are new to the process. However, with the right tools and techniques provided with UnetStack, it can be accomplished smoothly and efficiently. In this blog, we will provide you with a step-by-step guide on how to deploy and verify a pair of acoustic modems running UnetStack in the field to ensure that it is working correctly and reliably during field deployment. Whether you are setting up a new pair of acoustic modems or troubleshooting an existing one, this guide will provide you with the essential steps to ensure that your wireless system is up and running correctly.&lt;/p&gt;

&lt;p&gt;Let’s say you are deploying two acoustic modems (modem A and B) in water to establish a communication link between them. For this article, we use the example of a Subnero S60H series acoustic modem. After installing and powering up both modems, you can access the modems’ web interface (over the Ethernet interface) by connecting to their respective IP addresses using a web browser. Once you have logged into the modem’s web interface, the landing dashboard shows the current settings along with a web shell.&lt;/p&gt;

&lt;p align=&quot;center&quot; width=&quot;100%&quot;&gt;
   &lt;img width=&quot;80%&quot; src=&quot;../assets/img/landing.png&quot; /&gt; 
&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Landing dashboard of a Subnero S60H series modem&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Depending on the distance between the devices, the first thing you may want to adjust is the power level setting of the two modems to avoid saturating the receiving modem. There is a slider in the landing page that you can use for this (default value set to -42) or you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl&lt;/code&gt; command in the web shell.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: We recommend using the following power levels (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl&lt;/code&gt;) as the starting values for different distances - 42 to -20 for distances under 10 meters or in air, -20 to -10 for distances between 10 and 100 meters, and -10 and above for distances over 100 meters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;the-ping--tell-commands&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; commands&lt;/h2&gt;

&lt;p&gt;Once the power levels are set, the next thing is to test the basic connectivity between the modems, before tuning them to achieve the best performance. First, note the node address of both the modems which we will be using to address each of them. In this example, modem A has a node address of 100, and modem B’s address is 120.&lt;/p&gt;

&lt;p&gt;Now, we can test the connectivity between both modems using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; command. You can type the following in the web shell of modem A:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; ping 120
PING 120
Response from 120: seq=0 rthops=2 time=13974 ms
Response from 120: seq=1 rthops=2 time=12246 ms
Response from 120: seq=2 rthops=2 time=12478 ms
3 packets transmitted, 3 packets received, 0% packet loss
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This shows that modem A was able to ping modem B and get the response back. It has transmitted 3 ping packets and got a response for all of them.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; command uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTROL&lt;/code&gt; channel, which is the robust communication channel provided by UnetStack, typically used to exchange control information between the modems.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTROL&lt;/code&gt; channel is meant for low-rate robust data transmission, whereas the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt; channel is typically configured for higher-rate data transmission. You can read more about these in the &lt;a href=&quot;https://unetstack.net/handbook&quot;&gt;unet handbook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, most of the actual payload transmissions are done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt; channel. So, our next step is to verify that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt; channel works fine between the modems. This can be achieved using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; command. Type the following command in the web shell of modem A.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; tell 120, &apos;hi!&apos;
AGREE
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On successful reception on modem B, you will see the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[100]: hi!
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can repeat the same from modem B to modem A or use the “Messages” section in the lower right corner of the Overview dashboard. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; command uses a combination of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTROL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt; channels to transfer the payload.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can find more about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; command in section &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.6. Using acoustic modems&lt;/code&gt; in the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook.html&quot;&gt;unet handbook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;file-transfer-using-fput&quot;&gt;File transfer using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fput&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Now that we have a working link, you can transfer data or files between the modems. To transmit data, the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_unetsocket_api.html&quot;&gt;UnetSocket APIs&lt;/a&gt; are a good starting point. These are supported in a variety of languages and levels.&lt;/p&gt;

&lt;p&gt;To transmit a file, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fput&lt;/code&gt; command. First, you will need to enable the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_remote_access.html&quot;&gt;remote agent&lt;/a&gt; in the receiving modem. On modem B, type the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; remote.enable = true
true
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fput&lt;/code&gt; command in modem A to transfer the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abc.txt&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; fput 120, &apos;abc.txt&apos;
AGREE
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Upon completion of the file transfer, you will receive a notification once the transfer is complete on the receiving modem.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;remote &amp;gt;&amp;gt; RemoteFileNtf:INFORM[from:100 filename:abc.txt (4 bytes)]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;speedtest&quot;&gt;Speedtest&lt;/h2&gt;

&lt;p&gt;Once you establish connectivity, you are ready to test the performance of the link. This can be achieved using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speedtest&lt;/code&gt; agent.&lt;/p&gt;

&lt;p&gt;Typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speedtest&lt;/code&gt; on the shell shows the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; speedtest
« SpeedTest »

[org.arl.unet.utils.SpeedTest.Param]
  dutyCycle = 0.5
  nowDuration = 10
  nowput ⤇ 0
  rx ⤇ 0
  throughput ⤇ 0
  tx = 0
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To run a speedtest between the modems, simply type the following on modem A:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; speedtest.tx=100
100
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will run the speedtest with 100 packets with the peer modem.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The value calculated by the speedtest agent is the effective throughput seen by the user which includes the delays between each packet transmission and any lost packets. E.g. if you have a perfect link with no packet loss, the effective throughput will be half of the link rate due to the default value of 0.5 for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dutyCycle&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the test is completed, you can check the throughput using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throughput&lt;/code&gt; parameter.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; speedtest.throughput
12390
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The maximum value of throughput you can achieve is the per-packet signaling rate or link rate that is configured for the device. This can be verified by using the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; uwlink.dataRate
24780.055
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;For more details on each of the parameters, you can use the help text by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;help speedtest&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;tuning-the-link&quot;&gt;Tuning the link&lt;/h2&gt;

&lt;p&gt;Now that you have a working communication link, we want to tune the link to achieve the best performance. There are three ways to do this.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Link Tuner: A link tuner agent will make the required measurements and recommend the setting to achieve the best performance for a given link.&lt;/li&gt;
  &lt;li&gt;Communication Profiles: A set of preset configurations called communication profiles that the user can select from, depending on the environment.&lt;/li&gt;
  &lt;li&gt;Manual tuning: Users have complete control over each of the parameters for a communication scheme that they can modify to achieve the best performance for a given environment. However, this will require an understanding of what each of the parameters means and how they affect communication performance. Hence, this is recommended only for advanced users.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;link-tuner&quot;&gt;Link Tuner&lt;/h3&gt;

&lt;p&gt;The Link Tuner agent automatically makes channel measurements and provides the user with a recommended setting that works best in a given environment. To use the Link Tuner, navigate to the Link Tuner dashboard from the side menu. It shows the current scheme code which is a hexadecimal representation of all the current settings and the current link rate. Click the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tune&lt;/code&gt; button to begin the process. Once it is completed, a new scheme code is recommended that will provide the best performance in a given environment.&lt;/p&gt;

&lt;p align=&quot;center&quot; width=&quot;100%&quot;&gt;
   &lt;img width=&quot;80%&quot; src=&quot;../assets/img/tuner.png&quot; /&gt; 
&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Link Tuner dashboard&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;communication-profiles&quot;&gt;Communication Profiles&lt;/h3&gt;

&lt;p&gt;A communication profile is a set of preconfigured settings that are appropriate for different types of environments. To set a communication profile, navigate to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dashboards&lt;/code&gt; menu and select the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Profiles&lt;/code&gt; link. That will give you the following screen with the supported profiles on your device. You can select one that closely matches the environment that you are working on. Once your chosen profile is set, you can verify that the link speed is updated by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uwlink.dataRate&lt;/code&gt; command. Run the speed test again to verify the effective throughput you can achieve using the new settings.&lt;/p&gt;

&lt;p align=&quot;center&quot; width=&quot;100%&quot;&gt;
   &lt;img width=&quot;80%&quot; src=&quot;../assets/img/profile.png&quot; /&gt; 
&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Communication Profiles dashboard&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;basic-troubleshooting&quot;&gt;Basic Troubleshooting&lt;/h2&gt;

&lt;h3 id=&quot;1-the-landing-dashboard-is-not-loading&quot;&gt;1. The landing dashboard is not loading&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Check the connection to the modem by pinging the modem’s IP address from your laptop.&lt;/li&gt;
  &lt;li&gt;Make sure the modems are powered and the current drawn shown in the power supply corresponds to the published values.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;2-ping-is-not-working&quot;&gt;2. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; is not working&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Try adjusting the power levels of both modems.&lt;/li&gt;
  &lt;li&gt;Try adjusting the deployment depth of the modem as deploying very close to the surface may create challenging environments.&lt;/li&gt;
  &lt;li&gt;Check the logs (from the logs menu) to see if there are any error messages.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;3-tell-is-not-working-ping-is-working&quot;&gt;3. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; is not working (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; is working)&lt;/h3&gt;
&lt;p&gt;This indicates that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTROL&lt;/code&gt; channel is working and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA channel&lt;/code&gt; is having issues.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;You can start with the Link Tuner or use a profile that is configured for a robust link.&lt;/li&gt;
  &lt;li&gt;Try adjusting the power levels.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In general, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logs&lt;/code&gt; or unsolicited notification messages to understand what is going on. This can be achieved by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;subscribe&lt;/code&gt; command. E.g. you can subscribe to physical layer events  by:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; subscribe phy
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will print the various notifications generated by the agent that can be used for troubleshooting. E.g. when receiving packets, the following notifications will be printed in the shell while the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; command is used.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;phy &amp;gt;&amp;gt; RxFrameStartNtf:INFORM[type:CONTROL rxTime:1765508396]
phy &amp;gt;&amp;gt; RxFrameNtf:INFORM[type:CONTROL from:100 rxTime:1765508396]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
            <pubDate>Mon, 03 Apr 2023 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Low-cost DIY underwater modem using COTS components and Unet audio</title>
            <link>/Project-Sabine-Low-cost-DIY-underwater-modem-using-COTS-components-and-Unet-audio</link>
            <guid isPermaLink="true">/Project-Sabine-Low-cost-DIY-underwater-modem-using-COTS-components-and-Unet-audio</guid>
            <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the article titled &lt;a href=&quot;https://blog.unetstack.net/converting-your-laptop-into-a-janus-modem-using-unetaudio&quot;&gt;Converting your laptop into a JANUS modem using Unet audio&lt;/a&gt;, we saw how UnetStack, a Software-Defined Open Architecture Modem (SDOAM), can be used to turn your laptop into an acoustic modem. A true SDOAM can easily be extended to run on various hardware platforms with different types of physical layers (e.g. Acoustic, optical, RF) with minimal efforts to address different use cases. In this article, we will show how you can build a low-cost (&amp;lt; USD 300) , DIY underwater acoustic modem using only Commercial Off-The-Shelf (COTS) components and Unet audio. The goal of this article is to demonstrate the approach and basic steps one can use to build a low cost acoustic modem using Unet audio. We encourage the reader to build on these principles to build your own versions of the DIY modem.&lt;/p&gt;

&lt;h2 id=&quot;motivation-and-approach&quot;&gt;Motivation and Approach&lt;/h2&gt;
&lt;p&gt;Most commercially available modems are beyond the reach of a technology enthusiast or a hobbyist underwater roboticist, due to their price point. However, applications such as DIY underwater vehicles (e.g. for &lt;a href=&quot;https://sauvc.org/&quot;&gt;The Singapore AUV Challenge&lt;/a&gt;), low-cost swarms, etc. need low-cost underwater modems to realize their true potential. While there have been projects like the &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3376921&quot;&gt;AHOI modem&lt;/a&gt;, &lt;a href=&quot;https://ieeexplore.ieee.org/document/7271721&quot;&gt;SeaModem&lt;/a&gt;, &lt;a href=&quot;https://ieeexplore.ieee.org/document/7271578&quot;&gt;Seatrac&lt;/a&gt;, all of them have custom hardware associated with them. This means the user needs to spend time building the hardware, which can be cumbersome and time-consuming. Adding additional hardware to a micro-AUV can be challenging due to space and power limitations. Ensuring long-term support for these can also be tricky, depending on the creator’s other commitments.&lt;/p&gt;

&lt;p&gt;These are some of the challenges for anyone looking to use one of the existing projects to build on.&lt;/p&gt;

&lt;p&gt;Unet audio being a true SDOAM addresses these by using a commonly available hardware platform such as Raspberry Pi and using its sound card to transmit and receive using an underwater speaker and microphone. This approach allows the user to run Unet audio in their single board computer (SBC) thereby avoiding the need for dedicated digital hardware (e.g. SBC, FPGA). The audio amplifiers can then be chosen based on the use case. By using Unet audio, the user gets access to all the developer tools and the extendability to build their protocols on top of the DIY modem. Long term support is guaranteed since UnetStack is actively developed by both academia (&lt;a href=&quot;http://arl.nus.edu.sg/&quot;&gt;ARL&lt;/a&gt;) and industry (&lt;a href=&quot;https://subnero.com/&quot;&gt;Subnero&lt;/a&gt;).&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;iframe width=&quot;720&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/iu5tRlNhxdY&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Workshop on building a DIY underwater modem during &lt;a target=&quot;_blank&quot; href=&quot;https://sauvc.org/&quot;&gt;The Singapore AUV Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-diy-modem&quot;&gt;Overview of the DIY modem&lt;/h2&gt;

&lt;p&gt;A modem has three main functions&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Convert user-given data to a signal and transmit it to the receiver.&lt;/li&gt;
  &lt;li&gt;Decode the signal received at the receiver to recover the original data.&lt;/li&gt;
  &lt;li&gt;Configure various parameters to get the best communication performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To transmit a message, the user can use the various interfaces provided by Unet audio such as the web interface, shell, or various APIs in a variety of computer languages such as Java, Groovy, Python, C, Julia, Javascript, etc. The same interfaces can be used to configure various communication parameters to achieve the best performance in a given environment.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: UnetStack refers to a collection of technologies for extending networks underwater of which Unet audio is one of the components. An interested user may refer to the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_unet_basics.html&quot;&gt;Unet handbook&lt;/a&gt; to gain a deeper understanding of it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The user-provided data is then converted to passband signals in Unet audio. This includes transport and network layer processing (as required), fragmentation and reassembly, forward error correction (FEC), modulation, and demodulation depending on the communication scheme used. The passband signal (digital) is then converted to an analog signal using a sound card and passed through a power amplifier before being fed to the transducer/underwater speaker for transmission through the medium.&lt;/p&gt;

&lt;p&gt;On the receive side, the signal is received using a hydrophone/underwater mic, converted to a digital signal using a sound card’s mic in port, and digitally processed to detect and decode the data from the signal using Unet audio. On successful decoding, the data is passed back to the user. If the decoding fails, an appropriate notification is provided to the user.&lt;/p&gt;

&lt;p&gt;So the main hardware components of an SDOAM will be an SBC to run Unet audio, a sound card (with speaker out and mic in), audio amplifiers, and speaker and mic. The following sections list the hardware chain for both the transmit and receive chains.&lt;/p&gt;

&lt;h3 id=&quot;transmit-chain&quot;&gt;Transmit chain&lt;/h3&gt;

&lt;p&gt;Connect the speaker output from the sound card (either a discrete or USB sound card connected to an SBC) to the amplifier module input. The amplifier output is then connected to the underwater speaker. Depending on the amplifier used, it can be powered using the USB output of the RPi or a 12V battery.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;70%&quot; src=&quot;../assets/img/sabine/txc.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Transmit chain&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;receive-chain&quot;&gt;Receive chain&lt;/h3&gt;

&lt;p&gt;For the receiver side, the underwater microphone is connected directly to the mic in of the soundcard of the SBC.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;70%&quot; src=&quot;../assets/img/sabine/rxc.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Receive chain&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;hardware-selection&quot;&gt;Hardware Selection&lt;/h2&gt;

&lt;h3 id=&quot;digital-hardware&quot;&gt;Digital Hardware&lt;/h3&gt;

&lt;p&gt;One of the most important hardware components of an SDOAM is the digital hardware that runs Unet audio. We have selected a Raspberry Pi (3b+) due to its popularity, low cost, ease of availability, and community support to be the digital hardware to run Unet audio. This can easily be swapped with any similar SBCs that have an arm processor running Linux on it. A &lt;a href=&quot;https://www.aliexpress.com/item/4000598865391.html&quot;&gt;USB sound card&lt;/a&gt; connected to the Raspberry Pi is used as the data acquisition system.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The internal audio output was not used as it is disabled by default during setup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/rpi.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Raspberry Pi&lt;/em&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/sc.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;USB soundcard&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;transmit-chain-1&quot;&gt;Transmit Chain&lt;/h3&gt;

&lt;p&gt;The next step is the selection of the amplifier and the transducer/underwater speaker. To keep the costs down, we have chosen an underwater speaker &lt;a href=&quot;http://www.jiaxiangwang.com/spen/product.htm&quot;&gt;JH001&lt;/a&gt; for the transmitter.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/tx.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;JH001 Underwater Speaker&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most standard TDA series (e.g. TDA2030) mono amplifiers should work fine as the audio amplifier. We have selected the TDA2030A for use with our DIY setup. The user may choose an amplifier that meets your application.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/pa.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Power Amplifier&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;receive-chain-1&quot;&gt;Receive Chain&lt;/h3&gt;

&lt;p&gt;For the receive chain, we have used a simple electret microphone, waterproofed with household materials, connected to the sound card to receive signals.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/mic.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Electret Microphones&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The items used to waterproof the mic are listed below:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Chair bush: To be used as the backing for the mics. Choose a size that fits the electret microphone tightly. These are usually available in local hardware stores.&lt;/li&gt;
  &lt;li&gt;Cling wrap: For waterproofing the front of the electret microphone. The thinner the better.&lt;/li&gt;
  &lt;li&gt;Glue gun with glue stick: Used for waterproofing.&lt;/li&gt;
  &lt;li&gt;3.5mm mono audio jack: Connector for the sound card. If unable to find a mono jack, we can use a standard stereo jack as well. Either use only the left channel or short both the channels. Both schemes work.&lt;/li&gt;
  &lt;li&gt;Wires: To connect the mic to the sound card.&lt;/li&gt;
&lt;/ol&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;70%&quot; src=&quot;../assets/img/sabine/comp.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Components for waterproofing&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;waterproofing&quot;&gt;Waterproofing&lt;/h3&gt;

&lt;p&gt;One of the terminals of the electret microphone is connected to the case and is the ground terminal. Connect that to the audio jack ground. The other terminal is output and is connected to the other two (or one in case of mono) connectors of the audio jack.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;40%&quot; src=&quot;../assets/img/sabine/connect.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Mic pinout&lt;/em&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/cd.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Connection diagram&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To waterproof the microphone, use a chair bush of size that fits tightly around it. Make a hole in the closed part of the bush just large enough for the wire. Put the wire through the hole and then pour a sufficient quantity of hot glue to create a good seal and push in the microphone. The microphone should be pushed in in a way that it protrudes out a bit, just enough for the black diaphragm at the front to protrude out a bit from the bush. Let the hot glue dry.&lt;/p&gt;

&lt;p&gt;Next, wrap some cling wrap to waterproof the front portion. You can pour some hot glue on the outside surface of the bush and then wrap the cling wrap over the front of the microphone making sure that there is no gap between the cling wrap and the black diaphragm. If there is an air gap, then the performance might be affected.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/hydrophone1.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;50%&quot; src=&quot;../assets/img/sabine/hydrophone2.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Waterproofed mic&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;bill-of-materials&quot;&gt;Bill of materials&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Item&lt;/th&gt;
      &lt;th&gt;Qty&lt;/th&gt;
      &lt;th&gt;Cost (USD)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Raspberry Pi&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;129.00&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;USB sound card for RPi&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;0.87&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Power amplifier&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;0.45&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Underwater speaker&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;95.50&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Electret microphone&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;0.99&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3.5mm audio jack&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;1.36&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Bush, glue gun, glue stick, cling wrap,&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;&amp;lt; 20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;292.72&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: It is recommended to get more than 1 for the electret microphone, audio jacks, etc. in case of damage during assembly&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;software-installation&quot;&gt;Software installation&lt;/h2&gt;

&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Raspberry Pi 3+&lt;/li&gt;
  &lt;li&gt;USB Sound Card&lt;/li&gt;
  &lt;li&gt;Headphones/Loudspeaker&lt;/li&gt;
  &lt;li&gt;Microphone&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;/h3&gt;

&lt;h4 id=&quot;os&quot;&gt;OS&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Install the latest &lt;a href=&quot;https://www.raspberrypi.org/software/operating-systems/&quot;&gt;Raspbian&lt;/a&gt; on your Raspberry Pi&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;audio&quot;&gt;Audio&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Plug the USB audio card into your Raspberry Pi&lt;/li&gt;
  &lt;li&gt;Power on your Raspberry Pi&lt;/li&gt;
  &lt;li&gt;Ensure that the USB Audio Card is detected using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aplay -l&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; aplay -l
card 0: ...
card 1: Audio [USB Audio], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol&gt;
  &lt;li&gt;Disable the RaspberyPi onboard sound card, by commenting out the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dtparam=audio=on&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/config.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; sudo nano /boot/config.txt

# Enable audio (loads snd_bcm2835)
# dtparam=audio=on
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Make the USB Audio card the default device in alsa by updating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defaults.ctl.card&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defaults.pcm.card&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/share/alsa/alsa.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;defaults.ctl.card 1
defaults.pcm.card 1
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Reboot your Raspberry Pi and verify that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;card 0:&lt;/code&gt; is not enumerated by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aplay -l&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; aplay -l
card 1: Audio [USB Audio], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;You can test if your audio setup works properly using  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speaker-test -c2&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Install Java8&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;wget https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u265-b01/OpenJDK8U-jdk_arm_linux_hotspot_8u265b01.tar.gz
&lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;xzf OpenJDK8U-jdk_arm_linux_hotspot_8u265b01.tar.gz
&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;jdk8u265-b01/src.zip
&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usr/lib/jvm/java-8-openjdk-armhf
&lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;jdk8u265&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; /usr/lib/jvm/java-8-openjdk-armhf/
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; jdk8u265&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;OpenJDK8U-jdk_arm_linux_hotspot_8u265b01.tar.gz
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-armhf&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/.bashrc
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;export PATH=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;PATH:/usr/lib/jvm/java-8-openjdk-armhf/bin&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/.bashrc
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Download &lt;a href=&quot;http://files.portaudio.com/download.html&quot;&gt;portaudio for Linux&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Build and install &lt;a href=&quot;http://files.portaudio.com/docs/v19-doxydocs/compile_linux.html&quot;&gt;Portaudio&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;libasound-dev

...

./configure &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make

...

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;

...

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;ldconfig

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;run-unetstack&quot;&gt;Run UnetStack&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Get the UnetAudio Community distribution for RaspberryPi from &lt;a href=&quot;https://github.com/org-arl/unet-doc/raw/master/docs/downloads/unet-community-pi-3.1.0.tgz&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Copy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unet-community-3.x.x.tgz&lt;/code&gt; file to the Raspberry Pi&lt;/li&gt;
  &lt;li&gt;Unzip the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tar -xvzf unet-community-pi-3.x.x.tgz&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Go to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/unet-3.x.x&lt;/code&gt; directory&lt;/li&gt;
  &lt;li&gt;Run UnetAudio using  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin/unet -c audio&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will give you a command shell for the user to interact with Unet audio.&lt;/p&gt;

&lt;h2 id=&quot;taking-it-for-a-spin&quot;&gt;Taking it for a spin&lt;/h2&gt;

&lt;p&gt;Once the Raspberry PI is set up as above, connect the various hardware components to form the transmit and receive chains. For our testing, we have one setup for transmission and one for the reception.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;80%&quot; src=&quot;../assets/img/sabine/modem.jpg&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Transmitter and Receiver Components&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once we have both setups ready, we need to make sure we are generating the frequencies that the hardware can transmit. If we look at the frequency response of the underwater speaker (provided by the vendor), we can see that the frequency response is from 2 kHz to 8 kHz.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img width=&quot;80%&quot; src=&quot;../assets/img/sabine/freq.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;em&gt;Frequency response of JH001&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We will need to configure Unet audio to use a frequency band within this space so that the speaker can convert the signals generated by Unet audio to acoustic energy. Unet audio uses frequency hopping &lt;a href=&quot;https://en.wikipedia.org/wiki/Frequency-shift_keying&quot;&gt;BFSK&lt;/a&gt; as its default communication scheme. The default parameters are as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[1]
« PHY »

...

[org.arl.unet.phy.fhbfsk.ModulationParam]
  chiplen = 1
  fmin = 9440
  fstep = 160
  hops = 13
  offset = 0
  sync = true
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first tone denoted by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmin&lt;/code&gt; starts at 9440 Hz, with 13 hops of 160 Hz each. This will be outside the frequency band of our underwater speaker. Hence, we will need to configure it to start after 3.5 kHz and end before 6 kHz. To achieve this, the frequency band of operation will need to be shifted slightly lower. This can be done by setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fc&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6000&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/modem.conf&lt;/code&gt; file (The default value is set to 12000).&lt;/p&gt;

&lt;p&gt;Next, we set the following parameters in the command line.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[1].fmin = 4700
4700
&amp;gt; phy[1].fstep = 80
80
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will need to apply the same settings to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2]&lt;/code&gt; to ensure that the higher layer features utilizing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2]&lt;/code&gt; such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; functions correctly.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[2].fmin = 4700
4700
&amp;gt; phy[2].fstep = 80
80
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will give us a starting frequency of 4700 Hz and a bandwidth of 1920 Hz. Now we are ready to transmit and receive.&lt;/p&gt;

&lt;p&gt;Depending on the environment of deployment, the transmit power level can also be adjusted as follows (A value of 0 denotes the maximum power).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; plvl -15
OK
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To get a notification of a reception, use the following command on the receiver side.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; subscribe phy
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can transmit a simple byte stream of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1,2,3&lt;/code&gt; using the following command on the shell.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy &amp;lt;&amp;lt; new TxFrameReq(data:[1,2,3])
AGREE
phy &amp;gt;&amp;gt; TxFrameNtf:INFORM[type:CONTROL txTime:71663975]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will also be able to hear the transmission from the underwater speaker.&lt;/p&gt;

&lt;p&gt;Once received and decoded, the following message will be printed in the shell of the receiver side.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;phy &amp;gt;&amp;gt; RxFrameStartNtf:INFORM[type:DATA rxTime:79709541 rxDuration:3880000 detector:0.27]
phy &amp;gt;&amp;gt; RxFrameNtf:INFORM[type:CONTROL from:1 rxTime:78466374 rssi:-29.8 cfo:0.0 (3 bytes)]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The data can be verified by typing the following.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; ntf.data
[1, 2, 3]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Congratulations, you have successfully made the first transmission and reception using your DIY acoustic modem.&lt;/p&gt;
</description>
            <pubDate>Wed, 14 Sep 2022 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Synchronizing physical clocks among different UnetStack-based modems</title>
            <link>/Synchronizing-physical-clocks-among-different-UnetStack-based-modems</link>
            <guid isPermaLink="true">/Synchronizing-physical-clocks-among-different-UnetStack-based-modems</guid>
            <description>&lt;p&gt;All UnetStack enabled modems have a Real-time Clock (RTC) to keep track of modem’s system time. A separate microsecond counter is provided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.time&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Physical&lt;/code&gt; agent in UnetStack.&lt;/p&gt;

&lt;p&gt;Although the clock (i.e., the hardware source of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.time&lt;/code&gt;) is reasonably stable, it is impossible to guarantee that all the crystals of different computers will operate at &lt;em&gt;exactly&lt;/em&gt; the same frequency. A crystal oscillator (XO) is an electronic circuit that uses the mechanical resonance of a vibrating piezoelectric crystal to create an electrical signal with the desired frequency. The resonant frequency depends on size, shape, elasticity, and the speed of sound in the material. Due to manufacturing tolerances, these properties are not identical across manufactured crystals, and so different crystals designed for the same nominal frequency produce slightly different frequency signals. Furthermore, as the operating temperature of the crystal changes, its material properties change, and so does its resonant frequency. These differences in frequency are tiny, but over long periods, the differences accumulate and cause the clocks to drift.&lt;/p&gt;

&lt;p&gt;There are different oscillator types that exist to chose from including OCXOs, TCXOs, and XOs. The crystal controlled clock oscillator (XO) is a device that achieves its temperature stability from the quartz crystal’s inherent temperature stability.
A temperature compensated crystal oscillator (TCXO) is a crystal oscillator with a temperature-sensitive reactance circuit in its oscillation loop to compensate the frequency-temperature characteristics inherent to the crystal unit. An OCXO is a crystal oscillator which is temperature controlled by a mini internal oven. This type of oscillator has a temperature controlling circuit to maintain a consistent temperature of the crystal and other key components. OCXOs are typically used when greater temperature stability is required. While this type of oscillator has a tenfold improvement over a TCXO for temperature vs. frequency stability, the OCXO tends to be higher in price and consumes more power.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: For example, UnetStack-based Subnero modems can be optionally upgraded to use &lt;a href=&quot;https://subnero.com/products/sensors.html&quot;&gt;low-drift clocks&lt;/a&gt;. Such clocks provide much better time stability and are suitable for such applications where time synchronization over long periods of time is critical.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, when there is a possibility of clock drift, it is not easy for having multiple spatially separated modems with synchronized physical clocks. So the question arises, if the synchronization of physical clocks across different UnetStack enabled modems is needed, how do we synchronize them with each other?&lt;/p&gt;

&lt;p&gt;There are two major problems to be addressed to synchronize clocks among different modems:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Modems start at different times so there may be a &lt;em&gt;clock offset&lt;/em&gt; as shown in figure below:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/clock/clock-offset.png&quot; alt=&quot;Clock offset between two modems&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Modem clocks tick at different rates causing a &lt;em&gt;clock drift&lt;/em&gt; as shown in figure below:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/clock/clock-drift.png&quot; alt=&quot;Clock drift between two modems&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The 20% clock drift shown in the figure is for illustration purpose only. In practice, the clock drift is expected to be much smaller in parts per million.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;compensating-for-clock-offset&quot;&gt;Compensating for clock offset&lt;/h1&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ranging&lt;/code&gt; agent in UnetStack running on the modem generates the clock offset information based on the message exchanges when range measurement is performed on the modem that initiates ranging. The clock offset between the two modems is populated in the ranging agent’s parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ranging[host(&apos;B&apos;)].offset&lt;/code&gt;. Where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host(&apos;B&apos;)&lt;/code&gt; is the node address of modem B. More details on this can be found &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_ranging_and_synchronization.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once, the clock offset is known, it can be used to adjust the time locally to synchronize the physical time (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.time&lt;/code&gt;). However, if a low-drift clock is not used, there is a possibility that the clocks tick at different rates, and clocks drift faster. Let us take a look at how we can compensate for the clock drift next.&lt;/p&gt;

&lt;h1 id=&quot;compensating-for-clock-drift&quot;&gt;Compensating for clock drift&lt;/h1&gt;

&lt;p&gt;Since the modems might tick at different rates, one modem’s clock may be faster than the other. An example is shown in the figure above where Modem A’s clock is faster than Modem B, i.e., a slope of 1.2 on Modem A’s clock. To compensate for this, the user of the modem can utilize a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib&lt;/code&gt; parameter. This parameter is a multiplier on the physical clock. So its default value is 1. If you set it to 1.2 the clock will run at 1.2x the rate of the actual hardware clock.&lt;/p&gt;

&lt;p&gt;Therefore, to compensate Modem A’s clock to run slower so that it matches Modem B’s clock, we can set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib = 1/1.2 = 0.83&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The users of the modem should make measurements to figure out the nomimal values that they should set for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;an-example-of-calibrating-clock&quot;&gt;An example of calibrating clock&lt;/h1&gt;

&lt;p&gt;We will consider two modems A and B for this example. To synchronize modem A’s clock with the modem B’s clock the following procedure may be followed:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Make a measurement of &lt;em&gt;system time&lt;/em&gt; and &lt;em&gt;physical clock time&lt;/em&gt; on modem A.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To measure system time, open modem’s web shell and type the following:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rtc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To measure physical clock time, open modem’s web shell and type the following:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;time&lt;/span&gt;

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.rtc.getTime()&lt;/code&gt; returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Date&lt;/code&gt; object (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.rtc&lt;/code&gt;). The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.time&lt;/code&gt; returns time in microseconds. Make a record of both these measurements in the same unit.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Repeat Step 1 after 1 hour and make another measurement. This step should be repeated hourly until the desired number of hours.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Plot a graph with measurements of &lt;em&gt;system time&lt;/em&gt; on x-axis and &lt;em&gt;physical clock time&lt;/em&gt; on y-axis.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Fit a straight line among these measurements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Compute the slope of the line, say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mA&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Repeat Steps 1-5 on modem B.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Compute the slope of the line, say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mB&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;To match the clocks to tick at the same rate, set modem A’s clock calibration parameter to following:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clockCalib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mA&lt;/span&gt;

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We show here a simple code snippet to run on two modems (say A &amp;amp; B) to measure the slope and compute the calibration factor to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib&lt;/code&gt; parameter. The code presented makes measurements every hour and runs for 24 hours.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;On modem A&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1 hour in ms&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;phy&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rtc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// compute slope based on measurements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])/(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; 
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;On modem B&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1 hour in ms&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;phy&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;systime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rtc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// compute slope based on measurements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/(systime[noOfMeasurments-1] - systime[0]) /&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slope&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, based on the computed slopes (mA and mB), the modem A’s clock can be set to the following to match the clocks to tick at the same rate:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;phy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clockCalib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mB&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mA&lt;/span&gt;

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The RTCs are long-term synchronized through mechanism such as Network Time Protocol (NTP) and therefore provide stability for clock calibration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;calibrating-clock-without-relying-on-rtc&quot;&gt;Calibrating clock without relying on RTC&lt;/h1&gt;

&lt;p&gt;In the earlier section we relied on NTP to provide stability to the RTC clock which was used as a reference for clock calibration. However, in cases where there is no such means (e.g. NTP) to provide long-term synchronization for RTC, we can measure and compare the clocks of the two modems directly. In this section, we describe through a simple python script on how one can achieve this.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;On user’s machine&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;unetpy&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# open a UnetSocket to modem A
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modemA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnetSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;modemA-IP&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# open a UnetSocket to modem B
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modemB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnetSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;modemB-IP&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# get physical agent ids on modem A and B
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phyA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modemA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;phy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phyB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modemB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;phy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# measure phy.time on both modem A and modem B
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 1 hour in seconds
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;noOfMeasurements&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;phytimeA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;phytimeB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;phytimeA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phyA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;phytimeB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phyB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# compute slope based on measurements
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phytimeB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytimeB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phytimeA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noOfMeasurments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phytimeA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# slope
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now based on the computed slope (m), we can set either modem A or modem B’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clockCalib&lt;/code&gt; parameter to match the clock rate of the other modem. Therefore, we can either set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib = m&lt;/code&gt; on modem A (or) set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.clockCalib = 1/m&lt;/code&gt; on modem B to match the clock rates.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The parameters used in all the code snippets shown in this blog such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interval&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noOfMeasurements&lt;/code&gt; can be varied as per the user’s need. The code snippets are to serve as reference only.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
            <pubDate>Mon, 28 Jun 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Scheduling transmissions intelligently in UnetStack enabled modems</title>
            <link>/intelligent-transmissions</link>
            <guid isPermaLink="true">/intelligent-transmissions</guid>
            <description>&lt;p&gt;UnetStack powered acoustic modems provide extreme flexibility to the user to automate processes such as the transmission of data frames (e.g. position updates) or signals, decision making after the reception, etc. enabling a hands-off approach to test various deployment scenarios. If you are using a program or a script to transmit and receive from your software-defined open architecture acoustic modem (SDOAM), it is often good to know your location (latitude, longitude, and depth), to make decisions such as when to transmit, what power level to use, etc. This is not a big problem if your acoustic modem is deployed in a fixed location. However, if the modem is installed in a mobile underwater asset like an autonomous underwater vehicle (AUV), such decisions are crucial.&lt;/p&gt;

&lt;p&gt;Since transducers are electromechanical devices, transmitting at high power closer to the water surface will cause cavitation that will result in a bad communication link. This may even damage the transducer. Additionally, if you are close to a receiving modem, transmitting at high power may saturate the receiver thereby causing the receiver to not being able to decipher your messages.&lt;/p&gt;

&lt;p&gt;Some SDOAMs like the Subnero modems in &lt;a href=&quot;https://subnero.com/products/wnc-m25mss3.html&quot;&gt;standalone configuration&lt;/a&gt; come with a depth sensor (with the option to add more sensors like &lt;a href=&quot;https://subnero.com/products/sensors.html&quot;&gt;GPS, compass&lt;/a&gt; etc.). Let us take a look at how a user would use this information to decide when to transmit and when not to, from a modem that is installed in an AUV.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;../assets/img/intelligent/auv.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;Figure 1: AUV internal connection&lt;/p&gt;

&lt;p&gt;Figure 1 shows our assumptions on how the various components are connected within the AUV for this article. A single-board computer (SBC) in the AUV is connected to the modem over an Ethernet interface. Both the AUV’s SBC and the modem are in the same network.&lt;/p&gt;

&lt;p&gt;To start with, let us assume the user would like to send periodic updates from AUV as a broadcast message. There are mainly two ways to do this.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Run a program in the SBC and connect to the modem using a UnetStack Gateway to send periodic commands to the modem, using Unet socket APIs. This can be done using any of the programming languages supported by UnetStack such as C, Java, Groovy, Python, Julia, etc. as detailed &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_unetsocket_api.html&quot;&gt;here&lt;/a&gt;. In this case, the user has access to various sensors of the AUV directly.&lt;/li&gt;
  &lt;li&gt;Running a groovy script in the modem to do the periodic transmissions. The advantage of this method is that you now have direct access to the modem and can deploy your own &lt;a href=&quot;https://github.com/org-arl/fjage&quot;&gt;fjåge&lt;/a&gt; agents. This is a lot more flexible as compared to what is offered by the APIs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To send a simple broadcast message once, you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tell&lt;/code&gt; command as follows.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;tell&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;OK&apos;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To execute this from a script, you can create a new file from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt; tab in the UnetStack’s web interface.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;../assets/img/intelligent/script-ui.png&quot; /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;Figure 2. UnetStack&apos;s web interface&lt;/p&gt;

&lt;p&gt;To repeat this 100 times, once every second, the script can be updated to:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tell&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;OK&apos;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The next step is to determine the current depth at which the device is, then decide whether to transmit or not.&lt;/p&gt;

&lt;p&gt;In UnetStack, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NODE_INFO&lt;/code&gt; service provides a single place to collate node-related information that is commonly needed by many agents. One of the parameters of this service is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; which tracks the location of the modem are (x, y, z) in meters if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin&lt;/code&gt; set, otherwise (latitude, longitude, z). If your modem has a depth sensor, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;z&lt;/code&gt; value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node.location&lt;/code&gt; contains the depth information. You can update the script to transmit only at a depth less than -2 m, as follows.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tell&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;OK&apos;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: Depth is indicated as 0 (at water surface), -1 (1 m below the water surface), -2 (2 m below the water surface), and so on. See &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_setting_up_small_networks.html#_node_locations_coordinate_systems&quot;&gt;Section 5.6&lt;/a&gt; of the unet handbook for a discussion on origin, location, and coordinate systems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What if your modem does not have a depth sensor (e.g. &lt;a href=&quot;https://subnero.com/products/wnc-m25mse3.html&quot;&gt;embedded configuration&lt;/a&gt;) and you would like to use the sensor data from your AUV? In this case, you will have to run a program in the AUV’s SBC to get the location data from AUV’s sensors and use Unet socket APIs to update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node.location&lt;/code&gt; parameter, periodically. A pseudo-code (in python) for doing this is as follows.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;unetpy&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;modem IP&apos;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Open a unet socket connection to modem
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnetSocket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Get the agent which provide NODE_INFO service
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;agentForService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NODE_INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Update depth when available
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Close the socket
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above code can easily be adapted in other languages such as C. A pseudo-code (in C) for the same is as follows:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;#define BUF_SIZE 12
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;unetsocket_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fjage_aid_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1100&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modem&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IP&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Open a unet socket connection to modem&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unetsocket_open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fjage_gw_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unetsocket_get_gateway&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Get the agent which provides SHELL service&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fjage_aid_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unetsocket_agent_for_service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;org.arl.fjage.shell.Services.SHELL&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Update depth when available&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_auv_depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// NOTE: get_auv_depth(), get_auv_lat(), get_auv_lon() to be implemented by user&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;snprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;snprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;snprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BUF_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_auv_lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;asprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;node.location=[%s, %s, %s]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fjage_msg_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fjage_msg_create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;org.arl.fjage.shell.ShellExecReq&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FJAGE_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fjage_msg_set_recipient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fjage_msg_add_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cmd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fjage_msg_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fjage_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fjage_msg_destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fjage_aid_destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Close the socket&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;unetsocket_close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The user will have to replace the above code with appropriate function calls to get the AUV sensor data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above examples can easily be adapted to check the range to a receiver (using &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_ranging_and_synchronization.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range&lt;/code&gt;&lt;/a&gt; command) and adjust the transmit power level accordingly, to avoid saturating a receiver.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While acoustic modems were traditionally used as simple devices to transmit and receive data, UnetStack enabled SDOAMs to provide features to intelligently manage transmission and reception of data frames as well as signals based on various deployment scenarios.&lt;/p&gt;
</description>
            <pubDate>Mon, 31 May 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Simulating motion in Unet Simulator</title>
            <link>/motion-models</link>
            <guid isPermaLink="true">/motion-models</guid>
            <description>&lt;p&gt;The Unet simulator supports various ways of simulating the motion of the simulated nodes, from simple dynamics models to completely custom functions that can generate motion updates. Let’s look at how one can go about simulating the motion of nodes in the Unet Simulator.&lt;/p&gt;

&lt;h2 id=&quot;dynamics-model&quot;&gt;Dynamics Model&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_node_information.html&quot;&gt;NodeInfo&lt;/a&gt; agent (which is typically run in each simulated node) implements a basic dynamics model. The functionality can be turned on using the &lt;a href=&quot;https://unetstack.net/javadoc/3.2/org/arl/unet/nodeinfo/NodeInfo.html#setMobility(boolean)&quot;&gt;mobility parameter&lt;/a&gt; which can be set in a simulation script or directly on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; agent in a running simulation.&lt;/p&gt;

&lt;p&gt;When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mobility&lt;/code&gt; is enabled, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; agent automatically updates its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; parameter based on motion parameters such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speed&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heading&lt;/code&gt; using the simple dynamics model. This can be handy to simulate the motion of a node, for example, an AUV swimming away from an underwater modem.&lt;/p&gt;

&lt;p&gt;Let’s try this out by manually updating the parameters of one of the nodes in a simulation, using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2-node-network&lt;/code&gt; example from Unet IDE. The map view of the IDE can be used to visualize the motion of the nodes. Connect to the WebShell of Node B and set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mobility&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heading&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speed&lt;/code&gt; parameters. As the simulation continues, the location of Node B will continue to be updated based on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;speed&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heading&lt;/code&gt; that you set.&lt;/p&gt;

&lt;p&gt;For example, setting these values in the shell will cause the simulated node to as shown in the map view.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// On Node B&apos;s shell, set heading to 45deg and speed to 10m/s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mobility&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;heading&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;assets/img/mobility/node.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Most &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_modems_and_channel_models.html#_channel_models&quot;&gt;channel models&lt;/a&gt; in UnetStack take into account the distance between the nodes for calculating successful receptions. Hence simulating the motion of nodes in a network simulation can be very useful to measure and verify network behavior and performance more accurately.&lt;/p&gt;

&lt;h2 id=&quot;setpoints&quot;&gt;Setpoints&lt;/h2&gt;

&lt;p&gt;While the NodeInfo agent only exposes a basic dynamics model, the Unet simulation scripts allow for much more control by letting the user set a series of Setpoints of motion parameters on a node. This is done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motionModel&lt;/code&gt; parameter on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt; Object in the simulation script. The Unet Handbook has a few examples of this in &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_writing_simulation_scripts.html#_node_mobility&quot;&gt;Chapter 30&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motionModel&lt;/code&gt; to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Maps&lt;/code&gt; with various motion properties for each of the Setpoint will automatically set the properties onto the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; agent in the simulated node at/for the appropriate time/duration. This in turn drives the dynamics model in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; agent, giving the interpolated location between the Setpoints.&lt;/p&gt;

&lt;p&gt;For example, a node moving in a square can be simulated using this simulation script using 4 Setpoints in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2-node-network&lt;/code&gt; example. Note that the motion automatically stops after the last Setpoint.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;web:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8082&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;api:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1102&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;stack:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;$home/etc/setup&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;mobility:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;motionModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;time:&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;heading:&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;time:&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;heading:&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;time:&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;heading:&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;time:&lt;/span&gt;     &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;heading:&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;assets/img/mobility/list.jpg&quot; alt=&quot;list&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The utility method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MotionModel.lawnmower&lt;/code&gt; helps to generate this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&lt;/code&gt; for a set of Setpoint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Map&lt;/code&gt; of properties for a lawnmower pattern of motion.&lt;/p&gt;

&lt;h2 id=&quot;custom-motion-model&quot;&gt;Custom motion model&lt;/h2&gt;

&lt;p&gt;Finally, if even more fine-grained motion control is required, one can set the property &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motionModel&lt;/code&gt; of the simulated node to a Groovy &lt;a href=&quot;https://groovy-lang.org/closures.html&quot;&gt;Closure&lt;/a&gt;. The closure is called by the simulator with the current simulation timestamp and is expected to return a single Setpoint in form of a Groovy &lt;a href=&quot;https://groovy-lang.org/groovy-dev-kit.html#Collections-Maps&quot;&gt;Map&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, a similar logic to a square pattern can be implemented with this closure assigned to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motionModel&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2-node-network&lt;/code&gt; example.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;web:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8082&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;api:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1102&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;stack:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;$home/etc/setup&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;mobility:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;motionModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;duration:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;heading&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;heading&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;heading&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;heading&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deg&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setpoint&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: Once a Setpoint is returned with its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;duration&lt;/code&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;, then it is assumed that the motion is complete and the simulator will stop calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;motionModel&lt;/code&gt; closure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;assets/img/mobility/closure.jpg&quot; alt=&quot;closure&quot; /&gt;&lt;/p&gt;

&lt;p&gt;More complex logic can also be implemented inside such closures including communicating with other Agents and even other nodes.&lt;/p&gt;

&lt;p&gt;Finally, the closure based approach can also allow one to override the builtin dynamics model in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; agent by simply returning a Setpoint with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; property which will allow the location of the node to be updated directly from the closure instead of going through the dynamics model. In such a mode, however, since there is no interpolation of motion parameters, the duration of each Setpoint would have to be small.&lt;/p&gt;

&lt;p&gt;For example, we can implement a similar pattern as our first example by updating the location of the node every second.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;km&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;web:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8082&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;api:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1102&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;stack:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;$home/etc/setup&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;mobility:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;motionModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; 
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agentForService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;arl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;unet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;NODE_INFO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;duration:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
            <pubDate>Tue, 27 Apr 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Frequency band control using UnetStack</title>
            <link>/frequency-band-control-in-unetstack</link>
            <guid isPermaLink="true">/frequency-band-control-in-unetstack</guid>
            <description>&lt;p&gt;Acoustic modems transmit physical sound waves via a transducer, typically a piezoelectric device. Such sound emitters have an ideal resonance frequency &lt;em&gt;F&lt;/em&gt; and a &lt;em&gt;Q&lt;/em&gt; factor of the order of 0.3. This means that the efficient region of the frequencies it can transmit centers around the resonance frequency with a bandwidth of about &lt;em&gt;0.3 x F&lt;/em&gt;. &lt;em&gt;Q&lt;/em&gt; may be higher or lower depending on the exact transducer.&lt;/p&gt;

&lt;p&gt;The transducer in the Subnero &lt;a href=&quot;https://subnero.com/products/modem.html&quot;&gt;M25M series&lt;/a&gt; modems has a resonance close to 26 kHz. The computationally possible bandwidth is 24 kHz, but not all of this bandwidth is feasible for the transducer. Thus the recommended default bandwidth is B = 12 kHz, which is half of the total possible. Thus an effective transmit modulation scheme can be set such that the center &lt;em&gt;C = 26 kHz&lt;/em&gt; and &lt;em&gt;B = 12 kHz&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Another reason may be due to acoustic underwater channel characteristics. A most basic property is that higher frequencies get absorbed more and in general have a lower transmission range. For this or other reasons related to the channel, the modem user may want to customize the frequencies transmitted by the modem.&lt;/p&gt;

&lt;p&gt;Multiple Access is another case where users may want to control the band used in each modem. One common multiple access method is Frequency Domain Multiple Access (FDMA). In this scheme, different modems or modem pairs may be allocated a different frequency band for transmission to avoid a collision. Simultaneous transmission-reception by two or more different and colocated modem pairs is possible using FDMA.&lt;/p&gt;

&lt;p&gt;Sometimes, there may be a frequency band the user may want to exclude from usage, due to it being occupied by other sources, noise, etc.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The reader may wish to install Unet audio and try out some basic examples in the following sections.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;ofdm-frequency-band-control&quot;&gt;OFDM frequency band control&lt;/h2&gt;

&lt;p&gt;OFDM is one of the main modulation schemes provided with UnetStack-based modems. It is the default DATA channel in UnetStack modems. Controlling the bandwidth and center of the frequency band used is very simple for this scheme.&lt;/p&gt;

&lt;p&gt;OFDM uses several carriers to modulate the baseband data and the number is specified via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2].nc&lt;/code&gt;. These carriers span the total available bandwidth (24 kHz for Medium Frequency Subnero modem variants), i.e., from 12 kHz to 36 kHz.&lt;/p&gt;

&lt;p&gt;The parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2].bw&lt;/code&gt;. controls a reduction in the usage of this total bandwidth. I.e., if we specify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2].bw = 0.5&lt;/code&gt;, it reduces the bandwidth used by half, i.e, 24 kHz / 2 = 12 kHz.&lt;/p&gt;

&lt;p&gt;The other parameter involved in bandwidth control is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2].dc0&lt;/code&gt;. This controls the starting carrier number.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dc0 &amp;gt;= -nc/2 || dc0 &amp;lt;= nc/2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This can be used to shift the center of the frequency band “left” or “right”.&lt;/p&gt;

&lt;p&gt;As mentioned above, to set the band to match the transducer, we need C = 26 kHz and B = 12 kHz.&lt;/p&gt;

&lt;p&gt;The default modem parameters are set as follows to achieve this.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[2]
  ...
  bw = 0.5
  dc0 = 85
  nc = 1024
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.dc0=85&lt;/code&gt; shifts the center by approximately 2000 Hz. Carriers go from -512 to +512 to span the band from 12 kHz to 36 kHz. &lt;em&gt;85/512 ~= 1/6&lt;/em&gt;, so the center will shift roughly by 1/6 of 12 kHz = 2000 Hz (the positive half band) to 26 kHz from 24 kHz.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[2].bw = 0.5&lt;/code&gt; will reduce the active carriers by half, so a bandwidth of 12 kHz. Thus together, the used bandwidth will go from 20kHz to 32kHz.&lt;/p&gt;

&lt;p&gt;For Unet audio, the same settings will shift the center by 1 kHz to 13 kHz with a bandwidth of 6 kHz. Therefore from 10kHz to 16kHz, this is seen below (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl = -25&lt;/code&gt;, trigger -70, may vary for user).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;./assets/img/freqBandControl/ofdm-psd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that if there is a frequency band to be avoided, we can position the used band to the “left” or “right” of it by adjusting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nc&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dc0&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bw&lt;/code&gt;. Note that going far away from the ideal transducer resonance region will reduce transmission efficiency.&lt;/p&gt;

&lt;p&gt;The usage and meaning of parameters can be found in &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook.html#_command_reference&quot;&gt;Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;fhbfsk-frequency-band-control&quot;&gt;FHBFSK frequency band control&lt;/h2&gt;

&lt;p&gt;For FHBFSK scheme, the parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[3].fmin&lt;/code&gt; specifies the starting frequency. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[3].fstep&lt;/code&gt; specifies the frequency steps and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[3].hops&lt;/code&gt; the total number of frequencies used.&lt;/p&gt;

&lt;p&gt;By default, you may see in the Unet audio modem&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3]
  ...
  fmin = 9520.0
  fstep = 160.0
  hops = 13
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So it starts from 9520 Hz and goes to &lt;em&gt;9520 + 160 x (13-1) x 2  = 13360 Hz&lt;/em&gt; as seen below. 
The effective bandwidth can be roughly taken as &lt;em&gt;fstep x hops x 2&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/freqBandControl/fhbfsk-psd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can alter the above parameters to use a band anywhere between 6 kHz and 18 kHz, which is the computationally feasible band of the Unet audio modem.&lt;/p&gt;

&lt;p&gt;Note that just as in OFDM, if there is a frequency band to be avoided, we can position the used band to the “left” or “right” of it by adjusting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmin&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstep&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hops&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The default CONTROL channel in UnetStack-based modems is such an FHBFSK scheme.&lt;/p&gt;

&lt;h2 id=&quot;control-of-preamble-bandwidth&quot;&gt;Control of Preamble bandwidth&lt;/h2&gt;

&lt;p&gt;To complete the picture of bandwidth control, it must be noted that the signal that is transmitted not only has a data modulated portion, but also a detection preamble at the start. This is usually a signal that has good autocorrelation properties like a pseudo-random noise signal or m-sequences, hyperbolic chirp (HFM), etc.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://unetstack.net/javadoc/3.3/org/arl/yoda/Preamble.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Preamble&lt;/code&gt; class&lt;/a&gt; provides both the above types of preambles via the methods such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mseq(..)&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hfmUpSweep(..)&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hfmDownSweep(..)&lt;/code&gt;. It allows controlling the bandwidth and center frequency of the preamble.&lt;/p&gt;

&lt;p&gt;Let’s look at one of them&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;public static Preamble hfmDownSweep(int len, int sps, float fc)
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len&lt;/code&gt; is the number of baseband samples&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sps&lt;/code&gt; controls the bandwidth
Preamble bandwidth = baseband bandwidth/sps. Note that sps must be an integer.
Thus for Unet audio, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sps = 4&lt;/code&gt; creates a bandwidth of &lt;em&gt;12 kHz / 4 = 3 kHz&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fc&lt;/code&gt; controls the center frequency. This is normalized to the baseband rate. So for Unet audio, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fc = 0.25&lt;/code&gt; will shift the carrier by &lt;em&gt;12 kHz x 0.25 = 3 kHz&lt;/em&gt;. i.e., from 12 kHz to 15 kHz.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E.g., the following creates an HFM down sweep signal with 1000 baseband samples, a bandwidth of 3 kHz, centered at 15 kHz.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3].preamble = org.arl.yoda.Preamble.hfmDownSweep(1000, 4, 0.25)
(1000 samples)

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To transmit this preamble alone (with no additional signal)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy &amp;lt;&amp;lt; new TxBasebandSignalReq(preamble: 3)
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the Diagnostic Scope dashboard, let us look at the passband PSD. With an appropriate trigger, you may get something as follows. It clearly shows the center of 15 kHz and the bandwidth of 3 kHz.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/freqBandControl/preamble.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The user can also generate and set custom preambles.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: Details of the custom preamble are available in section 16.4. Transmitting and detecting preambles` of the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_baseband_service.html&quot;&gt;Unet handbook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There is a need to control the frequency band of operation in acoustic modems and we have seen how easy it is to control it in both OFDM and FHBFSK schemes in the UnetStack-based modems.&lt;/p&gt;
</description>
            <pubDate>Wed, 21 Apr 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>What&apos;s new in UnetStack 3.3?</title>
            <link>/whats-new-in-UnetStack-3.3</link>
            <guid isPermaLink="true">/whats-new-in-UnetStack-3.3</guid>
            <description>&lt;p&gt;It is April again, and that means it is time for the next release of UnetStack! We are excited to bring several new features to you – a new JSON event logging framework for automated analysis of multi-agent protocols, support for signal strength and ambient noise level reporting in the Unet simulator, and experimental support for Julia agents! In addition, UnetStack 3.3 also incorporates numerous enhancements, bug fixes and performance improvements.&lt;/p&gt;

&lt;!--p style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://youtu.be/qFEYA1DlffI&quot; target=&quot;_blank&quot; style=&quot;font-size: 20px; text-decoration: none;&quot;&gt;[ Watch a short video about what&apos;s new in UnetStack 3.3 ]&lt;/a&gt;&lt;/p--&gt;

&lt;p&gt;Let’s take a brief look at the key new and exciting features:&lt;/p&gt;

&lt;h4 id=&quot;1-json-event-tracing-framework&quot;&gt;1. JSON event tracing framework&lt;/h4&gt;

&lt;p&gt;When Unet simulator was first developed, we adopted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace.nam&lt;/code&gt; file format from NS2 for event logging, since many users in the community were already familiar with it. While it served its purpose in the initial days, as agents became more sophisticated and interactions between agents more complicated, we received feedback from many users that they wanted a richer trace format that can be used for automated analysis of multi-agent protocols. We are happy to announce a new JSON trace format that provides a much richer trace that can be easily analyzed using most modern languages with JSON support.&lt;/p&gt;

&lt;p&gt;When running a simulation, a JSON trace file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace.json&lt;/code&gt; is automatically generated in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logs&lt;/code&gt; folder. This file contains a detailed trace for every event in the network stack, on each node. You can even enable trace file generation on real modems and other Unet nodes (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventTracer.enable()&lt;/code&gt;), and later combine the traces from multiple nodes to analyze network protocol operation and performance.&lt;/p&gt;

&lt;p&gt;A small extract from a typical trace file is shown below:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EventTrace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;events&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SIMULATION 1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;events&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1617877446718&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arp::org.arl.unet.addr.AddressResolution/B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;threadID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0bfb305d-4920-4df0-af95-5282b048b5ec&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stimulus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;clazz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.arl.unet.addr.AddressAllocReq&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;messageID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0bfb305d-4920-4df0-af95-5282b048b5ec&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;performative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;REQUEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sender&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;recipient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;response&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;clazz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.arl.unet.addr.AddressAllocRsp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;messageID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;3e421e28-89ca-44ec-bc65-16cc404d3703&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;performative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFORM&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;recipient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1617877446718&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arp::org.arl.unet.addr.AddressResolution/A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;threadID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;04f5b1b9-9178-4e27-aae7-e2a0c4ffcd89&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stimulus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;clazz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.arl.unet.addr.AddressAllocReq&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;messageID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;04f5b1b9-9178-4e27-aae7-e2a0c4ffcd89&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;performative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;REQUEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sender&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;recipient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;response&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;clazz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.arl.unet.addr.AddressAllocRsp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;messageID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e0fe806d-625d-4261-b24c-6655b90cc06a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;performative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFORM&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;recipient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The trace is organized into a hierarchy of groups, each describing a simulation run or the execution of specific commands. A group consists of a sequence of events, with each event providing information on time of event, component (agent running on a node), thread ID, stimulus and response. The stimulus is typically a message received from another agent, and response a message sent to another agent. The thread ID ties multiple events, potentially across multiple agents and nodes, but with the same root cause together.&lt;/p&gt;

&lt;p&gt;Integrating the event tracing framework into your own agents is simple. All you need to do is to wrap messages that you generate in response to a stimulus with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace()&lt;/code&gt; call. Some examples:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stimulus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DatagramDeliveryNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stimulus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stimulus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All the default agents in UnetStack 3.3 are now compliant with the JSON event logging framework.&lt;/p&gt;

&lt;h4 id=&quot;2-automated-trace-analysis-tool-experimental&quot;&gt;2. Automated trace analysis tool (experimental)&lt;/h4&gt;

&lt;p&gt;To illustrate the power of the event logging framework, we have built a simple &lt;a href=&quot;https://github.com/org-arl/unet-contrib/tree/master/tools/viztrace&quot;&gt;viztrace tool&lt;/a&gt; to automatically draw sequence diagrams from a JSON trace file. The tool is written in Julia, and will require a working installation of &lt;a href=&quot;https://julialang.org/downloads/&quot;&gt;Julia&lt;/a&gt; on your machine to run.&lt;/p&gt;

&lt;p&gt;To illustrate the power of the tool, let us simulate a simple &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_getting_started.html&quot;&gt;2-node network&lt;/a&gt; and make a range measurment from node A to B. On node A:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; range host(&apos;B&apos;)
999.99976
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you look in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logs&lt;/code&gt; folder in the simulator, you’ll find a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace.nam&lt;/code&gt; file. We can analyze it using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;viztrace&lt;/code&gt; tool:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;julia &lt;span class=&quot;nt&quot;&gt;--project&lt;/span&gt; viztrace.jl trace.json
Specify a trace:
1: 1617881734525 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;B] AddressAllocReq ⟦ node → arp ⟧ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1 events&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
2: 1617881734525 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;A] AddressAllocReq ⟦ node → arp ⟧ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1 events&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
3: 1617881734531 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;A] AddressResolutionReq ⟦ websh → arp ⟧ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1 events&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
4: 1617881734595 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;A] RangeReq ⟦ websh → ranging ⟧ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;23 events&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So the tool tells us that there are 4 event traces in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace.json&lt;/code&gt; file. The first 2 traces are related to address allocations on nodes B and A. The third trace is an address resolution for node B, when we called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host(&apos;B&apos;)&lt;/code&gt;. The final trace is the actual ranging event, consisting of 23 individual sub-events. Let’s explore that in more detail:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;julia &lt;span class=&quot;nt&quot;&gt;--project&lt;/span&gt; viztrace.jl &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 4 trace.json &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; event4.mmd
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This generates a &lt;a href=&quot;https://mermaid-js.github.io/&quot;&gt;mermaid&lt;/a&gt; sequence diagram for all the events in trace 4:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;sequenceDiagram
  participant websh_A as websh/A
  participant ranging_A as ranging/A
  participant mac_A as mac/A
  participant phy_A as phy/A
  participant phy_B as phy/B
  participant ranging_B as ranging/B
  websh_A-&amp;gt;&amp;gt;ranging_A: RangeReq
  ranging_A--&amp;gt;&amp;gt;websh_A: AGREE
  ranging_A-&amp;gt;&amp;gt;mac_A: ReservationReq
  mac_A-&amp;gt;&amp;gt;ranging_A: ReservationRsp
  mac_A-&amp;gt;&amp;gt;ranging_A: ReservationStatusNtf
  ranging_A-&amp;gt;&amp;gt;phy_A: ClearReq
  phy_A--&amp;gt;&amp;gt;ranging_A: AGREE
  ranging_A-&amp;gt;&amp;gt;phy_A: TxFrameReq
  phy_A--&amp;gt;&amp;gt;ranging_A: AGREE
  phy_A-&amp;gt;&amp;gt;ranging_A: TxFrameNtf
  phy_A-&amp;gt;&amp;gt;phy_B: HalfDuplexModem$TX
  phy_B-&amp;gt;&amp;gt;ranging_B: RxFrameNtf
  ranging_B-&amp;gt;&amp;gt;phy_B: ClearReq
  phy_B--&amp;gt;&amp;gt;ranging_B: AGREE
  ranging_B-&amp;gt;&amp;gt;phy_B: TxFrameReq
  phy_B--&amp;gt;&amp;gt;ranging_B: AGREE
  phy_B-&amp;gt;&amp;gt;ranging_B: TxFrameNtf
  phy_B-&amp;gt;&amp;gt;phy_A: HalfDuplexModem$TX
  phy_A-&amp;gt;&amp;gt;ranging_A: RxFrameNtf
  ranging_A-&amp;gt;&amp;gt;websh_A: RangeNtf
  ranging_A-&amp;gt;&amp;gt;mac_A: ReservationCancelReq
  mac_A--&amp;gt;&amp;gt;ranging_A: AGREE
  mac_A-&amp;gt;&amp;gt;ranging_A: ReservationStatusNtf
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can easily convert this to a nice sequence diagram using the &lt;a href=&quot;https://github.com/mermaid-js/mermaid-cli&quot;&gt;mermaid command-line interface&lt;/a&gt; or the &lt;a href=&quot;https://mermaid-js.github.io/mermaid-live-editor&quot;&gt;mermaid online live editor&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/img/mermaid-diagram-20210408195013.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;3-signal-strength-and-ambient-noise-level-reporting&quot;&gt;3. Signal strength and ambient noise level reporting&lt;/h4&gt;

&lt;p&gt;While most UnetStack-based modems support reporting of ambient noise level and received signal strength indicator (RSSI), the simulated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HalfDuplexModem&lt;/code&gt; in UnetStack did not previously provide this information. With UnetStack 3.3, it does!&lt;/p&gt;

&lt;p&gt;With the simulated &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_getting_started.html&quot;&gt;2-node network&lt;/a&gt;, for example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy.noise
96.1236
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;tells us that the ambient noise level is 96.1 dB. If we subscribe to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; agent on node B and transmit a frame from node A, we see RSSI of 112.4 dB in the notification on node B:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;phy &amp;gt;&amp;gt; RxFrameStartNtf:INFORM[type:CONTROL rxTime:973249369]
phy &amp;gt;&amp;gt; RxFrameNtf:INFORM[type:CONTROL from:232 rxTime:973249369 rssi:112.4]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This information may be useful to agents that automatically adapt transmit power or other link parameters based on signal strength or signal-to-noise ratio.&lt;/p&gt;

&lt;h4 id=&quot;4-julia-agents-experimental&quot;&gt;4. Julia agents (experimental)&lt;/h4&gt;

&lt;p&gt;As we have seen in two previous blog articles (&lt;a href=&quot;/harnessing-the-power-of-julia-in-unetstack&quot;&gt;part I&lt;/a&gt;, &lt;a href=&quot;/custom-phy-in-julia&quot;&gt;part II&lt;/a&gt;), the power of Julia can be harnessed by UnetStack agents via &lt;a href=&quot;https://github.com/org-arl/UnetSockets.jl&quot;&gt;UnetSockets.jl&lt;/a&gt; or the &lt;a href=&quot;https://github.com/org-arl/jajub&quot;&gt;Java-Julia bridge&lt;/a&gt;. While this is great, wouldn’t it be even better if we could write UnetStack agents fully in Julia?&lt;/p&gt;

&lt;p&gt;Well, now you can! We now have experimental support for first-class Julia agents in UnetStack via &lt;a href=&quot;https://github.com/org-arl/Fjage.jl&quot;&gt;Fjage.jl&lt;/a&gt;. Stay tuned for an upcoming blog article on how to write a custom PHY as a first-class Julia agent!&lt;/p&gt;

&lt;h4 id=&quot;5-numerous-other-improvements&quot;&gt;5. Numerous other improvements&lt;/h4&gt;

&lt;p&gt;There are many other enhancements, bug fixes and performance improvements in UnetStack 3.3. While we won’t list of of them explicitly, there are a few enhancements that are worth a passing mention:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeInfo&lt;/code&gt; service parameters for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;roll&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pitch&lt;/code&gt;, allowing UnetStack on autonomous underwater vehicles (AUVs) to use orientation information in making intelligent decisions.&lt;/li&gt;
  &lt;li&gt;On modems supporting low power &lt;em&gt;sleep mode&lt;/em&gt;, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AboutToSleepNtf&lt;/code&gt; message is broadcasted before a modem goes to sleep, enabling agents to do housekeeping before taking a nap.&lt;/li&gt;
  &lt;li&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eternity&lt;/code&gt; as an alias for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forever&lt;/code&gt; for sleep scheduling shell commands.&lt;/li&gt;
  &lt;li&gt;Improved communication performance for UdpLink and acoustic OFDM links.&lt;/li&gt;
  &lt;li&gt;Added support for 32x upsampling and 16x decimation to support additional frequency bands of operation.&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Thu, 01 Apr 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Converting your laptop into a JANUS modem using Unet audio</title>
            <link>/converting-your-laptop-into-a-janus-modem-using-unetaudio</link>
            <guid isPermaLink="true">/converting-your-laptop-into-a-janus-modem-using-unetaudio</guid>
            <description>&lt;p&gt;Imagine you are developing an application for an underwater use case such as messaging or file transfer and you intend to eventually deploy the app on a network of &lt;a href=&quot;http://www.januswiki.com/&quot;&gt;JANUS&lt;/a&gt; compliant modems in the field. Or you may be developing a new routing protocol that is intended to work on a network of JANUS compliant modems. Or you might be a university Professor designing an exercise for your students to learn about underwater communications and networking.&lt;/p&gt;

&lt;p&gt;Along with developing the app or the protocol, a common step is to simulate its performance using simulators like &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_getting_started.html#_setting_up_a_simple_simulated_network&quot;&gt;UnetSim&lt;/a&gt;. However, before deploying the app on actual modems and going to the field for testing, you want to make sure it works on actual devices as intended. If you are in a classroom, having a hardware component that can actually transmit and receive the frames would be extremely useful. This is where &lt;a href=&quot;https://unetstack.net/&quot;&gt;Unet audio&lt;/a&gt; comes in handy.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;iframe width=&quot;720&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/8bR5uV_h5hM&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-is-unet-audio&quot;&gt;What is Unet audio?&lt;/h2&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;../assets/img/unetaudio/unetaudio-logo.png&quot; style=&quot;zoom:50%;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unet audio&lt;/strong&gt; is one of the software-defined open architecture modems (SDOAMs) that is built using UnetStack technologies that let users convert their computers to an acoustic modem. It uses a computer’s sound card (or any sound card attached to a computer) along with its speaker and microphone as the hardware to transmit and receive data or signals as instructed by the user.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;../assets/img/unetaudio/unetaudio-block.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unet audio Block Diagram&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;running-unet-audio&quot;&gt;Running Unet audio&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Make sure your computer meets all the prerequisites as listed in below:
    &lt;ul&gt;
      &lt;li&gt;Operating system: OS X / Linux (x86_64)&lt;/li&gt;
      &lt;li&gt;Software: Java 8 runtime environment&lt;/li&gt;
      &lt;li&gt;Driver: &lt;a href=&quot;http://www.portaudio.com/&quot;&gt;PortAudio&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Browser: Chrome 61+ / Firefox 60+ / Safari 10.1+&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Head to &lt;a href=&quot;www.unetstack.net&quot;&gt;www.unetstack.net&lt;/a&gt; and download a copy of the UnetStack community edition.&lt;/li&gt;
  &lt;li&gt;Untar the zip file, open a terminal in the download’s root folder and type:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; bin/unet audio
Modem web: http://localhost:8080/
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;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:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; tell 0, &apos;hello sea!&apos;
AGREE
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;../assets/img/unetaudio/unetaudio-webif.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You should hear the transmission from your computer speaker! If you don’t, check your speaker volume and try again.&lt;/p&gt;

&lt;p&gt;Great, you have just transmitted a message using the default settings of Unet audio.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: If you have two computers with speakers and microphones, you can run Unet audio on both, and communicate between the two. If you happen to have only one computer handy,  we can get one Unet audio instance to transmit and receive at the same time as detailed in &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_physical_service.html&quot;&gt;section 15.4. Transmitting &amp;amp; receiving using Unet audio&lt;/a&gt; of the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_preface.html&quot;&gt;Unet handbook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;transmitting--receiving-janus-frames&quot;&gt;Transmitting &amp;amp; receiving JANUS frames&lt;/h2&gt;

&lt;p&gt;The physical layer in Unet audio typically supports 3 logical channels . The first two are used for CONTROL and DATA, and the third, by default, is configured as JANUS. The CONTROL channel uses FH-BFSK (frequency-hopping binary frequency shift keying) by default, which is very close to JANUS, but not exactly the same. Let us take a look at the differences between the two and how to make your transmissions fully JANUS compliant.&lt;/p&gt;

&lt;p&gt;If you simply type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; on the web shell, you get a list of physical layer parameters for Unet audio:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy
« Physical layer »

Provides software-defined physical layer communication services (including error detection &amp;amp; correction).

[org.arl.unet.DatagramParam]
  MTU ⤇ 31
  RTU ⤇ 31

[org.arl.unet.phy.PhysicalParam]
  maxPowerLevel ⤇ 0.0
  minPowerLevel ⤇ -138.0
  propagationSpeed = 1500.0
  rxEnable = true

[org.arl.yoda.ModemParam]
  adcrate ⤇ 48000.0
  dacrate ⤇ 96000.0
  fullduplex = false
  loopback = false
  model ⤇ Unet audio
  vendor ⤇ UnetStack
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: For brevity, we have omitted the baseband service, scheduler service parameters and some of the non-relevant parameters in the listings given in this article. Even then, there are many parameters that allow you to configure the SDOAM. We cannot cover each parameter in detail here, but we encourage you to explore the help pages for the parameters by simply typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;help phy&lt;/code&gt; followed by the parameter name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unet audio defines three types of frames:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CONTROL frame = 1&lt;/li&gt;
  &lt;li&gt;DATA frame = 2&lt;/li&gt;
  &lt;li&gt;JANUS frame = 3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get the details of each type of frame, you can use indexed parameters. For getting the details of CONTROL channel, type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[1]&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[CONTROL]&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[1]
« PHY »

[org.arl.unet.phy.PhysicalChannelParam]
  dataRate ⤇ 70.588234
  errorDetection ⤇ true
  fec = 1
  fecList ⤇ [ICONV2]
  frameDuration ⤇ 2.04
  frameLength = 18
  janus = false

[org.arl.yoda.FhbfskParam]
  chiplen = 1
  fmin = 9520.0
  fstep = 160.0
  hops = 13
  scrambler = 0
  sync = true
  tukey = true
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similarly, typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy[3]&lt;/code&gt; will list the parameters of JANUS frame.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3]
« PHY »

[org.arl.unet.phy.PhysicalChannelParam]
  dataRate ⤇ 58.181816
  errorDetection ⤇ true
  fec = 1
  fecList ⤇ [ICONV2]
  frameDuration ⤇ 1.1
  frameLength = 8
  janus = true

[org.arl.yoda.FhbfskParam]
  chiplen = 1
  fmin = 9520.0
  fstep = 160.0
  hops = 13
  scrambler = 0
  sync = true
  tukey = true
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first difference you will notice between the three is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.janus&lt;/code&gt; parameter which is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; for the CONTROL channel and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; for JANUS channel. The settings &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.janus&lt;/code&gt; &amp;amp;  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modulation = fhbfsk&lt;/code&gt; sets up the modulation for JANUS.&lt;/p&gt;

&lt;p&gt;The other key parameters to take note of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmin = 9520.0&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fstep = 160.0&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hops = 13&lt;/code&gt; are the modulation parameters to setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fhbfsk&lt;/code&gt; as required by JANUS.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fec = 7&lt;/code&gt; chooses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICONV2&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fecList&lt;/code&gt;, to set up UnetStack to use the Interleaved Convolution Code (2:1) as required by JANUS&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;threshold = 0.0&lt;/code&gt; indicates that the reception of JANUS frames is disabled by turning off the detector&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice how they are different between the CONTROL channel and the JANUS channel. As a result, the data rate provided by the CONTROL channel is different from that of the JANUS channel.&lt;/p&gt;

&lt;p&gt;To enable JANUS reception, you need to set:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3].threshold = 0.3
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: To avoid detection for other type of frames, you can disable the other two channels by setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;threshold&lt;/code&gt; to zero.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now comes the most exciting part – communicating between two computers using JANUS with Unet audio. First you need to setup you receiving computer to generate notification after a reception by typing:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;subscribe phy
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will show notifications from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; on the shell.&lt;/p&gt;

&lt;p&gt;Next, you can make a JANUS transmission by typing:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy &amp;lt;&amp;lt; new TxJanusFrameReq()
AGREE
phy &amp;gt;&amp;gt; TxFrameNtf:INFORM[type:#3 txTime:127730682]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will transmit a broadcast JANUS frame.&lt;/p&gt;

&lt;p&gt;On the receiving computer, you should see:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;phy &amp;gt;&amp;gt; RxFrameStartNtf:INFORM[type:#3 rxTime:127730375 rxDuration:1100000 detector:0.96]
phy &amp;gt;&amp;gt; RxJanusFrameNtf:INFORM[type:#3 classUserID:0 appType:0 appData:0 mobility:false canForward:true txRxFlag:true rxTime:127730374 rssi:-44.2 cfo:0.0]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;NOTE: The JANUS frame format doesn’t contain user data by default, and so the MTU is 0 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frameLength&lt;/code&gt; of 8 as defined in JANUS specifications). JANUS allows vendors to provide their own “cargo”, and so UnetStack lets you increase the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frameLength&lt;/code&gt; to make space for user data (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MTU&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you would like to add a payload, you can increase the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.frameLength&lt;/code&gt; parameter (default is 8). Let us transmit 1 byte of data.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3].frameLength=9
9
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Data can be added to the transmission by typing:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy &amp;lt;&amp;lt; new TxJanusFrameReq(data:[1])
AGREE
phy &amp;gt;&amp;gt; TxFrameNtf:INFORM[type:#3 txTime:1754760016]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the receiving side:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy &amp;lt;&amp;lt; new TxJanusFrameReq(data:[1])
AGREE
phy &amp;gt;&amp;gt; RxFrameStartNtf:INFORM[type:#3 rxTime:1754759709 rxDuration:1300000 detector:0.96]
phy &amp;gt;&amp;gt; RxJanusFrameNtf:INFORM[type:#3 classUserID:0 appType:0 appData:0 mobility:false canForward:true txRxFlag:true reservationDuration:0.15031052 rxTime:1754759708 rssi:-44.3 cfo:0.0 (1 byte)]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can check the content of the received frame by typing:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; ntf.data
[1]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similarly, if you want to transmit 2 bytes of data, you can set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy.frameLength&lt;/code&gt; parameter to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10&lt;/code&gt; and transmit an array of 2 bytes as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;gt; phy[3].frameLength=10
10
&amp;gt; phy &amp;lt;&amp;lt; new TxJanusFrameReq(data:[1,2])
AGREE
phy &amp;gt;&amp;gt; TxFrameNtf:INFORM[type:#3 txTime:398270432]

&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is that simple to set up an SODAM on your laptop/computer and transmit and receive acoustic communication signals using Unet audio.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Unet audio provides an easy method for researchers, teachers and students to convert their computers to a JANUS compliant SDOAM. Even the cheapest of the underwater acoustic modems comes at a cost and may not be the best option to invest in, if the intended purpose is teaching. Unet audio community edition is free for academic and research use.&lt;/p&gt;

&lt;p&gt;Even if you happen to own some UnetStack compatible acoustic modems, testing with a modem means setting up a dedicated test setup &amp;amp; equipment, access to a water body and dealing with the logistics. With Unet audio, you can develop and test from the comfort of your seat. Additionally, Unet audio provides an SDOAM that covers the frequency band of operation as defined by the JANUS specifications.&lt;/p&gt;

&lt;p&gt;This post only gives you a glimpse of how you can do JANUS transmissions and receptions using Unet audio. There are many more interesting things you can do like transmit and receive the raw baseband signals from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.wav&lt;/code&gt; file and plot a spectrogram to verify the signal is indeed JANUS compliant (&lt;a href=&quot;https://stackoverflow.com/questions/65027940/how-do-i-record-janus-signal-as-wav-file&quot;&gt;as illustrated here&lt;/a&gt;), or setup a network of SDOAMs that uses JANUS as their physical layer.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PpVggzkmwbQ&amp;amp;ab_channel=Subnero&quot;&gt;OCEANS’19 JANUS Tutorial - Highlights Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Sun, 06 Dec 2020 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Harnessing the power of Julia in UnetStack — Part II</title>
            <link>/custom-phy-in-julia</link>
            <guid isPermaLink="true">/custom-phy-in-julia</guid>
            <description>&lt;p&gt;In my previous article on &lt;a href=&quot;/custom-phy&quot;&gt;developing your own acoustic PHY&lt;/a&gt;, I showed you how to develop your own acoustic PHY in Groovy or Java. However, Groovy and Java are not well suited to writing complex mathematical algorithms. Wouldn’t it be nice if we could write the algorithms in Julia instead? In this article, we take the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/MyPhy/MyPhy.groovy&quot;&gt;custom PHY we developed previously&lt;/a&gt;, and replace the signal processing methods with the Julia equivalents. The technique applies not just to PHY agents, and so this article should get you started on leveraging Julia in any UnetStack agents (or for that matter in any Java or Groovy code).&lt;/p&gt;

&lt;h3 id=&quot;java-julia-bridge&quot;&gt;Java-Julia Bridge&lt;/h3&gt;

&lt;p&gt;Julia is a wonderful language to implement mathematical and signal processing algorithms. It solves the &lt;em&gt;two-language problem&lt;/em&gt; by allowing you to write your algorithm in a nice high-level mathematically intuitive style, while generating performant native code that can be used in real-time systems. In the “&lt;a href=&quot;/harnessing-the-power-of-julia-in-unetstack&quot;&gt;Harnessing the power of Julia in UnetStack — Part I&lt;/a&gt;” article, we looked at how to access UnetStack functionality from Julia. In this article, we’ll do the reverse – we’ll explore how to use Julia code in UnetStack agents.&lt;/p&gt;

&lt;p&gt;In order to access Julia’s mathematical prowess from Groovy or Java agents, we need a way to call Julia functions from the JVM. The &lt;a href=&quot;https://github.com/org-arl/jajub&quot;&gt;Java-Julia Bridge (JaJuB)&lt;/a&gt; project provides exactly this functionality, and we’ll leverage it in this article.&lt;/p&gt;

&lt;h3 id=&quot;modulation-and-demodulation&quot;&gt;Modulation and demodulation&lt;/h3&gt;

&lt;p&gt;Recall from my previous article on &lt;a href=&quot;/custom-phy&quot;&gt;developing your own acoustic PHY&lt;/a&gt; that we developed a simple uncoded binary frequency-shift keying (BFSK) implementation in Groovy. While this implementation wasn’t difficult to do, Groovy or Java aren’t ideally suited for mathematical algorithms. So let’s see what the equivalent code would look like in Julia.&lt;/p&gt;

&lt;p&gt;The Groovy modulation code we used was encapsulated within a single method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes2signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// 8 bits/byte, 2 floats/sample&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The equivalent Julia code is this:&lt;/p&gt;
&lt;div class=&quot;language-julia highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt; bytes2signal&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ComplexF32&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;}(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;undef&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Being able to use complex numbers directly in Julia is such a pleasure! While this code isn’t particularly different, as you start implemeting more complex algorithms, you’ll appreciate the different a lot more.&lt;/p&gt;

&lt;p&gt;The Groovy demodulation code we used was in the method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal2bytes()&lt;/code&gt; and a helper method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abs2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;signal2bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/ (2 * SAMPLES_PER_SYMBOL * 8))       /&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// real path of matched filter for f0&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// imaginary path of matched filter for f0&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// real path of matched filter for f1&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// imaginary path of matched filter for f0&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In Julia, we don’t need the helper method, and the complex number calculations become simpler:&lt;/p&gt;
&lt;div class=&quot;language-julia highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt; signal2bytes&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;÷&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int8&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@view&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.*&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;s0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s0&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;x&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;using-jajub-from-our-phy-agent&quot;&gt;Using JaJuB from our PHY agent&lt;/h3&gt;

&lt;p&gt;In order to run the Julia code from our PHY agent, we need to pass it to JaJuB as a string. For a complex piece of code, we might store it in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jl&lt;/code&gt; file and load it as a resource from Groovy, but since our code is simple, we’ll just insert it in our Groovy source code directly. This also enables us to directly insert constants in our Groovy code (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SAMPLES_PER_SYMBOL&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NFREQ&lt;/code&gt;) into the Julia code using Groovy’s string interpolation syntax (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${...}&lt;/code&gt;), rather than have to pass them as arguments to the function.&lt;/p&gt;

&lt;p&gt;The modulation method now looks like this:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;julia_bytes2signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&quot;
  function bytes2signal(buf)
    signal = Array{ComplexF32}(undef, length(buf) * 8 * ${SAMPLES_PER_SYMBOL})
    p = 1
    for b in buf
      for j in 0:7
        bit = (b &amp;gt;&amp;gt; j) &amp;amp; 0x01
        f = bit == 1 ? -${NFREQ} : ${NFREQ}
        signal[p:p+${SAMPLES_PER_SYMBOL-1}] .= cis.(2pi * f * (0:${SAMPLES_PER_SYMBOL-1}))
        p += ${SAMPLES_PER_SYMBOL}
      end
    end
    return signal
  end
&quot;&quot;&quot;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes2signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dims:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[])&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FloatArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bytes2signal&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt; method in Groovy is replaced by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;julia.call()&lt;/code&gt; to the Julia implementation of the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt; defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;julia_bytes2signal&lt;/code&gt;. To pass the byte array to Julia, we need to wrap the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;byte[]&lt;/code&gt; in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteArray&lt;/code&gt; instance provided by JaJuB. The return value from the function is a complex float array, which we get as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FloatArray&lt;/code&gt; instance. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; field of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FloatArray&lt;/code&gt; object is simply the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float[]&lt;/code&gt; that we return from the Groovy method.&lt;/p&gt;

&lt;p&gt;Similarly, we convert the demodulation function to also use the Julia code:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;julia_signal2bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&quot;
  function signal2bytes(signal)
    n = length(signal) ÷ (${SAMPLES_PER_SYMBOL} * 8)
    buf = zeros(Int8, n)
    p = 1
    for i in 1:length(buf)
      for j in 0:7
        s = @view signal[p:p+${SAMPLES_PER_SYMBOL-1}]
        p += ${SAMPLES_PER_SYMBOL}
        x = cis.(2pi * ${NFREQ} .* (0:${SAMPLES_PER_SYMBOL-1}))
        s0 = sum(s .* conj.(x))
        s1 = sum(s .* x)
        if abs(s1) &amp;gt; abs(s0)
          buf[i] = buf[i] | (0x01 &amp;lt;&amp;lt; j)
        end
      end
    end
    return buf
  end
&quot;&quot;&quot;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;signal2bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FloatArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[],&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;dims:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;intdiv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[],&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;isComplex:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByteArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;signal2bytes&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we pass in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FloatArray&lt;/code&gt; representing the complex baseband signal to the Julia function, and get back a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteArray&lt;/code&gt; with the demodulated data.&lt;/p&gt;

&lt;p&gt;Before we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;julia.call()&lt;/code&gt; functionality from JaJuB, we need to initialize Julia. We do this by adding an attribute to our class (after importing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.arl.jajub.*&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JuliaBridge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JuliaBridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and loading the two functions at startup (code inserted in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup()&lt;/code&gt; method):&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;julia_bytes2signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;julia_signal2bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shutdown()&lt;/code&gt; method to our agent to cleanly shutdown Julia when the agent terminates:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;julia&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Thats it!&lt;/p&gt;

&lt;p&gt;The entire modified agent source code can be found in the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/MyPhy/MyJuliaPhy.groovy&quot;&gt;unet-contrib repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;testing-our-custom-julia-phy&quot;&gt;Testing our custom Julia PHY&lt;/h3&gt;

&lt;p&gt;Now that we’ve the modified Julia-based &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent, it is time to try it out on Unet audio. Copy the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/MyPhy/MyJuliaPhy.groovy&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyJuliaPhy.groovy&lt;/code&gt;&lt;/a&gt; file to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classes&lt;/code&gt; folder in &lt;a href=&quot;https://unetstack.net/#downloads&quot;&gt;Unet audio&lt;/a&gt;. Download &lt;a href=&quot;https://repo1.maven.org/maven2/com/github/org-arl/jajub/0.1.0/jajub-0.1.0.jar&quot;&gt;JaJuB jar&lt;/a&gt; and put it in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jars&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;If you don’t already have Julia installed, &lt;a href=&quot;https://julialang.org/downloads/&quot;&gt;download&lt;/a&gt; and install it on your computer and ensure it’s in your PATH.&lt;/p&gt;

&lt;p&gt;Then on the shell:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; phy.fullduplex &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true
true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; container.add &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;, new MyJuliaPhy&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; subscribe phy2
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We turn on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullduplex&lt;/code&gt; so that we can transmit and receive on the same device. We subscribe to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent’s topic so that we see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt; when data is received.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Writing agents in Groovy in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classes&lt;/code&gt; folder of UnetStack is often convenient since Groovy can load the class directly from source, without needing explicit compilation. However, if there are errors in the code, Groovy’s classloader sometimes gives a cryptic “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUG! exception in phase &apos;semantic analysis&apos; in source unit&lt;/code&gt;” error message. If you encounter this, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;groovyc&lt;/code&gt; to get a clearer error report:&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ groovyc -cp lib/unet-framework-3.2.0.jar:lib/fjage-1.8.0.jar:lib/unet-yoda-3.2.0.jar:jars/jajub-0.1.0.jar classes/MyJuliaPhy.groovy&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;and remember to delete off the resultant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyJuliaPhy.class&lt;/code&gt; file to avoid a stale class file being used later accidentally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To test the agent, we make a transmission:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; phy2 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; TxFrameReq(data: [1,2,3])
AGREE
phy2 &amp;gt;&amp;gt; TxFrameNtf:INFORM[txTime:19013099]
phy2 &amp;gt;&amp;gt; RxFrameNtf:INFORM[type:CONTROL from:1 rxTime:19039936 rssi:-49.1 (3 bytes)]
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You should have been able to hear the transmission on your speaker. After a short delay, you’d see the reception (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt;). We check the contents to ensure that we got the correct data back:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ntf.data
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1, 2, 3]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the frame had any errors, you’d have gotten a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BadFrameNtf&lt;/code&gt;. In that case, you may want to try adjusting your computer’s volume setting or transmit power (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl&lt;/code&gt; command), and try again.&lt;/p&gt;

&lt;p&gt;Now that we can transmit and receive correctly, we can enable the rest of the network stack to use our new Julia PHY:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; uwlink.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mac.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ranging.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can send a text message via UnetStack’s remote agent:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; tell 0, &lt;span class=&quot;s1&quot;&gt;&apos;hi&apos;&lt;/span&gt;
AGREE
phy2 &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; RxFrameNtf:INFORM[type:DATA from:1 protocol:3 rxTime:96861353 rssi:-48.7 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;3 bytes&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]: hi
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This resulting datagram goes down the layers of the stack, passed through our new PHY to yield an acoustic signal, gets received by the PHY again to be converted to a datagram, which then goes back up the stack all the way to the remote agent who sends it to the shell for display!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;With Unet audio, Julia calls from Java work seamlessly. However, if you’re running on a real modem, chances are that the modem’s JVM sandbox won’t let you install and run non-JVM code directly. If you have a coprocessor on your modem, you can install Julia on the coprocessor and run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent in a fjåge slave container. Alternatively you can run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent even on your laptop, as long as the laptop is connected over Ethernet to thr modem. To start a slave container, just install Unet audio on the coprocessor/laptop, and start Unet with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin/unet sh &amp;lt;ipaddr&amp;gt; 1100&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;ipaddr&amp;gt;&lt;/code&gt; is replaced by the IP address of your modem, and port 1100 is the API port set on the modem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Developing complex algorithms in Julia is much easier than in Java or Groovy. By leveraging Julia from UnetStack agents, we bring the power of Julia to UnetStack. The custom Julia-based PHY implementation developed in this article demonstrates how easy it is to combine Groovy and Julia code seamlessly.&lt;/p&gt;

&lt;p&gt;I am excited about developing cool new agents in UnetStack using Julia, and I hope you are too!&lt;/p&gt;

</description>
            <pubDate>Sun, 01 Nov 2020 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title>Developing your own acoustic PHY with UnetStack</title>
            <link>/custom-phy</link>
            <guid isPermaLink="true">/custom-phy</guid>
            <description>&lt;p&gt;UnetStack enables software-defined open architecture modems (SDOAMs). While such modems come with one or more implementations of physical layers (PHY) for your use, there are times when you may wish to develop your own PHY. Perhaps it is because you have a special environment that demands a unique PHY, or because you want to interoperate with another modem. Or maybe you just want to try your hands at implementing communication techniques. Whatever the reason, I have often been asked for advice on how to go about writing a custom PHY. In this article, I will walk you through the process of implementing a simple PHY from scratch.&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;In an acoustic communication system, the PHY is responsible for converting data bits into an acoustic signal to be transmitted through the channel, and the received signal back into data bits. In UnetStack based modems, this functionality is usually provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; agent. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; agent implements the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_physical_service.html&quot;&gt;PHYSICAL service&lt;/a&gt;, and other agents such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uwlink&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mac&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ranging&lt;/code&gt; use this service to provide communication and navigation services to the user (and to others agents in the network stack).&lt;/p&gt;

&lt;p&gt;At this point, it may be useful to fire up a &lt;a href=&quot;https://unetstack.net/#downloads&quot;&gt;Unet audio&lt;/a&gt; instance, or connect to a UnetStack powered modem if you’ve one handy.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bin/unet &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; audio
Modem web: http://localhost:8080/
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ps
node: org.arl.unet.nodeinfo.NodeInfo - IDLE
phy: org.arl.yoda.Physical - IDLE
ranging: org.arl.unet.localization.Ranging - IDLE
uwlink: org.arl.unet.link.ReliableLink - IDLE
  ⋮
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; agent among all the agents running on the modem. The Unet audio community edition, as well as most UnetStack based underwater modems (e.g. &lt;a href=&quot;https://subnero.com/products/modem.html&quot;&gt;Subnero M25M series modems&lt;/a&gt;), use Yoda PHY (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.arl.yoda.Physical&lt;/code&gt;) as the default PHY. The Yoda PHY not only provides the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_physical_service.html&quot;&gt;PHYSICAL service&lt;/a&gt;, but also the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_baseband_service.html&quot;&gt;BASEBAND service&lt;/a&gt; and a signal detection capability that we’ll be using shortly.&lt;/p&gt;

&lt;p&gt;Just typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; on the shell tells us more about the active PHY:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; phy
« Physical layer »

Provides software-defined physical layer communication services &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;including error detection &amp;amp; correction&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;org.arl.unet.DatagramParam]
  MTU ⤇ 31
  RTU ⤇ 31

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;org.arl.unet.bb.BasebandParam]
  basebandRate ⤇ 12000.0
  carrierFrequency &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 12000.0
  maxPreambleID ⤇ 4
  maxSignalLength ⤇ 2147483647
  signalPowerLevel &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-42&lt;/span&gt;.0

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;org.arl.unet.phy.PhysicalParam]
  busy ⤇ &lt;span class=&quot;nb&quot;&gt;false
  &lt;/span&gt;maxPowerLevel ⤇ 0.0
  minPowerLevel ⤇ &lt;span class=&quot;nt&quot;&gt;-138&lt;/span&gt;.0
  propagationSpeed &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 1500.0
  refPowerLevel ⤇ 0.0
  rxEnable &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true
  &lt;/span&gt;rxSensitivity ⤇ 0.0
  &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 20157105
  timestampedTxDelay &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 1.0

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;org.arl.yoda.ModemParam]
  adcrate ⤇ 48000.0
  dacrate ⤇ 96000.0
  downconvRatio &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 4.0
  fullduplex &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false
  &lt;/span&gt;upconvRatio ⤇ 8.0
    ⋮
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a lot more parameters, but I’ve only reproduced the ones that might interest us here.&lt;/p&gt;

&lt;p&gt;If we check the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uwlink&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mac&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ranging&lt;/code&gt; agents, we’ll see that they are using this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; agent as their PHY:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; uwlink.phy
phy
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mac.phy
phy
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ranging.phy
phy
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our aim is to write our own custom PHY agent (we’ll call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt;), load it on the modem, and then ask &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uwlink&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mac&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ranging&lt;/code&gt; to use it instead!&lt;/p&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; will use the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_baseband_service.html&quot;&gt;BASEBAND service&lt;/a&gt; provided by Yoda PHY (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt;) to transmit and record acoustic signals. We will also use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; to sense the acoustic channel, accurately timestamp transmissions and receptions, and continuously monitor the acoustic channel for incoming signals. However, we will implement our own frame format and modulation scheme in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We’ll be writing our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent here in Groovy, but you could choose to write yours in Java if you wish. While our example here will be 100% pure Groovy for illustration, you may prefer to &lt;a href=&quot;/custom-phy-in-julia&quot;&gt;develop complex signal processing components in Julia&lt;/a&gt; or C (invoked via &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/jni/&quot;&gt;JNI&lt;/a&gt;) if you need higher performance or access to GPUs.&lt;/p&gt;

&lt;h3 id=&quot;modulation-and-demodulation&quot;&gt;Modulation and demodulation&lt;/h3&gt;

&lt;p&gt;The core component of a PHY implementation is the modulator and demodulator. The modulator converts a sequence of bits into an acoustic signal for transmission through the channel. The demodulator converts a received acoustic signal (noisy distorted version of the transmitted signal) back into the sequence of bits. In UnetStack, the acoustic signals are represented as sampled complex baseband signals. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basebandRate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;carrierFrequency&lt;/code&gt; of the signal were shown when you looked up the parameters of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; earlier. For Unet audio, these are 12 kSa/s and 12 kHz respectively (but they may be different on other modems).&lt;/p&gt;

&lt;p&gt;The focus of this article is to understand how the PHY agent is developed, and so we won’t spend much time on the signal processing. For the purposes of illustration, we will develop a simple low-rate uncoded binary frequency-shift keying (BFSK) scheme. In reality, you’d probably want to use a more performant communication technique, and also include forward error correction coding (FEC).&lt;/p&gt;

&lt;p&gt;For the simple BFSK scheme, we’ll use 150 baseband samples for each bit (symbol). We’ll use frequency &lt;em&gt;f0&lt;/em&gt; to represent a bit 0, and &lt;em&gt;f1&lt;/em&gt; to represent a bit 1:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;f0&lt;/em&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;carrierFrequency&lt;/code&gt; + 1/15 × &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basebandRate&lt;/code&gt;&lt;br /&gt;
&lt;em&gt;f1&lt;/em&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;carrierFrequency&lt;/code&gt; - 1/15 × &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basebandRate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For Unet audio, this will translate to &lt;em&gt;f0&lt;/em&gt; and &lt;em&gt;f1&lt;/em&gt; being 12.8 kHz and 11.2 kHz respectively, and a signaling rate of 80 bps.&lt;/p&gt;

&lt;p&gt;The modulator function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt; takes in a byte array and converts it into a float array representing the baseband acoustic signal. Alternate entries in the float array are real and imaginary parts of each sample. The implementation is fairly straightforward:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bytes2signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// 8 bits/byte, 2 floats/sample&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The demodulator function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal2bytes()&lt;/code&gt; takes in a float array with the received baseband acoustic signal and returns a byte array containing the decoded bits. Bit decisions are taken by running two matched filters for &lt;em&gt;f0&lt;/em&gt; and &lt;em&gt;f1&lt;/em&gt; frequencies, and comparing the output:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;signal2bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/ (2 * SAMPLES_PER_SYMBOL * 8))       /&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// real path of matched filter for f0&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// imaginary path of matched filter for f0&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// real path of matched filter for f1&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// imaginary path of matched filter for f1&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++]&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NFREQ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rclk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iclk&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s0re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s0im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;abs2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second argument &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt; tells the function where in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal&lt;/code&gt; array to start demodulating. This is required because the recorded signal that we will receive from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt; contains an additional detection preamble that we’ll need to skip over.&lt;/p&gt;

&lt;h3 id=&quot;writing-the-agent&quot;&gt;Writing the agent&lt;/h3&gt;

&lt;p&gt;Now that we have our modulator and demodulator functions, we are ready to put together our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent (we call the agent class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyPhy&lt;/code&gt;). If you’re not familar with developing agents, now would be a good time to &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_developing_your_own_agents.html&quot;&gt;familiarize yourself&lt;/a&gt; with the key concepts.&lt;/p&gt;

&lt;p&gt;Any PHY agent needs to implement the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_physical_service.html&quot;&gt;PHYSICAL service&lt;/a&gt; and the &lt;a href=&quot;https://unetstack.net/handbook/unet-handbook_datagram_service.html&quot;&gt;DATAGRAM service&lt;/a&gt;. We’ll limit ourselves to the basic functionality and honor the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameReq&lt;/code&gt; (subclass of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DatagramReq&lt;/code&gt;), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxRawFrameReq&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClearReq&lt;/code&gt; requests. We’ll generate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt; (subcalss of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DatagramNtf&lt;/code&gt;) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BadFrameNtf&lt;/code&gt; notifications. The other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameStartNtf&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameStartNtf&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CollisionNtf&lt;/code&gt; are generated by the Yoda PHY automatically, and we do not need to generate those. We will also need to implement all the parameters in both services.&lt;/p&gt;

&lt;p&gt;Let’s start by registering the services we provide, as well as the parameters we support:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATAGRAM&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PHYSICAL&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getParameterList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatagramParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getParameterList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatagramParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we transmit data, we need to add a header to indicate the source node address, destination node address, data length and protocol number. Additionally, we also include a parity byte for error detection (in practice you may want to use a CRC, but we stick to parity byte for simplicity). We define the header:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// bytes&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDU&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PDU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;parity&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;protocol&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;from&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;to&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;len&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We fix the number of user data bytes in a frame (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MTU&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTU&lt;/code&gt;). These are DATAGRAM service parameters, and we mark them as read-only through the use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;final&lt;/code&gt; modifier:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll be needing the Yoda PHY (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy&lt;/code&gt;) agent often, so we save a reference to it in an attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bbsp&lt;/code&gt; (baseband service provider). We subscribe to notifications from Yoda PHY, and also configure it to provide us acoustic signals when it detects a frame:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AgentID&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;phy&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// Yoda PHY&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;startup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;subscribe&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nsamples&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;modulation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;basebandExtra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nsamples&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;basebandRx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;modulation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;basebandExtra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nsamples&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModemChannelParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;basebandRx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modulation&lt;/code&gt; parameters for both CONTROL and DATA channels to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;none&apos;&lt;/code&gt;, we have instructed Yoda not to process the received frames. By setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basebandRx&lt;/code&gt; parameter to true, we have asked Yoda PHY to send us the baseband signal each time a CONTROL or DATA frame is detected. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basebandExtra&lt;/code&gt; parameter is set to the number of samples in our frame, so that Yoda PHY knows how long a signal to record for us.&lt;/p&gt;

&lt;p&gt;Yoda PHY detects acoustic signals in the channel by detecting unique preamble signals transmitted just before CONTROL and DATA frames. These signals are included in the recordings and therefore our modulated signal starts a few samples into the signal buffer. To find out exactly how long the preamble signals are (can be configured using Yoda PHY parameters), we ask Yoda PHY for a copy of the preamble and extract the length:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getPreambleLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// ndx is Physical.CONTROL or Physical.DATA&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetPreambleSignalReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;recipient:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;preamble:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BasebandSignal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BasebandSignal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;signalLength&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelen&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we implement all the PHYSICAL service parameters by delegating them to Yoda PHY:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// Physical service parameters (read-only) delegated to Yoda PHY&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRefPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getMaxPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;maxPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getMinPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;minPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRxSensitivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rxSensitivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getPropagationSpeed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;propagationSpeed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Long&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;              &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBusy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;busy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRxEnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PhysicalParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rxEnable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also implement the PHYSICAL service indexed parameters:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;// Physical service indexed parameter (read-only)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getMTU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRTU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getFrameLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getMaxFrameLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getFec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// no FEC&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFecList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// FEC not supported&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getErrorDetection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// 8 bits&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getLlr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// LLR not supported&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Physical service indexed dynamic parameters&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lvl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BasebandParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;signalPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lvl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BasebandParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;signalPowerLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getFrameDuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbrate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BasebandParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;basebandRate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbrate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prelen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getPreambleLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prelen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLES_PER_SYMBOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbrate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getDataRate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONTROL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFrameLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFrameDuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;powerLevel&lt;/code&gt; parameter is delegated to Yoda PHY &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signalPowerLevel&lt;/code&gt; since we will ask Yoda PHY to transmit signals for us.&lt;/p&gt;

&lt;p&gt;We often require our node address. Rather than ask the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt; agent each time, we use the UnetStack utility to request and cache the node address:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeAddressCache&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addrCache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeAddressCache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also need to keep a temporarily store pending transmission requests, so that when Yoda PHY informs us that the transmission is complete, we can inform our client (agent who sent us the transmission request) that the transmission was completed:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[:]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To process various requests, we override the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processRequest()&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DatagramReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processDatagramReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TxRawFrameReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processTxRawFrameReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ClearReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ClearReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;recipient:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AGREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We don’t need an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; condition for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameReq&lt;/code&gt;, as it is a subclass of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DatagramReq&lt;/code&gt; and therefore &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processDatagramReq()&lt;/code&gt; will be called when a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameReq&lt;/code&gt; is received.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processTxRawFrameReq()&lt;/code&gt; simply delegates the transmission to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transmit()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processTxRawFrameReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TxRawFrameReq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transmit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AGREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;FAILURE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processDatagramReq()&lt;/code&gt; also delegates transmission to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transmit()&lt;/code&gt; after composing a data frame (PDU) with the required header prepended:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processDatagramReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DatagramReq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addrCache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;address&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;composePDU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TxFrameReq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DATA&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// default to DATA if DatagramReq&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transmit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AGREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;FAILURE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;composePDU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;parity:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;from:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;to:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;len:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MTU&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;arraycopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;arraycopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// compute parity bits&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transmit()&lt;/code&gt; method simply converts the buffer into a signal and makes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxBasebandSignalReq&lt;/code&gt; request to Yoda PHY to do the transmission. It adds the transmission request to the temporary store so that a notification can be sent to the requester when the transmission is completed.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;transmit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes2signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbreq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TxBasebandSignalReq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;recipient:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bbsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;preamble:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;signal:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbreq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;performative&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Performative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AGREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bbreq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;messageID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Incoming transmit notifications and signal receptions are processed by overriding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processMessage()&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;addrCache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TxFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handleTxFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RxBasebandSignalNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handleRxBasebandSignalNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addrCache.update()&lt;/code&gt; call ensures that any node address changes are update to the address cache.&lt;/p&gt;

&lt;p&gt;When a transmission is completed by Yoda PHY, it sends us a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameNtf&lt;/code&gt;. We in turn send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TxFrameNtf&lt;/code&gt; to our client:&lt;/p&gt;
&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handleTxFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TxFrameNtf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pending&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inReplyTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ntf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TxFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ntf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ntf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;txTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;txTime&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ntf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ntf&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a baseband signal is received from Yoda PHY, we process it and convert it to bits. If the parity bits suggest that the frame is error-free, we send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt; for the received frame. In case of errors, we send a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BadFrameNtf&lt;/code&gt; instead. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt; is published on the agent’s default topic if the frame is a BROADCAST or intended for our node address. Otherwise it is published on the agent’s SNOOP topic.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handleRxBasebandSignalNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RxBasebandSignalNtf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal2bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getPreambleLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;preamble&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// compute parity bits&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[])&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;len&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rcpt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;BROADCAST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addrCache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rcpt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;agentID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Physical&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SNOOP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;arraycopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HDRSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RxFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;recipient:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rcpt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;preamble&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;rxTime:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rxTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;rssi:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rssi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;from:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;to:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;send&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BadFrameNtf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;recipient:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;preamble&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;rxTime:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rxTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;location:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;rssi:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;rssi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;The complete implementation (with a few additional error checks) is available from the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/MyPhy/MyPhy.groovy&quot;&gt;unet-contrib repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;testing-our-custom-phy&quot;&gt;Testing our custom PHY&lt;/h3&gt;

&lt;p&gt;Now that we’ve implemented &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent, it is time to try it out on Unet audio or your modem. Copy the &lt;a href=&quot;https://github.com/org-arl/unet-contrib/blob/master/contrib/MyPhy/MyPhy.groovy&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyPhy.groovy&lt;/code&gt;&lt;/a&gt; file to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classes&lt;/code&gt; folder in Unet audio or the modem. Then on the shell:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; phy.fullduplex &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true
true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; container.add &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;, new MyPhy&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; subscribe phy2
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We turn on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullduplex&lt;/code&gt; so that we can transmit and receive on the same device. We subscribe to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent’s topic so that we see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt; when data is received.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Writing agents in Groovy in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classes&lt;/code&gt; folder of UnetStack is often convenient since Groovy can load the class directly from source, without needing explicit compilation. However, if there are errors in the code, Groovy’s classloader sometimes gives a cryptic “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUG! exception in phase &apos;semantic analysis&apos; in source unit&lt;/code&gt;” error message. If you encounter this, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;groovyc&lt;/code&gt; to get a clearer error report:&lt;/p&gt;

  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ groovyc -cp lib/unet-framework-3.2.0.jar:lib/fjage-1.8.0.jar:lib/unet-yoda-3.2.0.jar classes/MyPhy.groovy&lt;/code&gt;&lt;/p&gt;

  &lt;p&gt;and remember to delete off the resultant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyPhy.class&lt;/code&gt; file to avoid a stale class file being used later accidentally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To test the agent, we make a transmission:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; phy2 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; TxFrameReq(data: [1,2,3])
AGREE
phy2 &amp;gt;&amp;gt; TxFrameNtf:INFORM[txTime:19013099]
phy2 &amp;gt;&amp;gt; RxFrameNtf:INFORM[type:CONTROL from:1 rxTime:19039936 rssi:-49.1 (3 bytes)]
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are using Unet audio, you should have been able to hear the transmission on your speaker. After a short delay, you’d see the reception (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RxFrameNtf&lt;/code&gt;). We can check the contents to ensure that we got the correct data back:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ntf.data
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1, 2, 3]
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the frame had any errors, you’d have gotten a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BadFrameNtf&lt;/code&gt;. In that case, you may want to try adjusting your computer’s volume setting (for Unet audio) or transmit power (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plvl&lt;/code&gt; command on Unet audio or modem), and try again.&lt;/p&gt;

&lt;p&gt;Now that we can transmit and receive correctly, we can enable the rest of the network stack to use our new PHY:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; uwlink.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; mac.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ranging.phy &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;phy2&apos;&lt;/span&gt;
phy2
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can send a text message via UnetStack’s remote agent:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; tell 0, &lt;span class=&quot;s1&quot;&gt;&apos;hi&apos;&lt;/span&gt;
AGREE
phy2 &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; RxFrameNtf:INFORM[type:DATA from:1 protocol:3 rxTime:96861353 rssi:-48.7 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;3 bytes&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]: hi
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This resulting datagram goes down the layers of the stack, passed through our new PHY to yield an acoustic signal, gets received by the PHY again to be converted to a datagram, which then goes back up the stack all the way to the remote agent who sends it to the shell for display!&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In this article, we have seen how to write a simple custom PHY agent. We intentionally kept the implementation simple by using an uncoded BFSK communication scheme, as the focus of this article was to illustrate how to implement a custom PHY.&lt;/p&gt;

&lt;p&gt;In a practical system, you may wish to replace the communication scheme (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal2bytes()&lt;/code&gt; methods) with something more sophisticated, including FEC coding. You may also want to use a stronger error detection scheme (CRC rather than parity bits). You’d perhaps also want to consider supporting variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MTU&lt;/code&gt; and some of the optional features of the PHYSICAL service (e.g. timed transmission, timestamping, etc).&lt;/p&gt;

&lt;p&gt;If you find that Java or Groovy doesn’t meet your signal processing needs, you may consider writing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes2signal()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signal2bytes()&lt;/code&gt; methods in C (using &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/jni/&quot;&gt;JNI&lt;/a&gt;) or &lt;a href=&quot;/custom-phy-in-julia&quot;&gt;in Julia&lt;/a&gt; (my preferred choice!).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;With Unet audio, C or Julia calls from Java work seamlessly. However, if you’re running on a real modem, chances are that the modem’s JVM sandbox won’t let you run non-JVM code directly. If you have a coprocessor on your modem, you can run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent on the coprocessor in a fjåge slave container, and you will have no JVM sandbox restrictions. Alternatively you can run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phy2&lt;/code&gt; agent even on your laptop, as long as the laptop is connected over Ethernet to thr modem. To start a slave container, just install Unet audio on the coprocessor/laptop, and start Unet with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin/unet sh &amp;lt;ipaddr&amp;gt; 1100&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;ipaddr&amp;gt;&lt;/code&gt; is replaced by the IP address of your modem, and port 1100 is the API port set on the modem.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
            <pubDate>Sat, 31 Oct 2020 00:00:00 +0000</pubDate>
        </item>
        
    </channel>
</rss>