Browse Source

Rewrite thermal calibration (and add visible calibration)

tags/v1.8.0
Xerbo 1 year ago
parent
commit
d4146f4eb9
No known key found for this signature in database GPG Key ID: 34103F6D8F11CEB0
11 changed files with 255 additions and 694 deletions
  1. +1
    -1
      CMakeLists.txt
  2. +1
    -1
      src/algebra.h
  3. +4
    -1
      src/apt.h
  4. +120
    -0
      src/calibration.c
  5. +55
    -0
      src/calibration.h
  6. +2
    -1
      src/common.h
  7. +56
    -49
      src/image.c
  8. +0
    -384
      src/libs/argparse.c
  9. +0
    -130
      src/libs/argparse.h
  10. +16
    -2
      src/main.c
  11. +0
    -125
      src/satcal.h

+ 1
- 1
CMakeLists.txt View File

@@ -11,7 +11,7 @@ find_package(PNG)
# libsndfile
find_package(LibSndFile)

set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/algebra.c src/libs/median.c src/util.c)
set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/algebra.c src/libs/median.c src/util.c src/calibration.c)
set(EXE_C_SOURCE_FILES src/main.c src/pngio.c src/argparse/argparse.c src/util.c)
set(LIB_C_HEADER_FILES src/apt.h)



+ 1
- 1
src/algebra.h View File

@@ -33,6 +33,6 @@ typedef struct {
linear_t linear_regression(const float *independent, const float *dependent, size_t len);

float linear_calc(float x, linear_t line);
float quadratic_calc(float x, quadratic_t line);
float quadratic_calc(float x, quadratic_t quadratic);

#endif

+ 4
- 1
src/apt.h View File

@@ -100,7 +100,10 @@ apt_channel_t APT_API apt_calibrate(float **prow, int nrow, int offset, int widt
void APT_API apt_denoise(float **prow, int nrow, int offset, int width);
void APT_API apt_flipImage(apt_image_t *img, int width, int offset);
int APT_API apt_cropNoise(apt_image_t *img);
void APT_API apt_temperature(int satnum, apt_image_t *img, int offset, int width);
void APT_API apt_calibrate_thermal(int satnum, apt_image_t *img, int offset, int width);
void APT_API apt_calibrate_visible(int satnum, apt_image_t *img, int offset, int width);
// Moved to apt_calibrate_thermal
#define apt_temperature apt_calibrate_thermal

apt_rgb_t APT_API apt_applyPalette(char *palette, int val);
apt_rgb_t APT_API apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a);


+ 120
- 0
src/calibration.c View File

@@ -0,0 +1,120 @@
/*
* 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/>.
*/

#include "calibration.h"
#include "util.h"

const calibration_t calibration[3] = {
{
.name = "NOAA-15",
.prt = {
{ 1.36328e-06f, 0.051045f, 276.60157f }, // PRT 1
{ 1.47266e-06f, 0.050909f, 276.62531f }, // PRT 2
{ 1.47656e-06f, 0.050907f, 276.67413f }, // PRT 3
{ 1.47656e-06f, 0.050966f, 276.59258f } // PRT 4
},
.visible = {
{
.low = { 0.0568f, -2.1874f },
.high = { 0.1633f, -54.9928f },
.cutoff = 496.0f
}, {
.low = { 0.0596f, -2.4096f },
.high = { 0.1629f, -55.2436f },
.cutoff = 511.0f
}
},
.rad = {
{ 925.4075f, 0.337810f, 0.998719f }, // Channel 4
{ 839.8979f, 0.304558f, 0.999024f }, // Channel 5
{ 2695.9743f, 1.621256f, 0.998015f } // Channel 3B
},
.cor = {
{ -4.50f, { 0.0004524f, -0.0932f, 4.76f } }, // Channel 4
{ -3.61f, { 0.0002811f, -0.0659f, 3.83f } }, // Channel 5
{ 0.0f, { 0.0f, 0.0f , 0.0f } } // Channel 3B
}
}, {
.name = "NOAA-18",
.prt = {
{ 1.657e-06f, 0.05090f, 276.601f }, // PRT 1
{ 1.482e-06f, 0.05101f, 276.683f }, // PRT 2
{ 1.313e-06f, 0.05117f, 276.565f }, // PRT 3
{ 1.484e-06f, 0.05103f, 276.615f } // PRT 4
},
.visible = {
{
.low = { 0.06174f, -2.434f },
.high = { 0.1841f, -63.31f },
.cutoff = 501.54f
}, {
.low = { 0.07514f, -2.960f },
.high = { 0.2254f, -78.55f },
.cutoff = 500.40f
}
},
.rad = {
{ 928.1460f, 0.436645f, 0.998607f }, // Channel 4
{ 833.2532f, 0.253179f, 0.999057f }, // Channel 5
{ 2659.7952f, 1.698704f, 0.996960f } // Channel 3B
},
.cor = {
{ -5.53f, { 0.00052337f, -0.11069f, 5.82f } }, // Channel 4
{ -2.22f, { 0.00017715f, -0.04360f, 2.67f } }, // Channel 5
{ 0.0f, { 0.0f, 0.0f, 0.0f } } // Channel 3B
}
}, {
.name = "NOAA-19",
.prt = {
{ 1.405783e-06f, 0.051111f, 276.6067f }, // PRT 1
{ 1.496037e-06f, 0.051090f, 276.6119f }, // PRT 2
{ 1.496990e-06f, 0.051033f, 276.6311f }, // PRT 3
{ 1.493110e-06f, 0.051058f, 276.6268f } // PRT 4
},
.visible = {
{
.low = { 0.05555f, -2.159f },
.high = { 0.1639f, -56.33f },
.cutoff = 496.43f
}, {
.low = { 0.06614f, -2.565f },
.high = { 0.1970f, -68.01f },
.cutoff = 500.37f
}
},
.rad = {
{ 928.9f, 0.53959f, 0.998534f }, // Channel 4
{ 831.9f, 0.36064f, 0.998913f }, // Channel 5
{ 2670.0f, 1.67396f, 0.997364f } // Channel 3B
},
.cor = {
{ -5.49f, { 0.00054668f, -0.11187f, 5.70f } }, // Channel 4
{ -3.39f, { 0.00024985f, -0.05991f, 3.58f } }, // Channel 5
{ 0.0f, { 0.0f, 0.0f, 0.0f } } // Channel 3B
}
}
};

calibration_t get_calibration(int satid) {
switch (satid) {
case 15: return calibration[0];
case 18: return calibration[1];
case 19: return calibration[2];
default: error("Invalid satid in get_calibration()"); /* following is only to shut up the compiler */ return calibration[0];
}
}

+ 55
- 0
src/calibration.h View File

@@ -0,0 +1,55 @@
/*
* 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/>.
*/

#ifndef APTDEC_CALIBRATION_H
#define APTDEC_CALIBRATION_H
#include "algebra.h"

typedef struct {
char *name;

// Quadratics for calculating PRT temperature
quadratic_t prt[4];
// Visible calibration coefficients
struct {
linear_t low;
linear_t high;
float cutoff;
} visible[2];

// Radiance coefficients
struct {
float vc, A, B;
} rad[3];

// Non linear correction coefficients
struct {
float Ns;
quadratic_t quadratic;
} cor[3];
} calibration_t;

// First radiation constant (mW/(m2-sr-cm-4))
static const float C1 = 1.1910427e-5f;
// Second radiation constant (cm-K)
static const float C2 = 1.4387752f;

calibration_t get_calibration(int satid);

#endif

+ 2
- 1
src/common.h View File

@@ -47,7 +47,8 @@ enum imagetypes {
Temperature='t',
Channel_A='a',
Channel_B='b',
Distribution='d'
Distribution='d',
Visible='v'
};
enum effects {
Crop_Telemetry='t',


+ 56
- 49
src/image.c View File

@@ -310,8 +310,8 @@ int apt_cropNoise(apt_image_t *img){
return startCrop;
}

// --- Temperature Calibration --- //
#include "satcal.h"
// --- Visible and Temperature Calibration --- //
#include "calibration.h"

typedef struct {
float Nbb;
@@ -321,71 +321,78 @@ typedef struct {
} tempparam_t;

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

tpr->ch = ch - 4;

// Compute equivalent T blackbody temperature
for (int n = 0; n < 4; n++) {
float d0, d1, d2;

C = t[9 + n] * 4.0;
d0 = satcal[satnum].d[n][0];
d1 = satcal[satnum].d[n][1];
d2 = satcal[satnum].d[n][2];
T[n] = d0;
T[n] += d1 * C;
C *= C;
T[n] += d2 * C;
tempparam_t tempcomp(float t[16], int ch, int satnum) {
tempparam_t tpr;
tpr.ch = ch - 4;

const calibration_t calibration = get_calibration(satnum);
const float Vc = calibration.rad[tpr.ch].vc;
const float A = calibration.rad[tpr.ch].A;
const float B = calibration.rad[tpr.ch].B;

// Compute PRT temperature
float T[4];
for (size_t n = 0; n < 4; n++) {
T[n] = quadratic_calc(t[n+9] * 4.0, calibration.prt[n]);
}
Tbb = (T[0] + T[1] + T[2] + T[3]) / 4.0;
Tbb = satcal[satnum].rad[tpr->ch].A + satcal[satnum].rad[tpr->ch].B * Tbb;

// Compute blackbody radiance temperature
C = satcal[satnum].rad[tpr->ch].vc;
tpr->Nbb = c1 * C * C * C / (expm1(c2 * C / Tbb));
float Tbb = (T[0]+T[1]+T[2]+T[3]) / 4.0; // Blackbody temperature
float Tbbstar = A + Tbb*B; // Effective blackbody temperature

// Store blackbody count and space
tpr->Cs = Cs * 4.0;
tpr->Cb = t[14] * 4.0;
tpr.Nbb = C1 * pow(Vc, 3) / (expf(C2 * Vc / Tbbstar) - 1.0f); // Blackbody radiance

tpr.Cs = 246.4 * 4.0; // FIXME
tpr.Cb = t[14] * 4.0;
return tpr;
}

// IR channel temperature calibration
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;
Nl = Ns + (rgpr->Nbb - Ns) * (rgpr->Cs - Ce * 4.0) / (rgpr->Cs - rgpr->Cb);
Nc = satcal[satnum].cor[rgpr->ch].b[0] +
satcal[satnum].cor[rgpr->ch].b[1] * Nl +
satcal[satnum].cor[rgpr->ch].b[2] * Nl * Nl;
static float tempcal(float Ce, int satnum, tempparam_t tpr) {
const calibration_t calibration = get_calibration(satnum);
const float Ns = calibration.cor[tpr.ch].Ns;
const float Vc = calibration.rad[tpr.ch].vc;
const float A = calibration.rad[tpr.ch].A;
const float B = calibration.rad[tpr.ch].B;

Ne = Nl + Nc;
float Nl = Ns + (tpr.Nbb - Ns) * (tpr.Cs - Ce * 4.0) / (tpr.Cs - tpr.Cb); // Linear radiance estimate
float Nc = quadratic_calc(Nl, calibration.cor[tpr.ch].quadratic); // Non-linear correction
float Ne = Nl + Nc; // Corrected radiance

vc = satcal[satnum].rad[rgpr->ch].vc;
T = c2 * vc / log(c1 * vc * vc * vc / Ne + 1.0);
T = (T - satcal[satnum].rad[rgpr->ch].A) / satcal[satnum].rad[rgpr->ch].B;
float Testar = C2 * Vc / logf(C1 * powf(Vc, 3) / Ne + 1.0); // Equivlent black body temperature
float Te = (Testar - A) / B; // Temperature (kelvin)

// Convert to celsius
T -= 273.15;
Te -= 273.15;
// Rescale to 0-255 for -100°C to +60°C
T = (T + 100.0) / 160.0 * 255.0;

return T;
return (Te + 100.0) / 160.0 * 255.0;
}

// Temperature calibration wrapper
void apt_temperature(int satnum, apt_image_t *img, int offset, int width){
tempparam_t temp;
void apt_calibrate_thermal(int satnum, apt_image_t *img, int offset, int width) {
tempparam_t temp = tempcomp(tele, img->chB, satnum);

for (int y = 0; y < img->nrow; y++) {
for (int x = 0; x < width; x++) {
img->prow[y][x + offset] = (float)tempcal(img->prow[y][x + offset], satnum, temp);
}
}
}

float calibrate_pixel(float value, int channel, calibration_t cal) {
if (value > cal.visible[channel].cutoff) {
return linear_calc(value*4.0f, cal.visible[channel].high) * 255.0f/100.0f;
} else {
return linear_calc(value*4.0f, cal.visible[channel].low) * 255.0f/100.0f;
}
}

tempcomp(tele, img->chB, satnum - 15, &temp);
void apt_calibrate_visible(int satnum, apt_image_t *img, int offset, int width) {
const calibration_t calibration = get_calibration(satnum);
int channel = img->chA-1;

for (int y = 0; y < img->nrow; y++) {
for (int x = 0; x < width; x++) {
img->prow[y][x + offset] = (float)tempcal(img->prow[y][x + offset], satnum - 15, &temp);
img->prow[y][x + offset] = clamp(calibrate_pixel(img->prow[y][x + offset], channel, calibration), 255.0f, 0.0f);
}
}
}

+ 0
- 384
src/libs/argparse.c View File

@@ -1,384 +0,0 @@
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* All rights reserved.
*
* Use of this source code is governed by a MIT-style license that can be found
* in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "argparse.h"

#define OPT_UNSET 1
#define OPT_LONG (1 << 1)

static const char *
prefix_skip(const char *str, const char *prefix)
{
size_t len = strlen(prefix);
return strncmp(str, prefix, len) ? NULL : str + len;
}

static int
prefix_cmp(const char *str, const char *prefix)
{
for (;; str++, prefix++)
if (!*prefix) {
return 0;
} else if (*str != *prefix) {
return (unsigned char)*prefix - (unsigned char)*str;
}
}

static void
argparse_error(struct argparse *self, const struct argparse_option *opt,
const char *reason, int flags)
{
(void)self;
if (flags & OPT_LONG) {
fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason);
} else {
fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason);
}
exit(1);
}

static int
argparse_getvalue(struct argparse *self, const struct argparse_option *opt,
int flags)
{
const char *s = NULL;
if (!opt->value)
goto skipped;
switch (opt->type) {
case ARGPARSE_OPT_BOOLEAN:
if (flags & OPT_UNSET) {
*(int *)opt->value = *(int *)opt->value - 1;
} else {
*(int *)opt->value = *(int *)opt->value + 1;
}
if (*(int *)opt->value < 0) {
*(int *)opt->value = 0;
}
break;
case ARGPARSE_OPT_BIT:
if (flags & OPT_UNSET) {
*(int *)opt->value &= ~opt->data;
} else {
*(int *)opt->value |= opt->data;
}
break;
case ARGPARSE_OPT_STRING:
if (self->optvalue) {
*(const char **)opt->value = self->optvalue;
self->optvalue = NULL;
} else if (self->argc > 1) {
self->argc--;
*(const char **)opt->value = *++self->argv;
} else {
argparse_error(self, opt, "requires a value", flags);
}
break;
case ARGPARSE_OPT_INTEGER:
errno = 0;
if (self->optvalue) {
*(int *)opt->value = strtol(self->optvalue, (char **)&s, 0);
self->optvalue = NULL;
} else if (self->argc > 1) {
self->argc--;
*(int *)opt->value = strtol(*++self->argv, (char **)&s, 0);
} else {
argparse_error(self, opt, "requires a value", flags);
}
if (errno)
argparse_error(self, opt, strerror(errno), flags);
if (s[0] != '\0')
argparse_error(self, opt, "expects an integer value", flags);
break;
case ARGPARSE_OPT_FLOAT:
errno = 0;
if (self->optvalue) {
*(float *)opt->value = strtof(self->optvalue, (char **)&s);
self->optvalue = NULL;
} else if (self->argc > 1) {
self->argc--;
*(float *)opt->value = strtof(*++self->argv, (char **)&s);
} else {
argparse_error(self, opt, "requires a value", flags);
}
if (errno)
argparse_error(self, opt, strerror(errno), flags);
if (s[0] != '\0')
argparse_error(self, opt, "expects a numerical value", flags);
break;
default:
assert(0);
}

skipped:
if (opt->callback) {
return opt->callback(self, opt);
}

return 0;
}

static void
argparse_options_check(const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
switch (options->type) {
case ARGPARSE_OPT_END:
case ARGPARSE_OPT_BOOLEAN:
case ARGPARSE_OPT_BIT:
case ARGPARSE_OPT_INTEGER:
case ARGPARSE_OPT_FLOAT:
case ARGPARSE_OPT_STRING:
case ARGPARSE_OPT_GROUP:
continue;
default:
fprintf(stderr, "wrong option type: %d", options->type);
break;
}
}
}

static int
argparse_short_opt(struct argparse *self, const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
if (options->short_name == *self->optvalue) {
self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL;
return argparse_getvalue(self, options, 0);
}
}
return -2;
}

static int
argparse_long_opt(struct argparse *self, const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
const char *rest;
int opt_flags = 0;
if (!options->long_name)
continue;

rest = prefix_skip(self->argv[0] + 2, options->long_name);
if (!rest) {
// negation disabled?
if (options->flags & OPT_NONEG) {
continue;
}
// only OPT_BOOLEAN/OPT_BIT supports negation
if (options->type != ARGPARSE_OPT_BOOLEAN && options->type !=
ARGPARSE_OPT_BIT) {
continue;
}

if (prefix_cmp(self->argv[0] + 2, "no-")) {
continue;
}
rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name);
if (!rest)
continue;
opt_flags |= OPT_UNSET;
}
if (*rest) {
if (*rest != '=')
continue;
self->optvalue = rest + 1;
}
return argparse_getvalue(self, options, opt_flags | OPT_LONG);
}
return -2;
}

int
argparse_init(struct argparse *self, struct argparse_option *options,
const char *const *usages, int flags)
{
memset(self, 0, sizeof(*self));
self->options = options;
self->usages = usages;
self->flags = flags;
self->description = NULL;
self->epilog = NULL;
return 0;
}

void
argparse_describe(struct argparse *self, const char *description,
const char *epilog)
{
self->description = description;
self->epilog = epilog;
}

int
argparse_parse(struct argparse *self, int argc, const char **argv)
{
self->argc = argc - 1;
self->argv = argv + 1;
self->out = argv;

argparse_options_check(self->options);

for (; self->argc; self->argc--, self->argv++) {
const char *arg = self->argv[0];
if (arg[0] != '-' || !arg[1]) {
if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) {
goto end;
}
// if it's not option or is a single char '-', copy verbatim
self->out[self->cpidx++] = self->argv[0];
continue;
}
// short option
if (arg[1] != '-') {
self->optvalue = arg + 1;
switch (argparse_short_opt(self, self->options)) {
case -1:
break;
case -2:
goto unknown;
}
while (self->optvalue) {
switch (argparse_short_opt(self, self->options)) {
case -1:
break;
case -2:
goto unknown;
}
}
continue;
}
// if '--' presents
if (!arg[2]) {
self->argc--;
self->argv++;
break;
}
// long option
switch (argparse_long_opt(self, self->options)) {
case -1:
break;
case -2:
goto unknown;
}
continue;

unknown:
fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]);
argparse_usage(self);
exit(1);
}

end:
memmove(self->out + self->cpidx, self->argv,
self->argc * sizeof(*self->out));
self->out[self->cpidx + self->argc] = NULL;

return self->cpidx + self->argc;
}

void
argparse_usage(struct argparse *self)
{
if (self->usages) {
fprintf(stdout, "Usage: %s\n", *self->usages++);
while (*self->usages && **self->usages)
fprintf(stdout, " or: %s\n", *self->usages++);
} else {
fprintf(stdout, "Usage:\n");
}

// print description
if (self->description)
fprintf(stdout, "%s\n", self->description);

fputc('\n', stdout);

const struct argparse_option *options;

// figure out best width
size_t usage_opts_width = 0;
size_t len;
options = self->options;
for (; options->type != ARGPARSE_OPT_END; options++) {
len = 0;
if ((options)->short_name) {
len += 2;
}
if ((options)->short_name && (options)->long_name) {
len += 2; // separator ", "
}
if ((options)->long_name) {
len += strlen((options)->long_name) + 2;
}
if (options->type == ARGPARSE_OPT_INTEGER) {
len += strlen("=<int>");
}
if (options->type == ARGPARSE_OPT_FLOAT) {
len += strlen("=<flt>");
} else if (options->type == ARGPARSE_OPT_STRING) {
len += strlen("=<str>");
}
len = (len + 3) - ((len + 3) & 3);
if (usage_opts_width < len) {
usage_opts_width = len;
}
}
usage_opts_width += 4; // 4 spaces prefix

options = self->options;
for (; options->type != ARGPARSE_OPT_END; options++) {
size_t pos = 0;
int pad = 0;
if (options->type == ARGPARSE_OPT_GROUP) {
fputc('\n', stdout);
fprintf(stdout, "%s", options->help);
fputc('\n', stdout);
continue;
}
pos = fprintf(stdout, " ");
if (options->short_name) {
pos += fprintf(stdout, "-%c", options->short_name);
}
if (options->long_name && options->short_name) {
pos += fprintf(stdout, ", ");
}
if (options->long_name) {
pos += fprintf(stdout, "--%s", options->long_name);
}
if (options->type == ARGPARSE_OPT_INTEGER) {
pos += fprintf(stdout, "=<int>");
} else if (options->type == ARGPARSE_OPT_FLOAT) {
pos += fprintf(stdout, "=<flt>");
} else if (options->type == ARGPARSE_OPT_STRING) {
pos += fprintf(stdout, "=<str>");
}
if (pos <= usage_opts_width) {
pad = usage_opts_width - pos;
} else {
fputc('\n', stdout);
pad = usage_opts_width;
}
fprintf(stdout, "%*s%s\n", pad + 2, "", options->help);
}

// print epilog
if (self->epilog)
fprintf(stdout, "%s\n", self->epilog);
}

int
argparse_help_cb(struct argparse *self, const struct argparse_option *option)
{
(void)option;
argparse_usage(self);
exit(0);
}

+ 0
- 130
src/libs/argparse.h View File

@@ -1,130 +0,0 @@
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* All rights reserved.
*
* Use of this source code is governed by a MIT-style license that can be found
* in the LICENSE file.
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H

/* For c++ compatibility */
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

struct argparse;
struct argparse_option;

typedef int argparse_callback (struct argparse *self,
const struct argparse_option *option);

enum argparse_flag {
ARGPARSE_STOP_AT_NON_OPTION = 1,
};

enum argparse_option_type {
/* special */
ARGPARSE_OPT_END,
ARGPARSE_OPT_GROUP,
/* options with no arguments */
ARGPARSE_OPT_BOOLEAN,
ARGPARSE_OPT_BIT,
/* options with arguments (optional or required) */
ARGPARSE_OPT_INTEGER,
ARGPARSE_OPT_FLOAT,
ARGPARSE_OPT_STRING,
};

enum argparse_option_flags {
OPT_NONEG = 1, /* disable negation */
};

/**
* argparse option
*
* `type`:
* holds the type of the option, you must have an ARGPARSE_OPT_END last in your
* array.
*
* `short_name`:
* the character to use as a short option name, '\0' if none.
*
* `long_name`:
* the long option name, without the leading dash, NULL if none.
*
* `value`:
* stores pointer to the value to be filled.
*
* `help`:
* the short help message associated to what the option does.
* Must never be NULL (except for ARGPARSE_OPT_END).
*
* `callback`:
* function is called when corresponding argument is parsed.
*
* `data`:
* associated data. Callbacks can use it like they want.
*
* `flags`:
* option flags.
*/
struct argparse_option {
enum argparse_option_type type;
const char short_name;
const char *long_name;
void *value;
const char *help;
argparse_callback *callback;
intptr_t data;
int flags;
};

/**
* argpparse
*/
struct argparse {
// user supplied
const struct argparse_option *options;
const char *const *usages;
int flags;
const char *description; // a description after usage
const char *epilog; // a description at the end
// internal context
int argc;
const char **argv;
const char **out;
int cpidx;
const char *optvalue; // current option value
};

// built-in callbacks
int argparse_help_cb(struct argparse *self,
const struct argparse_option *option);

// built-in option macros
#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 }
#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ }
#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__ }
#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ }
#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 }
#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \
"show this help message and exit", \
argparse_help_cb, 0, OPT_NONEG)

int argparse_init(struct argparse *self, struct argparse_option *options,
const char *const *usages, int flags);
void argparse_describe(struct argparse *self, const char *description,
const char *epilog);
int argparse_parse(struct argparse *self, int argc, const char **argv);
void argparse_usage(struct argparse *self);

#ifdef __cplusplus
}
#endif

#endif

+ 16
- 2
src/main.c View File

@@ -29,7 +29,7 @@
#include <sndfile.h>
#include <errno.h>
#include <time.h>
#include "libs/argparse.h"
#include "argparse/argparse.h"

#include "common.h"
#include "apt.h"
@@ -222,10 +222,24 @@ static int processAudio(char *filename, options_t *opts){
}

// Perform temperature calibration
apt_temperature(opts->satnum, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH);
apt_calibrate_thermal(opts->satnum, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH);
ImageOut(opts, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH, "Temperature", Temperature, (char *)apt_TempPalette);
}

// Temperature
if (CONTAINS(opts->type, Visible) && img.chA <= 2) {
// Create another buffer as to not modify the orignal
apt_image_t tmpimg = img;
for(int i = 0; i < img.nrow; i++){
tmpimg.prow[i] = (float *) malloc(sizeof(float) * APT_PROW_WIDTH);
memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * APT_PROW_WIDTH);
}

// Perform visible calibration
apt_calibrate_visible(opts->satnum, &tmpimg, APT_CHA_OFFSET, APT_CH_WIDTH);
ImageOut(opts, &tmpimg, APT_CHA_OFFSET, APT_CH_WIDTH, "Visible", Visible, (char *)apt_TempPalette);
}

// MCIR
if (CONTAINS(opts->type, MCIR))
ImageOut(opts, &img, APT_CHA_OFFSET, APT_CH_WIDTH, "MCIR", MCIR, NULL);


+ 0
- 125
src/satcal.h View File

@@ -1,125 +0,0 @@
/*
* This file is part of Aptdec.
* Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2022
*
* 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 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/>.
*
*/

const struct {
float d[4][3];
struct {
float vc, A, B;
} rad[3];
struct {
float Ns;
float b[3];
} cor[3];
/* Calibration corficcients taken from the NOAA KLM satellite user guide
* https://web.archive.org/web/20141220021557/https://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/tables.htm
*/
} satcal[] = {
{ // NOAA 15
{ // PRT coefficient d0, d1, d2
{276.60157f, 0.051045f, 1.36328E-06f},
{276.62531f, 0.050909f, 1.47266E-06f},
{276.67413f, 0.050907f, 1.47656E-06f},
{276.59258f, 0.050966f, 1.47656E-06f}
},
{ // Channel radiance coefficient vc, A, B
{925.4075f, 0.337810f, 0.998719f}, // Channel 4
{839.8979f, 0.304558f, 0.999024f}, // Channel 5
{2695.9743f, 1.621256f, 0.998015f} // Channel 3B
},
{ // Nonlinear radiance correction Ns, b0, b1, b2
{-4.50f, {4.76f, -0.0932f, 0.0004524f}}, // Channel 4
{-3.61f, {3.83f, -0.0659f, 0.0002811f}}, // Channel 5
{0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B
}
},
{ // NOAA 16
{ // PRT coeff d0, d1, d2
{276.355f, 5.562E-02f, -1.590E-05f},
{276.142f, 5.605E-02f, -1.707E-05f},
{275.996f, 5.486E-02f, -1.223E-05f},
{276.132f, 5.494E-02f, -1.344E-05f}
},
{ // Channel radiance coefficient vc, A, B
{917.2289f, 0.332380f, 0.998522f}, // Channel 4
{838.1255f, 0.674623f, 0.998363f}, // Channel 5
{2700.1148f, 1.592459f, 0.998147f} // Channel 3B
},
{ // Nonlinear radiance correction Ns, b0, b1, b2
{-2.467f, {2.96f, -0.05411f, 0.00024532f}}, // Channel 4
{-2.009f, {2.25f, -0.03665f, 0.00014854f}}, // Channel 5
{0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B
}
},
{ // NOAA 17
{ // PRT coefficient d0, d1, d2
{276.628f, 0.05098f, 1.371e-06f},
{276.538f, 0.05098f, 1.371e-06f},
{276.761f, 0.05097f, 1.369e-06f},
{276.660f, 0.05100f, 1.348e-06f}
},
{ // Channel radiance coefficient vc, A, B
{926.2947f, 0.271683f, 0.998794f}, // Channel 4
{839.8246f, 0.309180f, 0.999012f}, // Channel 5
{2669.3554f, 1.702380f, 0.997378f} // Channel 3B
},
{ // Nonlinear radiance correction Ns, b0, b1, b2
{-8.55f, {8.22f, -0.15795f, 0.00075579f}}, // Channel 4
{-3.97f, {4.31f, -0.07318f, 0.00030976f}}, // Channel 5
{0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B
}
},
{ // NOAA 18
{ // PRT coefficient d0, d1, d2
{276.601f, 0.05090f, 1.657e-06f},
{276.683f, 0.05101f, 1.482e-06f},
{276.565f, 0.05117f, 1.313e-06f},
{276.615f, 0.05103f, 1.484e-06f}
},
{ // Channel radiance coefficient vc, A, B
{928.1460f, 0.436645f, 0.998607f}, // Channel 4
{833.2532f, 0.253179f, 0.999057f}, // Channel 5
{2659.7952f, 1.698704f, 0.996960f} // Channel 3B
},
{ // Nonlinear radiance correction Ns, b0, b1, b2
{-5.53f, {5.82f, -0.11069f, 0.00052337f}}, // Channel 4
{-2.22f, {2.67f, -0.04360f, 0.00017715f}}, // Channel 5
{0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B
}
},
{ // NOAA 19
{ // PRT coefficient d0, d1, d2
{276.6067f, 0.051111f, 1.405783E-06f},
{276.6119f, 0.051090f, 1.496037E-06f},
{276.6311f, 0.051033f, 1.496990E-06f},
{276.6268f, 0.051058f, 1.493110E-06f}
},
{ // Channel radiance coefficient vc, A, B
{928.9f, 0.53959f, 0.998534f}, // Channel 4
{831.9f, 0.36064f, 0.998913f}, // Channel 5
{2670.0f, 1.67396f, 0.997364f} // Channel 3B
},
{ // Nonlinear radiance correction Ns, b0, b1, b2
{-5.49f, {5.70f, -0.11187f, 0.00054668f}}, // Channel 4
{-3.39f, {3.58f, -0.05991f, 0.00024985f}}, // Channel 5
{0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B
}
}};

const float c1 = 1.1910427e-5f;
const float c2 = 1.4387752f;

Loading…
Cancel
Save