You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1 vuosi sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * aptdec - A lightweight FOSS (NOAA) APT decoder
  3. * Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2023 Xerbo (xerbo@protonmail.com)
  4. *
  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.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #include <float.h>
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <aptdec.h>
  24. #include "filter.h"
  25. #include "util.h"
  26. #include "algebra.h"
  27. #define BUFFER_SIZE 16384
  28. #define LOW_PASS_SIZE 101
  29. #define CARRIER_FREQ 2400.0f
  30. #define MAX_CARRIER_OFFSET 10.0f
  31. typedef struct {
  32. float alpha;
  33. float beta;
  34. float min_freq;
  35. float max_freq;
  36. float freq;
  37. float phase;
  38. } pll_t;
  39. typedef struct {
  40. float *ring_buffer;
  41. size_t ring_size;
  42. float *taps;
  43. size_t ntaps;
  44. } fir_t;
  45. struct aptdec_t {
  46. float sample_rate;
  47. float sync_frequency;
  48. pll_t *pll;
  49. fir_t *hilbert;
  50. float low_pass[LOW_PASS_SIZE];
  51. };
  52. char *aptdec_get_version(void) {
  53. return VERSION;
  54. }
  55. fir_t *fir_init(size_t max_size, size_t ntaps) {
  56. fir_t *fir = (fir_t *)malloc(sizeof(fir_t));
  57. fir->ntaps = ntaps;
  58. fir->ring_size = max_size + ntaps;
  59. fir->taps = (float *)malloc(ntaps * sizeof(float));
  60. fir->ring_buffer = (float *)malloc((max_size + ntaps) * sizeof(float));
  61. return fir;
  62. }
  63. void fir_free(fir_t *fir) {
  64. free(fir->ring_buffer);
  65. free(fir->taps);
  66. free(fir);
  67. }
  68. pll_t *pll_init(float alpha, float beta, float min_freq, float max_freq, float sample_rate) {
  69. pll_t *pll = (pll_t *)malloc(sizeof(pll_t));
  70. pll->alpha = alpha;
  71. pll->beta = beta;
  72. pll->min_freq = M_TAUf * min_freq / sample_rate;
  73. pll->max_freq = M_TAUf * max_freq / sample_rate;
  74. pll->phase = 0.0f;
  75. pll->freq = 0.0f;
  76. return pll;
  77. }
  78. aptdec_t *aptdec_init(float sample_rate) {
  79. if (sample_rate > 96000 || sample_rate < (CARRIER_FREQ + APT_IMG_WIDTH) * 2.0f) {
  80. return NULL;
  81. }
  82. aptdec_t *apt = (aptdec_t *)malloc(sizeof(aptdec_t));
  83. apt->sample_rate = sample_rate;
  84. apt->sync_frequency = 1.0f;
  85. // PLL configuration
  86. // https://www.trondeau.com/blog/2011/8/13/control-loop-gain-values.html
  87. float damp = 0.7f;
  88. float bw = 0.005f;
  89. float alpha = (4.0f * damp * bw) / (1.0f + 2.0f * damp * bw + bw * bw);
  90. float beta = (4.0f * bw * bw) / (1.0f + 2.0f * damp * bw + bw * bw);
  91. apt->pll = pll_init(alpha, beta, CARRIER_FREQ-MAX_CARRIER_OFFSET, CARRIER_FREQ+MAX_CARRIER_OFFSET, sample_rate);
  92. if (apt->pll == NULL) {
  93. free(apt);
  94. return NULL;
  95. }
  96. // Hilbert transform
  97. apt->hilbert = fir_init(BUFFER_SIZE, 31);
  98. if (apt->hilbert == NULL) {
  99. free(apt->pll);
  100. free(apt);
  101. return NULL;
  102. }
  103. design_hilbert(apt->hilbert->taps, apt->hilbert->ntaps);
  104. design_low_pass(apt->low_pass, apt->sample_rate, (2080.0f + CARRIER_FREQ) / 2.0f, LOW_PASS_SIZE);
  105. return apt;
  106. }
  107. void aptdec_free(aptdec_t *apt) {
  108. fir_free(apt->hilbert);
  109. free(apt->pll);
  110. free(apt);
  111. }
  112. static complexf_t pll_work(pll_t *pll, complexf_t in) {
  113. // Internal oscillator (90deg offset)
  114. complexf_t osc = complex_build(cosf(pll->phase), -sinf(pll->phase));
  115. in = complex_multiply(in, osc);
  116. // Error detector
  117. float error = cargf(in);
  118. // Loop filter (single pole IIR)
  119. pll->freq += pll->beta * error;
  120. pll->freq = clamp(pll->freq, pll->min_freq, pll->max_freq);
  121. pll->phase += pll->freq + (pll->alpha * error);
  122. pll->phase = remainderf(pll->phase, M_TAUf);
  123. return in;
  124. }
  125. static int am_demod(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) {
  126. size_t read = callback(&apt->hilbert->ring_buffer[apt->hilbert->ntaps], count, context);
  127. for (size_t i = 0; i < read; i++) {
  128. complexf_t sample = hilbert_transform(&apt->hilbert->ring_buffer[i], apt->hilbert->taps, apt->hilbert->ntaps);
  129. out[i] = crealf(pll_work(apt->pll, sample));
  130. }
  131. memcpy(apt->hilbert->ring_buffer, &apt->hilbert->ring_buffer[read], apt->hilbert->ntaps*sizeof(float));
  132. return read;
  133. }
  134. static int get_pixels(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) {
  135. static float buffer[BUFFER_SIZE];
  136. static size_t n = BUFFER_SIZE;
  137. static float offset = 0.0;
  138. float ratio = apt->sample_rate / (4160.0f * apt->sync_frequency);
  139. for (size_t i = 0; i < count; i++) {
  140. // Get more samples if there are less than `LOW_PASS_SIZE` available
  141. if (n + LOW_PASS_SIZE > BUFFER_SIZE) {
  142. memcpy(buffer, &buffer[n], (BUFFER_SIZE-n) * sizeof(float));
  143. size_t read = am_demod(apt, &buffer[BUFFER_SIZE-n], n, callback, context);
  144. if (read != n) {
  145. return i;
  146. }
  147. n = 0;
  148. }
  149. out[i] = interpolating_convolve(&buffer[n], apt->low_pass, LOW_PASS_SIZE, offset);
  150. // Do not question the sacred code
  151. int shift = ceilf(ratio - offset);
  152. offset = shift + offset - ratio;
  153. n += shift;
  154. }
  155. return count;
  156. }
  157. const float sync_pattern[] = {-1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1,
  158. 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0};
  159. #define SYNC_SIZE (sizeof(sync_pattern)/sizeof(sync_pattern[0]))
  160. // Get an entire row of pixels, aligned with sync markers
  161. int aptdec_getrow(aptdec_t *apt, float *row, aptdec_callback_t callback, void *context) {
  162. static float pixels[APT_IMG_WIDTH + SYNC_SIZE + 2];
  163. // Wrap the circular buffer
  164. memcpy(pixels, &pixels[APT_IMG_WIDTH], (SYNC_SIZE + 2) * sizeof(float));
  165. // Get a lines worth (APT_IMG_WIDTH) of samples
  166. if (get_pixels(apt, &pixels[SYNC_SIZE + 2], APT_IMG_WIDTH, callback, context) != APT_IMG_WIDTH) {
  167. return 0;
  168. }
  169. // Error detector
  170. float left = FLT_MIN;
  171. float middle = FLT_MIN;
  172. float right = FLT_MIN;
  173. size_t phase = 0;
  174. for (size_t i = 0; i < APT_IMG_WIDTH; i++) {
  175. float _left = convolve(&pixels[i + 0], sync_pattern, SYNC_SIZE);
  176. float _middle = convolve(&pixels[i + 1], sync_pattern, SYNC_SIZE);
  177. float _right = convolve(&pixels[i + 2], sync_pattern, SYNC_SIZE);
  178. if (_middle > middle) {
  179. left = _left;
  180. middle = _middle;
  181. right = _right;
  182. phase = i + 1;
  183. }
  184. }
  185. // Frequency
  186. float bias = (left / middle) - (right / middle);
  187. apt->sync_frequency = 1.0f + bias / APT_IMG_WIDTH / 2.0f;
  188. // Phase
  189. memcpy(&row[APT_IMG_WIDTH], &pixels[phase], (APT_IMG_WIDTH - phase) * sizeof(float));
  190. memcpy(&row[APT_IMG_WIDTH - phase], pixels, phase * sizeof(float));
  191. return 1;
  192. }