2 * Pulse detection functions
4 * Copyright (C) 2015 Tommy Vestermark
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
11 #include "pulse_detect.h"
12 #include "pulse_demod.h"
19 void pulse_data_clear(pulse_data_t *data) {
20 *data = (const pulse_data_t) {
26 void pulse_data_print(const pulse_data_t *data) {
27 fprintf(stderr, "Pulse data: %u pulses\n", data->num_pulses);
28 for(unsigned n = 0; n < data->num_pulses; ++n) {
29 fprintf(stderr, "[%3u] Pulse: %4u, Gap: %4u, Period: %4u\n", n, data->pulse[n], data->gap[n], data->pulse[n] + data->gap[n]);
34 // OOK adaptive level estimator constants
35 #define OOK_HIGH_LOW_RATIO 8 // Default ratio between high and low (noise) level
36 #define OOK_MIN_HIGH_LEVEL 1000 // Minimum estimate of high level
37 #define OOK_MAX_HIGH_LEVEL (128*128) // Maximum estimate for high level (A unit phasor is 128, anything above is overdrive)
38 #define OOK_MAX_LOW_LEVEL (OOK_MAX_HIGH_LEVEL/2) // Maximum estimate for low level
39 #define OOK_EST_HIGH_RATIO 64 // Constant for slowness of OOK high level estimator
40 #define OOK_EST_LOW_RATIO 1024 // Constant for slowness of OOK low level (noise) estimator (very slow)
42 // FSK adaptive frequency estimator constants
43 #define FSK_DEFAULT_FM_DELTA 6000 // Default estimate for frequency delta
44 #define FSK_EST_RATIO 32 // Constant for slowness of FSK estimators
47 /// Internal state data for pulse_FSK_detect()
49 unsigned int fsk_pulse_length; // Counter for internal FSK pulse detection
51 PD_FSK_STATE_INIT = 0, // Initial frequency estimation
52 PD_FSK_STATE_F1 = 1, // High frequency (pulse)
53 PD_FSK_STATE_F2 = 2, // Low frequency (gap)
54 PD_FSK_STATE_ERROR = 3 // Error - stay here until cleared
57 int fm_f1_est; // Estimate for the F1 frequency for FSK
58 int fm_f2_est; // Estimate for the F2 frequency for FSK
63 /// Demodulate Frequency Shift Keying (FSK) sample by sample
65 /// Function is stateful between calls
66 /// Builds estimate for initial frequency. When frequency deviates more than a
67 /// threshold value it will determine whether the deviation is positive or negative
68 /// to classify it as a pulse or gap. It will then transition to other state (F1 or F2)
69 /// and build an estimate of the other frequency. It will then transition back and forth when current
70 /// frequency is closer to other frequency estimate.
71 /// Includes spurious suppression by coalescing pulses when pulse/gap widths are too short.
72 /// Pulses equal higher frequency (F1) and Gaps equal lower frequency (F2)
73 /// @param fm_n: One single sample of FM data
74 /// @param *fsk_pulses: Will return a pulse_data_t structure for FSK demodulated data
75 /// @param *s: Internal state
76 void pulse_FSK_detect(int16_t fm_n, pulse_data_t *fsk_pulses, pulse_FSK_state_t *s) {
77 const int fm_f1_delta = abs(fm_n - s->fm_f1_est); // Get delta from F1 frequency estimate
78 const int fm_f2_delta = abs(fm_n - s->fm_f2_est); // Get delta from F2 frequency estimate
79 s->fsk_pulse_length++;
81 switch(s->fsk_state) {
82 case PD_FSK_STATE_INIT: // Initial frequency - High or low?
84 if (s->fsk_pulse_length < PD_MIN_PULSE_SAMPLES) {
85 s->fm_f1_est = s->fm_f1_est/2 + fm_n/2; // Quick initial estimator
86 // Above default frequency delta?
87 } else if (fm_f1_delta > (FSK_DEFAULT_FM_DELTA/2)) {
88 // Positive frequency delta - Initial frequency was low (gap)
89 if (fm_n > s->fm_f1_est) {
90 s->fsk_state = PD_FSK_STATE_F1;
91 s->fm_f2_est = s->fm_f1_est; // Switch estimates
92 s->fm_f1_est = fm_n; // Prime F1 estimate
93 fsk_pulses->pulse[0] = 0; // Initial frequency was a gap...
94 fsk_pulses->gap[0] = s->fsk_pulse_length; // Store gap width
95 fsk_pulses->num_pulses++;
96 s->fsk_pulse_length = 0;
97 // Negative Frequency delta - Initial frequency was high (pulse)
99 s->fsk_state = PD_FSK_STATE_F2;
100 s->fm_f2_est = fm_n; // Prime F2 estimate
101 fsk_pulses->pulse[0] = s->fsk_pulse_length; // Store pulse width
102 s->fsk_pulse_length = 0;
104 // Still below threshold
106 s->fm_f1_est += fm_n/FSK_EST_RATIO - s->fm_f1_est/FSK_EST_RATIO; // Slow estimator
109 case PD_FSK_STATE_F1: // Pulse high at F1 frequency
110 // Closer to F2 than F1?
111 if (fm_f1_delta > fm_f2_delta) {
112 s->fsk_state = PD_FSK_STATE_F2;
113 // Store if pulse is not too short (suppress spurious)
114 if (s->fsk_pulse_length >= PD_MIN_PULSE_SAMPLES) {
115 fsk_pulses->pulse[fsk_pulses->num_pulses] = s->fsk_pulse_length; // Store pulse width
116 s->fsk_pulse_length = 0;
117 // Else rewind to last gap
119 s->fsk_pulse_length += fsk_pulses->gap[fsk_pulses->num_pulses-1]; // Restore counter
120 fsk_pulses->num_pulses--; // Rewind one pulse
121 // Are we back to initial frequency? (Was initial frequency a gap?)
122 if ((fsk_pulses->num_pulses == 0) && (fsk_pulses->pulse[0] == 0)) {
123 s->fm_f1_est = s->fm_f2_est; // Switch back estimates
124 s->fsk_state = PD_FSK_STATE_INIT;
127 // Still below threshold
129 s->fm_f1_est += fm_n/FSK_EST_RATIO - s->fm_f1_est/FSK_EST_RATIO; // Slow estimator
132 case PD_FSK_STATE_F2: // Pulse gap at F2 frequency
133 // Freq closer to F1 than F2 ?
134 if (fm_f2_delta > fm_f1_delta) {
135 s->fsk_state = PD_FSK_STATE_F1;
136 // Store if pulse is not too short (suppress spurious)
137 if (s->fsk_pulse_length >= PD_MIN_PULSE_SAMPLES) {
138 fsk_pulses->gap[fsk_pulses->num_pulses] = s->fsk_pulse_length; // Store gap width
139 fsk_pulses->num_pulses++; // Go to next pulse
140 s->fsk_pulse_length = 0;
141 // When pulse buffer is full go to error state
142 if (fsk_pulses->num_pulses >= PD_MAX_PULSES) {
143 fprintf(stderr, "pulse_FSK_detect(): Maximum number of pulses reached!\n");
144 s->fsk_state = PD_FSK_STATE_ERROR;
146 // Else rewind to last pulse
148 s->fsk_pulse_length += fsk_pulses->pulse[fsk_pulses->num_pulses]; // Restore counter
149 // Are we back to initial frequency?
150 if (fsk_pulses->num_pulses == 0) {
151 s->fsk_state = PD_FSK_STATE_INIT;
154 // Still below threshold
156 s->fm_f2_est += fm_n/FSK_EST_RATIO - s->fm_f2_est/FSK_EST_RATIO; // Slow estimator
159 case PD_FSK_STATE_ERROR: // Stay here until cleared
162 fprintf(stderr, "pulse_FSK_detect(): Unknown FSK state!!\n");
163 s->fsk_state = PD_FSK_STATE_ERROR;
164 } // switch(s->fsk_state)
168 /// Wrap up FSK modulation and store last data at End Of Package
170 /// @param fm_n: One single sample of FM data
171 /// @param *fsk_pulses: Pulse_data_t structure for FSK demodulated data
172 /// @param *s: Internal state
173 void pulse_FSK_wrap_up(pulse_data_t *fsk_pulses, pulse_FSK_state_t *s) {
174 if (fsk_pulses->num_pulses < PD_MAX_PULSES) { // Avoid overflow
175 s->fsk_pulse_length++;
176 if(s->fsk_state == PD_FSK_STATE_F1) {
177 fsk_pulses->pulse[fsk_pulses->num_pulses] = s->fsk_pulse_length; // Store last pulse
178 fsk_pulses->gap[fsk_pulses->num_pulses] = 0; // Zero gap at end
180 fsk_pulses->gap[fsk_pulses->num_pulses] = s->fsk_pulse_length; // Store last gap
182 fsk_pulses->num_pulses++;
187 /// Internal state data for pulse_pulse_package()
190 PD_OOK_STATE_IDLE = 0,
191 PD_OOK_STATE_PULSE = 1,
192 PD_OOK_STATE_GAP_START = 2,
195 int pulse_length; // Counter for internal pulse detection
196 int max_pulse; // Size of biggest pulse detected
198 int data_counter; // Counter for how much of data chunck is processed
199 int lead_in_counter; // Counter for allowing initial noise estimate to settle
201 int ook_low_estimate; // Estimate for the OOK low level (base noise level) in the envelope data
202 int ook_high_estimate; // Estimate for the OOK high level
204 pulse_FSK_state_t FSK_state;
207 static pulse_state_t pulse_state;
210 /// Demodulate On/Off Keying (OOK) and Frequency Shift Keying (FSK) from an envelope signal
211 int pulse_detect_package(const int16_t *envelope_data, const int16_t *fm_data, int len, int16_t level_limit, uint32_t samp_rate, pulse_data_t *pulses, pulse_data_t *fsk_pulses) {
212 const int samples_per_ms = samp_rate / 1000;
213 pulse_state_t *s = &pulse_state;
214 s->ook_high_estimate = max(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL); // Be sure to set initial minimum level
216 // Process all new samples
217 while(s->data_counter < len) {
218 // Calculate OOK detection threshold and hysteresis
219 const int16_t am_n = envelope_data[s->data_counter];
220 int16_t ook_threshold = s->ook_low_estimate + (s->ook_high_estimate - s->ook_low_estimate) / 2;
221 if (level_limit != 0) ook_threshold = level_limit; // Manual override
222 const int16_t ook_hysteresis = ook_threshold / 8; // ±12%
225 switch (s->ook_state) {
226 case PD_OOK_STATE_IDLE:
227 if (am_n > (ook_threshold + ook_hysteresis) // Above threshold?
228 && s->lead_in_counter > OOK_EST_LOW_RATIO // Lead in counter to stabilize noise estimate
230 // Initialize all data
231 pulse_data_clear(pulses);
232 pulse_data_clear(fsk_pulses);
235 s->FSK_state = (pulse_FSK_state_t){0};
236 s->ook_state = PD_OOK_STATE_PULSE;
237 } else { // We are still idle..
238 // Estimate low (noise) level
239 const int ook_low_delta = am_n - s->ook_low_estimate;
240 s->ook_low_estimate += ook_low_delta / OOK_EST_LOW_RATIO;
241 s->ook_low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling
242 // Calculate default OOK high level estimate
243 s->ook_high_estimate = OOK_HIGH_LOW_RATIO * s->ook_low_estimate; // Default is a ratio of low level
244 s->ook_high_estimate = max(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL);
245 s->ook_high_estimate = min(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL);
246 if (s->lead_in_counter <= OOK_EST_LOW_RATIO) s->lead_in_counter++; // Allow inital estimate to settle
249 case PD_OOK_STATE_PULSE:
251 // End of pulse detected?
252 if (am_n < (ook_threshold - ook_hysteresis)) { // Gap?
253 // Check for spurious short pulses
254 if (s->pulse_length < PD_MIN_PULSE_SAMPLES) {
255 s->ook_state = PD_OOK_STATE_IDLE;
257 // Continue with OOK decoding
258 pulses->pulse[pulses->num_pulses] = s->pulse_length; // Store pulse width
259 s->max_pulse = max(s->pulse_length, s->max_pulse); // Find largest pulse
261 s->ook_state = PD_OOK_STATE_GAP_START;
265 // Calculate OOK high level estimate
266 s->ook_high_estimate += am_n / OOK_EST_HIGH_RATIO - s->ook_high_estimate / OOK_EST_HIGH_RATIO;
267 s->ook_high_estimate = max(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL);
268 s->ook_high_estimate = min(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL);
269 // Estimate pulse carrier frequency
270 pulses->fsk_f1_est += fm_data[s->data_counter] / OOK_EST_HIGH_RATIO - pulses->fsk_f1_est / OOK_EST_HIGH_RATIO;
273 if(pulses->num_pulses == 0) { // Only during first pulse
274 pulse_FSK_detect(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
277 case PD_OOK_STATE_GAP_START: // Beginning of gap - it might be a spurious gap
279 // Pulse detected again already? (This is a spurious short gap)
280 if (am_n > (ook_threshold + ook_hysteresis)) { // New pulse?
281 s->pulse_length += pulses->pulse[pulses->num_pulses]; // Restore counter
282 s->ook_state = PD_OOK_STATE_PULSE;
283 // Or this gap is for real?
284 } else if (s->pulse_length >= PD_MIN_PULSE_SAMPLES) {
285 s->ook_state = PD_OOK_STATE_GAP;
286 // Determine if FSK modulation is detected
287 if(fsk_pulses->num_pulses > PD_MIN_PULSES) {
288 // Store last pulse/gap
289 pulse_FSK_wrap_up(fsk_pulses, &s->FSK_state);
291 fsk_pulses->fsk_f1_est = s->FSK_state.fm_f1_est;
292 fsk_pulses->fsk_f2_est = s->FSK_state.fm_f2_est;
293 fsk_pulses->ook_low_estimate = s->ook_low_estimate;
294 fsk_pulses->ook_high_estimate = s->ook_high_estimate;
295 s->ook_state = PD_OOK_STATE_IDLE; // Ensure everything is reset
296 return 2; // FSK package detected!!!
299 // FSK Demodulation (continue during short gap - we might return...)
300 if(pulses->num_pulses == 0) { // Only during first pulse
301 pulse_FSK_detect(fm_data[s->data_counter], fsk_pulses, &s->FSK_state);
304 case PD_OOK_STATE_GAP:
306 // New pulse detected?
307 if (am_n > (ook_threshold + ook_hysteresis)) { // New pulse?
308 pulses->gap[pulses->num_pulses] = s->pulse_length; // Store gap width
309 pulses->num_pulses++; // Next pulse
311 // EOP if too many pulses
312 if (pulses->num_pulses >= PD_MAX_PULSES) {
313 s->ook_state = PD_OOK_STATE_IDLE;
315 pulses->ook_low_estimate = s->ook_low_estimate;
316 pulses->ook_high_estimate = s->ook_high_estimate;
317 return 1; // End Of Package!!
321 s->ook_state = PD_OOK_STATE_PULSE;
324 // EOP if gap is too long
325 if (((s->pulse_length > (PD_MAX_GAP_RATIO * s->max_pulse)) // gap/pulse ratio exceeded
326 && (s->pulse_length > (PD_MIN_GAP_MS * samples_per_ms))) // Minimum gap exceeded
327 || (s->pulse_length > (PD_MAX_GAP_MS * samples_per_ms)) // maximum gap exceeded
329 pulses->gap[pulses->num_pulses] = s->pulse_length; // Store gap width
330 pulses->num_pulses++; // Store last pulse
331 s->ook_state = PD_OOK_STATE_IDLE;
333 pulses->ook_low_estimate = s->ook_low_estimate;
334 pulses->ook_high_estimate = s->ook_high_estimate;
335 return 1; // End Of Package!!
339 fprintf(stderr, "demod_OOK(): Unknown state!!\n");
340 s->ook_state = PD_OOK_STATE_IDLE;
346 return 0; // Out of data
350 #define MAX_HIST_BINS 16
352 /// Histogram data for single bin
361 /// Histogram data for all bins
364 hist_bin_t bins[MAX_HIST_BINS];
368 /// Generate a histogram (unsorted)
369 void histogram_sum(histogram_t *hist, const int *data, unsigned len, float tolerance) {
370 unsigned bin; // Iterator will be used outside for!
372 for(unsigned n = 0; n < len; ++n) {
373 // Search for match in existing bins
374 for(bin = 0; bin < hist->bins_count; ++bin) {
376 int bm = hist->bins[bin].mean;
377 if (abs(bn - bm) < (tolerance * max(bn, bm))) {
378 hist->bins[bin].count++;
379 hist->bins[bin].sum += data[n];
380 hist->bins[bin].mean = hist->bins[bin].sum / hist->bins[bin].count;
381 hist->bins[bin].min = min(data[n], hist->bins[bin].min);
382 hist->bins[bin].max = max(data[n], hist->bins[bin].max);
383 break; // Match found! Data added to existing bin
386 // No match found? Add new bin
387 if(bin == hist->bins_count && bin < MAX_HIST_BINS) {
388 hist->bins[bin].count = 1;
389 hist->bins[bin].sum = data[n];
390 hist->bins[bin].mean = data[n];
391 hist->bins[bin].min = data[n];
392 hist->bins[bin].max = data[n];
399 /// Delete bin from histogram
400 void histogram_delete_bin(histogram_t *hist, unsigned index) {
401 const hist_bin_t zerobin = {0};
402 if (hist->bins_count < 1) return; // Avoid out of bounds
403 // Move all bins afterwards one forward
404 for(unsigned n = index; n < hist->bins_count-1; ++n) {
405 hist->bins[n] = hist->bins[n+1];
408 hist->bins[hist->bins_count] = zerobin; // Clear previously last bin
412 /// Swap two bins in histogram
413 void histogram_swap_bins(histogram_t *hist, unsigned index1, unsigned index2) {
415 if ((index1 < hist->bins_count) && (index2 < hist->bins_count)) { // Avoid out of bounds
416 tempbin = hist->bins[index1];
417 hist->bins[index1] = hist->bins[index2];
418 hist->bins[index2] = tempbin;
423 /// Sort histogram with mean value (order lowest to highest)
424 void histogram_sort_mean(histogram_t *hist) {
425 if (hist->bins_count < 2) return; // Avoid underflow
426 // Compare all bins (bubble sort)
427 for(unsigned n = 0; n < hist->bins_count-1; ++n) {
428 for(unsigned m = n+1; m < hist->bins_count; ++m) {
429 if (hist->bins[m].mean < hist->bins[n].mean) {
430 histogram_swap_bins(hist, m, n);
437 /// Sort histogram with count value (order lowest to highest)
438 void histogram_sort_count(histogram_t *hist) {
439 if (hist->bins_count < 2) return; // Avoid underflow
440 // Compare all bins (bubble sort)
441 for(unsigned n = 0; n < hist->bins_count-1; ++n) {
442 for(unsigned m = n+1; m < hist->bins_count; ++m) {
443 if (hist->bins[m].count < hist->bins[n].count) {
444 histogram_swap_bins(hist, m, n);
451 /// Fuse histogram bins with means within tolerance
452 void histogram_fuse_bins(histogram_t *hist, float tolerance) {
453 if (hist->bins_count < 2) return; // Avoid underflow
455 for(unsigned n = 0; n < hist->bins_count-1; ++n) {
456 for(unsigned m = n+1; m < hist->bins_count; ++m) {
457 int bn = hist->bins[n].mean;
458 int bm = hist->bins[m].mean;
459 if (abs(bn - bm) < (tolerance * max(bn, bm))) {
460 // Fuse data for bin[n] and bin[m]
461 hist->bins[n].count += hist->bins[m].count;
462 hist->bins[n].sum += hist->bins[m].sum;
463 hist->bins[n].mean = hist->bins[n].sum / hist->bins[n].count;
464 hist->bins[n].min = min(hist->bins[n].min, hist->bins[m].min);
465 hist->bins[n].max = max(hist->bins[n].max, hist->bins[m].max);
467 histogram_delete_bin(hist, m);
468 m--; // Compare new bin in same place!
469 } // if within tolerance
475 /// Print a histogram
476 void histogram_print(const histogram_t *hist, uint32_t samp_rate) {
477 for(unsigned n = 0; n < hist->bins_count; ++n) {
478 fprintf(stderr, " [%2u] count: %4u, width: %5u [%2u;%2u]\t(%4.0f us)\n", n,
483 1E6f * hist->bins[n].mean / samp_rate);
488 #define TOLERANCE (0.2) // 20% tolerance should still discern between the pulse widths: 0.33, 0.66, 1.0
490 /// Analyze the statistics of a pulse data structure and print result
491 void pulse_analyzer(pulse_data_t *data, uint32_t samp_rate)
493 // Generate pulse period data
494 int pulse_total_period = 0;
495 pulse_data_t pulse_periods = {0};
496 pulse_periods.num_pulses = data->num_pulses;
497 for(unsigned n = 0; n < pulse_periods.num_pulses; ++n) {
498 pulse_periods.pulse[n] = data->pulse[n] + data->gap[n];
499 pulse_total_period += data->pulse[n] + data->gap[n];
501 pulse_total_period -= data->gap[pulse_periods.num_pulses-1];
503 histogram_t hist_pulses = {0};
504 histogram_t hist_gaps = {0};
505 histogram_t hist_periods = {0};
507 // Generate statistics
508 histogram_sum(&hist_pulses, data->pulse, data->num_pulses, TOLERANCE);
509 histogram_sum(&hist_gaps, data->gap, data->num_pulses-1, TOLERANCE); // Leave out last gap (end)
510 histogram_sum(&hist_periods, pulse_periods.pulse, pulse_periods.num_pulses-1, TOLERANCE); // Leave out last gap (end)
512 // Fuse overlapping bins
513 histogram_fuse_bins(&hist_pulses, TOLERANCE);
514 histogram_fuse_bins(&hist_gaps, TOLERANCE);
515 histogram_fuse_bins(&hist_periods, TOLERANCE);
517 fprintf(stderr, "Analyzing pulses...\n");
518 fprintf(stderr, "Total count: %4u, width: %5i\t\t(%4.1f ms)\n",
519 data->num_pulses, pulse_total_period, 1000.0f*pulse_total_period/samp_rate);
520 fprintf(stderr, "Pulse width distribution:\n");
521 histogram_print(&hist_pulses, samp_rate);
522 fprintf(stderr, "Gap width distribution:\n");
523 histogram_print(&hist_gaps, samp_rate);
524 fprintf(stderr, "Pulse period distribution:\n");
525 histogram_print(&hist_periods, samp_rate);
526 fprintf(stderr, "Level estimates [high, low]: %6i, %6i\n",
527 data->ook_high_estimate, data->ook_low_estimate);
528 fprintf(stderr, "Frequency offsets [F1, F2]: %6i, %6i\t(%+.1f kHz, %+.1f kHz)\n",
529 data->fsk_f1_est, data->fsk_f2_est,
530 (float)data->fsk_f1_est/INT16_MAX*samp_rate/2.0/1000.0,
531 (float)data->fsk_f2_est/INT16_MAX*samp_rate/2.0/1000.0);
533 fprintf(stderr, "Guessing modulation: ");
534 struct protocol_state device = { .name = "Analyzer Device", 0};
535 histogram_sort_mean(&hist_pulses); // Easier to work with sorted data
536 histogram_sort_mean(&hist_gaps);
537 if(hist_pulses.bins[0].mean == 0) { histogram_delete_bin(&hist_pulses, 0); } // Remove FSK initial zero-bin
539 // Attempt to find a matching modulation
540 if(data->num_pulses == 1) {
541 fprintf(stderr, "Single pulse detected. Probably Frequency Shift Keying or just noise...\n");
542 } else if(hist_pulses.bins_count == 1 && hist_gaps.bins_count == 1) {
543 fprintf(stderr, "Un-modulated signal. Maybe a preamble...\n");
544 } else if(hist_pulses.bins_count == 1 && hist_gaps.bins_count > 1) {
545 fprintf(stderr, "Pulse Position Modulation with fixed pulse width\n");
546 device.modulation = OOK_PULSE_PPM_RAW;
547 device.short_limit = (hist_gaps.bins[0].mean + hist_gaps.bins[1].mean) / 2; // Set limit between two lowest gaps
548 device.long_limit = hist_gaps.bins[1].max + 1; // Set limit above next lower gap
549 device.reset_limit = hist_gaps.bins[hist_gaps.bins_count-1].max + 1; // Set limit above biggest gap
550 } else if(hist_pulses.bins_count == 2 && hist_gaps.bins_count == 1) {
551 fprintf(stderr, "Pulse Width Modulation with fixed gap\n");
552 device.modulation = OOK_PULSE_PWM_RAW;
553 device.short_limit = (hist_pulses.bins[0].mean + hist_pulses.bins[1].mean) / 2; // Set limit between two pulse widths
554 device.long_limit = hist_gaps.bins[hist_gaps.bins_count-1].max + 1; // Set limit above biggest gap
555 device.reset_limit = device.long_limit;
556 } else if(hist_pulses.bins_count == 2 && hist_gaps.bins_count == 2 && hist_periods.bins_count == 1) {
557 fprintf(stderr, "Pulse Width Modulation with fixed period\n");
558 device.modulation = OOK_PULSE_PWM_RAW;
559 device.short_limit = (hist_pulses.bins[0].mean + hist_pulses.bins[1].mean) / 2; // Set limit between two pulse widths
560 device.long_limit = hist_gaps.bins[hist_gaps.bins_count-1].max + 1; // Set limit above biggest gap
561 device.reset_limit = device.long_limit;
562 } else if(hist_pulses.bins_count == 2 && hist_gaps.bins_count == 2 && hist_periods.bins_count == 3) {
563 fprintf(stderr, "Manchester coding\n");
564 device.modulation = OOK_PULSE_MANCHESTER_ZEROBIT;
565 device.short_limit = min(hist_pulses.bins[0].mean, hist_pulses.bins[1].mean); // Assume shortest pulse is half period
566 device.long_limit = 0; // Not used
567 device.reset_limit = hist_gaps.bins[hist_gaps.bins_count-1].max + 1; // Set limit above biggest gap
568 } else if((hist_pulses.bins_count >= 3 && hist_gaps.bins_count >= 3)
569 && (abs(hist_pulses.bins[1].mean - 2*hist_pulses.bins[0].mean) <= hist_pulses.bins[0].mean/8) // Pulses are multiples of shortest pulse
570 && (abs(hist_pulses.bins[2].mean - 3*hist_pulses.bins[0].mean) <= hist_pulses.bins[0].mean/8)
571 && (abs(hist_gaps.bins[0].mean - hist_pulses.bins[0].mean) <= hist_pulses.bins[0].mean/8) // Gaps are multiples of shortest pulse
572 && (abs(hist_gaps.bins[1].mean - 2*hist_pulses.bins[0].mean) <= hist_pulses.bins[0].mean/8)
573 && (abs(hist_gaps.bins[2].mean - 3*hist_pulses.bins[0].mean) <= hist_pulses.bins[0].mean/8)
575 fprintf(stderr, "Pulse Code Modulation (Not Return to Zero)\n");
576 device.modulation = FSK_PULSE_PCM;
577 device.short_limit = hist_pulses.bins[0].mean; // Shortest pulse is bit width
578 device.long_limit = hist_pulses.bins[0].mean; // Bit period equal to pulse length (NRZ)
579 device.reset_limit = hist_pulses.bins[0].mean*1024; // No limit to run of zeros...
580 } else if(hist_pulses.bins_count == 3) {
581 fprintf(stderr, "Pulse Width Modulation with startbit/delimiter\n");
582 device.modulation = OOK_PULSE_PWM_TERNARY;
583 device.short_limit = (hist_pulses.bins[0].mean + hist_pulses.bins[1].mean) / 2; // Set limit between two lowest pulse widths
584 device.long_limit = (hist_pulses.bins[1].mean + hist_pulses.bins[2].mean) / 2; // Set limit between two next lowest pulse widths
585 device.reset_limit = hist_gaps.bins[hist_gaps.bins_count-1].max +1; // Set limit above biggest gap
586 // Re-sort to find lowest pulse count index (is probably delimiter)
587 histogram_sort_count(&hist_pulses);
588 if (hist_pulses.bins[0].mean < device.short_limit) { device.demod_arg = 0; } // Shortest pulse is delimiter
589 else if (hist_pulses.bins[0].mean < device.long_limit) { device.demod_arg = 1; } // Middle pulse is delimiter
590 else { device.demod_arg = 2; } // Longest pulse is delimiter
592 fprintf(stderr, "No clue...\n");
595 // Demodulate (if detected)
596 if(device.modulation) {
597 fprintf(stderr, "Attempting demodulation... short_limit: %.0f, long_limit: %.0f, reset_limit: %.0f, demod_arg: %lu\n",
598 device.short_limit, device.long_limit, device.reset_limit, device.demod_arg);
599 switch(device.modulation) {
601 pulse_demod_pcm(data, &device);
603 case OOK_PULSE_PPM_RAW:
604 data->gap[data->num_pulses-1] = device.reset_limit + 1; // Be sure to terminate package
605 pulse_demod_ppm(data, &device);
607 case OOK_PULSE_PWM_RAW:
608 data->gap[data->num_pulses-1] = device.reset_limit + 1; // Be sure to terminate package
609 pulse_demod_pwm(data, &device);
611 case OOK_PULSE_PWM_TERNARY:
612 data->gap[data->num_pulses-1] = device.reset_limit + 1; // Be sure to terminate package
613 pulse_demod_pwm_ternary(data, &device);
615 case OOK_PULSE_MANCHESTER_ZEROBIT:
616 data->gap[data->num_pulses-1] = device.reset_limit + 1; // Be sure to terminate package
617 pulse_demod_manchester_zerobit(data, &device);
620 fprintf(stderr, "Unsupported\n");
624 fprintf(stderr, "\n");