In each project, we will explain our project part by part. Each part includes a brief explanation and the test method. At the end of each project, we will have an acknowledgement. You can build the code documentation by the following command:
cargo doc --open[TOC]
We have mainly four components:
- Block buffer: The queue-like structure for stream data. Both original version and concurrent version are defined in block_buffer.rs.
- Sample I/O Stream: The structures operate on sample streams. Sample streams are divided into instream and outstream. Instreams read samples from physics world and store the data in its buffer. Ostreams fetch samples to its buffer and write them to the physics world. The sample streams are in samples_stream.rs.
- Physics packet sender/receiver: Structures send or receive packet. Sender owns an sample instream and receiver owns an sample outstream. They are responsible for packet detection, modulation and demodulation. The sender and receiver are in phy_packet.rs
- Physics layer: The assembled physics layer. Provide basic data transmission over acoustic link. There three types of links: PSK, OFDM and PSK with error correction. The physics layers are in phy_layer.rs.
The whole project structure lies below:

In this part, we implement
bufferandconcurrent_buffer: Basic block data structure. (buffer.rs, concurrent_buffer.rs)cpal_stream: Audio I/O stream. (cpal_stream.rs)hound_stream: wav file I/O stream. (hound_stream.rs)
We use cpal_stream to realize audio recording and playing. We use hound_stream to read audio files.
You can test part1 ck1 by the following command.
cargo test part1_ck1 --release -- --ignoredThe program will start recording immediately for 10s.
You can test part1 ck2 by
cargo test part1_ck2 --release -- --ignoredThe program will play a 10-second music clip while recording at the same time. After 10 seconds, it will replay the recorded sound.
We use previously defined structure: cpal_stream to write part2.
You can test part2 ck1 by
cargo test part2_ck1 --release -- --ignoredThe program will play the signal

In this part, we implement
- PSK modulation:
PSKis an implementor ofModemwhich supoortmodulateanddemodulate.(psk.rs) - Correlation frame detection:
CorrelationFramingis an implementor ofFrameDetectorwhich supporton_sample.(frame_detect.rs) - Chirp signal as preamble:
ChirpUpDownis an implementor ofPreambleGen, which supportgenerate,len,normand other helper functions.(preambles.rs) - Packet sender and receiver:
PhySenderis an implementor ofPacketSender, which supportsendfunction.PhyReceiveris an implementor ofPacketReceiver, which supporrecvandrecv_timeoutfunctions.(txrx.rs).
Note: This test need two nodes to test. This test should be done in a quite room.
To test part 3, you can run the following POSIX shell command on two devices,
where $seed is a integer for pseudo-random generator seed.
# on sender device
./input_gen.py $seed > INPUT.txt
cargo test part3_ck1_send --release -- --ignored
# on receiver device
cargo test part3_ck1_recv --release -- --ignored
./input_gen.py $seed > INPUT.txt
./cmp.pyLess than 15 seconds transmission time is expected.
Less than 100 bit filps is expected.
In this part, we implemented file transmission with error correction.
- In
phy_layermodule, we addedAtomicPHYwhich use sequence number and CRC checksum to ensure the data integrity of received data packets and infer the number of lost packets between two successful transmitted packets. - In
tests/part4.rs,- sender:
The data file is chunked into fixed size shards
and extra 30 chunks are generated with Reed-Solomon encoder.
The chunks are then sent via
AtomicPHY. - receiver:
Receiver data shards and error correction chunks via
AtomicPHY. Erase the lost shards and corrupted shards. Recover the data file with Reed-Solomon decode.
- sender:
The data file is chunked into fixed size shards
and extra 30 chunks are generated with Reed-Solomon encoder.
The chunks are then sent via
To test part 4, you can run the following POSIX shell command on two devices,
where $seed is a integer for pseudo-random generator seed.
# on sender device
./input_gen.py $seed > INPUT.txt
cargo test part4_send --release --features nofloat -- --ignored
# on receiver device
cargo test part4_recv --release --features nofloat -- --ignored
./input_gen.py $seed > INPUT.txt
./cmp.pyLess than 20 seconds transmission time is expected.
The comparison result should be empty which indicates that the OUTPUT.txt is identical to INPUT.txt.
In this part, we implemented OFDM+BPSK modulation which should at least double the bandwidth.
- In
modemmodule, we implemented OFDM+BPSK modem inofdmsub-module. - In
phy_layermodule, we implementedHighBpsPHYwhich use the OFDM modem to achieve higher bit rate in file transmission task.
To test part 5, you can run the following POSIX shell command on two devices,
where $seed is a integer for pseudo-random generator seed.
# on sender device
./input_gen.py $seed > INPUT.txt
cargo test part5_send --release --features nofloat -- --ignored
# on receiver device
cargo test part5_recv --release --features nofloat -- --ignored
./input_gen.py $seed > INPUT.txt
./cmp.pyLess than 9 seconds transmission time is expected.
We should see less than 100 bit flips in the comparison result.
In this part, we use fixed-point numbers instead of floating point nubers in preamble generation/detection and modulation/demodulation.
Thanks to the trait oriented feature provided by rust programming language, we are able to complete this part by only adding a few lines of code.
- In
traits/sample.rs, thetrait Sampleis an abstraction of the common operations required to support acoustic link on floating point numbers and fixed point number. - Fixed point number special function evaluation are done by CORDIC algorithm, which involves only integer arithmetics.
- For
modem,preambleandframe_detectmodule, we can use eitherfp32orfixed::types::I32F32, which is controlled by the compilation flagnofloat. - NOTE our OFDM modem currently only works with floating point numbers, so it is excluded when the flag
nofloatis presented.
You can test part 6 by running the following POSIX shell command on two devices,
where $seed is an integer used as pseudo-random number generator seed.
# on sender device
./input_gen.py $seed > INPUT.txt
cargo test part3_ck1_send --release --features nofloat -- --ignored
# on receiver device
cargo test part3_ck1_recv --release --features nofloat -- --ignored
./input_gen.py $seed > INPUT.txt
./cmp.pyThe sender should finish transmission within 15 seconds.
The receiver should receive and write the file OUTPUT.txt without error.
Less than 100 bit flips is expected in the result of comparison.
We didn't build everything from ground up, instead, we leverage the existing vast rust eco-system.
As designing and analysing the whole system is quite beyond our capability, we referred to some journal papers, academic reports and blog posts.
Here, we express our sincere gratefulness to the authors of the following libraries/papers
- crates.io cpal: for audio input/output.
- crates.io hound: for WAV audio file format encode/decode.
- crates.io crc: for various CRC checksum/digest algorithm.
- crates.io reed-solomon-erasure: for high-performance reed solomon erasure code encode/decode.
- crates.io rustfft: for heavily optimized radix-4 FFT/IFFT.
- crates.io fixed, crates.io cordic, crates.io az: for fixed point number arithmetic operation and elementary function evaluation using only integer arithmetic.
- IEEE SIGCOMM 2013. Dhwani: secure peer-to-peer acoustic NFC: The paper gives a brief analysis of the transmission media (the air, within 0.5 meter). They also measures the basic property of the commodity audio I/O devices (the microphone and the speaker on middle-end laptop/cellphone). We have borrowed the frame preamble from Dhwani, which is a linear up-down chirp signal. It shows great synchronization accuracy and anti-noise ability.
- openofdm: an hardware implementation of 802.11 OFDM decoder: We have implemented a phase shifting correction similar to the one in OpenOFDM. Our preamble detection algorithm is also inspired by OpenOFDM.
- See
proj1_acoustic_linkcrate for PHY layer optimization for wired-connection - See
proj2_multiple_accesscrate for MAC implementation
- In
proj1_acoustic_link::phy_packet::modem, addedline_code::LineCodefor 4b5b+nrzi encoding. We try to utilize digital baseband transmission for wired-connection which have better throughput. - In
proj1_acoustic_link::phy_packet::frame_detectandproj1_acoustic_link::phy_packet::preamble, use shorter preamble for each frame to achieve higher efficiency. - In
proj2_multiple_access/bin/part1_send.rsandproj2_multiple_access/bin/part1_recv.rs, we send/receive the file directly using PHY layer service.
git checkout proj2-part1
cd proj2_multiple_access
# sender
cargo run --release --bin part1_send
# receiver
cargo run --release --bin part1_recv
# checking correctness
./cmp INPUT.bin OUTPUT.binThe transmission should finish in about 6 seconds after tx/rx started.
There should be no more than 100 bit filps.
- In
proj2_multiple_access/bin/part2_send.rsandproj2_multiple_access/bin/part2_recv.rs, we introduce ACK mechanism, that is:- Tx sends every data chunk and its sequence number to Rx
- Rx reply ACK with the sequence number if a data chunk can be correctly decoded.
- Tx wait for
ACK_TIMEOUTtime and try to receive ACK packets from Rx. - Tx tries to re-send the data chunks whose ACK never come after
ACK_TIMEOUTtime. - Repeat the above steps until Tx/Rx find out that all the data chunks are correctly delivered.
git checkout proj2-part1
cd proj2_multiple_access
# sender
cargo run --release --bin part2_send
# receiver
cargo run --release --bin part2_recv
# checking correctness
./cmp INPUT.bin OUTPUT.bin- The transmission should finish in about 9 seconds after tx/rx started.
- There should be no bit filps.
- If we unplug the wire during transmission, sender should detect and report
link errorafter 20 seconds.
Not done yet.
Failed to meet the performance requirements
Failed to meet the performance requirements
Not done yet.
Not done yet.
- WARP project for CSMA MAC reference design