Browse Source

Convert entire code base to single precision

tags/v1.8.0
Xerbo 2 years ago
parent
commit
be640ffe80
No known key found for this signature in database GPG Key ID: 34103F6D8F11CEB0
8 changed files with 248 additions and 249 deletions
  1. +3
    -1
      .github/workflows/build.yml
  2. +2
    -2
      CMakeLists.txt
  3. +59
    -89
      src/dsp.c
  4. +37
    -46
      src/filter.c
  5. +18
    -94
      src/filter.h
  6. +17
    -17
      src/image.c
  7. +92
    -0
      src/taps.h
  8. +20
    -0
      src/util.h

+ 3
- 1
.github/workflows/build.yml View File

@@ -18,7 +18,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest


steps: steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Install dependencies - name: Install dependencies
# The user does not run as root # The user does not run as root


+ 2
- 2
CMakeLists.txt View File

@@ -41,7 +41,7 @@ if (PNG_FOUND AND LIBSNDFILE_FOUND)
if(CMAKE_BUILD_TYPE MATCHES "Release") if(CMAKE_BUILD_TYPE MATCHES "Release")
target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers)
else() else()
target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic)
target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers)
endif() endif()
endif() endif()
else() else()
@@ -59,7 +59,7 @@ else()
if(CMAKE_BUILD_TYPE MATCHES "Release") if(CMAKE_BUILD_TYPE MATCHES "Release")
target_compile_options(apt PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers) target_compile_options(apt PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers)
else() else()
target_compile_options(apt PRIVATE -Wall -Wextra -pedantic)
target_compile_options(apt PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers)
endif() endif()
endif() endif()




+ 59
- 89
src/dsp.c View File

@@ -1,20 +1,19 @@
/*
* This file is part of Aptdec.
* Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2022
/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2022 Xerbo (xerbo@protonmail.com)
* *
* Aptdec is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */


#include <stdlib.h> #include <stdlib.h>
@@ -24,6 +23,7 @@


#include "apt.h" #include "apt.h"
#include "filter.h" #include "filter.h"
#include "taps.h"


// In case your C compiler is so old that Pi hadn't been invented yet // In case your C compiler is so old that Pi hadn't been invented yet
#ifndef M_PI #ifndef M_PI
@@ -41,13 +41,13 @@
#define RSMULT 15 #define RSMULT 15
#define Fi (Fp * RSMULT) #define Fi (Fp * RSMULT)


static double Fe;
static float Fe;


static double offset = 0.0;
static double FreqLine = 1.0;
static float offset = 0.0;
static float FreqLine = 1.0;


static double FreqOsc;
static double K1, K2;
static float FreqOsc;
static float K1, K2;


// Check the sample rate and calculate some constants // Check the sample rate and calculate some constants
int apt_init(double F) { int apt_init(double F) {
@@ -63,56 +63,25 @@ int apt_init(double F) {
return 0; return 0;
} }


/* Fast phase estimator
* Calculates the phase angle of a signal from a IQ sample
*/
static inline double Phase(double I, double Q) {
double angle, r;
int s;

if(I == 0.0 && Q == 0.0) return 0.0;

if (Q < 0) {
s = -1;
Q = -Q;
} else {
s = 1;
}

if (I >= 0) {
r = (I - Q) / (I + Q);
angle = 0.25 - 0.25 * r;
} else {
r = (I + Q) / (Q - I);
angle = 0.75 - 0.25 * r;
}

if(s > 0){
return angle;
}else{
return -angle;
}
}

/* Phase locked loop /* Phase locked loop
* https://arachnoid.com/phase_locked_loop/ * https://arachnoid.com/phase_locked_loop/
* Model of this filter here https://www.desmos.com/calculator/m0uadgkoee * Model of this filter here https://www.desmos.com/calculator/m0uadgkoee
*/ */
static double pll(double I, double Q) {
static float pll(float I2, float Q) {
// PLL coefficient // PLL coefficient
static double PhaseOsc = 0.0;
double Io, Qo;
double Ip, Qp;
double DPhi;
static float PhaseOsc = 0.0;
float Io, Qo;
float Ip, Qp;
float DPhi;


// Quadrature oscillator / reference // Quadrature oscillator / reference
Io = cos(PhaseOsc); Io = cos(PhaseOsc);
Qo = sin(PhaseOsc); Qo = sin(PhaseOsc);


// Phase detector // Phase detector
Ip = I * Io + Q * Qo;
Qp = Q * Io - I * Qo;
DPhi = Phase(Ip, Qp);
Ip = I2 * Io + Q * Qo;
Qp = Q * Io - I2 * Qo;
DPhi = atan2f(Qp, Ip);


// Loop filter // Loop filter
PhaseOsc += 2.0 * M_PI * (K1 * DPhi + FreqOsc); PhaseOsc += 2.0 * M_PI * (K1 * DPhi + FreqOsc);
@@ -131,16 +100,16 @@ static double pll(double I, double Q) {
} }


// Convert samples into pixels // Convert samples into pixels
static int getamp(double *ampbuff, int count, apt_getsamples_t getsamples, void *context) {
static int getamp(float *ampbuff, int count, apt_getsamples_t getsamples, void *context) {
static float inbuff[BLKIN]; static float inbuff[BLKIN];
static int idxin = 0; static int idxin = 0;
static int nin = 0; static int nin = 0;


for (int n = 0; n < count; n++) { for (int n = 0; n < count; n++) {
double I, Q;
float I2, Q;


// Get some more samples when needed // Get some more samples when needed
if (nin < IQFilterLen * 2 + 2) {
if (nin < HILBERT_FILTER_SIZE * 2 + 2) {
// Number of samples read // Number of samples read
int res; int res;
memmove(inbuff, &(inbuff[idxin]), nin * sizeof(float)); memmove(inbuff, &(inbuff[idxin]), nin * sizeof(float));
@@ -151,13 +120,15 @@ static int getamp(double *ampbuff, int count, apt_getsamples_t getsamples, void
nin += res; nin += res;


// Make sure there is enough samples to continue // Make sure there is enough samples to continue
if (nin < IQFilterLen * 2 + 2)
if (nin < HILBERT_FILTER_SIZE * 2 + 2)
return n; return n;
} }


// Process read samples into a brightness value // Process read samples into a brightness value
iqfir(&inbuff[idxin], iqfilter, IQFilterLen, &I, &Q);
ampbuff[n] = pll(I, Q);
float complex tmp = hilbert_transform(&inbuff[idxin], hilbert_filter, HILBERT_FILTER_SIZE);
I2 = crealf(tmp);
Q = cimagf(tmp);
ampbuff[n] = pll(I2, Q);


// Increment current sample // Increment current sample
idxin++; idxin++;
@@ -167,25 +138,25 @@ static int getamp(double *ampbuff, int count, apt_getsamples_t getsamples, void
return count; return count;
} }


// Sub-pixel offsetting + FIR compensation
// Sub-pixel offsetting
int getpixelv(float *pvbuff, int count, apt_getsamples_t getsamples, void *context) { int getpixelv(float *pvbuff, int count, apt_getsamples_t getsamples, void *context) {
// Amplitude buffer // Amplitude buffer
static double ampbuff[BLKAMP];
static float ampbuff[BLKAMP];
static int nam = 0; static int nam = 0;
static int idxam = 0; static int idxam = 0;


double mult;
float mult;


// Gaussian resampling factor // Gaussian resampling factor
mult = (double) Fi / Fe * FreqLine;
int m = (int)(RSFilterLen / mult + 1);
mult = (float) Fi / Fe * FreqLine;
int m = (int)(LOW_PASS_SIZE / mult + 1);


for (int n = 0; n < count; n++) { for (int n = 0; n < count; n++) {
int shift; int shift;


if (nam < m) { if (nam < m) {
int res; int res;
memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double));
memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(float));
idxam = 0; idxam = 0;
res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsamples, context); res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsamples, context);
nam += res; nam += res;
@@ -193,8 +164,7 @@ int getpixelv(float *pvbuff, int count, apt_getsamples_t getsamples, void *conte
return n; return n;
} }


// Gaussian FIR compensation filter
pvbuff[n] = (float)(rsfir(&(ampbuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0);
pvbuff[n] = interpolating_convolve(&(ampbuff[idxam]), low_pass, LOW_PASS_SIZE, offset, mult) * mult * 256.0;


shift = ((int) floor((RSMULT - offset) / mult)) + 1; shift = ((int) floor((RSMULT - offset) / mult)) + 1;
offset = shift * mult + offset - RSMULT; offset = shift * mult + offset - RSMULT;
@@ -208,15 +178,15 @@ int getpixelv(float *pvbuff, int count, apt_getsamples_t getsamples, void *conte


// Get an entire row of pixels, aligned with sync markers // Get an entire row of pixels, aligned with sync markers
int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamples_t getsamples, void *context) { int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamples_t getsamples, void *context) {
static float pixels[PixelLine + SyncFilterLen];
static int npv;
static float pixels[PixelLine + SYNC_PATTERN_SIZE];
static size_t npv;
static int synced = 0; static int synced = 0;
static double max = 0.0;
static double minDoppler = 1000000000, previous = 0;
static float max = 0.0;
static float minDoppler = 1000000000, previous = 0;


if(reset) synced = 0; if(reset) synced = 0;


double corr, ecorr, lcorr;
float corr, ecorr, lcorr;
int res; int res;


// Move the row buffer into the the image buffer // Move the row buffer into the the image buffer
@@ -224,20 +194,20 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp
memmove(pixelv, pixels, npv * sizeof(float)); memmove(pixelv, pixels, npv * sizeof(float));


// Get the sync line // Get the sync line
if (npv < SyncFilterLen + 2) {
res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsamples, context);
if (npv < SYNC_PATTERN_SIZE + 2) {
res = getpixelv(&(pixelv[npv]), SYNC_PATTERN_SIZE + 2 - npv, getsamples, context);
npv += res; npv += res;
if (npv < SyncFilterLen + 2)
if (npv < SYNC_PATTERN_SIZE + 2)
return 0; return 0;
} }


// Calculate the frequency offset // Calculate the frequency offset
ecorr = fir(pixelv, Sync, SyncFilterLen);
corr = fir(&pixelv[1], Sync, SyncFilterLen - 1);
lcorr = fir(&pixelv[2], Sync, SyncFilterLen - 2);
ecorr = convolve(pixelv, sync_pattern, SYNC_PATTERN_SIZE);
corr = convolve(&pixelv[1], sync_pattern, SYNC_PATTERN_SIZE - 1);
lcorr = convolve(&pixelv[2], sync_pattern, SYNC_PATTERN_SIZE - 2);
FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0); FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0);


double val = fabs(lcorr - ecorr)*0.25 + previous*0.75;
float val = fabs(lcorr - ecorr)*0.25 + previous*0.75;
if(val < minDoppler && nrow > 10){ if(val < minDoppler && nrow > 10){
minDoppler = val; minDoppler = val;
*zenith = nrow; *zenith = nrow;
@@ -255,19 +225,19 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp
int mshift; int mshift;
static int lastmshift; static int lastmshift;


if (npv < PixelLine + SyncFilterLen) {
res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsamples, context);
if (npv < PixelLine + SYNC_PATTERN_SIZE) {
res = getpixelv(&(pixelv[npv]), PixelLine + SYNC_PATTERN_SIZE - npv, getsamples, context);
npv += res; npv += res;
if (npv < PixelLine + SyncFilterLen)
if (npv < PixelLine + SYNC_PATTERN_SIZE)
return 0; return 0;
} }


// Test every possible position until we get the best result // Test every possible position until we get the best result
mshift = 0; mshift = 0;
for (int shift = 0; shift < PixelLine; shift++) { for (int shift = 0; shift < PixelLine; shift++) {
double corr;
float corr;


corr = fir(&(pixelv[shift + 1]), Sync, SyncFilterLen);
corr = convolve(&(pixelv[shift + 1]), sync_pattern, SYNC_PATTERN_SIZE);
if (corr > max) { if (corr > max) {
mshift = shift; mshift = shift;
max = corr; max = corr;


+ 37
- 46
src/filter.c View File

@@ -1,65 +1,56 @@
/*
* This file is part of Aptdec.
* Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2022
/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2022 Xerbo (xerbo@protonmail.com)
* *
* Aptdec is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */


#include <math.h> #include <math.h>
#include "filter.h"
#include "util.h"


// Finite impulse response
float fir(float *buff, const float *coeff, const int len) {
double r;

r = 0.0;
for (int i = 0; i < len; i++) {
r += buff[i] * coeff[i];
float convolve(const float *in, const float *taps, size_t len) {
float sum = 0.0;
for (size_t i = 0; i < len; i++) {
sum += in[i] * taps[i];
} }
return (float)r;

return sum;
} }


/* IQ finite impulse response
* Turn samples into a single IQ sample
*/
void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q) {
double i = 0.0, q = 0.0;
float complex hilbert_transform(const float *in, const float *taps, size_t len) {
float i = 0.0;
float q = 0.0;


for (int k = 0; k < len; k++) {
q += buff[2*k] * coeff[k];
i += buff[2*k];
for (size_t k = 0; k < len; k++) {
q += in[2*k] * taps[k];
i += in[2*k];
} }


i = buff[len-1] - (i / len);
*I = i, *Q = q;
i = in[len-1] - (i / len);
return i + q*I;
} }


/* Gaussian finite impulse responce compensation
* https://www.recordingblogs.com/wiki/gaussian-window
*/
float rsfir(double *buff, const float *coeff, const int len, const double offset, const double delta) {
double out;
float interpolating_convolve(const float *in, const float *taps, size_t len, float offset, float delta) {
float out = 0.0;
float n = offset;


out = 0.0;
double n = offset;
for (int i = 0; i < (len-1)/delta-1; n += delta, i++) {
int k;
double alpha;
for (size_t i = 0; i < (len-1)/delta-1; n += delta, i++) {
int k = (int)floor(n);
float alpha = n - k;


k = (int)floor(n);
alpha = n - k;
out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha);
out += in[i] * (taps[k] * (1.0f-alpha) + taps[k + 1] * alpha);
} }
return (float)out;
return out;
} }

+ 18
- 94
src/filter.h View File

@@ -1,100 +1,24 @@
/*
* This file is part of Aptdec.
* Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2022
/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2019-2022 Xerbo (xerbo@protonmail.com)
* *
* Aptdec is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
float fir(float *buff, const float *coeff, const int len);
void iqfir(float *buff, const float *coeff, const int len, double *I, double *Q);
float rsfir(double *buff, const float *coeff, const int len, const double offset, const double delta);
// IQ finite impulse response filter
#define IQFilterLen 32
const float iqfilter[IQFilterLen] = { 0.0205361, 0.0219524, 0.0235785, 0.0254648, 0.0276791, 0.0303152,
0.0335063, 0.0374482, 0.0424413, 0.0489708, 0.0578745, 0.0707355, 0.0909457, 0.127324, 0.212207, 0.63662,
-0.63662, -0.212207, -0.127324, -0.0909457, -0.0707355, -0.0578745, -0.0489708, -0.0424413, -0.0374482,
-0.0335063, -0.0303152, -0.0276791, -0.0254648, -0.0235785, -0.0219524, -0.0205361 };
// Pattern of a NOAA sync line
#define SyncFilterLen 32
const float Sync[SyncFilterLen] = { -14, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14,
18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, -14 };
#include <stddef.h>
#include <complex.h>
// Gaussian finite impulse response compensation filter
#define RSFilterLen 437
const float rsfilter[RSFilterLen] = { -3.37279e-04, -8.80292e-06, -3.96418e-04, -1.78544e-04, -5.27511e-04,
-3.75376e-04, -6.95337e-04, -5.93148e-04, -8.79730e-04, -8.15327e-04, -1.05669e-03, -1.01377e-03,
-1.19836e-03, -1.15443e-03, -1.26937e-03, -1.20955e-03, -1.23904e-03, -1.15302e-03, -1.08660e-03,
-9.64235e-04, -8.02450e-04, -6.46202e-04, -3.95376e-04, -2.18096e-04, 1.11906e-04, 2.89567e-04,
6.67167e-04, 8.19039e-04, 1.21725e-03, 1.30556e-03, 1.69365e-03, 1.68588e-03, 2.03277e-03, 1.90159e-03,
2.18455e-03, 1.90833e-03, 2.12100e-03, 1.69052e-03, 1.77484e-03, 1.42542e-03, 1.18292e-03, 8.66979e-04,
5.54161e-04, 2.15793e-04, -1.11623e-04, -4.35173e-04, -7.27194e-04, -9.91551e-04, -1.20407e-03,
-1.37032e-03, -1.46991e-03, -1.51120e-03, -1.48008e-03, -1.39047e-03, -1.23115e-03, -1.02128e-03,
-7.60099e-04, -4.68008e-04, -1.46339e-04, 1.80867e-04, 5.11244e-04, 8.19243e-04, 1.09739e-03, 1.32668e-03,
1.50632e-03, 1.61522e-03, 1.66246e-03, 1.62390e-03, 1.52430e-03, 1.34273e-03, 1.10736e-03, 8.10335e-04,
4.76814e-04, 1.13622e-04, -2.64150e-04, -6.26595e-04, -9.95436e-04, -1.27846e-03, -1.54080e-03,
-1.74292e-03, -1.86141e-03, -1.89318e-03, -1.83969e-03, -1.69770e-03, -1.47938e-03, -1.18696e-03,
-8.37003e-04, -4.39507e-04, -1.56907e-05, 4.19904e-04, 8.43172e-04, 1.23827e-03, 1.58411e-03,
1.86382e-03, 2.06312e-03, 2.17177e-03, 2.18121e-03, 2.08906e-03, 1.89772e-03, 1.61153e-03,
1.24507e-03, 8.13976e-04, 3.29944e-04, -1.74591e-04, -6.83619e-04, -1.17826e-03, -1.61659e-03,
-2.00403e-03, -2.29070e-03, -2.49179e-03, -2.56546e-03, -2.53448e-03, -2.37032e-03, -2.10060e-03,
-1.72140e-03, -1.24542e-03, -7.15425e-04, -1.24964e-04, 4.83736e-04, 1.08328e-03, 1.64530e-03,
2.14503e-03, 2.55400e-03, 2.85589e-03, 3.02785e-03, 3.06271e-03, 2.95067e-03, 2.69770e-03,
2.30599e-03, 1.79763e-03, 1.18587e-03, 5.04003e-04, -2.23591e-04, -9.57591e-04, -1.66939e-03,
-2.31717e-03, -2.87636e-03, -3.31209e-03, -3.60506e-03, -3.73609e-03, -3.69208e-03, -3.44913e-03,
-3.06572e-03, -2.50229e-03, -1.80630e-03, -1.00532e-03, -1.22305e-04, 7.83910e-04, 1.69402e-03,
2.53826e-03, 3.30312e-03, 3.91841e-03, 4.38017e-03, 4.63546e-03, 4.68091e-03, 4.50037e-03,
4.09614e-03, 3.47811e-03, 2.67306e-03, 1.70418e-03, 6.20542e-04, -5.36994e-04, -1.70981e-03,
-2.84712e-03, -3.88827e-03, -4.78659e-03, -5.48593e-03, -5.95049e-03, -6.14483e-03, -6.05118e-03,
-5.65829e-03, -4.97525e-03, -4.01796e-03, -2.82224e-03, -1.43003e-03, 1.00410e-04, 1.71169e-03,
3.31983e-03, 4.87796e-03, 6.23237e-03, 7.31013e-03, 8.20642e-03, 8.67374e-03, 8.77681e-03,
8.43444e-03, 7.66794e-03, 6.46827e-03, 4.87294e-03, 2.92923e-03, 6.98913e-04, -1.72126e-03,
-4.24785e-03, -6.75380e-03, -9.13309e-03, -1.12532e-02, -1.30038e-02, -1.42633e-02, -1.49338e-02,
-1.49145e-02, -1.41484e-02, -1.25761e-02, -1.01870e-02, -6.97432e-03, -2.97910e-03, 1.75386e-03,
7.11899e-03, 1.30225e-02, 1.93173e-02, 2.58685e-02, 3.24965e-02, 3.90469e-02, 4.53316e-02,
5.11931e-02, 5.64604e-02, 6.09924e-02, 6.46584e-02, 6.73547e-02, 6.90049e-02, 6.97096e-02,
6.90049e-02, 6.73547e-02, 6.46584e-02, 6.09924e-02, 5.64604e-02, 5.11931e-02, 4.53316e-02,
3.90469e-02, 3.24965e-02, 2.58685e-02, 1.93173e-02, 1.30225e-02, 7.11899e-03, 1.75386e-03,
-2.97910e-03, -6.97432e-03, -1.01870e-02, -1.25761e-02, -1.41484e-02, -1.49145e-02, -1.49338e-02,
-1.42633e-02, -1.30038e-02, -1.12532e-02, -9.13309e-03, -6.75380e-03, -4.24785e-03, -1.72126e-03,
6.98913e-04, 2.92923e-03, 4.87294e-03, 6.46827e-03, 7.66794e-03, 8.43444e-03, 8.77681e-03,
8.67374e-03, 8.20642e-03, 7.31013e-03, 6.23237e-03, 4.87796e-03, 3.31983e-03, 1.71169e-03,
1.00410e-04, -1.43003e-03, -2.82224e-03, -4.01796e-03, -4.97525e-03, -5.65829e-03, -6.05118e-03,
-6.14483e-03, -5.95049e-03, -5.48593e-03, -4.78659e-03, -3.88827e-03, -2.84712e-03, -1.70981e-03,
-5.36994e-04, 6.20542e-04, 1.70418e-03, 2.67306e-03, 3.47811e-03, 4.09614e-03, 4.50037e-03,
4.68091e-03, 4.63546e-03, 4.38017e-03, 3.91841e-03, 3.30312e-03, 2.53826e-03, 1.69402e-03,
7.83910e-04, -1.22305e-04, -1.00532e-03, -1.80630e-03, -2.50229e-03, -3.06572e-03, -3.44913e-03,
-3.69208e-03, -3.73609e-03, -3.60506e-03, -3.31209e-03, -2.87636e-03, -2.31717e-03, -1.66939e-03,
-9.57591e-04, -2.23591e-04, 5.04003e-04, 1.18587e-03, 1.79763e-03, 2.30599e-03, 2.69770e-03,
2.95067e-03, 3.06271e-03, 3.02785e-03, 2.85589e-03, 2.55400e-03, 2.14503e-03, 1.64530e-03,
1.08328e-03, 4.83736e-04, -1.24964e-04, -7.15425e-04, -1.24542e-03, -1.72140e-03, -2.10060e-03,
-2.37032e-03, -2.53448e-03, -2.56546e-03, -2.49179e-03, -2.29070e-03, -2.00403e-03, -1.61659e-03,
-1.17826e-03, -6.83619e-04, -1.74591e-04, 3.29944e-04, 8.13976e-04, 1.24507e-03, 1.61153e-03,
1.89772e-03, 2.08906e-03, 2.18121e-03, 2.17177e-03, 2.06312e-03, 1.86382e-03, 1.58411e-03,
1.23827e-03, 8.43172e-04, 4.19904e-04, -1.56907e-05, -4.39507e-04, -8.37003e-04, -1.18696e-03,
-1.47938e-03, -1.69770e-03, -1.83969e-03, -1.89318e-03, -1.86141e-03, -1.74292e-03, -1.54080e-03,
-1.27846e-03, -9.95436e-04, -6.26595e-04, -2.64150e-04, 1.13622e-04, 4.76814e-04, 8.10335e-04,
1.10736e-03, 1.34273e-03, 1.52430e-03, 1.62390e-03, 1.66246e-03, 1.61522e-03, 1.50632e-03,
1.32668e-03, 1.09739e-03, 8.19243e-04, 5.11244e-04, 1.80867e-04, -1.46339e-04, -4.68008e-04,
-7.60099e-04, -1.02128e-03, -1.23115e-03, -1.39047e-03, -1.48008e-03, -1.51120e-03, -1.46991e-03,
-1.37032e-03, -1.20407e-03, -9.91551e-04, -7.27194e-04, -4.35173e-04, -1.11623e-04, 2.15793e-04,
5.54161e-04, 8.66979e-04, 1.18292e-03, 1.42542e-03, 1.77484e-03, 1.69052e-03, 2.12100e-03,
1.90833e-03, 2.18455e-03, 1.90159e-03, 2.03277e-03, 1.68588e-03, 1.69365e-03, 1.30556e-03,
1.21725e-03, 8.19039e-04, 6.67167e-04, 2.89567e-04, 1.11906e-04, -2.18096e-04, -3.95376e-04,
-6.46202e-04, -8.02450e-04, -9.64235e-04, -1.08660e-03, -1.15302e-03, -1.23904e-03, -1.20955e-03,
-1.26937e-03, -1.15443e-03, -1.19836e-03, -1.01377e-03, -1.05669e-03, -8.15327e-04, -8.79730e-04,
-5.93148e-04, -6.95337e-04, -3.75376e-04, -5.27511e-04, -1.78544e-04, -3.96418e-04, -8.80292e-06,
-3.37279e-04 };
float convolve(const float *in, const float *taps, size_t len);
float complex hilbert_transform(const float *in, const float *taps, size_t len);
float interpolating_convolve(const float *in, const float *taps, size_t len, float offset, float delta);

+ 17
- 17
src/image.c View File

@@ -33,8 +33,8 @@ static linear_t compute_regression(float *wedges) {
return linear_regression(wedges, teleramp, 9); return linear_regression(wedges, teleramp, 9);
} }


static double tele[16];
static double Cs;
static float tele[16];
static float Cs;


void apt_histogramEqualise(float **prow, int nrow, int offset, int width){ void apt_histogramEqualise(float **prow, int nrow, int offset, int width){
// Plot histogram // Plot histogram
@@ -97,9 +97,9 @@ void calibrateImage(float **prow, int nrow, int offset, int width, linear_t regr
} }
} }


double teleNoise(float *wedges){
double pattern[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 };
double noise = 0;
float teleNoise(float *wedges){
float pattern[9] = { 31.07, 63.02, 94.96, 126.9, 158.86, 191.1, 228.62, 255.0, 0.0 };
float noise = 0;
for(int i = 0; i < 9; i++) for(int i = 0; i < 9; i++)
noise += fabs(wedges[i] - pattern[i]); noise += fabs(wedges[i] - pattern[i]);


@@ -108,7 +108,7 @@ double teleNoise(float *wedges){


// Get telemetry data for thermal calibration // Get telemetry data for thermal calibration
apt_channel_t apt_calibrate(float **prow, int nrow, int offset, int width) { apt_channel_t apt_calibrate(float **prow, int nrow, int offset, int width) {
double teleline[APT_MAX_HEIGHT] = { 0.0 };
float teleline[APT_MAX_HEIGHT] = { 0.0 };
float wedge[16]; float wedge[16];
linear_t regr[APT_MAX_HEIGHT/APT_FRAME_LEN + 1]; linear_t regr[APT_MAX_HEIGHT/APT_FRAME_LEN + 1];
int telestart, mtelestart = 0; int telestart, mtelestart = 0;
@@ -156,7 +156,7 @@ apt_channel_t apt_calibrate(float **prow, int nrow, int offset, int width) {
} }


// Find the least noisy frame // Find the least noisy frame
double minNoise = -1;
float minNoise = -1;
int bestFrame = -1; int bestFrame = -1;
for (int n = telestart, k = 0; n < nrow - APT_FRAME_LEN; n += APT_FRAME_LEN, k++) { for (int n = telestart, k = 0; n < nrow - APT_FRAME_LEN; n += APT_FRAME_LEN, k++) {
int j; int j;
@@ -170,7 +170,7 @@ apt_channel_t apt_calibrate(float **prow, int nrow, int offset, int width) {
wedge[j] /= 6; wedge[j] /= 6;
} }


double noise = teleNoise(wedge);
float noise = teleNoise(wedge);
if(noise < minNoise || minNoise == -1){ if(noise < minNoise || minNoise == -1){
minNoise = noise; minNoise = noise;
bestFrame = k; bestFrame = k;
@@ -313,16 +313,16 @@ int apt_cropNoise(apt_image_t *img){
#include "satcal.h" #include "satcal.h"


typedef struct { typedef struct {
double Nbb;
double Cs;
double Cb;
float Nbb;
float Cs;
float Cb;
int ch; int ch;
} tempparam_t; } tempparam_t;


// IR channel temperature compensation // IR channel temperature compensation
static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) {
double Tbb, T[4];
double C;
static void tempcomp(float t[16], int ch, int satnum, tempparam_t *tpr) {
float Tbb, T[4];
float C;


tpr->ch = ch - 4; tpr->ch = ch - 4;


@@ -352,9 +352,9 @@ static void tempcomp(double t[16], int ch, int satnum, tempparam_t *tpr) {
} }


// IR channel temperature calibration // IR channel temperature calibration
static double tempcal(float Ce, int satnum, tempparam_t * rgpr) {
double Nl, Nc, Ns, Ne;
double T, vc;
static float tempcal(float Ce, int satnum, tempparam_t * rgpr) {
float Nl, Nc, Ns, Ne;
float T, vc;


Ns = satcal[satnum].cor[rgpr->ch].Ns; Ns = satcal[satnum].cor[rgpr->ch].Ns;
Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb); Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb);


+ 92
- 0
src/taps.h View File

@@ -0,0 +1,92 @@
/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2004-2009 Thierry Leconte (F4DWV) 2019-2022 Xerbo (xerbo@protonmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

static const float hilbert_filter[] = { 0.0205361, 0.0219524, 0.0235785, 0.0254648, 0.0276791, 0.0303152,
0.0335063, 0.0374482, 0.0424413, 0.0489708, 0.0578745, 0.0707355, 0.0909457, 0.127324, 0.212207, 0.63662,
-0.63662, -0.212207, -0.127324, -0.0909457, -0.0707355, -0.0578745, -0.0489708, -0.0424413, -0.0374482,
-0.0335063, -0.0303152, -0.0276791, -0.0254648, -0.0235785, -0.0219524, -0.0205361 };
#define HILBERT_FILTER_SIZE (sizeof(hilbert_filter)/sizeof(hilbert_filter[0]))

static const float low_pass[] = { -3.37279e-04, -8.80292e-06, -3.96418e-04, -1.78544e-04, -5.27511e-04,
-3.75376e-04, -6.95337e-04, -5.93148e-04, -8.79730e-04, -8.15327e-04, -1.05669e-03, -1.01377e-03,
-1.19836e-03, -1.15443e-03, -1.26937e-03, -1.20955e-03, -1.23904e-03, -1.15302e-03, -1.08660e-03,
-9.64235e-04, -8.02450e-04, -6.46202e-04, -3.95376e-04, -2.18096e-04, 1.11906e-04, 2.89567e-04,
6.67167e-04, 8.19039e-04, 1.21725e-03, 1.30556e-03, 1.69365e-03, 1.68588e-03, 2.03277e-03, 1.90159e-03,
2.18455e-03, 1.90833e-03, 2.12100e-03, 1.69052e-03, 1.77484e-03, 1.42542e-03, 1.18292e-03, 8.66979e-04,
5.54161e-04, 2.15793e-04, -1.11623e-04, -4.35173e-04, -7.27194e-04, -9.91551e-04, -1.20407e-03,
-1.37032e-03, -1.46991e-03, -1.51120e-03, -1.48008e-03, -1.39047e-03, -1.23115e-03, -1.02128e-03,
-7.60099e-04, -4.68008e-04, -1.46339e-04, 1.80867e-04, 5.11244e-04, 8.19243e-04, 1.09739e-03, 1.32668e-03,
1.50632e-03, 1.61522e-03, 1.66246e-03, 1.62390e-03, 1.52430e-03, 1.34273e-03, 1.10736e-03, 8.10335e-04,
4.76814e-04, 1.13622e-04, -2.64150e-04, -6.26595e-04, -9.95436e-04, -1.27846e-03, -1.54080e-03,
-1.74292e-03, -1.86141e-03, -1.89318e-03, -1.83969e-03, -1.69770e-03, -1.47938e-03, -1.18696e-03,
-8.37003e-04, -4.39507e-04, -1.56907e-05, 4.19904e-04, 8.43172e-04, 1.23827e-03, 1.58411e-03,
1.86382e-03, 2.06312e-03, 2.17177e-03, 2.18121e-03, 2.08906e-03, 1.89772e-03, 1.61153e-03,
1.24507e-03, 8.13976e-04, 3.29944e-04, -1.74591e-04, -6.83619e-04, -1.17826e-03, -1.61659e-03,
-2.00403e-03, -2.29070e-03, -2.49179e-03, -2.56546e-03, -2.53448e-03, -2.37032e-03, -2.10060e-03,
-1.72140e-03, -1.24542e-03, -7.15425e-04, -1.24964e-04, 4.83736e-04, 1.08328e-03, 1.64530e-03,
2.14503e-03, 2.55400e-03, 2.85589e-03, 3.02785e-03, 3.06271e-03, 2.95067e-03, 2.69770e-03,
2.30599e-03, 1.79763e-03, 1.18587e-03, 5.04003e-04, -2.23591e-04, -9.57591e-04, -1.66939e-03,
-2.31717e-03, -2.87636e-03, -3.31209e-03, -3.60506e-03, -3.73609e-03, -3.69208e-03, -3.44913e-03,
-3.06572e-03, -2.50229e-03, -1.80630e-03, -1.00532e-03, -1.22305e-04, 7.83910e-04, 1.69402e-03,
2.53826e-03, 3.30312e-03, 3.91841e-03, 4.38017e-03, 4.63546e-03, 4.68091e-03, 4.50037e-03,
4.09614e-03, 3.47811e-03, 2.67306e-03, 1.70418e-03, 6.20542e-04, -5.36994e-04, -1.70981e-03,
-2.84712e-03, -3.88827e-03, -4.78659e-03, -5.48593e-03, -5.95049e-03, -6.14483e-03, -6.05118e-03,
-5.65829e-03, -4.97525e-03, -4.01796e-03, -2.82224e-03, -1.43003e-03, 1.00410e-04, 1.71169e-03,
3.31983e-03, 4.87796e-03, 6.23237e-03, 7.31013e-03, 8.20642e-03, 8.67374e-03, 8.77681e-03,
8.43444e-03, 7.66794e-03, 6.46827e-03, 4.87294e-03, 2.92923e-03, 6.98913e-04, -1.72126e-03,
-4.24785e-03, -6.75380e-03, -9.13309e-03, -1.12532e-02, -1.30038e-02, -1.42633e-02, -1.49338e-02,
-1.49145e-02, -1.41484e-02, -1.25761e-02, -1.01870e-02, -6.97432e-03, -2.97910e-03, 1.75386e-03,
7.11899e-03, 1.30225e-02, 1.93173e-02, 2.58685e-02, 3.24965e-02, 3.90469e-02, 4.53316e-02,
5.11931e-02, 5.64604e-02, 6.09924e-02, 6.46584e-02, 6.73547e-02, 6.90049e-02, 6.97096e-02,
6.90049e-02, 6.73547e-02, 6.46584e-02, 6.09924e-02, 5.64604e-02, 5.11931e-02, 4.53316e-02,
3.90469e-02, 3.24965e-02, 2.58685e-02, 1.93173e-02, 1.30225e-02, 7.11899e-03, 1.75386e-03,
-2.97910e-03, -6.97432e-03, -1.01870e-02, -1.25761e-02, -1.41484e-02, -1.49145e-02, -1.49338e-02,
-1.42633e-02, -1.30038e-02, -1.12532e-02, -9.13309e-03, -6.75380e-03, -4.24785e-03, -1.72126e-03,
6.98913e-04, 2.92923e-03, 4.87294e-03, 6.46827e-03, 7.66794e-03, 8.43444e-03, 8.77681e-03,
8.67374e-03, 8.20642e-03, 7.31013e-03, 6.23237e-03, 4.87796e-03, 3.31983e-03, 1.71169e-03,
1.00410e-04, -1.43003e-03, -2.82224e-03, -4.01796e-03, -4.97525e-03, -5.65829e-03, -6.05118e-03,
-6.14483e-03, -5.95049e-03, -5.48593e-03, -4.78659e-03, -3.88827e-03, -2.84712e-03, -1.70981e-03,
-5.36994e-04, 6.20542e-04, 1.70418e-03, 2.67306e-03, 3.47811e-03, 4.09614e-03, 4.50037e-03,
4.68091e-03, 4.63546e-03, 4.38017e-03, 3.91841e-03, 3.30312e-03, 2.53826e-03, 1.69402e-03,
7.83910e-04, -1.22305e-04, -1.00532e-03, -1.80630e-03, -2.50229e-03, -3.06572e-03, -3.44913e-03,
-3.69208e-03, -3.73609e-03, -3.60506e-03, -3.31209e-03, -2.87636e-03, -2.31717e-03, -1.66939e-03,
-9.57591e-04, -2.23591e-04, 5.04003e-04, 1.18587e-03, 1.79763e-03, 2.30599e-03, 2.69770e-03,
2.95067e-03, 3.06271e-03, 3.02785e-03, 2.85589e-03, 2.55400e-03, 2.14503e-03, 1.64530e-03,
1.08328e-03, 4.83736e-04, -1.24964e-04, -7.15425e-04, -1.24542e-03, -1.72140e-03, -2.10060e-03,
-2.37032e-03, -2.53448e-03, -2.56546e-03, -2.49179e-03, -2.29070e-03, -2.00403e-03, -1.61659e-03,
-1.17826e-03, -6.83619e-04, -1.74591e-04, 3.29944e-04, 8.13976e-04, 1.24507e-03, 1.61153e-03,
1.89772e-03, 2.08906e-03, 2.18121e-03, 2.17177e-03, 2.06312e-03, 1.86382e-03, 1.58411e-03,
1.23827e-03, 8.43172e-04, 4.19904e-04, -1.56907e-05, -4.39507e-04, -8.37003e-04, -1.18696e-03,
-1.47938e-03, -1.69770e-03, -1.83969e-03, -1.89318e-03, -1.86141e-03, -1.74292e-03, -1.54080e-03,
-1.27846e-03, -9.95436e-04, -6.26595e-04, -2.64150e-04, 1.13622e-04, 4.76814e-04, 8.10335e-04,
1.10736e-03, 1.34273e-03, 1.52430e-03, 1.62390e-03, 1.66246e-03, 1.61522e-03, 1.50632e-03,
1.32668e-03, 1.09739e-03, 8.19243e-04, 5.11244e-04, 1.80867e-04, -1.46339e-04, -4.68008e-04,
-7.60099e-04, -1.02128e-03, -1.23115e-03, -1.39047e-03, -1.48008e-03, -1.51120e-03, -1.46991e-03,
-1.37032e-03, -1.20407e-03, -9.91551e-04, -7.27194e-04, -4.35173e-04, -1.11623e-04, 2.15793e-04,
5.54161e-04, 8.66979e-04, 1.18292e-03, 1.42542e-03, 1.77484e-03, 1.69052e-03, 2.12100e-03,
1.90833e-03, 2.18455e-03, 1.90159e-03, 2.03277e-03, 1.68588e-03, 1.69365e-03, 1.30556e-03,
1.21725e-03, 8.19039e-04, 6.67167e-04, 2.89567e-04, 1.11906e-04, -2.18096e-04, -3.95376e-04,
-6.46202e-04, -8.02450e-04, -9.64235e-04, -1.08660e-03, -1.15302e-03, -1.23904e-03, -1.20955e-03,
-1.26937e-03, -1.15443e-03, -1.19836e-03, -1.01377e-03, -1.05669e-03, -8.15327e-04, -8.79730e-04,
-5.93148e-04, -6.95337e-04, -3.75376e-04, -5.27511e-04, -1.78544e-04, -3.96418e-04, -8.80292e-06,
-3.37279e-04 };
#define LOW_PASS_SIZE (sizeof(low_pass)/sizeof(low_pass[0]))

static const float sync_pattern[] = { -14, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14,
18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, 18, 18, -14, -14, -14 };
#define SYNC_PATTERN_SIZE (sizeof(sync_pattern)/sizeof(sync_pattern[0]))

+ 20
- 0
src/util.h View File

@@ -0,0 +1,20 @@
/*
* aptdec - A lightweight FOSS (NOAA) APT decoder
* Copyright (C) 2019-2022 Xerbo (xerbo@protonmail.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))

Loading…
Cancel
Save