The BASEBAND service exposes the modem as a software-defined modem, giving direct access to the raw acoustic waveforms beneath the framing and modulation of the physical layer (Chapter 17). This makes it possible to develop and test custom acoustic communication and signal processing techniques without building new hardware.
The service supports three basic operations:
Transmitting an arbitrary signal, using a TxBasebandSignalReq. The signal may be specified at passband (real samples) or baseband (complex samples around a carrier frequency fc), and an optional preamble may be prepended for detection at the receiver.
Recording a signal from the channel, using a RecordBasebandSignalReq. The recording can be scheduled to start at a precise time, and is returned as an RxBasebandSignalNtf.
Detecting signals passively. When a configured detector (for example, a matched filter for a known preamble) fires, a DetectionNtf is generated, optionally triggering a recording.
Received signals are delivered as RxBasebandSignalNtf messages, and transmissions are bracketed by TxStartNtf and TxEndNtf notifications for precise timing. The default baseband agent is accessed as bb (on most modems, the same agent as phy).
Warning
Baseband transmissions bypass medium access control entirely — the modem transmits your signal without consulting the MAC agent, and other nodes cannot even decode it to know how long the channel is busy. On a shared channel, reserve the channel through the MAC service (Chapter 19) before transmitting signals of any significant duration.
ClearReq – clear all queued (and ongoing, when possible) transmissions
A transmission request is answered with an AGREE once the signal is accepted (a REFUSE if the signal is too long, the preamble ID is invalid, or a requested option is unsupported), and the transmission is then bracketed by notifications marking its exact start and end. A recording request is answered with an AGREE, followed by the recorded signal. Notifications generated by this service:
The recorded RxBasebandSignalNtf is sent to the agent that requested the recording; recordings triggered by detections, along with TxStartNtf, TxEndNtf and DetectionNtf, are published on the agent’s topic. The signal of an RxBasebandSignalNtf is a flat array of interleaved real/imaginary baseband samples (or real samples for passband), along with its center frequency fc and sampling rate fs. In the Python and Julia APIs, the same signals appear as native complex arrays. (Why modems favor the complex baseband representation is explained in a callout in Chapter 2.)
maxInAirPowerLevel :: float – transmit power if modem is near surface or in air
This parameter sets the transmit power level limit used when the modem is near the surface or in air for safety. If depth information (node.depth) is unavailable, this parameter is not used.
Example:
bb.maxInAirPowerLevel = -20 // Set maximum in-air transmit power to -20 dB
syncSystemTime :: long – system time at last sync event (µs)
clockCalib :: float – clock calibration ratio (1.0 = no correction)
busy :: boolean – true if signal transmission ongoing, false otherwise
fullduplex :: boolean – allow reception when transmitting
Full duplex mode. In this mode, the baseband service is able to transmit and receive simultaneously. When disabled, receptions are inhibited while a transmission is ongoing.
Mute the output data stream. Output data streams are automatically muted after transmission. A user may unmute early to avoid delays for time sensitive transmissions.
standby :: float – idle time before putting power amplifier in standby (seconds)
Power amplifier is shutdown automatically after the specified idle time after the last transmission.
A value of 0 shutsdown the power amplifier immediately after a transmission, only if it was turned on automatically for that transmission.
A value of -1 disables auto-shutdown.
Examples:
bb.standby = 15 // shutdown poweramp after 15 s idle time
bb.standby = -1 // disable auto-shutdown of poweramp
pbsblk :: int – passband streaming block size (samples)
pbscnt :: int – number of passband data blocks to stream
Setting this parameter starts streaming of passband data for a specified number of blocks. A value of 0 stops streaming. A value of -1 enables long-term streaming. Setting this parameter to -1 may affect modem performance. For applications requiring continuous streaming, consider using UDP based streaming using bb.pbsport.
Example:
bb.pbscnt = 10 // stream 10 blocks of pasband data
bbsblk :: int – baseband streaming block size (samples)
bbscnt :: int – number of baseband data blocks to stream
Setting this parameter starts streaming of baseband data for a specified number of blocks. A value of 0 stops streaming. A value of -1 enables long-term streaming. Setting this parameter to -1 may affect modem performance. For applications requiring continuous streaming, consider using UDP based streaming using bb.bbsport.
Example:
bb.bbscnt = 10 // stream 10 blocks of baseband data
Setting this parameter to a valid IPv4 address enables UDP streaming of baseband or passband data. A value of “0.0.0.0” or “none” disables streaming. This parameter must be set along with either bb.pbsport or bb.bbsport to enable streaming.
Examples:
bb.ip = '192.168.0.100' // set destination IP address
bb.ip = '0.0.0.0' // disable streaming
Setting this parameter (along with bb.ip) starts streaming of passband data over UDP. A value of 0 stops streaming. Passband data is streamed as a 12-byte header followed by float32 samples with interleaved channels.
Header format:
byte 0: uint8 version number (0x01)
byte 1: uint8 channel count
bytes 2-3: uint16 sequence number
bytes 4-7: float32 carrier frequency (Hz), 0 for passband
bytes 8-11: float32 sampling rate (Sa/s)
All float32 and uint16 are in little-endian byte order.
Example:
bb.ip = '192.168.0.100' // set destination IP address
bb.pbsport = 8080 // start streaming to UDP port 8080
bb.pbsport = 0 // stop streaming
Setting this parameter (along with bb.ip) starts streaming of baseband data over UDP. A value of 0 stops streaming. Baseband data is streamed as a 12-byte header followed by complex float32 samples (real, imaginary) with interleaved channels.
Header format:
byte 0: uint8 version number (0x01)
byte 1: uint8 channel count
bytes 2-3: uint16 sequence number
bytes 4-7: float32 carrier frequency (Hz)
bytes 8-11: float32 sampling rate (Sa/s)
All float32 and uint16 are in little-endian byte order.
Example:
bb.ip = '192.168.0.100' // set destination IP address
bb.bbsport = 8080 // start streaming to UDP port 8080
bb.bbsport = 0 // stop streaming
noise :: float[] – ambient noise floor estimate (dB re full scale)
wakeupDelay :: int – gap between wakeup signal and transmission (ms)
wakeupSignal :: float[] – baseband samples of wakeup signal
The noise parameter reports one estimate per receiver channel, using the same dB-re-full-scale reference as the rssi reported in received-signal notifications — so the two can be compared directly to judge received signal levels against the background noise floor.
27.5 Detector parameters
Each preamble detector exposes indexed parameters, accessed as bb[1], bb[2], etc.:
preamble :: float[] – baseband samples for detection preamble
Preambles are specified as complex baseband samples, with alternate samples in the array being real and imaginary parts. When setting a preamble, one may specify an array or use supported preset preambles.
inhibit :: int – detection inhibition (baseband sample count)
Detections are reported only if there are no stronger detections within the specified number of baseband samples before or after them. The capture starts at the time of the strongest detection in the overall inhibition period. This period may be longer than inhibit if there is a sequence of detections of increasing strength.
capture :: int – number of baseband samples to capture at each detection
bbrec 1000 // record 1000 baseband samples
bbrec 1000, 87897287 // schedule a recording at given PHY time
bbtx – transmit a baseband signal
Examples:
bbtx sig // transmit complex baseband signal
bbtx sig, 87897287 // schedule a transmission at given PHY time
pbtx – transmit a passband signal sampled at 8 x basebandRate
Examples:
pbtx sig // transmit real passband signal
pbtx sig, 87897287 // schedule a transmission at given PHY time
cw – create a tonal signal with unit amplitude
Examples:
cw(10000, 0.5) // 0.5 second 10 kHz baseband tonal
cw(15000, 0.2, 0) // 0.2 second 15 kHz passband tonal
sweep – create a linear sweep with unit amplitude
Examples:
sweep(10000, 12000, 0.5) // 0.5 second baseband sweep from 10-12 kHz
sweep(10000, 12000, 0.5, 0) // 0.5 second passband sweep from 10-12 kHz
wav – load a wav file (mono track, sampling rate should be same as bb.dacrate)
Examples:
wav 'test.wav' // loads a wav file
save – save signal to a file in the scripts folder
Example:
save 'data.txt', ntf // save notification signal to file
save 'data.txt', ntf.signal, 2 // save signal in 2-column format
load – load floating point signal from a file in the scripts folder
Example:
signal = load('data.txt') // load data from file
27.7 Examples
Transmit a continuous-wave (CW) tone with bbtx. The cw(freq, duration) command builds a baseband tonal signal — here a 0.5 s tone at 24 kHz, the simulated modem’s carrier frequency (the tone must lie within the modem’s baseband passband):
The same tone can be generated at passband — real samples at the modem’s DAC rate — by passing 0 as a third argument (the carrier frequency) to cw(). Passband signals are transmitted with pbtx. The simulated modem has no DAC (there is no actual audio path), so this one needs a real modem:
> pbtx cw(24000,0.25,0)AGREE
Generate both versions of a signal and compare their lengths — the passband representation needs many times more samples to carry the same information, which is why baseband is the default.
Then capture samples from the channel with bbrec, which records a given number of baseband samples and returns them as an RxBasebandSignalNtf:
Recordings can also be scheduled. On an agent with the TIMED_BBREC capability, a RecordBasebandSignalReq carrying a recStartTime starts recording at exactly that instant on the physical-layer clock — here, 2 s in the future:
In simulation, bbrec returns placeholder samples of the requested length, so the captured signal is not a meaningful recording of the transmitted tone. Run the same commands against a real modem to capture actual channel data.
On a real modem, the recording machinery has one more trick: it can record the past. The modem continuously retains the last few seconds of received baseband samples in a buffer, so a recording that starts slightly in the past is served from that buffer. A negativerecStartTime is interpreted relative to the current time, making “give me the last 2 seconds” a one-liner. Asking for a start time further back than the buffer reaches is refused (Start time too far in the past). The simulator does not model this buffer, so this is one to try against real hardware:
This is remarkably useful in practice: when a detector fires or a frame arrives, the signal that caused it has already happened — recording the past lets you go back and capture it.
27.8 Preambles & detection
Every frame transmission begins with a preamble — a known signal that receivers continuously correlate against, so that they can detect an incoming frame in the noise and know when it starts. The baseband service exposes this machinery directly: preambles can be transmitted on their own, and detectors can be configured to report whenever a chosen preamble is heard.
Each detector is configured through the indexed parameters bb[1], bb[2], … (see Detector parameters). Detectors 1 and 2 correlate against the preambles of the CONTROL and DATA channels respectively. A detector is enabled by setting its threshold to a value between 0 and 1 (0 disables it): a low threshold detects weaker signals but false-alarms more often in noise, a high threshold does the reverse (Chapter 17).
Let’s watch a detection happen. On node B, we subscribe to the physical agent’s topic (where DetectionNtfs are published); on node A, we transmit a bare CONTROL preamble — a TxBasebandSignalReq with a preamble but no signal:
Since preamble 1 announces a CONTROL frame, the receiver also treats the detection as the start of an incoming frame (an RxFrameStartNtf, Chapter 17); as no frame data follows a bare preamble, no RxFrameNtf ever arrives — on a real modem, the attempted decode eventually fails with a BadFrameNtf. This makes a bare preamble a cheap way to exercise a receiver’s detection chain.
A few more things the detector machinery can do:
Detection-triggered capture. Setting bb[n].capture to a sample count makes each detection trigger a recording of that many baseband samples, published as an RxBasebandSignalNtf on the agent’s topic — detect-and-capture without any round-trip.
Custom preambles. The bb[n].preamble parameter accepts arbitrary baseband samples, or preset generators such as hfm, lfm(f1, f2, duration) and mseq — so you can define your own signaling alongside the standard channels.
Channel impulse-response estimation. The exact baseband samples of any preamble are available via a GetPreambleSignalReq (or bb[n].preamble). Record the channel while a peer transmits that preamble, cross-correlate the recording with the known preamble signal, and the peaks give you an estimate of the channel’s impulse response — multipath structure included.
27.9 Implementations
The BASEBAND service is not loaded by setup.groovy; it is provided by the modem, alongside the PHYSICAL (Chapter 17) and, where supported, DOA (Chapter 26) services (see Chapter 13). Either way, the higher layers see the same BASEBAND service and messages described above.
On a commercial modem, the baseband service is backed by the modem firmware running on the modem’s signal-processing hardware. From the rest of the stack’s point of view, there is simply a bb agent provides BASEBAND, exposing the modem’s software-defined modem capabilities — arbitrary signal transmission, timed recording, preamble detectors, and (on supported hardware) signal streaming.
27.9.2 HalfDuplexModem (phy)
In simulation, the HalfDuplexModem agent (Chapter 17) provides the baseband interface with the TIMED_BBTX and TIMED_BBREC capabilities. Transmissions and detections are modelled with correct timing and energy, but recordings return placeholder samples of the correct length rather than a true capture of the channel — the simulator does not synthesize received waveforms. Higher-layer agents that depend on baseband access therefore run unchanged, but signal content is only meaningful against real hardware.