OMNIC SPA file formatο
Note
This is an unofficial interoperability reference for the OMNIC .spa
format. It is based on independent controlled binary and oracle analysis
across several observed SPA variants. OMNIC producers and versions may use
different subsets of these structures. The certainty tags below describe
the strength and scope of each claim; they do not turn this page into an
official vendor specification. See OMNIC file formats for
provenance and the definitions of the certainty levels.
Evidence and scopeο
The reference separates structural evidence from semantic interpretation:
[ESTABLISHED]means that a structure or relationship is supported by independent binary/oracle evidence, controlled behavior, or exact arithmetic in multiple native cases.[OBSERVED]means that a reproducible structure or correlation was seen in the analyzed variants but is not established as universal.[HYPOTHESIS]means that a semantic interpretation is plausible but not demonstrated.[UNKNOWN]means that the position or structure may be known while its meaning remains unresolved.
The evidence covers ordinary acquired spectra, processed acquired spectra, library/retrieved spectra, acquired spectra with paired interferograms, standalone saved interferograms, a Raman variant, Experiment-Information- bearing variants, and a newer-layout variant. These descriptions are generic; they do not depend on particular proprietary files or on the availability of OMNIC-distributed examples.
Overall file organizationο
An SPA file is organized as a fixed file header followed by a counted table of 16-byte key records. The records point to blocks elsewhere in the file; the blocks are not required to be contiguous.
fixed file region
βββ signature at file offset 0
βββ saved name/title text at file offset 30
βββ nlines (number of key records) at file offset 294
βββ raw acquisition-time value at file offset 296
βββ key table beginning at file offset 304
referenced blocks
βββ 0x02 general/spectral header
βββ 0x03 primary data payload
βββ 0x04 comments or user text
βββ 0x1b processing/history text
βββ other variant-dependent blocks
[ESTABLISHED] The signature begins with the ASCII text Spectral Data
File for the SPA/SPG family. The saved name/title field begins at offset 30,
nlines is a little-endian uint16 at offset 294, the raw timestamp is at
offset 296, and the first key record is at offset 304.
The remaining fixed-header bytes are not assigned meanings here unless stated below. In particular, a recognizable file signature does not imply that every producer uses the same complete header map.
Key-record tableο
[ESTABLISHED] Each key record occupies 16 bytes in the observed SPA
families. The generic record layout is:
relative offset type role
+0 uint8 key
+1 uint8 reserved/variant-dependent byte
+2 uint32 referenced block position
+6 uint32 referenced block length
+10..+15 bytes trailing/variant-dependent data
Positions and lengths are file-relative for the referenced blocks. nlines
counts key records, not every byte between the table and the first payload.
[OBSERVED] Ordinary/acquired families use a 0x00 terminator slot and
zero padding after the active records. Observed library-derived variants use a
grid of 16-byte-stride 0x01 slots before the first main block. The gridβs
boundaries and structural role are known in those variants, but its slot
semantics are [UNKNOWN]. Terminator and following-region details remain
variant-dependent; no universal interpretation is assigned to every trailing
record byte.
Recognized key associationsο
The following table distinguishes an established association from a universal semantic guarantee. A key identifies a block in the observed variants; it does not by itself determine the signal interpretation of that block.
Key |
Generic association |
Certainty and scope |
|---|---|---|
|
General/spectral header block. |
|
|
Primary data payload. |
|
|
Comment or user-text block. |
|
|
Processing/acquisition history text. |
|
|
Library/retrieval-associated saved-spectrum text. |
|
|
Companion interferogram-related blocks. |
|
|
Sample interferogram in a validated acquired-pair variant. |
|
|
Background interferogram in the same validated acquired-pair variant. |
|
|
Recurring 12-byte auxiliary block outside the observed library variant. |
Block boundaries are |
|
Spectrometer/acquisition parameter block. |
|
|
128-byte all-zero block in one newer-layout/writer-associated family. |
|
|
Experiment Information block. |
|
|
Custom-information association. |
|
The presence or absence of a key is itself variant-dependent. In particular,
0x03 must not be described universally as the spectrum: its X-unit
context distinguishes a spectral payload from an explicit data-points
interferogram in the validated examples.
General 0x02 headerο
The following offsets are relative to the block referenced by 0x02. The
table deliberately separates mature meanings from observations and unresolved
fields.
Offset |
Type |
Meaning |
Scope/certainty |
|---|---|---|---|
|
|
Stored point count. |
|
|
|
X-unit code. |
|
|
|
Y/data-unit code. |
|
|
|
OMNIC |
|
|
|
OMNIC |
|
|
|
Scan points. |
|
|
|
OMNIC interferogram peak position. |
|
|
|
Sample scans. |
|
|
|
Duplicate numeric peak position. |
|
|
|
FFT points. |
|
|
|
Transform/trailing geometry field. |
|
|
|
Background scans. |
|
|
|
Background gain where applicable. |
|
|
|
Collection duration multiplied by 100. |
|
|
|
Reference/HeNe-class frequency. |
|
|
|
Sample-spacing factor. |
|
|
|
Aperture where applicable. |
|
|
|
Raman excitation/laser frequency. |
|
|
mixed |
Mirror of the beginning of |
|
|
|
Optical velocity mirror. |
|
Other numeric fields in the header are intentionally not assigned meanings by this reference. In particular, derived transform quantities must not be mistaken for stored fields.
Spectrometer and acquisition parameters (0x6a)ο
[ESTABLISHED] The recurring 0x6a block is a 56-byte
spectrometer/acquisition parameter block in the validated variants. The
following relationships are mature enough to document generically:
Relative offset |
Meaning |
Certainty/scope |
|---|---|---|
|
Instrument-family and acquisition codes. |
|
|
Digitizer-bit field. |
|
|
High-pass filter. |
|
|
Low-pass filter. |
|
|
Sample gain. |
|
|
Optical velocity. |
|
The +140..+188 header region can mirror these parameters, but the mirror is
blank in an observed newer-layout family. A reader or format consumer should
therefore treat 0x6a as the canonical parameter block and the header mirror
as variant-dependent.
Unit codesο
X-unit codesο
Code |
Meaning |
Certainty/scope |
|---|---|---|
|
Wavenumbers, |
|
|
Data points. |
|
|
Raman shift, |
|
|
Wavelength, nm / wavelength, micrometres. |
|
Y/data-unit codesο
Code |
Meaning |
Certainty/scope |
|---|---|---|
|
Percent transmittance. |
|
|
Absorbance. |
|
|
Volts-labelled detector signal. |
|
|
Transmittance. |
|
|
Raman intensity. |
|
|
Reflectance, log(1/R), single beam, KubelkaβMunk, reflectance, and photoacoustic mappings respectively. |
|
Spectrum payload and orientationο
The primary payload is referenced by key 0x03. [ESTABLISHED] in the
validated spectral family, it consists of little-endian float32 intensity
values whose count agrees with +4 and whose X coordinate is linear between
the two header endpoints.
For the validated spectral family:
header
+16is OMNIC Last X;header
+20is OMNIC First X;the native payload is stored in descending wavenumber order;
payload element 0 corresponds to
+16and the final element corresponds to+20.
The historical internal reader names firstx and lastx describe storage
order rather than OMNICβs display terminology. This orientation is not
independently generalized here to every library/retrieved variant.
The key association 0x03 does not by itself imply a spectrum. A header with
X-unit code 0x02 can use the same key for a standalone saved interferogram
with a data-points X coordinate.
Interferogramsο
In the validated acquired-pair variant, 0x66 is the sample interferogram
and 0x67 is the background interferogram. [ESTABLISHED] This identity
was supported by independent Fourier reconstruction, not merely by the
readerβs parameter names. It is scoped to that acquired-pair variant: a
standalone saved interferogram may place its primary data in 0x03 instead.
The native IFG payload is stored as float32 values. A standalone saved IFG
has an OMNIC Volts label, but [UNKNOWN] whether this implies a calibrated
absolute voltage scale. Do not generalize that label automatically to every
0x66/0x67 block, and do not infer a universal amplitude normalization
from the stored values.
Peak and transform geometryο
For the validated native IFG cases:
+32is auint32and+40is afloat32;both match OMNICβs interferogram peak position;
both match the raw signal
argmax;this establishes the peak/centerburst index relationship, but not a formal physical zero-path-difference (ZPD) definition.
[ESTABLISHED] In the same native cases:
+48 = N_stored - P
where N_stored is the native stored IFG payload length and P is the
peak position. The exact OMNIC semantic name or counting rationale for +48
remains [UNKNOWN]. Keep the following quantities distinct:
native stored IFG length
N_stored;peak position
P;stored field
+48;derived transform base
N_hat = 2 * (+48);FFT length
+44.
N_hat is a derived quantity, not a stored native field and not a universal
name for a native OMNIC quantity.
Zero fillingο
Where the validated transform relationship applies:
FFT = N_hat * 2**zero_fill_level
N_hat = 2 * (+48) (derived)
This is an arithmetic relationship between stored geometry and FFT length. The zero-filling level is directly supported for some acquired cases and inferred from the arithmetic in another native IFG case; it must not be treated as a universal interpretation of every SPA header.
Native IFG coordinate samplingο
[ESTABLISHED] in the validated native IFG cases, the physical optical-path
difference step is:
Delta_OPD = sample_spacing / (2 * reference_frequency)
where reference_frequency is header +80 and sample_spacing is
header +84. The peak/argmax supplies the origin used by the validated
reconstruction. Formal physical ZPD semantics remain [UNKNOWN].
This relationship is now implemented by the public reader for the corrected sample-spacing path, but the format statement is based on native evidence rather than on reader behavior alone.
Acquisition time and timezoneο
For ordinary acquired SPA variants, [ESTABLISHED] the raw little-endian
uint32 at file-relative offset +296 represents:
1899-12-31 00:00:00 UTC + raw seconds
The result is an absolute UTC acquisition instant. A 32-bit rollover is observed and must be handled when interpreting values near the counter limit.
The displayed GMT/local offset is not an intrinsic SPA timezone field in the
validated files. [ESTABLISHED] OMNIC renders the stored absolute instant
using the timezone configuration and rules of the Windows system displaying
the file; changing that viewing-system timezone changes the displayed offset
without changing the SPA bytes.
This interpretation is variant-dependent. Library/retrieved variants can use
+296 for a counter or default-like value that is not a valid acquisition
date. A reader must not promote the field to acquisition_date without
checking the variant.
Experiment Informationο
Key 0x82 identifies Experiment Information blocks. Native subtype 0x79
has a fixed-anchor layout supported by multiple independent native blocks:
Relative anchor |
Generic content |
Certainty |
|---|---|---|
|
Experiment path/file text begins. |
|
|
Experiment title/name text. |
|
|
Descriptive or custom text. |
|
|
Accessory-related text anchor. |
|
|
Duplicate or prefixed path-like text. |
|
The strings are NUL-terminated and padded between the observed anchors.
+413..+670 also contains unresolved numeric or padding content. Subtype
0x9d is structurally recognized but its semantics are [UNKNOWN]; it is
not mandatory before every subtype 0x79 block. The two subtypes must not be
collapsed into one universal record layout.
The current public readerβs sequential decoder is an implementation detail and does not define this fixed-slot native layout. A future reader audit may map these anchors into metadata, but no reader change is part of this reference.
Raman variantο
The validated Raman variant uses:
X-unit code
0x20for Raman shift incm^-1;Y/data-unit code
0x1ffor Raman intensity;header
+80for the reference/HeNe-class frequency;header
+96for the Raman excitation/laser frequency.
[ESTABLISHED] These are distinct physical quantities. The Raman +96
interpretation is scoped to the validated Raman variant and should not be
promoted to a general-purpose field for all SPA files. A reader metadata issue
must not be used to claim that the stored Raman X axis is shifted or otherwise
incorrect.
Library/retrieved variantsο
Library/retrieved spectra retain the key-table pointer model but can differ structurally from ordinary acquired spectra:
the
0x02block can occur at a different physical file location while retaining the relevant relative header fields;acquisition-only fields can be zero, default-like, or not applicable;
the raw
+296value must not automatically become an acquisition date;a 16-byte-stride
0x01grid can occur before the first main block;0x53is associated with saved-spectrum/library text;the primary payload remains located through the key table.
The grid boundaries and structural role are [OBSERVED] in these variants,
but its slot semantics are [UNKNOWN]. The full semantics of 0x53 and
the library-specific timestamp are also [UNKNOWN]. No complete library
format is claimed here.
Other unresolved structures and limitationsο
The following structures are useful format-research landmarks but should not be assigned unsupported meanings:
0x69β recurring 12-byte auxiliary block; semantics[UNKNOWN].0x80β 128-byte all-zero block associated with an observed newer-layout family; writer correlation is[OBSERVED]and the role is[UNKNOWN].0x9dβ recognized Experiment Information subtype; semantics[UNKNOWN].0x01grid β observed library/retrieved layout and boundaries; slot semantics[UNKNOWN].0x53β saved-spectrum/library-associated text; complete encoding and semantics[UNKNOWN].instrument-family code meanings within
0x6a;the formal physical meaning of ZPD and the exact native semantic name of
+48;general absolute IFG scaling and calibrated-voltage semantics;
generality of paired-IFG identities beyond the validated acquired-pair variant;
variant-specific timestamp meanings and Experiment Information tail fields.
Implementation notes and limitationsο
This page describes format evidence, not a complete critique of
read_omnic.py. The current implementation may not expose every established
field, may use variant-specific fallbacks, and may still need a separate
field-by-field audit against this reference. In particular:
the corrected
+84sample-spacing relation is implemented in the public reader;native subtype-
0x79Experiment Information is fixed-slot, whereas the current decoder uses a sequential strategy;some variant-specific metadata, including the Raman distinction between
+80and+96, may not yet be surfaced with native semantics.
No production reader behavior is changed by this document. The public reader, tests, and this reference should be reconciled in a separate reader-audit and implementation sequence.