HomeApplication notesExtract waveform data from Siglent oscilloscope …
OscilloscopesProgramming & remote controlIntermediate

Extract waveform data from Siglent oscilloscope binary files

Binary .bin captures are the fastest way to move deep-memory waveforms off a scope — here is how the format works and how to convert the raw codes back into volts and seconds with Python.

12 min readIncludes code

Waveform data can be saved in many formats, but binary (.bin) gives the smallest files and the fastest USB/LAN transfers — essential when a capture holds millions of points. The trade-off: binary is not human-readable. This note explains the structure of Siglent's binary waveform files and how to convert the raw sample codes back into real voltages and time.

The file structure in a nutshell

  • A header holds the acquisition context: which channels are on, V/div and offset per channel, timebase, trigger delay, sample rate and the code-per-division scaling
  • The data section follows: one sample code per point per enabled channel (8-bit on most models, 16-bit on high-resolution scopes)
  • The header layout is versioned via a bin_head_ver field — the official spec documents every version chapter by chapter, with byte-exact offsets (e.g. ch1_vert_code_per_div at 0x268)

Always read bin_head_ver first and use the matching chapter of the spec — field offsets differ between versions, and mixing them up produces garbage waveforms that still look plausible.

The four conversion formulas

Everything you need to reconstruct the waveform comes down to four documented formulas (values from the header; examples from the spec):

text
sample_rate  = wave_length / (hori_div_num * time_div_val)
vert_offset  = (ch_vert_offset - 220) * (ch_volt_div_val / pixel_per_div)
time_delay   = (time_offset - 349) * (time_div_val / pixel_per_div)
voltage[i]   = (code[i] - 128) * ch_volt_div_val / 1000 / code_per_div + vert_offset

A practical Python skeleton

python
import numpy as np

with open('SDS_capture.bin','rb') as f:
    raw = f.read()

# 1) read header fields at the offsets for YOUR bin_head_ver (see the spec)
#    e.g. vdiv, vert_offset, sample_rate, code_per_div, data_start, n_points

# 2) slice the data section and convert codes -> volts
codes  = np.frombuffer(raw, dtype=np.int8, count=n_points, offset=data_start)
volts  = codes.astype(float) * vdiv / code_per_div + vert_offset
t      = np.arange(n_points) / sample_rate + time_delay

# 3) plot or process
import matplotlib.pyplot as plt
plt.plot(t, volts); plt.xlabel('s'); plt.ylabel('V'); plt.show()
What you should see
1,000,000 samples converted -> 1.00 GSa/s, CH1 50 mV/div
peak-peak: 0.312 V   mean: -0.0021 V

Working with a 12-bit HD scope? The data section uses 16-bit codes — read with dtype=np.int16 and the HD code-per-div value from the header. The same four formulas apply.

Get the full format specification

The complete 62-page specification — every header field, every bin_head_ver version, all unit and magnitude tables — is available as a PDF: How to Extract Data from the Binary File of SIGLENT Oscilloscope (EN03B).

With the header decoded once for your scope's format version, the actual conversion is three lines of NumPy — and binary transfers stay an order of magnitude faster than CSV for deep-memory captures.