GX-TXT – IR Protocol Analysis and Identification with GNU Octave
These GNU Octave programs were developed during the characterization of the GX-TXT-v3 to analyze the IR signal acquired at the VIR node. The first program reconstructs the carrier, MARK, and SPACE intervals from the CSV file exported by the oscilloscope; the second uses the resulting data to attempt protocol identification and reconstruction of the transmitted data.
GXTXT_analisi_VIR_protocollo
Analyzes the acquisition from the VIR node, measures the IR carrier, and reconstructs the MARK and SPACE timing sequence, also generating plots and intermediate files that can be used by subsequent processing stages.
| Version | Description | Download | TODO |
|---|---|---|---|
| v2.4 | Oscilloscope CSV analysis, automatic signal detection, carrier measurement, MARK/SPACE reconstruction, plots, and summary files. | Download | — |
GXTXT_identifica_protocollo_IR
Uses the MARK/SPACE sequence reconstructed by the first program to compare the acquired command with several known IR protocols and, where possible, reconstruct bits, bytes, address, and command.
| Version | Description | Download | TODO |
|---|---|---|---|
| v1 | Experimental identification of IR protocols by comparing carrier frequency, timing, frame structure, and bit count. | Download | — |
The PDF manual provides operating instructions for using the two GNU Octave programs, from acquisition setup through MARK/SPACE analysis and experimental identification of the IR protocol.
Algorithms for IR Protocol Analysis and Identification
Purpose of the Processing Chain
The two GNU Octave programs use a two-stage processing chain. The first program starts from the samples acquired by the oscilloscope and reconstructs a timing representation of the signal consisting of MARK, during which the carrier is present, and SPACE, during which the carrier is absent. The second program uses only this timing representation, together with the measured carrier frequency when available, to compare the command with several known IR protocols.
The separation of the two programs is intentional. The first stage depends on the acquired waveform and must therefore handle issues such as baseline, polarity, noise, threshold, and carrier detection. The second stage no longer uses the original voltage values and works only with the durations of the reconstructed events.
The chain can be represented schematically as:
oscilloscope CSV → signal normalization → carrier → MARK/SPACE → timing → protocol comparison → bits and bytes
First program: GXTXT_analisi_VIR_protocollo
Time-Axis Reconstruction
The CSV file contains a sequence of numbered samples and the corresponding voltage values. In the Rigol format used during development, the header also provides the Start and Increment parameters. The program then reconstructs the time associated with each sample using:
$$ t_i = t_{\mathrm{Start}} + n_i \Delta t $$
where \(n_i\) is the sequential sample number and \(\Delta t\) is the time interval between two consecutive samples.
The sampling frequency follows directly from:
$$ F_s = \frac{1}{\Delta t} $$
The time reference also makes it possible to determine the position of the trigger at \(t=0\). The program therefore does not need to locate the trigger by analyzing the waveform: it uses the timing information provided by the oscilloscope.
Adaptive Pretest
Before processing the entire acquisition, an adaptive pretest is performed. Its purpose is not to decode the command, but to quickly verify that the recording contains a usable signal and to derive the parameters required for the full analysis.
In the automatic configuration of version 2.4, four windows around the trigger are tested progressively:
| Attempt | Before trigger | After trigger |
|---|---|---|
| 1 | 5 ms | 30 ms |
| 2 | 10 ms | 60 ms |
| 3 | 20 ms | 120 ms |
| 4 | 40 ms | 250 ms |
If the first window contains enough information, the analysis proceeds immediately. Otherwise, the next window is tested automatically. This avoids unnecessarily processing millions of samples when the file does not contain a recognizable signal, while still allowing for some time offset between the trigger and the transmission.
The automatic search can be replaced with a manually defined window.
The pretest also checks that enough valid numerical samples are available, removes any NaN or Inf values, and verifies the regularity of the sample sequence.
Baseline and Noise Estimation
To avoid imposing an absolute voltage value, the program automatically determines the signal’s resting level. When a sufficiently long pre-trigger segment is available, the baseline is calculated as the median of the samples preceding \(t=0\):
$$ V_0 = \operatorname{median}\left(V_i\right)_{t_i<0} $$
The median was chosen instead of the mean because it is less sensitive to isolated pulses, disturbances, and outliers.
Noise is estimated using the Median Absolute Deviation:
$$ MAD = \operatorname{median}\left(\left|V_i-V_0\right|\right) $$
and converted into an equivalent estimate of the standard deviation using:
$$ \sigma_n \approx 1.4826 \cdot MAD $$
This choice makes the noise estimate robust even in the presence of a small number of anomalous samples.
Automatic Polarity Detection
The program does not assume that the carrier produces positive or negative pulses. After determining the baseline, both possible excursions are measured:
$$ A_{\mathrm{down}} = V_0 – V_{\min} $$
$$ A_{\mathrm{up}} = V_{\max} – V_0 $$
The direction with the larger excursion is taken as the useful signal polarity.
The waveform is then internally transformed into an always-positive signal:
$$ s_i = \max\left[0,\;p\left(V_i-V_0\right)\right] $$
where \(p=+1\) for upward-going pulses and \(p=-1\) for downward-going pulses.
All subsequent processing can therefore use the same algorithm regardless of the electrical polarity at the circuit point selected for measurement.
Automatic Threshold Calculation
The threshold used to convert the analog signal into a logic sequence is not expressed as an absolute voltage. Two independent thresholds are calculated.
The first depends on the signal amplitude:
$$ V_{\mathrm{th,signal}} = 0.30\,A $$
The second depends on the measured noise:
$$ V_{\mathrm{th,noise}} = 8\,\sigma_n $$
The threshold actually used is the greater of the two:
$$ V_{\mathrm{th}} = \max\left( 0.30\,A,\; 8\,\sigma_n \right) $$
In this way, a very clean signal is analyzed with a threshold proportional to its excursion, whereas in the presence of noise the threshold is automatically kept sufficiently far above the background level.
In the current version, the pretest also requires a minimum excursion of 50 mV and rejects a threshold that reaches 90% of the signal amplitude, a condition that would make pulse detection unreliable.
Preliminary Carrier Check
Once the threshold has been applied, the pretest builds a logic sequence and identifies rising edges. The time intervals between consecutive edges are compared with the nominal period of the IR carrier.
In the current version, the nominal reference is:
$$ f_{\mathrm{nom}} = 38\,\mathrm{kHz} $$
and therefore:
$$ T_{\mathrm{nom}} = \frac{1}{f_{\mathrm{nom}}} $$
For the pretest, intervals within the following range are accepted as possible carrier periods:
$$ 0.5\,T_{\mathrm{nom}} < \Delta t_{\mathrm{fronti}} < 1.5\,T_{\mathrm{nom}} $$
The tolerance is intentionally very broad: the 38 kHz value serves as an initial reference and does not require the signal to have exactly that frequency. The pretest is considered valid only if at least a few intervals consistent with an IR carrier are found.
Pulse Detection
Once the pretest has been passed, the same baseline, polarity, and threshold are applied to the entire acquisition. Each sample is classified as being above or below the threshold:
$$ L_i = \begin{cases} 1 & s_i \geq V_{\mathrm{th}} \\ 0 & s_i < V_{\mathrm{th}} \end{cases} $$
To identify the edges, the program does not scan the samples one by one with an explicit loop; instead, it uses a vector difference of the logic sequence.
A transition:
$$ 0 \rightarrow 1 $$
identifies the beginning of a pulse, whereas:
$$ 1 \rightarrow 0 $$
identifies its end.
From these pairs of edges, the start time, end time, and width of each carrier pulse are obtained.
Carrier Frequency Measurement
The carrier period is estimated using the time intervals between the starts of consecutive pulses:
$$ \Delta T_i = t_{\mathrm{start},i+1}-t_{\mathrm{start},i} $$
Intervals compatible with the nominal reference are initially selected. The measured period is then calculated using the median:
$$ T_c = \operatorname{median}\left(\Delta T_i\right) $$
and the frequency is obtained from:
$$ f_c = \frac{1}{T_c} $$
Using the median reduces the influence of gaps between bursts, anomalous edges, and isolated thresholding errors.
The median pulse width is also calculated:
$$ T_{\mathrm{ON}} = \operatorname{median}\left(t_{\mathrm{fall}}-t_{\mathrm{rise}}+\Delta t\right) $$
from which an apparent duty cycle is obtained:
$$ D_{\mathrm{app}} = \frac{T_{\mathrm{ON}}}{T_c}\cdot100 $$
This value describes the waveform present at the point where the measurement was taken and does not necessarily have to match the duty cycle used to physically drive the transmitter’s IR LED.
MARK Reconstruction
After recognizing the individual carrier cycles, the program must determine which pulses belong to the same burst. For each pair of consecutive pulses, the gap is calculated:
$$ G_i = t_{\mathrm{start},i+1} – t_{\mathrm{end},i} $$
In the current version, pulses separated by a gap no greater than three carrier periods are considered to belong to the same burst:
$$ G_i \leq 3T_c $$
When:
$$ G_i > 3T_c $$
the beginning of a new burst is recognized instead.
Each group of consecutive cycles therefore constitutes a MARK. For each MARK, the start, end, duration, number of carrier cycles, and average width of the pulses it contains are stored.
SPACE Reconstruction and Command Detection
Once the MARK intervals have been identified, the SPACE intervals are obtained directly from the gaps between the end of one MARK and the start of the next:
$$ T_{\mathrm{SPACE},k} = t_{\mathrm{MARK},k+1,\mathrm{start}} – t_{\mathrm{MARK},k,\mathrm{end}} $$
The final sequence therefore has the form:
MARK → SPACE → MARK → SPACE → MARK → …
The start of the command is automatically set to the start of the first recognized MARK:
$$ t_{\mathrm{command,start}} = t_{\mathrm{MARK},1,\mathrm{start}} $$
while the end coincides with the end of the last MARK:
$$ t_{\mathrm{command,end}} = t_{\mathrm{MARK},N,\mathrm{end}} $$
The total observed duration is therefore:
$$ T_{\mathrm{command}} = t_{\mathrm{command,end}} – t_{\mathrm{command,start}} $$
This is the stage at which the program automatically determines the portion of the recording actually occupied by the transmission, without requiring the CSV file to be manually cropped around the command.
Grouping of Recurring Durations
The durations of the MARK and SPACE intervals are also automatically grouped into classes. This processing does not yet identify the bits; it is used to highlight recurring timing values in the transmission and provides a useful diagnostic tool before decoding.
The durations are sorted in ascending order. For each new value, the median of the current group is calculated and a tolerance is defined:
$$ \Delta T_{\mathrm{tol}} = \max\left( 1\,\mu s,\; 0.20\,T_{\mathrm{mediana}} \right) $$
A new duration is assigned to the same class if:
$$ \left| T_i-T_{\mathrm{mediana}} \right| \leq \Delta T_{\mathrm{tol}} $$
Otherwise, a new class is created.
For each group, the mean, median, minimum, maximum, and number of occurrences are then calculated. The median is the most useful parameter for recognizing the characteristic timing values of the protocol without giving excessive weight to individual anomalous measurements.
Files Produced by the First Algorithm
The key result of the analysis is not the original waveform but a much more compact timing description.
| File | Contents |
|---|---|
eventi_mark_space.csv |
Ordered sequence of MARK and SPACE intervals with start, end, duration, and number of carrier cycles. |
burst.csv |
Detailed information on each recognized burst. |
riepilogo_VIR.txt |
Acquisition parameters, baseline, polarity, threshold, carrier, command duration, and timing classes. |
The second program mainly uses eventi_mark_space.csv and, when available, the carrier frequency reported in the summary.
Second program: GXTXT_identifica_protocollo_IR
General Principle of the Classifier
The second program no longer analyzes the oscilloscope samples. Its input is the MARK/SPACE timing sequence produced by the first program.
Each known protocol is described by a set of nominal parameters: carrier frequency, optional header, MARK duration, SPACE duration, encoding method, and expected number of bits.
For each candidate protocol, an error score is calculated. The lower the score, the greater the compatibility between the acquired signal and the protocol’s timing model.
The score does not represent a statistical probability. It is a heuristic index used to rank the candidates based on the relative differences between measured and nominal timing values.
Timing Models Used
| Protocol | Carrier | Encoding | Main Parameters |
|---|---|---|---|
| NEC family | 38 kHz | Pulse distance | Header 9000/4500 µs; MARK 560 µs; SPACE 0 = 560 µs; SPACE 1 = 1690 µs; 32 bits |
| Samsung | 38 kHz | Pulse distance | Header 4480/4480 µs; MARK 560 µs; SPACE 0 = 560 µs; SPACE 1 = 1680 µs; 32 or 48 bits |
| Panasonic/Kaseikyo | 37 kHz | Pulse distance | Header 3456/1728 µs; MARK 432 µs; SPACE 0 = 432 µs; SPACE 1 = 1296 µs; 48 bits |
| Sony SIRC | 40 kHz | Pulse width | Header 2400/600 µs; MARK 0 = 600 µs; MARK 1 = 1200 µs; SPACE = 600 µs; 12, 15, or 20 bits |
| Philips RC5 | 36 kHz | Biphase | Nominal time unit 889 µs |
| Philips RC6 | 36 kHz | Biphase | Header 2666/889 µs; nominal time unit 444 µs |
Header Search
For protocols with a header, the program examines all consecutive MARK/SPACE pairs in the sequence.
For each pair, the relative errors are calculated:
$$ e_M = \frac{ \left|T_M-T_{M,\mathrm{nom}}\right| }{ T_{M,\mathrm{nom}} } $$
$$ e_S = \frac{ \left|T_S-T_{S,\mathrm{nom}}\right| }{ T_{S,\mathrm{nom}} } $$
The header error is:
$$ e_H = \frac{e_M+e_S}{2} $$
The program selects the pair with the smallest error. If even the best candidate has:
$$ e_H > 0.65 $$
the header is considered absent and the candidate protocol receives a strong penalty.
Decoding Pulse-Distance Protocols
In pulse-distance protocols such as NEC, Samsung, and Kaseikyo, the MARK duration remains approximately constant, while the bit value is encoded in the duration of the following SPACE.
For each SPACE, two errors are calculated:
$$ e_0 = \frac{ \left|T_S-T_{0,\mathrm{nom}}\right| }{ T_{0,\mathrm{nom}} } $$
$$ e_1 = \frac{ \left|T_S-T_{1,\mathrm{nom}}\right| }{ T_{1,\mathrm{nom}} } $$
The bit value is determined by choosing the model with the lower error:
$$ b = \begin{cases} 0 & e_0 \leq e_1 \\ 1 & e_1 < e_0 \end{cases} $$
If both errors are too large:
$$ \min(e_0,e_1)>0.55 $$
the sequence is no longer considered compatible with the frame data.
At the same time, the relative error of the MARK duration with respect to the nominal value is also measured. At the end of the sequence, the MARK and data timing errors are summarized using their median values.
Detecting the End of a Pulse-Distance Frame
To prevent a subsequent repetition of the command from being interpreted as a continuation of the first frame, a maximum interval compatible with data encoding is defined:
$$ T_{\mathrm{framegap}} = \max\left( 8000\,\mu s,\; 5T_{1,\mathrm{SPACE}} \right) $$
A SPACE equal to or greater than this value is interpreted as a separation from the next frame or from a repeat event, and bit extraction is stopped.
A final stop MARK without a following SPACE is also allowed.
Pulse-Distance Protocol Scores
For pulse-distance protocols, the overall score used by the current version is:
$$ S = 0.20\,e_C + 0.35\,e_H + 0.25\,e_D + 0.10\,e_M + 0.10\,e_B $$
where:
| Term | Meaning |
|---|---|
| \(e_C\) | Relative error of the carrier frequency. |
| \(e_H\) | Header error. |
| \(e_D\) | Median error of the timing values representing 0 and 1. |
| \(e_M\) | Median error of the bit MARK durations. |
| \(e_B\) | Relative error of the bit count with respect to the expected lengths. |
The greater weight assigned to the header is intentional because the initial timing values are often particularly useful for distinguishing protocol families whose data use very similar durations.
Sony SIRC Pulse-Width Decoding
Sony SIRC uses a different encoding scheme. The SPACE remains essentially constant, while the MARK duration represents the logic value.
For each MARK, the following are therefore calculated:
$$ e_0 = \frac{ \left|T_M-T_{0,\mathrm{nom}}\right| }{ T_{0,\mathrm{nom}} } $$
$$ e_1 = \frac{ \left|T_M-T_{1,\mathrm{nom}}\right| }{ T_{1,\mathrm{nom}} } $$
and the bit is assigned to the value with the smaller error. If:
$$ \min(e_0,e_1)>0.45 $$
extraction is stopped.
Intermediate SPACE intervals are compared with the expected nominal duration; a SPACE longer than four times this duration is interpreted as the end of the frame.
The score used is:
$$ S = 0.20\,e_C + 0.35\,e_H + 0.20\,e_D + 0.15\,e_S + 0.10\,e_B $$
Evaluation of RC5 and RC6 Biphase Protocols
For RC5 and RC6, the current version does not yet perform full Manchester/biphase bit decoding. Instead, the program checks whether the observed durations are compatible with multiples of the protocol’s fundamental time unit.
For each interval, the following is calculated:
$$ r_i = \frac{T_i}{T_u} $$
and the nearest integer multiple is identified:
$$ n_i = \operatorname{round}(r_i) $$
limited to values from 1 to 4 in the current algorithm.
The timing error is therefore:
$$ e_T = \operatorname{median} \left( \frac{ \left|T_i-n_iT_u\right| }{ T_u } \right) $$
The fraction of intervals that are excessively long relative to the nominal unit is also calculated.
For RC5, the score is:
$$ S_{\mathrm{RC5}} = 0.35\,e_C + 0.55\,e_T + 0.10\,e_X $$
whereas for RC6, which also has a characteristic header:
$$ S_{\mathrm{RC6}} = 0.25\,e_C + 0.35\,e_H + 0.35\,e_T + 0.05\,e_X $$
The RC5/RC6 classification should therefore be interpreted as a timing-compatibility check. Version 1 of the program does not yet reconstruct the bits of biphase protocols.
Contribution of Carrier Frequency
When the carrier frequency is available, its error is calculated as:
$$ e_C = \frac{ \left|f_{\mathrm{mis}}-f_{\mathrm{nom}}\right| }{ f_{\mathrm{nom}} } $$
However, the carrier is not used as an exclusive criterion. Very similar frequencies are in fact shared by many protocols.
If the frequency is unavailable, the program assigns this term a neutral value of 0.10, preventing the absence of the measurement from automatically eliminating a candidate.
Contribution of the Bit Count
The reconstructed bit count is compared with all lengths allowed by the candidate protocol.
For each nominal length \(N_k\), the following is calculated:
$$ e_{B,k} = \frac{ \left|N_{\mathrm{mis}}-N_k\right| }{ N_k } $$
and the minimum value is used:
$$ e_B = \min_k(e_{B,k}) $$
with a maximum limit of 1.
In this way, a protocol with plausible timing but an incompatible frame length is penalized without being eliminated on the basis of a single criterion.
Confidence Classification
After calculating the score for all protocols, the candidates are sorted from the lowest value to the highest.
| Score | Displayed Indication |
|---|---|
| \(S < 0.08\) | HIGH |
| \(0.08 \leq S < 0.16\) | GOOD |
| \(0.16 \leq S < 0.28\) | POSSIBLE |
| \(S \geq 0.28\) | LOW |
These definitions represent internal operating thresholds of the classifier, not statistical confidence levels. The most important parameter remains the relative comparison between the best candidate and the other protocols analyzed.
LSB-First Byte Reconstruction
For protocols specified as LSB-first, once the bit sequence has been reconstructed the program groups the data into blocks of eight.
The numerical value of each byte is calculated using:
$$ B = \sum_{k=0}^{7} b_k\,2^k $$
where \(b_0\) is the first bit transmitted in the group.
It is therefore important to distinguish the timing sequence of the bits, shown in transmission order, from the hexadecimal representation of the resulting byte.
Specific Checks for the NEC Family
When the best candidate belongs to the NEC family and exactly four bytes have been reconstructed, the program performs additional checks on the payload structure.
In standard NEC, the second byte must be the complement of the first, and the fourth must be the complement of the third. The check is performed using XOR:
$$ B_1 \oplus B_2 = \mathrm{FF}_{16} $$
$$ B_3 \oplus B_4 = \mathrm{FF}_{16} $$
If both conditions are satisfied, the payload is strongly compatible with standard NEC.
If only the command/complement pair is valid, the program indicates the possibility of extended NEC encoding or a variant belonging to the same timing family. In this case, the first two bytes are interpreted as a 16-bit address:
$$ Address_{16} = B_1 + 256B_2 $$
If even the complement checks are not consistent, the program still retains any timing-based identification as NEC family, but reports that the payload does not follow the standard NEC structure.
Limitations of the Identification Algorithm
The identifier is intentionally an experimental classifier rather than a universal decoder. Some protocols share the same carrier frequency, very similar timing, or the same physical frame structure. A good timing match can therefore identify a protocol family with high reliability, but does not always guarantee unambiguous identification of the specific variant.
This is particularly important for the NEC family, in which NEC, NEC2, some extended variants, and other derived protocols can have practically identical timing characteristics.
The current version directly recognizes the bits of the supported pulse-distance and pulse-width protocols, while for RC5 and RC6 it mainly compares biphase timing characteristics. The algorithm has been structured so that new protocols, additional payload checks, and more specific decoders can be added in later versions.
Why the Two Algorithms Are Separate
Separating waveform analysis from protocol identification makes the system much more general.
The first program is concerned exclusively with transforming a real analog signal, with its own offset, noise, polarity, and distortion, into a reliable timing sequence. The second does not need to know either the voltage level or the circuit point from which the acquisition originates: it receives only the MARK/SPACE events.
This separation also makes it possible to change the acquisition method, the CSV parser, or even the measuring instrument in the future without having to rewrite the protocol identifier. Likewise, the protocol database can be expanded without modifying the algorithm that analyzes the waveform.