
PhasedUltrasonicArray
Tonikiller10000/UltrasonicPhasedArray
An ultrasonic Phased Array made out of 8 10mm ultrasonc transmitters.

Sodar is a semester project exploring directional ultrasonic object detection using a custom 19-element phased array.
Sodar is an open-source printed circuit board by Stachu1, from the Stachu1/Sodar repository on GitHub. It is a 2-layer board of 100 × 62 mm with 74 parts on 103 nets, routed with 555 tracks and 217 vias.
It is built around the TC78H621FNG,EL and QBLP680-RGB1. Its parts include 25 capacitors, 10 ICs, 9 resistors, 4 diodes and 3 connectors.
Sodar is a semester project exploring directional ultrasonic object detection using a custom 19-element phased array. The system combines a custom PCB, a Digilent Zedboard with Xilinx Zynq-7000 SoC, VHDL-based signal generation, C firmware running on the Zynq processing system, and a Python visualization tool.
The project was developed as a concept and experimental prototype rather than a finished sensing system. The main goals were to learn the Zynq-7000 architecture and its peripherals, investigate phased-array beam steering, and build a complete hardware-to-software signal path.
The system consists of four main parts:
The system was able to detect a small object at distances of up to approximately 4 m when transmitting straight ahead. When steering the beam towards ±20°, the received signal became substantially weaker and more affected by noise, limiting reliable detection of the test object to approximately 1 m.
The array contains 19 identical 40 kHz ultrasonic transducers arranged in two staggered rows: one row contains 10 transducers and the other contains 9.
The physical spacing between adjacent transducers along each row is 10 mm. The second row is shifted by 5 mm, creating a staggered arrangement where the projected spacing between elements along the left-right steering axis is approximately 5 mm.
At 40 kHz, the acoustic wavelength in air is approximately 8.6 mm at room temperature, making the projected element spacing close to λ/2. The arrangement was chosen for horizontal beam steering while keeping the projected element spacing small enough to reduce unwanted grating lobes.
The array was designed for horizontal steering only; there is no intended vertical beam steering.
A 3D radiation pattern simulation was used to visualize the array's predicted transmission characteristics and beam steering performance.
The custom PCB contains the 19 ultrasonic transducers together with the electronics required to drive them.
Each transducer has an independent H-bridge output provided by a motor-driver IC (TC78H621FNG). The Zynq PL provides the control signals required for each channel, including an enable signal and drive-direction signals.
The board was designed, assembled, and soldered as part of the project.
Main hardware:
The Zynq-7000 is divided into two parts in the project:
The PL contains a reusable PWM generator with programmable:
The top-level design instantiates 19 generators, with the phase of each channel calculated from the requested beam angle.
The phase of each channel is calculated from a common base phase and the channel index. This allows the relative phase between the 19 transmitters to be changed from the PS firmware without modifying the FPGA design.
The system generates 40 kHz square-wave bursts with phase offsets corresponding to the requested steering angle. The steering range used during testing was approximately -20° to +20°.
The array is steered horizontally by introducing a constant phase difference between adjacent transducers. Since the projected element spacing in the steering direction is approximately 5 mm, the required phase shift can be calculated from the wavelength of the 40 kHz ultrasonic signal.
Assuming a speed of sound of 343 m/s:
$$ \lambda = \frac{343\frac{m}{s}}{40\text{ kHz}} = 8.575\text{ mm} $$
The phase difference between adjacent elements is then:
$$ \Delta\phi = 2\pi\frac{d}{\lambda}\sin(\theta) $$
where $d = 5$ mm is the projected element spacing and $\theta$ is the desired steering angle.
This gives:
$$ \Delta\phi \approx 3.664\sin(\theta)\text{ rad} $$
or, in degrees:
$$ \Delta\phi \approx 209.9\sin(\theta)^\circ $$
The firmware therefore uses a constant of 209.9 to convert the requested steering angle into the phase difference between adjacent elements.
The calculated phase difference is converted into FPGA clock cycles and provided to the VHDL signal-generation logic. The phase of each element is then scaled according to its position in the array, producing the progressive phase shift required for beam steering.
The steering range used during testing was approximately -20° to +20°.
I'd make this section a little more detailed, because the burst-length/multiple-pulse experiments show useful engineering tradeoffs without overselling the DSP:
The receiving transducer is sampled using the Zynq-7000's internal XADC at approximately 500 kHz.
The implemented processing pipeline:
During testing, different transmit burst lengths were investigated to find a good balance between transmitted energy, echo detectability, and range resolution. In our experiments, a burst length of approximately 7 periods of the 40 kHz carrier gave the best results.
We also experimented with transmitting multiple bursts consecutively and summing the corresponding received waveforms. This provided some noise rejection by averaging out variations between individual measurements, but increased the acquisition time for each beam angle. As a result, using more bursts improved signal quality at the cost of a lower scanning refresh rate.
The average value of the acquired ADC buffer is calculated and subtracted from each sample. This centres the waveform approximately around zero before further processing.
The centred signal is passed through an absolute-value operation and then through a 30-tap FIR low-pass filter. This produces a smoothed representation of the received signal energy, making the location of the echo easier to identify.
The strongest point in the filtered signal is then used as the detected echo position.
The average value of the acquired ADC buffer is calculated and subtracted from each sample. This centres the waveform approximately around zero before further processing.
The centred signal is passed through an absolute-value operation and then through a 30-tap FIR low-pass filter. This produces a smoothed representation of the received signal energy, making the location of the echo easier to identify.
The strongest point in the filtered signal is then used as the detected echo position.
Distance is calculated from the measured round-trip travel time using the standard ultrasonic time-of-flight relationship:
distance = speed_of_sound × time / 2
The speed of sound is configurable in the host-side Python script. No temperature compensation was implemented.
Matched filtering was also investigated experimentally during development, including testing against the transmitted 40 kHz burst. It was not included in the final implemented signal-processing pipeline.
The system can scan through a range of beam angles and transmit an ultrasonic burst at each angle.
For each angle, the received signal is sampled and processed before the resulting data is sent to the host computer over UART.
A small spray-paint can placed on a flat surface in a laboratory was used as the main test object.
In straight-ahead operation, the system was able to detect the object at approximately 4 m. At larger steering angles, the received signal became weaker and noisier, with reliable detection of the same object reaching approximately 1 m around the ±20° steering range.
These results were obtained in a normal laboratory environment rather than an acoustically controlled room, so reflections and background noise were present during testing.
An experimental tracking mode was also implemented in the PS firmware.
Instead of performing a full angular scan, the system compares the echo strength at neighbouring beam angles and moves the beam towards the stronger response.
The implementation was experimental and not sufficiently reliable to be considered a finished tracking system. It is included primarily as an experiment demonstrating how the beam-steering mechanism could be used for closed-loop object tracking.
The repository contains a Python script for receiving the processed data over UART and displaying it as a real-time distance-versus-angle heatmap.
The visualization represents:
The Python visualization can also be used to inspect received data and experiment with parameters such as the assumed speed of sound.
In scan mode, the firmware transmits the processed samples for each beam angle over UART.
The implementation uses a compact hexadecimal representation containing the angle index followed by the sampled data.
The Python script contains the corresponding serial parsing and visualization code.
The repository is organized into the following main components:
firmware/ - C firmware running on the Zynq processing systemhardware/ - PCB and schematic filesscripts/ - Python visualization and host-side toolsvhdl/ - VHDL source for the programmable logicsimulations/ - Beam-pattern simulationsREADME.md - Project documentationThe Vivado project itself is not intended to be directly reproducible from the repository. The VHDL source is provided separately so that the hardware logic can be inspected without including the generated Vivado project files.
The prototype demonstrated the basic principle of electronically steering an ultrasonic phased array and detecting echoes from a physical object.
The main experimental results were:
| Configuration | Approximate result |
|---|---|
| Straight-ahead detection | Up to ~4 m |
| Beam steering | -20° to +20° |
| Detection at large steering angles | Up to ~1 m |
| Transmit frequency | 40 kHz |
| Number of transmit elements | 19 |
| ADC sampling rate | ~500 kHz |
| FIR filter | 30 taps |
The system was a semester project and has several limitations. In particular, the received signal became significantly weaker as the beam was steered away from the centre, limiting the useful detection range. The tracking mode was also experimental rather than a robust tracking system.
The project was primarily intended as a proof-of-concept and learning exercise rather than as a finished ultrasonic sensing platform.
The project provided practical experience with several parts of a mixed hardware/software system:
The project was developed as a second-year engineering project, and the prototype left several areas open for further development, including improved analogue signal conditioning, more robust echo detection, better calibration of the array, and improved performance at larger steering angles. A natural next step for the signal processing would be to transmit a frequency-modulated chirp and use matched filtering on the received signal, which could improve range resolution and provide better noise immunity compared with the simple burst and peak-detection approach used in the prototype.
| Qty | Value | Footprint | References |
|---|---|---|---|
| 20 | 100n | Capacitor_SMD:C_0805_2012Metric | C1, C2, C3, C4, C5, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20 +4 |
| 19 | Speaker_Ultrasound | footprints:CUSA-T80-15-2400-TH | LS1, LS2, LS3, LS4, LS5, LS6, LS10, LS11, LS12, LS13, LS14, LS15, LS16, LS17, LS18, LS19 +3 |
| 10 | TC78H621FNG | Package_SO:TSSOP-16_4.4x5mm_P0.65mm | U1, U2, U3, U4, U5, U6, U7, U8, U9, U10 |
| 4 | 560u | footprints:CAP_EEEFT1V561AP | C21, C22, C23, C24 |
| 4 | QBLP680-RGB1 | footprints:QBLP680-RGB1 | D1, D2, D3, D4 |
| 3 | 43 | Resistor_SMD:R_0805_2012Metric | R4, R5, R8 |
| 2 | 100 | Resistor_SMD:R_0805_2012Metric | R6, R7 |
| 2 | MountingHole_3.2mm_M3_Pad_TopBottom | MountingHole:MountingHole_3.2mm_M3_Pad_TopBottom | MountingHole1, MountingHole2 |
| 1 | 100k | Resistor_SMD:R_0805_2012Metric | R1 |
| 1 | 10u | Capacitor_SMD:C_0805_2012Metric | C25 |
| 1 | 20k | Resistor_SMD:R_0805_2012Metric | R3 |
| 1 | 2k | Resistor_SMD:R_0805_2012Metric | R9 |
| 1 | 51k | Resistor_SMD:R_0805_2012Metric | R2 |
| 1 | Conn_01x02 | Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical | J3 |
| 1 | Conn_02x12_Counter_Clockwise | Connector_PinSocket_2.54mm:PinSocket_2x12_P2.54mm_Vertical | J2 |
| 1 | LOGO | footprints:SDU_logo | G*** |
| 1 | Screw_Terminal_01x02 | TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x02_P3.50mm_Horizontal | J1 |
| 1 | Speaker_Ultrasound | footprints:MCUSR16A39S12RO | LS20 |
It measures 100 × 62 mm and has 2 copper layers, 1.6 mm thick.
74 parts, built around the TC78H621FNG,EL and QBLP680-RGB1. 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.
From the Stachu1/Sodar repository on GitHub, at the commit this page was made from: the board is hardware/sodar.kicad_pcb and its schematic hardware/sodar.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Its repository states no licence, so its author keeps all rights: ask Stachu1 before reusing the design.

Tonikiller10000/UltrasonicPhasedArray
An ultrasonic Phased Array made out of 8 10mm ultrasonc transmitters.


lucanatorvs/eZ-Green
This repository contains the firmware and related files for the eZ-Green gauge cluster project, designed for a BMW E36, as part of an EV conversion detailed on vanstraatenelectric.nl.


hackclub/OnBoard
💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

CRImier/MyKiCad
My KiCad boards. Can't be bothered uploading individually anymore, so here you go.

Teslafly/Dead-OpenBMS-dead
A scalable, open source battery management system

profdc9/RFBitBanger
A QRP digital transceiver created from readily available parts for off-the-grid maintenance