Skip to content

SCP-ECG (Standard Communications Protocol for Computer-Assisted Electrocardiography)

Interchange format for resting-ECG recordings: patient demographics, acquisition metadata, lead definitions, optionally compressed waveform data, optional reference-beat data, and optional measurements and interpretive statements. A file is a 6-byte record header followed by a sequence of variable-length sections, each prefixed by its own 16-byte section header.

The reference text is EN 1064:2005+A1:2007 (CEN/TC 251 “Health informatics”), which supersedes ENV 1064:1993 and incorporates the SCP-ECG specification from the AIM SCP-ECG Project (1989-1990).

A file has two structural parts:

  • Record header — fixed 6 bytes: a 2-byte CRC over the rest of the record, then a 4-byte unsigned record length in bytes (including the 6-byte header itself).
  • Section list — a concatenation of sections, each with its own 16-byte ID header (CRC, section ID, section length, section version, protocol version, reserved) followed by a variable-length data part. Section 0 (Pointer Section) must come first; the other sections may appear in any order.

Twelve sections are defined by the spec (numbered 0..11):

# Required Content
0 required Pointers to every section present in the record
1 required Patient demographic data + ECG acquisition data (tag/length/value layout)
2 dependent Huffman tables (required if Sections 5/6 use Huffman encoding)
3 required ECG lead definition (lead identifiers, sample ranges, simultaneity flags)
4 optional QRS locations, reference-beat subtraction zones, protected areas
5 optional Encoded reference beat type 0
6 required Rhythm data (full ECG or residual signal after reference-beat subtraction)
7 optional Global measurements + pacemaker spike data
8 optional Full-text interpretive statements
9 optional Manufacturer-specific interpretive statements / overreading trail
10 optional Per-lead measurement block
11 optional Universal ECG interpretation statement codes (Annex F vocabulary)

Valid Section IDs range from 0 to 32767. IDs 0..11 are defined by the protocol, 12..127 and 1024..32767 are reserved for future use, and 128..1023 are manufacturer-specific. A manufacturer-specific section’s layout is not constrained by the spec, but the Section ID header (16 bytes) is still mandatory.

A conforming writer commits to one of two data-format categories. The upper four bits of Section 1 tag 14 byte 16 encode the category that the record itself was written under. The lower four bits are reserved and shall be zero:

Category Required sections Compatibility bits (tag 14 byte 16, MSB first) Content
I 0, 1, [2], 3, 6, (7), (8), (10) 1101 0000 Demographics + rhythm data (uncompressed or with lossless compression)
II 0, 1, [2], 3, 4, 5, 6, (7), (8), (10) 1110 0000 Demographics + rhythm data + reference beats (lossless or “high” compression allowed)

Square brackets mean Section 2 is required when Huffman encoding is used. Parentheses mark optional sections.

Normative Annex B distinguishes three functions independently of the communication channel:

  • Export creates an SCP-ECG record of a stated Data Format Category from raw ECG data, including the compression performance required by Clause 6.
  • Import accepts an SCP-ECG record of a stated category, extracts its information, and makes that information available to the user. An importing device shall support at minimum Sections 0, 1, 3, 6, 7, and 8.
  • Transfer re-exports a previously imported record in the same Data Format, with or without modifications to individual sections. Components that the importer cannot process are preserved, and imported waveform data shall incur no further compression loss: either the original compressed data is sent or any recompression is lossless.

SCP-ECG has no magic number. A reader detects the format by:

  • CRC-CCITT at bytes 0..1 of the record, covering bytes 2 through record-length-1. A correct CRC at that position is the strongest signal.
  • Record length at bytes 2..5 (unsigned 32-bit little-endian) that matches the actual file size.
  • Section 0 marker: bytes 11..16 of Section 0’s ID header contain the ASCII string "SCPECG".

Files conventionally use no fixed extension; clinical systems pick their own (often .scp, .ecg).

These rules apply to every field, every section, every byte.

  • Byte order: little-endian for all multi-byte integers (“least significant byte transmitted first”). Single-byte values are unsigned unless declared signed.
  • Signed values: two’s complement.
  • Byte numbering: bytes are numbered from left to right, starting at 1. Bits within a byte are numbered from right (LSB = bit 0) to left (MSB = bit 7).
  • Record byte 1 is the first byte of the 2-byte CRC.
  • Sample numbering: ECG samples are 1-based. Sample index 0 is not used. Sample 1 is at time 0; with a 500 Hz rate sample 2 is at time 2 ms.
  • Section alignment and size: every section begins at an odd 1-based byte index, equivalently an even zero-based offset, and has an even byte count. If a section’s payload is odd, a single 0x00 padding byte is appended. Padding occurs only at the end of a section.
  • Reserved fields are 0x00.
  • Text fields are NULL-terminated and the NULL is counted toward the declared length. They follow the ISO/IEC 2022 conformance profile in Multi-lingual text encoding; the default character set is ISO/IEC 8859-1 (Latin-1).
  • KByte in this document means exactly 1024 bytes.
  • Pointer arithmetic: all byte indexes and pointers are 1-based unless stated otherwise.
Off Size Field Content
0 2 crc CRC-CCITT over bytes 2..end-of-record (see CRC-CCITT)
2 4 record_size Unsigned 32-bit total record size in bytes, including the 6 bytes here

After the record header comes Section 0, then any subset of the other sections in any order.

Record overview:

+-----+---------------+-----------+-----------+ ... +---------------+
| CRC | Record Length | Section 0 | Section X | ... | Final Section |
+-----+---------------+-----------+-----------+ ... +---------------+
| 2 | 4 | 136 + var | var | ... | var |
+--------------------------------------------------------+
CRC domain

Every section begins with the same 16-byte layout. The data part length equals section_length - 16.

Off Size Field Content
0 2 crc CRC-CCITT over the rest of the section (bytes 2..section_length-1)
2 2 section_id Section ID number in 0..32767 (0..11 defined; 128..1023 manufacturer-specific)
4 4 section_length Total section length in bytes, including these 16 header bytes; always even
8 1 section_version Protocol version under which a standard section was approved; manufacturer-defined for 128..1023
9 1 protocol_version Protocol version, mirror of Section 1 tag 14 byte 15
10 6 reserved Zero, except in Section 0 where bytes 11..16 hold the ASCII string "SCPECG"

If a section is not present in the record, its pointer entry in Section 0 carries length 0 and index 0 (see Section 0). Sections 2..11 always have a pointer slot in Section 0 even when absent.

Always present, always first. Section 0 inventories the location and length of every other section. Bytes 11..16 of the Section ID header are the ASCII bytes "SCPECG" (no NULL terminator).

The data part is a sequence of 10-byte pointer fields, one per section. Pointer fields appear in ascending section-ID order:

Off Size Field Content
0 2 section_id Section ID (0..32767)
2 4 length Section length in bytes, including its 16-byte ID header; 0 if absent
6 4 index 1-based byte offset of the section’s first byte; 0 if absent

Constraints:

  • Pointer fields for Sections 0..11 must all be present even when the section itself is absent. Absent sections set length = 0 and index = 0.
  • The first pointer field is for Section 0 itself. Its index is always 7, because Section 0 sits immediately after the 6-byte record header.
  • Manufacturer-specific sections (128..1023) get pointer fields too if they are present.
  • Section 0 has total length 136 bytes (16-byte header + twelve 10-byte pointer fields for Sections 0..11), plus 10 bytes for each manufacturer-specific section that is present. Its base data part is 120 bytes; figures that show 120 + var exclude the 16-byte Section ID header.

Section 1 — Patient and acquisition data

Section titled “Section 1 — Patient and acquisition data”

Variable-length sequence of header fields. Each field has a 1-byte tag, a 2-byte unsigned length (counting only the value bytes, not the tag or length), and length value bytes. The section ends at the terminator tag 255 with length 0.

Field-level encoding rules:

  • The tag and length bytes are not included in the declared length.
  • Text values are NULL-terminated; the NULL is counted in length. Length 0 means “field not defined”.
  • The 2-byte length can represent up to 65535 bytes, but a field value shall not exceed 64 bytes except tags 13, 30, and 35, whose maximum is 80 bytes.
  • Tags 200..254 are reserved for manufacturer-defined fields.
  • Tag 255 is the section terminator; length is 0.
  • At most one instance per tag, except tags 10, 13, 30, 32, 35 which allow repetition.

Mandatory fields:

Tag Field Notes
2 Patient ID Primary key. First 16 characters must be unique.
14 Acquiring Device ID
25 Date of Acquisition
26 Time of Acquisition Local wall-clock time at acquisition

Strongly recommended:

Tag Field
0 Patient Last Name
1 Patient First Name
5 Patient Date of Birth
8 Patient Sex
15 Analyzing Device ID
34 Date Time Zone
Tag Length Field Encoding
0 var (text) Last name Used for the entire name if no first name is split out
1 var (text) First name
2 var (text) Patient ID
3 var (text) Second last name Locale-specific (US: family-member prefix; FR: maiden name; ES/PT/LATAM: second surname)
4 3 Age Bytes 1-2: age as unsigned int; byte 3: unit (0=unspecified, 1=years, 2=months, 3=weeks, 4=days, 5=hours). All-zero = not specified.
5 4 Date of birth Bytes 1-2: year (full 4-digit); byte 3: month 1..12; byte 4: day 1..31. All-zero = not specified.
6 3 Height Bytes 1-2: value; byte 3: unit (0=unspecified, 1=cm, 2=in, 3=mm)
7 3 Weight Bytes 1-2: value; byte 3: unit (0=unspecified, 1=kg, 2=g, 3=lb, 4=oz)
8 1 Sex 0=not known, 1=male, 2=female, 9=unspecified
9 1 Race 0=unspecified, 1=Caucasian, 2=Black, 3=Oriental, 4..9 reserved, 10..255 manufacturer
10 var Drugs Byte 1: drug-table indicator (0 = standard table below); byte 2: class code; byte 3: drug code within class; bytes 4..: optional drug name as NULL-terminated text. Multiple instances allowed.
11 2 Systolic blood pressure mmHg
12 2 Diastolic blood pressure mmHg
13 var (text) Diagnosis or referral indication Multiple instances allowed
14 var Acquiring device ID See Device ID structure
15 var Analyzing device ID Same layout as tag 14
16 var (text) Acquiring institution description
17 var (text) Analyzing institution description
18 var (text) Acquiring department description
19 var (text) Analyzing department description
20 var (text) Referring physician
21 var (text) Latest confirming physician
22 var (text) Technician description
23 var (text) Room description
24 1 Stat code 0=routine; higher = more urgent (1..10 recommended)
25 4 Date of acquisition Same layout as tag 5
26 3 Time of acquisition Byte 1: hours 0..23; byte 2: minutes 0..59; byte 3: seconds 0..59. Local time in the acquisition timezone.
27 2 Baseline filter cutoff -3 dB high-pass cutoff in 1/100 Hz
28 2 Low-pass filter cutoff -3 dB cutoff in Hz
29 1 Filter bit map Bit 0: 60 Hz notch; bit 1: 50 Hz notch; bit 2: artifact; bit 3: baseline (adaptive/spline); bits 4..7 undefined. All-zero = not specified.
30 var (text) Free text Multiple instances allowed
31 var (text) ECG sequence number
32 var Medical history codes Byte 1: code-table indicator (0 = standard table below); remaining bytes: one code per byte. Multiple instances allowed.
33 2 Electrode configuration code Byte 1: 12-lead placement system; byte 2: XYZ-lead system (see Electrode configuration)
34 var Date time zone See Time zone
35 var (text) Free-text medical history Multiple instances allowed
255 0 Section terminator No value

The 64-byte and 80-byte field limits above are normative. Within those limits, the spec gives the following reasonable lengths. Multiple instances are allowed where noted; each instance is independently NULL-terminated.

Tag Field Multiple Recommended length
0 Last name no 40
1 First name no 40
2 Patient ID no 40
3 Second last name no 40
10 Drugs yes 40
13 Diagnosis / referral yes 80
14 Acquiring device ID no 40
15 Analyzing device ID no 40
16 Acquiring institution no 40
17 Analyzing institution no 40
18 Acquiring department no 40
19 Analyzing department no 40
20 Referring physician no 60
21 Latest confirming physician no 60
22 Technician description no 40
23 Room description no 40
30 Free text yes 80
31 ECG sequence number no 12
35 Free-text medical history yes 80

Used by tags 14 (acquiring device) and 15 (analyzing device).

Off Size Field
0 2 Institution number
2 2 Department number
4 2 Device ID
6 1 Device type: 0=cart, 1=system/host
7 1 Set to 255. Legacy use: numeric manufacturer code (0..21 assigned, 100 = other). Use the trailing string instead.
8 6 Model description as up to 5 ASCII bytes + NULL terminator
14 1 SCP-ECG protocol revision (e.g. 1.0 -> 10, 2.0 -> 20; backward-compatible revisions where possible)
15 1 SCP-ECG compatibility level (per Annex B; upper 4 bits encode the conformance category, lower 4 bits are reserved and zero)
16 1 Language support code, bit-mapped (see Language support)
17 1 Device capability bit map: bit 4 = can print ECG reports; bit 5 = can interpret; bit 6 = can store; bit 7 = can acquire; bits 0..3 reserved
18 1 AC mains frequency: 0=unspecified, 1=50 Hz, 2=60 Hz
19 16 Reserved (bytes 20..35 of the tag value); zero-fill
35 1 Length of the analysing-program revision string (>= 1)
36 var NULL-terminated analysing-program revision number
var NULL-terminated serial number of the acquisition device
var NULL-terminated acquisition-device system software identifier
var NULL-terminated SCP implementation software identifier (<= 24 chars + NULL)
var NULL-terminated manufacturer registered trade name

Each trailing string is a separate NULL-terminated character string under the restricted ISO/IEC 2022 profile in Annex A, with ISO/IEC 8859-1 as the default character set. Each string starts in the default character-set state. An empty trailing string is encoded as a single NULL byte.

One byte in tag 14 byte 17. Bit map identifies the character sets the device can read and write:

Bit pattern (MSB..LSB) Meaning
xxxx xx00 8-bit ASCII only
xxxx xx01 ISO/IEC 8859-1 Latin-1
0000 0011 ISO/IEC 8859-2 Latin-2 (Central/Eastern European)
0000 1011 ISO/IEC 8859-4 Latin-4 (Baltic)
0001 0011 ISO/IEC 8859-5 Cyrillic
0001 1011 ISO/IEC 8859-6 Arabic
0010 0011 ISO/IEC 8859-7 Greek
0010 1011 ISO/IEC 8859-8 Hebrew
0011 0011 ISO/IEC 8859-11 Thai
0011 1011 ISO/IEC 8859-15 Latin-9 (“Latin-0”)
0000 1111 ISO/IEC 10646 (Unicode)
0001 1111 JIS X 0201-1976 (Japanese single-byte)
0010 1111 JIS X 0208-1997 (Japanese multi-byte)
0011 1111 JIS X 0212-1990 (Japanese supplementary)
0100 1111 GB 2312-80 (Simplified Chinese)
0101 1111 KS C5601-1987 (Korean)
1111 1111 Manufacturer-specific

Other bit combinations are reserved.

Tag 10 byte 2 selects a class; byte 3 selects a drug within the class. Codes 100..255 in byte 2 are out-of-band markers (“not taking drugs”, “drugs unknown”, “other”, or manufacturer-specific).

Class Name Examples (byte 3)
0 Unspecified byte 3 must also be 0; text in bytes 4.. is the only description
1 Digitalis 1=Digoxin/Lanoxin, 2=Digitoxin
2 Antiarrhythmic 1=Disopyramide, 2=Quinidine, 3=Procainamide, 4=Lidocaine, 5=Phenytoin, 6=Dilantin, 7=Amiodarone, 8=Tocainide, 9=other, 10=Encainide, 11=Mexiletine, 12=Flecainide, 13=Lorcainide
3 Diuretics 1=Thiazide, 2=Furosemide, 3=Potassium chloride
4 Antihypertensive 1=Clonidine, 2=Prazosin, 3=Hydralazine
5 Antianginal 1=Isosorbide, 2=Calcium blockers, 3=Nitrates
6 Antithrombotic 1=Aspirin, 2=Coumadin, 3=Heparin, 4=Warfarin, 5=Streptokinase, 6=t-PA
7 Beta blockers 1=Propranolol, 2=Corgard, 3=Atenolol, 4=Metoprolol, 5=Pindolol, 6=Acebutolol
8 Psychotropic 1=Tricyclic antidepressant, 2=Phenothiazide, 3=Barbiturate
9 Calcium blockers 1=Nifedipine, 2=Verapamil
10 Antihypotensive 1=Asthmatic drug, 2=Aminophyline, 3=Isuprel
11 Anticholesterol 1=Colestid, 2=Lovastatin, 3=Simvastatin, 4=Fibrates
12 ACE inhibitors 1=Captopril
13..99 Reserved
100 Not taking drugs byte 3 = 0
101 Drugs, unknown byte 3 = 0
102 Other medication byte 3 = 0
103..255 Manufacturer-specific

Sub-code 9 is reserved for “other” within each class.

Tag 32 byte 1 selects the code table; byte 1 = 0 means the standard SCP-ECG table below, where each subsequent byte is one diagnosis code:

Code Meaning
0 Not specified
1 Apparently healthy
10 Acute myocardial infarction
11 Myocardial infarction
12 Previous myocardial infarction
15 Ischemic heart disease
18 Peripheral vascular disease
20 Cyanotic congenital heart disease
21 Acyanotic congenital heart disease
22 Valvular heart disease
25 Hypertension
27 Cerebrovascular accident
30 Cardiomyopathy
35 Pericarditis
36 Myocarditis
40 Post-operative cardiac surgery
42 Implanted cardiac pacemaker
45 Pulmonary embolism
50 Respiratory disease
55 Endocrine disease
60 Neurological disease
65 Alimentary disease
70 Renal disease
80 Pre-operative general surgery
81 Post-operative general surgery
90 General medical
100 Other
128..255 Manufacturer-specific

Codes 2..9, 13, 14, 16, 17, 19, 23, 24, 26, 28, 29, 31..34, 37..39, 41, 43, 44, 46..49, 51..54, 56..59, 61..64, 66..69, 71..79, 82..89, 91..99 are reserved for future extension.

Tag 33 byte 1: 12-lead electrode placement system.

Code System
0 Unspecified
1 Standard 12-lead: RA, RL, LA, LL on limb extremities; V1..V6 at standard chest sites
2 Mason-Likar: RA/RL/LA/LL on torso; V1..V6 standard chest, individually placed
3 Mason-Likar limb; V1..V6 in a single chest-pad assembly
4 All electrodes (limb + V1..V6) in one chest pad (e.g. Omnitrode)
5 12-lead derived from Frank XYZ leads
6 12-lead derived from non-standard leads
7..255 Reserved

Tag 33 byte 2: XYZ-lead electrode placement system.

Code System
0 Unspecified
1 Frank lead system (Frank 1956)
2 McFee-Parungao lead system
3 Cube lead system (Grishman et al. 1951)
4 Bipolar uncorrected XYZ
5 Pseudo-orthogonal XYZ (Holter-style)
6 XYZ derived from 12-lead
7..255 Reserved

Tag 34. Lets the date/time in tags 25/26 be converted to UTC. Three ways to specify the zone are stacked; later mechanisms are consulted only when offset == 0x7FFF.

Off Size Field Content
0 2 offset Signed minutes east of UTC, range -780..+780 (i.e. ±13 h); 0x7FFF = unset
2 2 index Unsigned manufacturer-defined lookup index when offset == 0x7FFF; 0 = unset; 1..1000 reserved; 1001..32766 manufacturer; 32767 reserved
4 var description NULL-terminated POSIX TZ-style string when offset == 0x7FFF; 1 byte minimum (the NULL)

Tag 34 may be omitted entirely if the device does not record a time zone. A present tag 34 with offset = 0x7FFF, index = 0, description = "" is the explicit “unknown” form.

Optional. Required when Sections 5 (reference beat) or 6 (rhythm) use Huffman encoding. Defines one or more Huffman tables used to compress the reference-beat and residual data.

Off Size Field Content
0 2 table_count Number of Huffman tables; value 19999 means “use default table” (see Default Huffman table)
2 2 structure_count[0] Number of code structures in table 1
4 N*9 structures[0] structure_count[0] × 9-byte code structure
2 structure_count[k] Number of code structures in table k+1
N*9 structures[k] Code structures for table k+1

Tables are referenced by 1-based position. The first table is the implicit default; Huffman streams in Sections 5/6 start by decoding under table 1.

Each code structure is 9 bytes:

Off Size Field Content
0 1 prefix_bits Number of bits in the prefix
1 1 total_bits Number of bits in the entire code
2 1 mode 0 = switch to another Huffman table (the table number is in base_value); 1 = Huffman or initial encoding (see below)
3 2 base_value Decoded sample value in AVM units (signed 16-bit). When mode == 0, this holds the target table number.
5 4 base_code The prefix bit pattern. First bit in the code is the least significant bit of this 4-byte little-endian field.

If mode == 1 and prefix_bits == total_bits, the structure is a pure-Huffman code: the prefix is a single self-contained code mapping to base_value. If prefix_bits < total_bits, the structure is an initial-encoding code: after the prefix the bitstream carries an explicit (total_bits - prefix_bits)-bit remainder, which is the actual signed sample. The MSB of the remainder is sign-extended into the reconstructed sample word.

If mode == 0, the structure switches the active table to the table indexed by base_value. The active table resets at the start of each lead.

Bits inside a byte are picked MSB-first. Bytes are consumed in stream order.

When Section 2’s table_count == 19999, the default table below is used. If Section 2 is absent, Sections 5 and 6 carry raw signed 16-bit values as described below. The default table is tuned for second-difference residuals of typical resting ECGs:

# Total bits Prefix bits Mode Base value Prefix (binary) Stored base_code (decimal)
1 1 1 1 0 0 0
2 3 3 1 +1 100 1
3 3 3 1 -1 101 5
4 4 4 1 +2 1100 3
5 4 4 1 -2 1101 11
6 5 5 1 +3 11100 7
7 5 5 1 -3 11101 23
8 6 6 1 +4 111100 15
9 6 6 1 -4 111101 47
10 7 7 1 +5 1111100 31
11 7 7 1 -5 1111101 95
12 8 8 1 +6 11111100 63
13 8 8 1 -6 11111101 191
14 9 9 1 +7 111111100 127
15 9 9 1 -7 111111101 383
16 10 10 1 +8 1111111100 255
17 10 10 1 -8 1111111101 767
18 18 10 1 8-bit initial value 1111111110 511
19 26 10 1 16-bit initial value 1111111111 1023

base_code is stored bit-reversed in its 4-byte slot (LSB of the field carries the first bit of the prefix). Structures 18 and 19 encode out-of-table samples by appending an 8- or 16-bit signed remainder after the 10-bit prefix.

Each lead’s payload in Sections 5 and 6 is a self-contained Huffman bitstream. The active table resets to table 1 at the start of every lead. The decoder maintains a single bit cursor into the lead bytes; bits within a byte are consumed from the most significant bit toward the least significant, then to the next byte.

To decode one sample:

  1. Read the prefix. Read bits one at a time and compare the accumulated bit pattern against every structure in the active table whose prefix_bits equals the number of bits read. If nothing matches, read one more bit and repeat. Continue until exactly one structure matches.
  2. Branch on the matched structure’s mode:
    • mode == 0 (table switch). The active table changes to the table number stored in base_value. Do not emit a sample; loop back to step 1 and decode the next sample under the new table.
    • mode == 1, prefix_bits == total_bits (pure Huffman). Emit base_value as the decoded sample. Advance the cursor by prefix_bits (already consumed) and return.
    • mode == 1, prefix_bits < total_bits (initial encoding). Read total_bits - prefix_bits more bits from the stream as the remainder. Sign-extend the remainder by replicating its most significant bit into the higher bits of the 16-bit sample word, then emit. base_value is unused for initial-encoding structures.
  3. Repeat for the next sample.

A worked example: with the default table, the bit sequence 1111111110 00000101 decodes by matching structure 18 (prefix 1111111110, total 18 bits), then reading the 8-bit remainder 00000101 (decimal 5), sign-extending the MSB (0) into the upper 8 bits, and emitting 0x0005 = 5.

A switching example with custom tables: prefix 1110 matched in table 1 with mode = 0, base_value = 2 switches the active table to table 2; the next bit starts a fresh match against table 2.

The decoder stops when the lead’s declared byte length is exhausted. Trailing bits inside the last byte are discarded.

Required. Lists the leads in the record, the sample range covered by each lead, and whether reference-beat subtraction is used.

Off Size Field Content
0 1 lead_count Number of leads
1 1 flags Bit 0: 1 = reference-beat subtraction used in compression. Bit 1: reserved. Bit 2: 1 = all leads recorded simultaneously. Bits 3..7: count of leads recorded simultaneously
2 9*N leads lead_count × 9-byte lead descriptor

Each lead descriptor:

Off Size Field Content
0 4 start_sample Unsigned 1-based starting sample number
4 4 end_sample Unsigned 1-based ending sample number (inclusive)
8 1 lead_id Lead identification code (see Lead identification codes)

When leads are not all simultaneously recorded, descriptors are grouped: the first flags[3..7] descriptors describe one simultaneously-recorded group, the next descriptors describe the next group, and so on.

Sample numbering is 1-based and refers to all leads in a recording group together. For 8 leads (I, II, V1..V6) recorded simultaneously at 500 Hz for 10 s, every lead has start_sample = 1, end_sample = 5000. For two groups of three leads recorded at 500 Hz for 2.5 s each (I/II/III then aVR/aVL/aVF), the first group has samples 1..1250, the second 1251..2500.

To convert sample numbers to time, divide by the per-section sample rate from Section 6 (rhythm) or Section 5 (reference beat).

The lead-id byte uses the SCP-ECG lead vocabulary. Codes 200..255 are manufacturer-specific. Codes 185..199 are reserved for future use. The full vocabulary mirrors ISO/IEEE 11073-10101 (MDC_ECG_LEAD_*).

Standard 12-lead set:

Code Lead Code Lead Code Lead
0 Unspecified 61 III 66 V8
1 I 62 aVR 67 V9
2 II 63 aVL 68 V8R
3 V1 64 aVF 69 V9R
4 V2 65 aVR (inverted, aVRneg) 147 RL (right leg)
5 V3 21 LA (left arm)
6 V4 22 RA (right arm)
7 V5 23 LL (left leg)
8 V6

Right-sided precordials: 9 (V7), 10..15 (V2R..V7R).

Orthogonal Frank-lead set: 16 (X), 17 (Y), 18 (Z).

Frank-derived leads (“f” prefix): 24..30 (fI, fE, fC, fA, fM, fF, fH).

Nehb leads: 70 (D, dorsal), 71 (A, anterior), 72 (J, inferior).

Modified chest leads: 91..97 (MCL, MCL1..MCL6), 121 (CM7), 122 (CH5), 105 (CM), 106..110 (CM1..CM6), 123..125 (CS5, CB5, CR5), 126 (ML).

Stress-test bipolar leads: 19 (CC5), 20 (CM5), 98 (CC, symmetric), 99..104 (CC1..CC4, CC6, CC7).

EASI lead set: 131 (ES), 132 (AS), 133 (AI), 134 (S, upper sternum).

Auxiliary leads: 75..78 (A1..A4 unipolar), 127..130 (AB1..AB4 bipolar).

Defibrillator and pacing leads: 73 (Defib, anterior-lateral), 74 (Extern, anterior-posterior external pacing).

Other: 86 (Chest), 87 (V precordial), 88..90 (VR, VL, VF nonaugmented), 19 (CC5), 91 (MCL).

Canine leads: 148 (CV5RL), 149 (CV6LL), 150 (CV6LU), 151 (V10).

Derived versions of any lead use code original + 30 for IDs 1..30, or are listed individually at 31..60 (derived I, II, V1..V7, V2R..V7R, X, Y, Z, CC5, CM5, LA, RA, LL, fI, fE, fC, fA, fM, fF, fH) and 79..85 (derived V8, V9, V8R, V9R, D, A, J) and 111..120 (derived III, aVR, aVL, aVF, aVRneg, Chest, V, VR, VL, VF) and 135..146, 152..184 for the remaining derived leads.

Notes on lead semantics:

  • V2R is equivalent to V1; V1R is equivalent to V2.
  • X, Y, Z are the orthogonal Frank-lead set.
  • The “d-” prefix marks an algebraically derived lead, distinguished from a directly recorded one.
  • EASI is a trademark owned by Philips. Codes 131..134 use the positions described by Gordon Dower.

Section 4 — QRS locations, subtraction zones, protected areas

Section titled “Section 4 — QRS locations, subtraction zones, protected areas”

Optional. Stores the location and reference-beat type of each QRS in the rhythm record. Required when reference-beat subtraction or bimodal compression is used.

Off Size Field Content
0 2 ref_beat_length Length of reference beat type 0 in milliseconds
2 2 fcM 1-based sample number of the fiducial (QRS trigger) within reference beat 0
4 2 qrs_count Total number of QRS complexes in the record

To convert ref_beat_length from ms to samples, divide by the sample-time interval (in µs) from Section 5: N = (1000 * L) / SI, truncating toward zero. The writer is responsible for picking a length that gives the intended sample count.

Subtraction-zone blocks (14 bytes per QRS)

Section titled “Subtraction-zone blocks (14 bytes per QRS)”
Off Size Field Content
0 2 beat_type Reference-beat type for this QRS. Type 0 is the “normal” beat used for subtraction.
2 4 SB 1-based sample on residual data where subtraction of beat 0 starts. 0 if beat_type != 0.
6 4 fc 1-based sample on residual data of this QRS’s fiducial point
10 4 SE 1-based sample on residual data where subtraction of beat 0 ends. 0 if beat_type != 0.

All sample numbers refer to the original raw data before any decimation or filtering. First sample is 1.

Off Size Field Content
0 4 QB 1-based sample on residual data: start of this QRS’s protected area
4 4 QE 1-based sample on residual data: end of this QRS’s protected area

The protected area always includes QRS onset..offset and is sized so that the non-protected gap between consecutive complexes is an integer multiple of the decimation factor (see Sample decimation).

Section 4 may carry protected-area blocks even when reference-beat subtraction is not used, e.g. for bimodal-compression-only files. In that case SB and SE are 0.

Section 5 — Encoded type 0 reference beat

Section titled “Section 5 — Encoded type 0 reference beat”

Optional. The encoded representative beat used for subtraction reconstruction. Required when Section 3’s reference-beat-subtraction flag is set.

Off Size Field Content
0 2 avm Amplitude value multiplier in nanovolts (e.g. 1250 -> 1.250 µV per LSB)
2 2 sample_time Sample time interval in microseconds (e.g. 2000 -> 500 Hz)
4 1 diff_used 0 = raw samples; 1 = first differences; 2 = second differences (see Difference encoding)
5 1 reserved 0

lead_count × 2-byte unsigned values, listing the byte length of each encoded lead’s payload in the order leads are declared in Section 3.

Each lead’s bytes follow the length table, concatenated in lead order. When Section 2 is present, the payload is a Huffman bitstream keyed by the indicated table. When Section 2 is absent, the payload is signed 16-bit samples (or differences) in little-endian.

A writer wanting non-Huffman fixed-width encoding can supply a “dummy” Section 2 with one structure: prefix_bits = 0, total_bits = N. That yields plain N-bit two’s-complement samples.

Required. Carries either the full ECG rhythm or, if reference-beat subtraction is on, the residual signal after subtraction.

Off Size Field Content
0 2 avm Amplitude value multiplier in nanovolts
2 2 sample_time Sample time interval in microseconds
4 1 diff_used 0 = raw; 1 = first differences; 2 = second differences
5 1 bimodal 0 = bimodal compression off; 1 = bimodal compression on

When bimodal == 1, protected residual samples use the sample interval declared in Section 5 but the AVM declared in Section 6. Outside the protected areas listed in Section 4, residual samples use both the AVM and sample interval declared in Section 6.

Same layout as Section 5: a 2-byte length per lead, then the leads’ payloads concatenated in declaration order. Same Huffman / raw rules as Section 5.

Section 7 — Global measurements and pacemaker spikes

Section titled “Section 7 — Global measurements and pacemaker spikes”

Optional. Aggregates per-beat and global measurements across leads, plus a list of pacemaker spikes.

The Section 7 data part is concatenated in this order:

  1. The 6-byte header.
  2. count_marker consecutive 16-byte measurement blocks.
  3. pacemaker_count consecutive 4-byte pacemaker spike measurement blocks.
  4. pacemaker_count consecutive 6-byte pacemaker spike information blocks in the same spike order.
  5. The QRS type block: a 2-byte QRS count followed by one type byte per QRS.
  6. The additional global-measurement block and its tagged fields.
  7. An optional manufacturer-specific global-measurement block.
Off Size Field Content
0 1 count_marker Number of 16-byte measurement blocks: either the number of reference-beat types or QRS count + 1. The first block always describes reference beat type 0; when equal to QRS count + 1, the remaining blocks describe individual QRS complexes in sequence.
1 1 pacemaker_count Number of pacemaker spikes whose timing/amplitude is reported
2 2 rr_average Average RR interval over all QRS, in ms
4 2 pp_average Average PP interval over all QRS, in ms

Each measurement block is 16 bytes:

Off Size Field Content
0 2 p_onset ms from beat / record start
2 2 p_offset ms
4 2 qrs_onset ms
6 2 qrs_offset ms
8 2 t_offset ms
10 2 p_axis Angular degrees in frontal plane; 999 = undefined
12 2 qrs_axis Angular degrees; 999 = undefined
14 2 t_axis Angular degrees; 999 = undefined

Frontal-plane axis convention: 0 points to the patient’s left (positive horizontal); positive angles rotate clockwise (down); negative angles rotate counter-clockwise (up).

Onset/offset values are referenced to the start of the reference beat (when the block describes a beat type) or to the start of the ECG record (when the block describes one individual QRS).

The following CSE sentinel values replace measurement data where applicable:

Value Meaning
29999 Measurement not computed by the measurement program
29998 Measurement unavailable because the lead was rejected
19999 Measurement unavailable because the wave was not present
Off Size Field Content
0 2 time_ms Unsigned ms from start of rhythm record
2 2 amplitude_uv Signed µV

Spike time has a resolution of 2 ms or finer.

Pacemaker spike info (6 bytes per spike, same order as the spike-data list)

Section titled “Pacemaker spike info (6 bytes per spike, same order as the spike-data list)”
Off Size Field Content
0 1 spike_type 0 = unknown; 1 = triggers neither P nor QRS; 2 = triggers QRS; 3 = triggers P wave; 4..127 reserved; 128..254 manufacturer; 255 = no analysis
1 1 source 0 = unknown; 1 = internal; 2 = external; 3..255 reserved
2 2 triggered_qrs 1-based index into the QRS list; 0 = no link
4 2 pulse_width_us Microseconds; 0 = unknown
Off Size Field Content
0 2 qrs_count Number of QRS complexes
2 1 type_0 Reference-beat type of the first QRS
3 1 type_1 Reference-beat type of the second QRS
etc.
Off Size Field Content
0 2 vent_rate_bpm Ventricular rate, beats per minute
2 2 atrial_rate_bpm Atrial rate, beats per minute
4 2 qtc_ms Corrected QT in ms
6 1 qtc_formula 0=unknown, 1=Bazett, 2=Hodges, 3..127 reserved, 128..254 manufacturer, 255 = not available
7 2 tagged_bytes Bytes of tagged fields that follow (0 if none)
9 var tagged_fields Tag/length/value triples ending with tag 255 length 0

Defined tags in the tagged-field area:

Tag Length Field
0 5 QTend all-lead dispersion. Bytes: 1 = max-min QT in ms; 2 = HR-corrected max-min; 3 = stdev QT in ms; 4 = HR-corrected stdev; 5 = HR formula. Values 0..254 ms; 255 = not provided.
1 5 QTpeak all-lead dispersion. Same layout as tag 0, measured to T-wave peak instead of T-wave offset.
2 5 QTend precordial dispersion. Same layout, precordial leads only.
3 5 QTpeak precordial dispersion. Same layout, precordial leads only.
4..254 0 Reserved
255 0 Terminator

A variable-length manufacturer-specific block may follow the tagged fields. Its start is computed from the Section ID header length; its end is the section boundary.

Section 8 — Full-text interpretive statements

Section titled “Section 8 — Full-text interpretive statements”

Optional. Carries the latest free-text interpretation, including any overreading. Only the most recent interpretation is kept.

Off Size Field Content
0 1 confirmation 0 = original (not overread); 1 = confirmed; 2 = overread, not confirmed
1 2 year 4-digit year
3 1 month 1..12
4 1 day 1..31
5 1 hour 0..23
6 1 minute 0..59
7 1 second 0..59
8 1 statement_count Number of statement entries

Each statement entry:

Off Size Field Content
0 1 sequence_number 1-based statement index
1 2 statement_length Bytes in text including the NULL terminator
3 var text NULL-terminated text

Mnemonic codes from the Annex F vocabulary may appear in the text, but always alongside descriptive prose. Pure unaccompanied codes are not allowed in Section 8.

Section 9 — Manufacturer-specific interpretive data

Section titled “Section 9 — Manufacturer-specific interpretive data”

Optional. Carries vendor-defined diagnostic statements and the overreading trail of historical interpretations. The data part layout is entirely manufacturer-defined; only the 16-byte Section ID header is constrained.

Optional. One record per recorded lead with up to 50 standard measurements plus a manufacturer area.

Off Size Field Content
0 2 lead_count Number of leads with measurement records
2 2 manufacturer Manufacturer-specific

Bytes 5..104 are 50 signed 16-bit measurements. Bytes 105.. are a manufacturer measurement area. Bytes 67..104 are reserved and zero when a manufacturer block follows.

Off Size Field
0 2 lead_id (matches Section 3 lead codes)
2 2 Record length in bytes, excluding bytes 0..3
4 2 P_duration_ms (total P, including P+ and P-)
6 2 PR_interval_ms
8 2 QRS_duration_ms
10 2 QT_interval_ms
12 2 Q_duration_ms
14 2 R_duration_ms
16 2 S_duration_ms
18 2 R'_duration_ms
20 2 S'_duration_ms
22 2 Q_amplitude_uV (signed; Q is negative)
24 2 R_amplitude_uV (signed)
26 2 S_amplitude_uV (signed; S is negative)
28 2 R'_amplitude_uV
30 2 S'_amplitude_uV
32 2 J_point_amplitude_uV (= amplitude at end of QRS)
34 2 P+_amplitude_uV
36 2 P-_amplitude_uV (signed; negative)
38 2 T+_amplitude_uV
40 2 T-_amplitude_uV (signed; negative)
42 2 ST_slope_uV_per_s
44 2 P_morphology (see below)
46 2 T_morphology (see below)
48 2 iso_onset_ms (segment I: global QRS onset to lead’s QRS onset)
50 2 iso_offset_ms (segment K: lead’s QRS offset to global QRS offset)
52 2 intrinsicoid_deflection_ms
54 2 quality_code (see below)
56 2 ST_at_J_plus_20ms_uV
58 2 ST_at_J_plus_60ms_uV
60 2 ST_at_J_plus_80ms_uV
62 2 ST_at_J_plus_RR_div16_uV
64 2 ST_at_J_plus_RR_div8_uV
66 38 Reserved (zeros if a manufacturer block follows)
104 var Manufacturer measurement block

Special amplitude codes:

Value Meaning
29999 Measurement not computed
29998 Lead rejected by the measurement program
19999 Wave not present (e.g. Q wave absent, P wave during atrial fibrillation)

P / T morphology codes:

Code Shape
0 Unknown
1 Positive
2 Negative
3 Positive / negative
4 Negative / positive
5 Positive / negative / positive
6 Negative / positive / negative
7 Notched M-shaped
8 Notched W-shaped

Quality code (2 bytes, 8 two-bit fields). Bit 0 is the LSB of byte 54; bit 15 is the MSB of byte 55. Each pair encodes a noise level in one category:

Bits Category Levels
0..1 AC mains noise 0 = none; 1 = moderate; 2 = severe; 3 = unknown
2..3 Overrange same
4..5 Baseline wander same
6..7 Tremor / muscle artifact same
8..9 Spikes / sudden jumps same
10..11 Electrode loose or off same
12..13 Pacemaker same
14..15 Interchanged lead same

Section 11 — Universal interpretation statement codes

Section titled “Section 11 — Universal interpretation statement codes”

Optional. Carries the same interpretation/overreading content as Section 8, but coded against the Annex F vocabulary instead of free text. Sections 8, 9, and 11 must be mutually consistent.

Same layout as Section 8: confirmation byte + 7-byte timestamp + statement count.

Off Size Field Content
0 1 sequence_number 1-based, used by Type 3 logical operands
1 2 statement_length Bytes from type through and including the terminating NULL
3 1 type 1 = universal statement code; 2 = full text; 3 = statement logic
4 var data Type-dependent payload, NULL-terminated

Type 1: one coded statement and zero or more modifiers, each NULL-terminated, concatenated. Total bytes capped at 65535.

Type 2: a single NULL-terminated free-text statement (same form as Section 8).

Type 3: a single NULL-terminated logical expression that combines prior statements by sequence number. Operators: + for OR, ; for AND, (...) for precedence, and the conjunctive terms in Conjunctives and modifiers. At most one Type 3 entry per Section 11.

Each code consists of one or more underscore-separated fields:

basic_diagnosis _ certainty _ modifier _ modifier _ ...
  • Basic diagnosis (5 bytes): one of the acronyms in Statement acronyms.
  • Certainty (1-2 bytes): DE definite, PR probable, PS possible, UN unknown, CE cannot exclude / rule out, SS strongly suggestive, CO consider, CW consistent with. The short forms A, B, C, U, D are also valid.
  • Modifiers (up to 3 bytes each): see Conjunctives and modifiers.

Adjacent statements are separated by ;. Conjunctive terms (up to 3 bytes) sit between statements, also flanked by ;. Within a single statement, the underscore links fields.

Example:

AMI_PR_AC probable acute anterior infarction
LVH_PR_AND_STT_LV probable LVH and ST-T changes compatible with LV strain
LVH_PR;AND;STT_LV same content as two linked statements

Boolean conjunctives: AND, OR, NOT, XOR, EOR. NOT reads as “in absence of the next statement”.

Arithmetic / relational: ADD, SUB, MPY, DIV, EXP, SQR, ABS, MAX, MIN, EQU, ILT, IGT, INE, IGE, ILE.

Serial-comparison: SER, DEC, INC, UNC, CHG, DIS, REP, IMP, WRS.

Other links: RES (results in), SEC (secondary to), ASS (associated with), EXC (exclude / also consider), WTH (with), ALT (alternating with).

Age-of-event modifiers: OL old, RE recent, AC acute, SU subacute, AI age indeterminate, AU age undetermined, EV evolving, XO probably old, XA probably acute, YO possibly old, YA possibly acute.

Location: AN, AS, AL, IN, IL, PO, LA, HL, IP, BA, AF, SE, PL, SN, SP, EX, WI, DI (anterior, anteroseptal, anterolateral, inferior, inferolateral, posterior, lateral, high-lateral, inferoposterior, basal, antero-inferior, septal, posterolateral, subendocardial, subepicardial, extensive, widespread, diffuse).

Severity: MA major, MO moderate, MI minor; or graded S1..S5.

Time course: SE serial changes, CC continuing changes, OC occasional, TR transient, UF unifocal, IM intermittent, FR frequent, MF multifocal, TE temporary, EV evolving, NE new, MU multiple.

ST-T physiopathology: LV LV strain, MD ischemic damage, PE pericarditis, EL electrolyte abnormality.

Normality: NO normal, NX may be normal variant, BO borderline, AB abnormal, BN borderline normal, BA borderline abnormal.

Rhythm location: SI sinus, AT atrial, SV supraventricular, ND nodal, VE ventricular.

Miscellaneous: IC incomplete, CP complete, TY typical, YT atypical.

Annex F catalogs interpretation acronyms by clinical category. Each acronym is 1..5 bytes. Representative selections:

  • Normal/abnormal: NORM, NLECG, NLQRS, NLP, NLSTT, WHNOR, POSNL, BOECG, ABECG, POSAB, ABQRS, ABSTT, NFA, NFB, ABFA, ABFB, UFB.
  • Hypertrophy: LVH, VCLVH, RVH, VCRVH, BVH, SEHYP, PRANT.
  • Myocardial infarction: MI, AMI, ASMI, ALMI, LMI, HLMI, APMI, IMI, ILMI, IPMI, IPLMI, PMI.
  • Conduction: BBB, CLBBB, ILBBB, ALBBB, CRBBB, IRBBB, IVCD, IVCD>, IVCD<, WPW, WPWA, WPWB, PREEX, LAFB, LPFB, BIFAS, TRFAS.
  • Rhythm: SR, NSR, SARRH, MSAR, STACH, SBRAD, JTACH, SVTAC, JBRAD, SVBRA, WQTAC, NQTAC, ARRHY, IRREG, REGRH, AFIB, AFLT, ATACH, PSVT, PAT, MFAT, RATAC, IDIOR, VFIB, VTACH, RVTAC, SVT, NSVT, TORSA, MTACH, VFLT, ASYST.
  • AV conduction defects: 1AVB, 2AVB, 3AVB, I2AVB, A2AVB, AVDIS, WENCK, MOBI2, SAR, SABLK, SPAUS, WANDP, LRR, OCAP.
  • Ectopic complexes: PAC / APC, PVC / VPC, JPC, MAPCS, MVPCS, RVPCS, RAPCS, RJPCS, VIC, SVPC, ABER, FUSC, CAPT, VEC, AEC, VPARA, APARA, VBIG, ABIG, SVBIG, BIGU, VTRIG, ATRIG, SVTRI, TRIGU, VQUAG, RECIP.
  • Block / conduction: B2T1, B3T1, B4T1, B5T1, VARBL, EXIBL, ENTBL, VABL, BLOCK, C2T1..C5T1, VARCO, SVR, IVR, RVR, WRV, AAVCO, RETCO, ANTCO, ABBCO, CONCO, AVREN, CONRE, RENTR, AECHO, VECHO, FCOUP, VCOUP.
  • Pacemaker: PACE, PACEA, PACEP, PACEF, PACED, PACEM, EPAVS, EPVC, EPDM, EPFC, EPFS, EPARV, EPU, EPURV, PAA, PAD, PAVA, PADEM. International ICHD codes PAVVI, PAAAI, PAVAT, PAVDD, PADVI, PADDD use bytes 3..5 to encode chamber paced / sensed / response.
  • Axis: LAD, RAD, AXL, AXR, AXIND, AXSUP, AXPOS, AXVER, AXHOR, TRSLT, TRSRT, CCWRT, CWRT.
  • ST-T descriptive: ISC_, INJ_, EPI_, STT_, NST_, STE_, STD_, RST_, TAB_, NT_. Region suffix replaces the trailing _ (e.g. ISCAN = ischemic anterior).
  • Atrial: LAO / LAE, RAO / RAE, BAO / BAE, IACD, HPVOL, NSPEP, ABPAX, UNPAX.
  • Pediatric: PED, RVD, ASD, ECD, EBSTA, TCA, ACA.
  • Calibration: HSCAL, HSPRE, HSLIM, DSCAL, DSPRE, DSLIM, NSCAL.
  • Technical / quality: ARMRE, LMISP, QCERR, AHERR, MEASE, NOISE, WANDR, FAULT, ARTEF, SIMUL, PINFO, INCAN, NODAT.

For overreading measurement results (Annex F.5), waveform tokens P, Q, R, S, R2, S2, R3, S3, J, ST, T, T+, T-, U, QRS, PR, PP, RR, QT, JT, TP and units MSEC, SEC, MVOLT, MUVLT, DEGR, RATIO, UNIT, together with LEAD, INN, AXIS, DUR, AMP, compose expressions like P_AMP_INN_LEAD_V1_EQU_120_MVOLT (“P amplitude in V1 equals 120 mV”).

The waveform payload in Sections 5 and 6 can be raw samples, first differences, or second differences. The choice is signaled by byte 5 of each section’s data-part header.

For a signal X(1..N):

diff_used == 0: data[n] = X[n]
diff_used == 1: data[1] = X[1]
data[n] = X[n] - X[n-1] n >= 2
diff_used == 2: data[1] = X[1]
data[2] = X[2]
data[n] = X[n] - 2*X[n-1] + X[n-2] n >= 3

Reconstruction:

diff_used == 1: X[n] = X[n-1] + data[n] n >= 2
diff_used == 2: X[n] = 2*X[n-1] - X[n-2] + data[n] n >= 3

The first one or two samples are stored as raw values so the recurrence can be seeded. Higher-order differences cluster around zero in well-band-limited ECG segments, which improves Huffman compression.

Optional. When bimodal == 1 in Section 6 header, the residual record is decimated outside QRS-protected areas. The protected areas (QB..QE per QRS, listed in Section 4) use the original sample interval declared in Section 5 and the residual AVM declared in Section 6. Outside the protected areas, the residual uses both the AVM and the coarser sample interval declared in Section 6.

The maximum sample interval is 8 ms (125 Hz). The non-protected gap between QE(k-1)+1 and QB(k)-1 should be an integer multiple of the decimation factor; writers pick QB and QE with that constraint.

Decimation algorithm: arithmetic average of decimation-factor consecutive samples. A typical 4× decimator stores one value per four input samples:

Z_av(m,1) = (X(m,1) + X(m,2) + X(m,3) + X(m,4)) / 4
Z_av(m,2) = (X(m,5) + X(m,6) + X(m,7) + X(m,8)) / 4
...

Decompression interpolates between consecutive averages. The first two reconstructed samples of an interval take the first average; the last two take the last average; intermediate samples interpolate linearly:

X'(m, a) = Z'_av(m, a)
X'(m, a+1) = Z'_av(m, a)
X'(m, a+2) = Z'_av(m, a)
X'(m, a+3) = Z'_av(m, a) + 1 * (Z'_av(m, a+1) - Z'_av(m, a)) / 4
X'(m, a+4) = Z'_av(m, a) + 2 * (Z'_av(m, a+1) - Z'_av(m, a)) / 4
X'(m, a+5) = Z'_av(m, a) + 3 * (Z'_av(m, a+1) - Z'_av(m, a)) / 4
X'(m, a+6) = Z'_av(m, a+1)
...

The exact decimation and reconstruction algorithm is implementation- defined; the spec only constrains the RMS and absolute reconstruction errors (see Compression error limits).

After reconstruction, a 3-sample non-recursive moving-average filter smooths the boundaries outside the protected areas. Boundaries at SB(k) and SE(k) are not filtered, so the discontinuities from reference-beat subtraction survive into the reconstructed residual and disappear cleanly when the reference beat is re-added.

Reference-beat subtraction (high compression)

Section titled “Reference-beat subtraction (high compression)”

When the Section 3 reference-beat-subtraction flag is set, the encoder:

  1. Locates one reference beat (type 0) per recorded lead by averaging “normal” complexes from the raw record.
  2. Synchronizes the reference beat’s fiducial fcM (stored in Section 4 bytes 3..4) to each type-0 QRS fiducial fc(k) in the raw record.
  3. Subtracts the reference beat from the raw signal at every type-0 complex location. The subtracted span is SB(k) = fc(k) - PM to SE(k) = fc(k) + TM, where PM and TM are the spans from fcM to the reference beat’s P-onset and T-offset respectively.
  4. Stores the reference beat in Section 5 and the residual in Section 6.

The residual is what remains after subtraction. Outside QRS protected areas it is low-amplitude, low-bandwidth, and compresses well with first/second differences and Huffman coding plus optional decimation.

Decoding reverses the encoded transforms. The exact composition depends on which compression knobs the encoder used; each step is conditional on the corresponding header field:

  1. Huffman decode of the lead bitstream into integer samples when Section 2 is present. If its table_count == 19999, use the default table. When Section 2 is absent, the payload is raw signed 16-bit data and this step is skipped. See Decoding a Huffman bitstream.
  2. Reverse 1st/2nd differences when Section 5 byte 5 or Section 6 byte 5 is 1 or 2. See Difference encoding.
  3. Reverse decimation (bimodal case only, Section 6 byte 6 == 1). Interpolates the missing samples in the non-protected ranges. See Sample decimation.
  4. 3-sample reconstruction filter on the non-protected ranges only. See Reconstruction smoothing filter.
  5. AVM scaling: use Section 5’s AVM for the reference beat and Section 6’s AVM for every residual sample, including protected samples, to recover nanovolts. See AVM scaling.
  6. Reference-beat addition at every fc(k) whose beat_type == 0. See Reference-beat addition.

A reader that targets a lighter compression mode runs a subset:

Mode Steps
Raw integers (no Section 2, no diff, no subtraction, no bimodal) 5
Plain Huffman over raw samples 1, 5
Huffman + 1st/2nd diff 1, 2, 5
Reference-beat subtraction (no bimodal) 1, 2, 5, 6
High compression (bimodal + subtraction) 1, 2, 3, 4, 5, 6

QRS complexes whose beat_type != 0 (e.g. extrasystoles) skip step 6: their full waveform sits in the residual record. Their protected areas in Section 4 still bypass steps 3 and 4 so the morphology is preserved.

Raw 1 µV/LSB data is truncated to 5 µV/LSB by:

X_t(m,n) = (X_r(m,n) + 2) / 5 when X_r(m,n) >= 0
X_t(m,n) = (X_r(m,n) - 2) / 5 when X_r(m,n) < 0

Integer division truncates toward zero. The same form applies to the reference beat. Rounding constants are negated for negative values.

A simple non-recursive moving-average filter, length 9 samples, applied by the encoder to the residual outside the protected areas:

F(m, n) = (X(m, n - (L-1)/2) + ... + X(m, n) + ... + X(m, n + (L-1)/2) + (L-1)/2) / L

where L = 9. Edge samples taper:

F(m, a) = X(m, a)
F(m, a+1) = (X(m, a) + X(m, a+1) + X(m, a+2) + 1) / 3
F(m, a+2) = (X(m, a) + X(m, a+1) + X(m, a+2) + X(m, a+3) + X(m, a+4) + 2) / 5
F(m, b-2) = (X(m, b-4) + X(m, b-3) + X(m, b-2) + X(m, b-1) + X(m, b) + 2) / 5
F(m, b-1) = (X(m, b-2) + X(m, b-1) + X(m, b) + 1) / 3
F(m, b) = X(m, b)

The filter does not cross SB(k) / SE(k) boundaries: the subtraction edges must survive into the residual so they cancel when the reference beat is re-added on decode.

After Sample decimation has been reversed, the decoder runs a length-3 non-recursive moving- average filter on the non-protected ranges to absorb interpolation steps. Inside protected areas the filter is not applied (the QRS must remain bit-exact under the 15 µV error budget). At SB / SE boundaries the filter does not cross either, so the reference-beat subtraction discontinuities survive into the filtered residual and cancel cleanly when the reference beat is re-added.

F''(m, a) = X''(m, a)
F''(m, a+1) = (X''(m, a) + X''(m, a+1) + X''(m, a+2) + 1) / 3
...
F''(m, n) = (X''(m, n-1) + X''(m, n) + X''(m, n+1) + 1) / 3
...
F''(m, b-1) = (X''(m, b-2) + X''(m, b-1) + X''(m, b) + 1) / 3
F''(m, b) = X''(m, b)

Rounding constants are negated for negative values.

The filter runs over four kinds of interval per record (K = number of QRS complexes, N = last sample index):

# Range start a Range end b Meaning
1 SE(k-1) + 1 SB(k) - 1 Between end of reference-beat subtraction for QRS k-1 and start of subtraction for k
2 SB(k) QB(k) - 1 From the start of subtraction for QRS k to its protected-area onset
3 QE(k) + 1 SE(k) From the protected-area end of QRS k to the end of its subtraction zone
4 SE(K) + 1 N Tail of the record after the last QRS

Use SE(0) = 0 as the sentinel for the leading interval.

After all integer-domain processing, samples become nanovolts by multiplying by the relevant AVM (Section 5 byte 1..2 for the reference beat, Section 6 byte 1..2 for the rhythm / residual):

X'_r(m, n) = X'(m, n) * Section6.AVM 1 <= n <= N, 1 <= m <= M
Y'_r(m, p) = Y'(m, p) * Section5.AVM 1 <= p <= P, 1 <= m <= M

X' is the integer residual after smoothing; Y' is the integer reference beat after its own Huffman + difference reconstruction. Both products are 32-bit signed nanovolts. To get microvolts divide by 1000; to get millivolts divide by 1000000.

For bimodal records every residual sample uses the Section 6 AVM, including samples inside protected areas. Protected samples differ only in time geometry: they use Section 5’s sample interval, while non-protected samples use Section 6’s sample interval.

For each QRS k with beat_type == 0 in Section 4:

  1. Align fcM (reference-beat fiducial, Section 4 bytes 3..4) with fc(k) (residual fiducial, Section 4 subtraction-zone bytes 7..10 of block k).
  2. Walk j from 0 through SE(k) - SB(k), mapping residual sample SB(k) + j to reference-beat sample fcM - (fc(k) - SB(k)) + j.
  3. Add the AVM-scaled reference-beat sample to the AVM-scaled residual sample. Both sides must be in the same physical unit (nanovolts) before addition.
X_raw(m, SB(k) + j) = X'_r(m, SB(k) + j) + Y'_r(m, fcM - (fc(k) - SB(k)) + j)
for 0 <= j <= SE(k) - SB(k)

SB(k) and SE(k) come from Section 4 bytes 3..6 and 11..14 of the QRS-k block. When beat_type != 0, SB(k) = SE(k) = 0 and the QRS contributes no addition; the residual already carries the full sample values for that complex.

When a file uses the default high-compression profile, the headers carry the following values. A decoder may use these as fallback expectations:

Field Default value
Section 3 byte 2 bit 0 (reference-beat subtraction) 1 (on)
Section 5 bytes 1..2 (reference-beat AVM) 5000 nV (= 5 µV)
Section 5 bytes 3..4 (reference-beat sample interval) 2000 µs (= 500 Hz)
Section 5 byte 5 (reference-beat diff encoding) 2 (second diff)
Section 6 bytes 1..2 (residual AVM) 20000 nV (= 20 µV)
Section 6 bytes 3..4 (residual sample interval outside QRS) 8000 µs (= 125 Hz)
Section 6 byte 5 (residual diff encoding) 2 (second diff)
Section 6 byte 6 (bimodal) 1 (on)
Huffman tables Default table (Section 2 table_count = 19999)
Sample interpolation target 2 ms inside the non-protected ranges

Files conforming to these defaults can be decoded without consulting custom Huffman tables and with hard-coded AVM and sample-interval constants. Non-default writers override any subset of these values in their section headers; the decoder follows the header in every case.

A conforming high-compression encoder must meet these limits on the SCP-ECG test set (Annex C.5):

Quantity Limit
Digitization >= 500 samples/s; <= 5 µV/LSB
Reference beat resolution >= 500 samples/s; <= 5 µV/LSB
Residual record truncation error <= ±15 µV
Residual record sample interval <= 8 ms
Reconstruction RMS error <= 10 µV
Absolute error in a single sample outside P-QRS-T <= 100 µV
Absolute error in a single sample inside QRS <= 15 µV

For pure redundancy reduction (no reference-beat subtraction, no decimation), the reconstruction error must be zero relative to a 500 Hz / 5 µV reference, modulo the initial quantization.

All leads must be recorded simultaneously when reference-beat subtraction is used for compression.

Text fields follow a restricted ISO/IEC 2022 profile. Latin-1 (ISO/IEC 8859-1) is the default character set and requires no escape sequences.

  • Designate ASCII (the left half of 8859-1) into G0 and invoke into GL.
  • Designate Latin-1 (the right half of 8859-1) into G1 and invoke into GR.
  • Designate ISO/IEC 646 control set into C0.
  • No designation to C1; only the C0 format effectors BS (0x08), HT (0x09), LF (0x0A), VT (0x0B), FF (0x0C), CR (0x0D), and ESC (0x1B) are allowed.
  • NULL (0x00) is reserved for string termination.
  • NEWLINE is CR + LF.

To switch to another character set within a string, the writer emits a designation escape sequence:

Sequence Effect
ESC 02/08 F Designate 94-character set F into G0
ESC 02/04 02/08 F Designate 94N-character multi-byte set into G0
ESC 02/04 F Designate special 94N set into G0 (F = 04/01..04/03)
ESC 02/09 F Designate 94-character set into G1
ESC 02/13 F Designate 96-character set into G1
ESC 02/04 02/09 F Designate 94N-character multi-byte set into G1

Each text field implicitly starts in the default state. A new field or the trailing NULL resets to the default.

Common final-character codes:

F Set type Description
04/02 94 7-bit ASCII graphics (ANSI X3.4-1968)
04/01 96 ISO/IEC 8859-1 Latin-1 right half
04/02 96 ISO/IEC 8859-2 Latin-2 right half
04/04 96 ISO/IEC 8859-4 Latin-4 right half
04/12 96 ISO/IEC 8859-5 Cyrillic right half
04/07 96 ISO/IEC 8859-6 Arabic right half
04/06 96 ISO/IEC 8859-7 Greek right half
04/08 96 ISO/IEC 8859-8 Hebrew right half
04/01 94² GB2312-1980 (Simplified Chinese)
04/02 94² JIS X 0208-1983 (Japanese)
04/03 94² KS C5601-1987 (Korean)
04/09 94 JIS X 0201-1976 right half (Japanese single-byte)
04/10 94 JIS X 0201-1976 left half

Final characters in 03/00..03/15 (private encoding) are forbidden. Intermediate characters 02/02, 02/03, 02/05, 02/06, 02/07, 02/0A, 02/0B, 02/0C, 02/0E, 02/0F are not permitted.

When an importer cannot render a foreign character set, it should fall back to backslash escapes: \ becomes \\, an ESC introducing an unsupported sequence becomes \033, and 8-bit GR bytes become \nnn (3-digit octal) on ASCII-only displays.

SCP-ECG uses CRC-CCITT (x^16 + x^12 + x^5 + 1). The CRC register is preset to 0xFFFF for each calculation.

Two CRC scopes are computed per record:

  • Record CRC at bytes 0..1 covers bytes 2..record_size-1.
  • Section CRC at the start of each section’s 16-byte ID header covers the rest of the section (bytes 2..section_length-1 of the section).

Byte-at-a-time algorithm (transcribed from Annex E.5.5):

A = current input byte
B = scratch byte
CRCHI = high byte of the 16-bit CRC
CRCLO = low byte of the 16-bit CRC
for each byte A in the CRC domain:
A = A XOR CRCHI
CRCHI = A
A = A >> 4 // logical shift, zero-fill
A = A XOR CRCHI // A now has bits IJKLMNOP after the prior XOR
CRCHI = CRCLO // swap halves
CRCLO = A
rotate A left 4 bits // bits MNOPIJKL
B = A // save
rotate A left 1 bit // bits NOPIJKLM
A = A AND 0x1F // mask to 000IJLLM
CRCHI = A XOR CRCHI // CRCHI partial
A = B AND 0xF0 // MNOP0000
CRCHI = A XOR CRCHI // CRCHI complete
rotate B left 1 bit // NOP0000M
B = B AND 0xE0 // NOP00000
CRCLO = B XOR CRCLO // CRCLO complete

Appending CRCHI then CRCLO at the end of the domain and feeding the extended stream back through the same algorithm yields zero on a correctly received block.

A conforming reader must reject inputs that violate any of the following:

  • Record is shorter than 6 bytes.
  • Record-length field is shorter than 6 + 136 (the record header plus the minimum Section 0).
  • Record-length field does not match the actual byte count of the file.
  • Record CRC does not validate over bytes 2..record_size-1.
  • Section 0 does not begin at byte 7.
  • Section 0 ID header bytes 11..16 are not the ASCII bytes "SCPECG".
  • Any section’s length is not even.
  • Any section’s length is less than 16 (the ID header alone).
  • Any section’s CRC does not validate over its bytes 2..length-1.
  • Pointer entries for Sections 0..11 are not all present in Section 0.
  • Section 0’s own pointer index is not 7.
  • A non-zero pointer index plus length extends beyond the record.
  • A section appears more than once.
  • Section 1 does not contain all four mandatory tags (2, 14, 25, 26).
  • Section 1 is not terminated by tag 255 with length 0.
  • A Section 1 field declares a length that overflows the section.
  • Section 3 is missing.
  • Section 3 declares zero leads.
  • A lead descriptor’s end_sample < start_sample.
  • A lead descriptor’s lead ID is in the reserved range 185..199.
  • A lead in Section 5 or 6 has a length-table entry whose value overflows the section’s data part.
  • Section 5 is referenced (via flag bit 0 of Section 3) but absent.
  • Section 5 is present and avm <= 0 or sample_time <= 0 or diff_used > 2.
  • Section 6 is missing.
  • Section 6’s diff_used > 2 or bimodal > 1.
  • Section 6 declares bimodal = 1 but Section 4 is absent.
  • Section 2 is required (per the Huffman-encoded lead payloads in Sections 5/6) but absent.
  • A Huffman stream consumes more bits than are present.
  • A Huffman code structure has prefix_bits > total_bits.
  • A Huffman switch (mode = 0) refers to a non-existent table number.
  • A Section 4 protected-area block has QE < QB.
  • A Section 7 measurement block reports an axis outside -360..360 unless it equals the literal 999 “undefined” code.
  • A Section 8/11 timestamp has an out-of-range field (month not 1..12, etc.).
  • A Section 11 statement of type 3 references a sequence number that does not exist in the same Section 11.
  • A Section 10 record’s declared length does not match its byte count.
  • A measurement value equals 29999, 29998, or 19999 but is then used in arithmetic instead of being treated as a sentinel.

The validation order is at the reader’s discretion. Structural checks (record length, CRC, Section 0 presence, section-length bounds) should run before per-section payload checks.

Annexes D and E of EN 1064 specify an informative pair of layers for exchanging SCP-ECG records over RS-232 between a cart and a host. They are not part of the file format and a writer/reader of SCP-ECG files does not need to implement them.

  • Annex D (Query messaging) defines 256-byte ASCII-tagged messages (types I, R, S, A, D) for identification, request, status, advisory, and done. Two devices first exchange I messages, then alternate between master and slave with R requests for ECG transfers, patient lists, and ECG lists. Status flags G (go) and E (error) carry error codes 0..255, with manufacturer codes at 128..255.
  • Annex E (Low-level transport) is a modified XMODEM with 256- byte blocks, CRC-CCITT framing, ENQ/ACK/NAK/SYN/TTD/EOT control bytes, a 2.5 s transmit timeout, and 3.5 s receive timeout. The CRC algorithm in CRC-CCITT is the same as used here.

Annex C.5 lists a reference test set of 10-second 12-lead ECGs (PD2-*, PD3-*, PWE-*, P120-N00), digitized at 500 samples/s and 5 µV/LSB. An encoder claiming high-compression compliance must meet the Compression error limits on this set. Decompressed records compare against the originals with documented absolute and RMS error caps per case.

  • The 6-byte record header sits before Section 0 and is not part of any section. Pointers in Section 0 are computed from byte 1 of the record, i.e. byte 1 of the record CRC.
  • Section CRCs are independent of the record CRC. A reader can validate Section 0 first, then jump to any referenced section and check its CRC before parsing the payload.
  • Sections may appear in any order in the file body. Only the pointer ordering is fixed (numerical by section ID). To enumerate the sections present, walk Section 0’s pointer fields and ignore any entry whose length == 0 and index == 0.
  • Samples are 1-based throughout; sample index 0 is reserved as “not used”.
  • The AVM (amplitude value multiplier) is in nanovolts; the on-the-wire integer multiplied by AVM gives the value in nanovolts. Divide by 1000 for µV, by 1000000 for mV.
  • Section 5/6 lead order matches Section 3 lead order. Each lead’s encoded byte count is in the length table at the start of the section’s data part; the encoded bitstreams (or raw sample arrays) follow concatenated.
  • record_duration is implied: it is the total number of samples in the rhythm record (max end_sample from Section 3) divided by 1000000 / sample_time Hz from Section 6.
  • The numeric “tag 14 byte 7 manufacturer code” was a fixed enumeration in legacy files; recent files set this byte to 255 and use the trailing manufacturer trade-name string instead. Code 100 meant “other”, codes 1..21 were assigned to specific vendors. Use the string for new writers.
  • Bit ordering inside the Quality Code field of Section 10 is unusual: bit 0 is the LSB of byte 54 (the first byte of the field), bit 15 the MSB of byte 55. AC noise is in the lowest bit pair.
  • The mandatory four Section 1 tags (2, 14, 25, 26) are not gated by the protocol parser. Readers that require those fields should check them explicitly. Tag 14 also carries the conformance-category byte (byte 16), the protocol version (byte 15), and language support (byte 17), which are practical hard requirements for cross-vendor decoding.