Skip to the content
4 layers40 × 100 mmASK, the printed circuit board in 3D

The flowgraphs transmit a random source, which are bytes with values between 0 and 255. A random sequence of 30,000 bytes is sent and repeated while the flowgraph is running.

Size
40 × 100 mm
Copper layers
4
Thickness
1.64 mm
Parts
83
Nets
41
Pads
209
Tracks, vias
213, 442
Pours
24
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
12 Nov 2025
Updated
1 Mar 2026

Overview

ASK is an open-source printed circuit board by Tanki777, from the Tanki777/telecomlab_fso repository on GitHub, published under the GPL-3.0 licence. It is a 4-layer board of 40 × 100 mm with 83 parts on 41 nets, routed with 213 tracks and 442 vias.

It is built around the AD5693RARMZ, INA226AIDGSR and ISL21080DIH309Z-TK, with the LT3042EMSE#PBF, VJ0402Y104KXJPW1BC and 520L103KT16T among its other parts. Its parts include 32 capacitors, 9 inductors, 8 resistors, 6 connectors and 4 ICs.

Main components

12

README

README.md

Modulation Schemes for Free Space Optical Communication

This repository contains all GNU Radio flowgraphs, Matlab and python scripts that were used during the project. Additionally, the test data which was transmitted and received during the experiments, as well as a documentation are included.

Table of contents

  1. GNU Radio flowgraphs
  2. Matlab scripts
  3. Utility scripts
  4. Electrical
  5. Troubleshooting

1. GNU Radio flowgraphs

If you are new to GNU Radio, it is recommended to have a look at the official tutorials first. After that, the following descriptions will be easier to understand.
While reading the following descriptions, it is adviced to open the corresponding flowgraph image to follow the explanations.
For this project, GNU Radio 3.10.12 was used.

1.1 Phase Shift Keying

1.1.1 Random source transmission

This section refers to the flowgraphs ber_bpsk.grc, ber_qpsk.grc, ber_8psk.grc and ber_16psk.grc. The diagram images can be found here: ber_bpsk.pdf, ber_qpsk.pdf, ber_8psk.pdf, ber_16psk.pdf.

The flowgraphs transmit a random source, which are bytes with values between 0 and 255. A random sequence of 30,000 bytes is sent and repeated while the flowgraph is running.

The transmission data is then modulated with the generic Constellation Modulator block, which can take different Constellation Object blocks as input. The Constellation Modulator also applies a Root-raised cosine filter. Since differential encoding is used, the constellation type parameter of the Constellation Object must not be set to QPSK as that prevents differential encoding and will not work. Instead, DQPSK may be selected. However, it is recommended to not use the preset types and instead set it to Variable Constellation and define symbol mapping and constellation points manually.

After that, the modulated signal is sent to the Pluto SDR (configured as the transmitter) using the PlutoSDR Sink block via USB and received at the Pluto SDR (Configured as the receiver), which sends the signal back to the computer via USB using the PlutoSDR Source block. In this project, two SDRs were used (one as transmitter, one as receiver). Thus, the IP in the Pluto blocks must be set accordingly in the IIO context URI parameter.

A FFT Root Raised Cosine Filter block is needed to match the filter at the transmitter.

In the Symbol Sync block, the symbols are synchronized. Different algorithms in the Timing Error Detector can be tested, while in our project y[n]y'[n] Maximum likelihood turned out to be the best overall.

The Costas Loop block locks the phase, making the constellation points appear as expected in the QT GUI Constellation Sink block. The Order parameter must be set according to how many constellation points are used. The exception is 16-PSK, where the order is still 8 (8 is the maximum value).

The Constellation Decoder block then decodes the complex signal to bytes.

Since differential encoding is used at the transmitter, a Differential Decoder block is required at the receiver.

The Map block remaps the symbol bytes and the order of the list must be the same as in the Constellation Object.

Until now, the signal contains log2(p) bits per byte, where p is the number of constellation points. Therefore, it must be unpacked such that each byte contains one bit.

Finally, the data is written to the file as configured in the File Sink block.

The Probe Rate block regularly prints the bit rate to the terminal.

1.1.2 General File transmission

This section refers to the flowgraphs pluto_bpsk_tx/rx.grc, pluto_qpsk_tx/rx.grc and pluto_8psk_tx/rx.grc. The diagram images can be found here: pluto_bpsk_tx.pdf, pluto_bpsk_rx.pdf, pluto_qpsk_tx.pdf, pluto_qpsk_rx.pdf, pluto_8psk_tx.pdf, pluto_8psk_rx.pdf.

These flowgraphs transmit any file, implementing the packeting inside the flowgraph. In contrast to repeated source transmission, the receiver should be turned on before the transmitter. Thus, the flowgraphs are splitted into a transmitter and receiver.
A GNU Radio tutorial1 was used as a starting point (author: Dubbage) and modified. The modulation scheme and the RB (Resource Blocks) used can be configured changing the value of txsim.RC, to find the R. use the Wireless Waveform Generator Tool/App that in the "reference channel" dropdown shows the modulation scheme and Resource blocks used plus other info. Resource Blocks are important as they define the necessary bandwidth.

Transmitter:
A HIER block File Source Packaged is used to read the file which should be transmitted and does the following (the diagram image can be found here: hier_file_source_packaged.pdf).

  • It starts with an embedded python block EPB: File Source to Tagged Stream, which first sends a preamble 64 times, then sends the file data in packets (each packet contains as many bytes as configured in the Pkt_len parameter of the File Source Packaged block). In front of each file data packet, the packet number is put. At the end, an end of file marker, the file name and a repeated post filler (64 times) is sent. A tag with the (new) packet length is also applied to make it a tagged stream (required by other blocks later). While the file data is encoded in Base64, everything else (including the packet number) is not encoded. The encoded file data packet is 4/3 as long as the decoded one, since Base64 encodes 3 Bytes into 4 Bytes.
    The preamble is &U...U] (50 times U), the packet number frame [000001] (always 6 digits, therefore a maximum of 999,999 packets are possible. This means a maximum file size of 999,999 times Pkt_len bytes. If larger files are desired, increase packet length or adjust packet number frame.), the end of file marker %UUU#EOF (followed by the file name), the post filler %UUU#EOF followed by 43 times the character U and ending with ].
  • After the embedded python block, a CRC32 code is also attached to each packet by the Stream CRC32 block to detect errors at the receiver. The Mode parameter must be set to generate.
  • Finally a header is also attached (including the access key 11100001010110101110100010010011) using the Protocol Formatter and Tagged Stream Mux blocks. The access key is used at the receiver for correlation.

As in random source transmission, the data is modulated by the Constellation Modulator block using a Constellation Object (which is configured depending on the number of constellation points). For more details, see the previous section.

The modulated signal is then sent to the Pluto SDR (configured as transmitter) using the PlutoSDR Sink via USB and sent to the Pluto SDR (configured as receiver).

Receiver:
The received signal is sent to the computer via USB using the PlutoSDR Source block.

A FFT Root Raised Cosine Filter block is used to match the filter at the transmitter (which is inside of the Constellation Modulator block).

In the Symbol Sync block, the symbols are synchronized. Different algorithms in the Timing Error Detector can be tested, while in our project y[n]y'[n] Maximum likelihood turned out to be the best overall.

The Costas Loop block locks the phase, making the constellation points appear as expected in the QT GUI Constellation Sink block. The Order parameter must be set according to how many constellation points are used. The exception is 16-PSK, where the order is still 8 (8 is the maximum value).

The Constellation Decoder block then decodes the complex signal to bytes.

Since differential encoding is used at the transmitter, a Differential Decoder block is required at the receiver.

The Probe Rate block at this time does not print the bit rate, but the symbol rate (except for BPSK as it is the same there).

A HIER block File Sink Unpackaged mod_scheme is used to perform further actions before writing the data to a file. Since the mapping and unpacking depends on the constellation points, there is one block for each modulation scheme (the diagram images can be found here: hier_file_sink_unpackaged_bpsk.pdf, hier_file_sink_unpackaged_qpsk.pdf, hier_file_sink_unpackaged_8psk.pdf).

  • The Map block remaps the symbol bytes and the order of the list must be the same as in the Constellation Object (not needed in BPSK, since there is only 0 and 1).
  • Until now, the signal contains log2(p) bits per byte, where p is the number of constellation points. Therefore, it must be unpacked such that each byte contains one bit (not needed in BPSK, since symbol is only 1 bit).
  • The Correlate Access Code - Tag Stream block looks for the access code. If not found (with the Threshold parameter, the maximum number of wrong bits allowed can be changed), the packet will already be dropped at this point. The access code used is TODO.
  • The data is repacked from 1 relevant bit per byte (that is how the previous block outputs the data) to 8 relevant bits per byte (that is how the next block expects the data if Packed is true).
  • The Stream CRC32 is now set to Mode check. It drops packets when errors in the payload are detected.
  • Finally, the data (without header and CRC32 checksum) is written to the configured file.

The File Sink Unpackaged mod_scheme block also outputs the input and output signal of the Correlate Access Code - Tag Stream block, comparing them in QT GUI Time Sink blocks. If, during transmission, there is an input signal but no output signal, the access code correlation failed and the packet is dropped. If there is no output signal visible during the entire transmission, it indicates something is wrong with the flowgraph.

1.1.3 File transmission using pre-processed .bin files

This section refers to the flowgraphs raw_file_bpsk_tx/rx.grc and raw_file_qpsk_tx/rx.grc. The diagram images can be found here: raw_file_bpsk_tx.pdf, raw_file_bpsk_rx.pdf, raw_file_qpsk_tx.pdf, raw_file_qpsk_rx.pdf.

1.2 Important notes using Pluto SDR

When testing flowgraphs and if the TX and RX SMA connectors of the SDRs are directly connected to each other with a cable, make sure to set the Attenuation TX1 parameter of the PlutoSDR Sink block to at least 20 dB to prevent damaging the device. Only when using antennas or the laser, it can be set to 0 dB.

2. Matlab scripts

2.1 OFDM

To test the optical channel with more complex modulation schemes, a MATLAB help example (see https://it.mathworks.com/help/lte/ug/image-transmission-reception-using-lte-waveform-and-sdr.html for the original example) was adapted for the setup. This script encodes and packs an image into a radio frame. A baseband LTE signal with OFDM modulation is transmitted. The signal is then received, and the frequency offset is determined. After OFDM demodulation, a channel estimation is performed, and the payload of the received packets is recombined to form the received image. OFDM subcarriers were modulated using 64-QAM (in the uploaded code, like in the original example), and 16-QAM.

2.2 Pre-Processed Binary File Transmission

In the folder there are the Matlab codes used to create packets from the binary file generated from the image 'capra.jpg', 'transmit_packets.m', and to post-process the file after it has been received, 'read_received.m', that recreates the image. The folder 'transmitted_file' contains the packeted file, the folder 'received_files' contains the successfully received files, before post-processing.

3. Utility scripts

3.1 Post-processing for file transmission using GNU Radio flowgraph

If using one of the following flowgraphs pluto_bpsk_rx/tx.grc, pluto_qpsk_rx/tx.grc or pluto_8psk_rx/tx.grc, the received .tmp file must be post-processed to reconstruct the file data. For this, the script strip_preamble_mod.py can be used.
The original script is authored by duggabe (see here) and was modified.1

Usage:

text
python .\strip_preamble_mod.py in_file_name.tmp out_file_name.txt

The file extension of the output file must match that of the transmitted file.

What it does:

  • Removes preamble.
  • Looks for packet number frames.
  • Decodes payload data (Base64) chunk-wise (each chunk is 4 Bytes) and writes it to the output file.
  • Prints how many (and which) packet number frames were not detected.
  • Compares content of detected packets with transmitted file and checks for bit errors.
  • Prints packet error rate.

Configuration:
Before using the script, it should be configured for the used transmission file and setting. The following should be checked and edited if necessary.

  • Packet length (only if modified in the flowgraph).
  • Preamble, end of file marker, post filler content (only if modified in the embedded python block in the flowgraph).
  • Total number of packets for the transmitted file (is displayed in GNU Radio terminal after the transmission has ended).
  • Whether the received file content should be compared with the transmitted file.
  • Filename of the transmitted file (only if the received file content is compared with the transmitted file).

3.2 Missing number check for .txt files for file transmission using GNU Radio flowgraph

If using one of the flowgraphs listed in the previous section, the script txt_scanner.py can check which numbers are missing in the received file.

Requirements:

  • The transmitted file contains ordered incrementing numbers (by 1), separated by commas (see test_file_tx.txt).

Usage:

text
python .\txt_scanner.py

What it does:

  • Prints how many (and which) numbers are missing in the received file.

Configuration:
Before using the script, it should be configured as follows.

  • Edit the name of the received file.
  • Edit the list of numbers to be checked to match the transmitted file content.

4. Electrical

4.1 Electrical schematics

All the design files are available in the folder "ElectricalDesign", which is subdivided into "Version 1" and "Version 2". The first is the one used during our tests. The second is the improved version with all the problems we encountered fixed, plus some other nice features like pin names, use of rule areas, fixed voltage reference for the amplifier, but with the possibility to switch back to the DAC if needed, and monitor of the amplifier voltage directly from VBUS of INA226, while shunt voltage keeps reading the photodiode resistor voltage. Moreover pull-up resistors were added. For the first version the 3 pins on the right of the receiver (SMA down) can't be used to set the voltage to the linear converter, if you want to do so remove first the DAC. Consider that SET pin provides a constant current, handle with care this connection! (Use a resistor) The central pin is a ground reference

4.2 Electrical connections

To connect the Arduino with the receiver you can simply connect grount to the lowermost pin (always SMA down), then moving up 5V, SDA, SCL as shown [here](ElectricalDesign/Version1/Pinout Receiver.png). On the Arduino side, if using an Arduino Mega 2560, use pin 20 for SDA and 21 for SCL. In case of Arduino Uno, connect SDA to A4 and SCL to A5, if using R4 version add pull-up resistors from the data lines to 5V or to 3.3V! You can connect 5V to Arduino's 5V pins and remember to always connect ground to the board and Arduino, even if using an external power supply. Connect the SMA connector to the receiver port of your radio with a suitable cable.

To connect the transmitter use the given cable (D-SUB connectors), and connect it to the laser driver. The cable has a mark to indicate the transmitter (laser) side. If you want to use a desk power supply (only 1M OPV310!) connect the cable as described before, then add the cut cable and connector available in the box. On the wires cut there is a marking for "LS" Laser, "PD" Photodiode, and GND for Ground. Always use a multimeter in current mode to check the current that should never exceed 7mA. Connect the multimeter in series to the transmitter. DO NOT TRUST THE CURRENT READINGS OF THE POWER SUPPLY, might damage the laser and exceed the 1M cathegory. Connect the SMA connector to the trasmitter port of the radio using a suitable connection

4.3 Alignment

To align the recevier you can run the program ADD LINK ARDUINO PROGRAM on the Arduino connected to the receiver while leaving only INA.getShuntVoltage_uV(); and its print not commented. Run the program and open the serial plotter, this will show the average voltage of the resistor connected to the photodiode, the more light enters the photodiode the greater the current it will let pass, the higher the voltage of the resistor will be. Start roughly aligning the transmitter and the receiver, you can help yourself with a phone camera, they usually seee in the NIR spectrum. after the rough alignment you can then check the serial plotter and try to reach the maximum value by moving both the receiver and transmitter set screws. Beware of local maxima, OPV302 has an output light concentration donut shaped, with the maximas on the outer part. Expect values around 1600uV for 6mA on the laser, with a receiver lens, and at oughly 1m, check the report for other values. You can also calculate the current of the photodiode by dividing the voltage by 50, the resistance value of the resistor of the photodiode. with the current you could calculate the power that enters the photodiode, at 850nm you can divide the current by 0.3 to find the input power, check the datasheet for other wavelengths.

5. Troubleshooting

5.1 General

Q: Impossible to find DAC or ADC or setup is not successfu (error from the code).

A: Check that that the 2 wires of I2C are connected properly SDA->SDA SCL->SCL, check to have a ground connection between the Arduino and the receiver, in case you are using an external power supply. If this is ok then if you are using an Arduino Uno R4 you need external pullup resistors (from 2.2k to 20k connected to 5V or 3.3V). If you are using an Arduino Mega check which I2C pair you are using, there are many! If free always choose the first couple, located at pin 20 and 21. The schematics annotated of the first version are available [here](ElectricalDesign/Version1/Pinout Receiver.png), for the second version the pins are annotated in the silkscreen.

5.2 GNU Radio flowgraphs

Q: The signal is bad, what could be wrong?

A: Check if the laser is on (also the current). Check the laser alignment towards the receiver. Check the attenuation of the PlutoSDR Sink block and set it to 0 dB (not if TX and RX directly connected to each other via SMA cable). Check that the IP addresses of the SDRs are configured correctly in the PlutoSDR Sink and PlutoSDR Source blocks.

Q: The SDR is not detected by GNU Radio (terminal shows an error when running the flowgraph), what should i do?

A: Check the IP addresses of the SDRs in the flowgraph, but also make sure they are correct by clicking on the SDR in file explorer and opening config.txt. The ip is listed at ipaddr under [NETWORK] (you can also change the address). Also make sure that usb_ethernet_mode under [SYSTEM] is set to rndis. If that still does not help, check the computer network (on Windows via ipconfig in the terminal). If no Ethernet adapter category is listed, the RNDIS driver might need to be reinstalled by opening the device manager → right click unknown device → update driver → browse my computer → let me pick from a list → network adapters → microsoft → remote NDIS compatible device.

Footnotes

  1. Note that the GNU Radio tutorial was reworked and this link refers to the older version which was used in this project. ↩ ↩2

Parts

83
QtyValueFootprintReferences
15VJ0402Y104KXJPW1BCFSCOM:C_0402_1005MetricC6, C7, C9, C12, C13, C14, C20, C21, C22, C23, C26, C27, C29, C30, C35
10MountingHole_PadFSCOM:MountingHole_2.7mm_M2.5_DIN965_PadH1, H2, H3, H4, H5, H6, H7, H8, H9, H10
9520L103KT16FSCOM:C_0402_1005MetricC1, C3, C5, C10, C11, C18, C19, C28, C102
9LQW15AN6N2G8ZDFSCOM:L_0402_1005MetricL1, L2, L3, L4, L5, L6, L7, L8, L9
6FerriteBeadFSCOM:L_0402_1005MetricFB1, FB2, FB3, FB4, FB5, FB6
504025J4R0ABSTRFSCOM:C_0402_1005MetricC2, C8, C31, C32, C33
3CL31B106KAHNNNEFSCOM:C_0402_1005MetricC4, C24, C25
3FC0603E50R0BST1FSCOM:R_0402_1005MetricR101, R102, R103
2CONSMA001-GFSCOM:CONSMA001GJ1, J2
2ERA-2AED472XFSCOM:R_0402_1005MetricR3, R4
2TNPW040210R0DEEDFSCOM:R_0402_1005MetricR2, R6
1AD5693RARMZFSCOM:SOP50P490X110-10NU2
1BFP620H7764XTSA1FSCOM:BFP620H7764XTSA1Q1
1BZT52C2V0-7-FFSCOM:D_SOD-123D2
1Conn_01x02_PinFSCOM:PinHeader_1x02_P2.54mm_VerticalJ5
1Conn_01x02_PinFSCOM:PinHeader_1x03_P2.54mm_VerticalJ4
1Conn_01x04_PinFSCOM:PinHeader_1x04_P2.54mm_VerticalJ6
1INA226AIDGSRFSCOM:VSSOP-10_3x3mm_P0.5mmU3
1ISL21080DIH309Z-TKFSCOM:SOT-23-3U4
1L77TSEH09SOL2FSCOM:L77TSEH09SOL2J3
1LT3042EMSE#PBFFSCOM:SOP50P490X110-11NU1
1MCS04020D1252BE100FSCOM:R_0402_1005MetricR1
1MTPD1346D-010FSCOM:MTPD1346D010D3
1MTSM1346SMR1-030FSCOM:SMD6_3X3_MTSM1346SMF1_MTOD1
1OPV302FSCOM:OPV302_OPTLASER1
1SolderJumper_2_OpenFSCOM:SolderJumper-2_P1.3mm_Open_RoundedPad1.0x1.5mmJP3
1SolderJumper_3_OpenFSCOM:SolderJumper-3_P2.0mm_Open_TrianglePad1.0x1.5mmJP1
1SolderJumper_3_OpenFSCOM:SolderJumper-3_P1.3mm_Open_RoundedPad1.0x1.5mm_NumberLabelsJP2

More from Tanki777/telecomlab_fso

1
  • 4 layers40 × 100 mmASK, the printed circuit board in 3D

    ASK

    Tanki777/telecomlab_fso

    The flowgraphs transmit a random source, which are bytes with values between 0 and 255. A random sequence of 30,000 bytes is sent and repeated while the flowgraph is running.

    64 partsGPL-3.0

Similar boards

  • 2 layers40 × 40 mmLDO, the printed circuit board in 3D

    LDO

    Ken-2511/LDO

    Two KiCad 10 projects, stacked on the same 40x40 mm footprint:

    26 parts
  • 6 layers200 × 170 mmMicrowave Beamer, the printed circuit board in 3D

    Microwave Beamer

    levisawatz/Microwave_beam_kicad

    474 parts
  • 4 layers50 × 56 mmRadar synth, the printed circuit board in 3D

    Radar synth

    sigma0us/radar-synth

    Dual PLL radar transmitter, design for prototyping

    87 parts
  • 2 layers46.1 × 83.1 mmSpock, the printed circuit board in 3D

    Spock

    PisterLab/scum-dev-board

    58 parts1
  • 2 layers44.9 × 47.2 mmIsc0901b0-breakout, the printed circuit board in 3D

    Isc0901b0-breakout

    festlv/isc0901b0-breakout

    Simple breakout board for ISC0901B0 sensor

    60 parts15MIT
  • 2 layers80.8 × 40.1 mmPCRD03, the printed circuit board in 3D

    PCRD03

    mlab-modules/PCRD03

    Silicon PIN diode cosmic radiation detector

    165 partsGPL-3.0
  • 2 layers70.6 × 40.1 mmPCRD08, the printed circuit board in 3D

    PCRD08

    mlab-modules/PCRD08

    PCB module PCRD08

    65 partsGPL-3.0
  • 2 layers70.6 × 50.3 mmUSTSIPIN03, the printed circuit board in 3D

    USTSIPIN03

    ust-modules/USTSIPIN03

    Semiconductor based ionizing radiation dosimeter and spectrometer.

    100 partsGPL-3.0

Questions

How big is the ASK PCB?

It measures 40 × 100 mm and has 4 copper layers, 1.64 mm thick.

What parts does the ASK use?

83 parts, built around the AD5693RARMZ, INA226AIDGSR, ISL21080DIH309Z-TK and LT3042EMSE#PBF. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the ASK KiCad files?

From the Tanki777/telecomlab_fso repository on GitHub, at the commit this page was made from: the board is ElectricalDesign/Version2/ASK-EXT-LD/ASK.kicad_pcb and its schematic ElectricalDesign/Version1/ASK-EXT-LD/ASK.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the ASK design in my own project?

Its repository publishes it under the GPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).