diff --git a/CMakeLists.txt b/CMakeLists.txt index 36e67c2038..7db078bd28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,6 +403,7 @@ ENDIF(OGGTHEORA_FOUND) ENDIF(UNIX) SET(libdsp_C_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/fits.c ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/file.c ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/buffer.c ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/convert.c @@ -2072,6 +2073,10 @@ if (INDI_BUILD_DRIVERS OR INDI_BUILD_CLIENT OR INDI_BUILD_QT5_CLIENT) ${CMAKE_CURRENT_SOURCE_DIR}/eventloop.h ${CMAKE_CURRENT_SOURCE_DIR}/indidriver.h ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/dsp.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/fits_extensions.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/fits.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/sdfits.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/dsp/fitsidi.h ${CMAKE_CURRENT_SOURCE_DIR}/libs/indibase/pid/pid.h ${CMAKE_CURRENT_SOURCE_DIR}/libs/indibase/indibase.h ${CMAKE_CURRENT_SOURCE_DIR}/libs/indibase/indibasetypes.h diff --git a/drivers/receiver/indi_rtlsdr.cpp b/drivers/receiver/indi_rtlsdr.cpp index 5ef9fd6dea..4ce81db6cc 100644 --- a/drivers/receiver/indi_rtlsdr.cpp +++ b/drivers/receiver/indi_rtlsdr.cpp @@ -113,10 +113,10 @@ RTLSDR::RTLSDR(int32_t index) char name[MAXINDIDEVICE]; snprintf(name, MAXINDIDEVICE, "%s %s%c", getDefaultName(), index < 0 ? "TCP" : "USB", index < 0 ? '\0' : index + '1'); setDeviceName(name); + // We set the Receiver capabilities uint32_t cap = SENSOR_CAN_ABORT | SENSOR_HAS_STREAMING | SENSOR_HAS_DSP; SetReceiverCapability(cap); - } bool RTLSDR::Connect() @@ -174,6 +174,7 @@ bool RTLSDR::initProperties() setMinMaxStep("RECEIVER_SETTINGS", "RECEIVER_GAIN", 0.0, 25.0, 0.1, false); setMinMaxStep("RECEIVER_SETTINGS", "RECEIVER_BANDWIDTH", 2.5e+5, 2.0e+6, 2.5e+5, false); setMinMaxStep("RECEIVER_SETTINGS", "RECEIVER_BITSPERSAMPLE", 16, 16, 0, false); + setMinMaxStep("RECEIVER_SETTINGS", "RECEIVER_ANTENNA", 1, 1, 0, false); setIntegrationFileExtension("fits"); // Add Debug, Simulator, and Configuration controls @@ -391,8 +392,7 @@ void RTLSDR::grabData() IntegrationComplete(); } else { StartIntegration(1.0 / Streamer->getTargetFPS()); - int32_t size = getBufferSize(); - Streamer->newFrame(getBuffer(), size); + Streamer->newFrame(getBuffer(), getBufferSize()); } } } diff --git a/libs/dsp/buffer.c b/libs/dsp/buffer.c old mode 100644 new mode 100755 index aff9c38269..498a7a6af3 --- a/libs/dsp/buffer.c +++ b/libs/dsp/buffer.c @@ -1,25 +1,30 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" +#include +#include void dsp_buffer_shift(dsp_stream_p stream) { + if(stream == NULL) + return; if(stream->dims == 0) return; dsp_t* tmp = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); @@ -43,6 +48,8 @@ void dsp_buffer_shift(dsp_stream_p stream) void dsp_buffer_removemean(dsp_stream_p stream) { + if(stream == NULL) + return; int k; dsp_t mean = dsp_stats_mean(stream->buf, stream->len); @@ -53,6 +60,8 @@ void dsp_buffer_removemean(dsp_stream_p stream) void dsp_buffer_sub(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); int k; @@ -64,17 +73,47 @@ void dsp_buffer_sub(dsp_stream_p stream, dsp_t* in, int inlen) void dsp_buffer_sum(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); - int k; - for(k = 0; k < len; k++) { + int k; + for(k = 0; k < len; k++) { stream->buf[k] += in[k]; - } + } + +} + +void dsp_buffer_max(dsp_stream_p stream, dsp_t* in, int inlen) +{ + if(stream == NULL) + return; + int len = Min(stream->len, inlen); + + int k; + for(k = 0; k < len; k++) { + stream->buf[k] = Max(stream->buf[k], in[k]); + } + +} + +void dsp_buffer_min(dsp_stream_p stream, dsp_t* in, int inlen) +{ + if(stream == NULL) + return; + int len = Min(stream->len, inlen); + + int k; + for(k = 0; k < len; k++) { + stream->buf[k] = Min(stream->buf[k], in[k]); + } } void dsp_buffer_div(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); int k; @@ -86,6 +125,8 @@ void dsp_buffer_div(dsp_stream_p stream, dsp_t* in, int inlen) void dsp_buffer_mul(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); int k; @@ -97,6 +138,8 @@ void dsp_buffer_mul(dsp_stream_p stream, dsp_t* in, int inlen) void dsp_buffer_pow(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); int k; @@ -108,6 +151,8 @@ void dsp_buffer_pow(dsp_stream_p stream, dsp_t* in, int inlen) void dsp_buffer_log(dsp_stream_p stream, dsp_t* in, int inlen) { + if(stream == NULL) + return; int len = Min(stream->len, inlen); int k; @@ -117,8 +162,10 @@ void dsp_buffer_log(dsp_stream_p stream, dsp_t* in, int inlen) } -void dsp_buffer_1sub(dsp_stream_p stream, double val) +void dsp_buffer_1sub(dsp_stream_p stream, dsp_t val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { @@ -127,8 +174,10 @@ void dsp_buffer_1sub(dsp_stream_p stream, double val) } -void dsp_buffer_sub1(dsp_stream_p stream, double val) +void dsp_buffer_sub1(dsp_stream_p stream, dsp_t val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { @@ -137,9 +186,11 @@ void dsp_buffer_sub1(dsp_stream_p stream, double val) } -void dsp_buffer_sum1(dsp_stream_p stream, double val) +void dsp_buffer_sum1(dsp_stream_p stream, dsp_t val) { - int k; + if(stream == NULL) + return; + int k; for(k = 0; k < stream->len; k++) { stream->buf[k] += val; @@ -149,50 +200,60 @@ void dsp_buffer_sum1(dsp_stream_p stream, double val) void dsp_buffer_1div(dsp_stream_p stream, double val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { - stream->buf[k] = (dsp_t)(val / (dsp_t)stream->buf[k]); + stream->buf[k] = val / stream->buf[k]; } } void dsp_buffer_div1(dsp_stream_p stream, double val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { - stream->buf[k] = (dsp_t)((dsp_t)stream->buf[k] / val); + stream->buf[k] /= val; } } void dsp_buffer_mul1(dsp_stream_p stream, double val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { - stream->buf[k] = (dsp_t)((dsp_t)stream->buf[k] * val); + stream->buf[k] = stream->buf[k] * val; } } void dsp_buffer_pow1(dsp_stream_p stream, double val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { - stream->buf[k] = (dsp_t)pow((dsp_t)stream->buf[k], val); + stream->buf[k] = pow(stream->buf[k], val); } } void dsp_buffer_log1(dsp_stream_p stream, double val) { + if(stream == NULL) + return; int k; for(k = 0; k < stream->len; k++) { - stream->buf[k] = (dsp_t)Log((dsp_t)stream->buf[k], val); + stream->buf[k] = Log(stream->buf[k], val); } } @@ -207,21 +268,170 @@ static int compare( const void* a, const void* b) else return 1; } -void dsp_buffer_median(dsp_stream_p stream, int size, int median) +static void* dsp_buffer_median_th(void* arg) { - int k; - int mid = (size / 2) + (size % 2); - dsp_t* sorted = (dsp_t*)malloc(size * sizeof(dsp_t)); - for(k = mid; k < stream->len; k++) { - memcpy (sorted, stream->buf + (k - mid), size * sizeof(dsp_t)); - qsort(sorted, size, sizeof(dsp_t), compare); - stream->buf[k] = sorted[median]; - } + struct { + int cur_th; + int size; + int median; + dsp_stream_p stream; + dsp_stream_p box; + } *arguments = arg; + dsp_stream_p stream = arguments->stream; + dsp_stream_p box = arguments->box; + dsp_stream_p in = stream->parent; + int cur_th = arguments->cur_th; + int size = arguments->size; + int median = arguments->median; + int start = cur_th * stream->len / dsp_max_threads(0); + int end = start + stream->len / dsp_max_threads(0); + end = Min(stream->len, end); + int x, y, dim, idx; + dsp_t* sorted = (dsp_t*)malloc(pow(size, stream->dims) * sizeof(dsp_t)); + int len = pow(size, in->dims); + for(x = start; x < end; x++) { + dsp_t* buf = sorted; + for(y = 0; y < box->len; y++) { + int *pos = dsp_stream_get_position(stream, x); + int *mat = dsp_stream_get_position(box, y); + for(dim = 0; dim < stream->dims; dim++) { + pos[dim] += mat[dim] - size / 2; + } + idx = dsp_stream_set_position(stream, pos); + if(idx >= 0 && idx < in->len) { + *buf++ = in->buf[idx]; + } + free(pos); + free(mat); + } + qsort(sorted, len, sizeof(dsp_t), compare); + stream->buf[x] = sorted[median*box->len/size]; + } + dsp_stream_free_buffer(box); + dsp_stream_free(box); + free(sorted); + return NULL; +} +void dsp_buffer_median(dsp_stream_p in, int size, int median) +{ + if(in == NULL) + return; + long unsigned int y; + int d; + dsp_stream_p stream = dsp_stream_copy(in); + dsp_buffer_set(stream->buf, stream->len, 0); + stream->parent = in; + pthread_t *th = (pthread_t *)malloc(sizeof(pthread_t)*dsp_max_threads(0)); + struct { + int cur_th; + int size; + int median; + dsp_stream_p stream; + dsp_stream_p box; + } thread_arguments[dsp_max_threads(0)]; + for(y = 0; y < dsp_max_threads(0); y++) + { + thread_arguments[y].cur_th = y; + thread_arguments[y].size = size; + thread_arguments[y].median = median; + thread_arguments[y].stream = stream; + thread_arguments[y].box = dsp_stream_new(); + for(d = 0; d < stream->dims; d++) + dsp_stream_add_dim(thread_arguments[y].box, size); + dsp_stream_alloc_buffer(thread_arguments[y].box, thread_arguments[y].box->len); + pthread_create(&th[y], NULL, dsp_buffer_median_th, &thread_arguments[y]); + } + for(y = 0; y < dsp_max_threads(0); y++) + pthread_join(th[y], NULL); + free(th); + stream->parent = NULL; + dsp_buffer_copy(stream->buf, in->buf, stream->len); + dsp_stream_free_buffer(stream); + dsp_stream_free(stream); +} + +static void* dsp_buffer_sigma_th(void* arg) +{ + struct { + int cur_th; + int size; + dsp_stream_p stream; + dsp_stream_p box; + } *arguments = arg; + dsp_stream_p stream = arguments->stream; + dsp_stream_p in = stream->parent; + dsp_stream_p box = arguments->box; + int cur_th = arguments->cur_th; + int size = arguments->size; + int start = cur_th * stream->len / dsp_max_threads(0); + int end = start + stream->len / dsp_max_threads(0); + end = Min(stream->len, end); + int x, y, dim, idx; + dsp_t* sigma = (dsp_t*)malloc(pow(size, stream->dims) * sizeof(dsp_t)); + int len = pow(size, in->dims); + for(x = start; x < end; x++) { + dsp_t* buf = sigma; + for(y = 0; y < box->len; y++) { + int *pos = dsp_stream_get_position(stream, x); + int *mat = dsp_stream_get_position(box, y); + for(dim = 0; dim < stream->dims; dim++) { + pos[dim] += mat[dim] - size / 2; + } + idx = dsp_stream_set_position(stream, pos); + if(idx >= 0 && idx < in->len) { + buf[y] = in->buf[idx]; + } + free(pos); + free(mat); + } + stream->buf[x] = dsp_stats_stddev(buf, len); + } + dsp_stream_free_buffer(box); + dsp_stream_free(box); + free(sigma); + return NULL; +} + +void dsp_buffer_sigma(dsp_stream_p in, int size) +{ + if(in == NULL) + return; + long unsigned int y; + int d; + dsp_stream_p stream = dsp_stream_copy(in); + dsp_buffer_set(stream->buf, stream->len, 0); + stream->parent = in; + pthread_t *th = (pthread_t *)malloc(sizeof(pthread_t)*dsp_max_threads(0)); + struct { + int cur_th; + int size; + dsp_stream_p stream; + dsp_stream_p box; + } thread_arguments[dsp_max_threads(0)]; + for(y = 0; y < dsp_max_threads(0); y++) + { + thread_arguments[y].cur_th = y; + thread_arguments[y].size = size; + thread_arguments[y].stream = stream; + thread_arguments[y].box = dsp_stream_new(); + for(d = 0; d < stream->dims; d++) + dsp_stream_add_dim(thread_arguments[y].box, size); + pthread_create(&th[y], NULL, dsp_buffer_sigma_th, &thread_arguments[y]); + } + for(y = 0; y < dsp_max_threads(0); y++) + pthread_join(th[y], NULL); + free(th); + stream->parent = NULL; + dsp_buffer_copy(stream->buf, in->buf, stream->len); + dsp_stream_free_buffer(stream); + dsp_stream_free(stream); } void dsp_buffer_deviate(dsp_stream_p stream, dsp_t* deviation, dsp_t mindeviation, dsp_t maxdeviation) { + if(stream == NULL) + return; dsp_stream_p tmp = dsp_stream_copy(stream); int k; for(k = 1; k < stream->len; k++) { diff --git a/libs/dsp/convert.c b/libs/dsp/convert.c index 5677fe1a40..73feeff35a 100755 --- a/libs/dsp/convert.c +++ b/libs/dsp/convert.c @@ -1,20 +1,21 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" diff --git a/libs/dsp/convolution.c b/libs/dsp/convolution.c index 7a1598999f..1c6a723ad4 100644 --- a/libs/dsp/convolution.c +++ b/libs/dsp/convolution.c @@ -1,68 +1,68 @@ /* - * libDSPAU - a digital signal processing library for astronoms usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" -static void* dsp_convolution_convolution_th(void* arg) -{ - dsp_stream_p matrix = (dsp_stream_p)arg; - dsp_stream_p field = (dsp_stream_p)matrix->parent; - dsp_stream_p stream = (dsp_stream_p)field->parent; - int y = matrix->ROI[0].start; - int* pos = dsp_stream_get_position(matrix, y); - int x, d; - for(x = 0; x < stream->len; x++) - { - int* pos1 = dsp_stream_get_position(field, x); - for(d = 0; d < field->dims; d++) - pos1[d] += pos[d]; - int z = dsp_stream_set_position(field, pos1); - if(z >= 0 && z < field->len && x >= 0 && x < stream->len && y >= 0) - stream->buf[x] += field->buf[z] * matrix->buf[y]; - free(pos1); +void dsp_convolution_convolution(dsp_stream_p stream, dsp_stream_p matrix) { + if(stream == NULL) + return; + if(matrix == NULL) + return; + int x, y, d; + dsp_t mn = dsp_stats_min(stream->buf, stream->len); + dsp_t mx = dsp_stats_max(stream->buf, stream->len); + int* d_pos = (int*)malloc(sizeof(int)*stream->dims); + for(y = 0; y < matrix->len; y++) { + int* pos = dsp_stream_get_position(matrix, y); + for(d = 0; d < stream->dims; d++) { + d_pos[d] = stream->sizes[d]/2+pos[d]-matrix->sizes[d]/2; + } + x = dsp_stream_set_position(stream, d_pos); + free(pos); + stream->magnitude->buf[x] *= sqrt(matrix->magnitude->buf[y]); } - free(pos); - dsp_stream_free_buffer(matrix); - dsp_stream_free(matrix); - return NULL; + free(d_pos); + dsp_fourier_idft(stream); + dsp_buffer_stretch(stream->buf, stream->len, mn, mx); } -dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream, dsp_stream_p object) { - dsp_stream_p field = dsp_stream_copy(stream); - dsp_stream_p tmp = dsp_stream_copy(stream); - dsp_buffer_set(tmp->buf, tmp->len, 0); - field->parent = tmp; - int n_threads = object->len; - pthread_t *th = malloc(sizeof(pthread_t)*n_threads); - int y, xy; - for(y = -n_threads; y < n_threads; y+=DSP_MAX_THREADS) - { - for(xy = 0; xy < DSP_MAX_THREADS; xy++) { - dsp_stream_p matrix = dsp_stream_copy(object); - matrix->parent = field; - matrix->ROI[0].start = xy; - matrix->ROI[0].len = 0; - pthread_create(&th[xy], NULL, dsp_convolution_convolution_th, (void*)matrix); +void dsp_convolution_correlation(dsp_stream_p stream, dsp_stream_p matrix) { + if(stream == NULL) + return; + if(matrix == NULL) + return; + int x, y, d; + dsp_t mn = dsp_stats_min(stream->buf, stream->len); + dsp_t mx = dsp_stats_max(stream->buf, stream->len); + int* d_pos = (int*)malloc(sizeof(int)*stream->dims); + dsp_buffer_shift(matrix->magnitude); + for(y = 0; y < matrix->len; y++) { + int* pos = dsp_stream_get_position(matrix, y); + for(d = 0; d < stream->dims; d++) { + d_pos[d] = stream->sizes[d]/2+pos[d]-matrix->sizes[d]/2; } - for(xy = 0; xy < DSP_MAX_THREADS; xy++) - pthread_join(th[xy], NULL); + x = dsp_stream_set_position(stream, d_pos); + free(pos); + stream->magnitude->buf[x] *= sqrt(matrix->magnitude->buf[y]); } - dsp_stream_free_buffer(field); - dsp_stream_free(field); - return tmp; + dsp_buffer_shift(matrix->magnitude); + free(d_pos); + dsp_fourier_idft(stream); + dsp_buffer_stretch(stream->buf, stream->len, mn, mx); } diff --git a/libs/dsp/dsp.h b/libs/dsp/dsp.h index ce4d143b4e..6fe5f47d59 100644 --- a/libs/dsp/dsp.h +++ b/libs/dsp/dsp.h @@ -1,19 +1,19 @@ -/* - * libDSP - a digital signal processing library - * Copyright (C) 2017 Ilia Platone +/* libDSP - a digital signal processing library + * Copyright © 2017-2022 Ilia Platone * - * 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 3 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser 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 . + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DSP_H @@ -27,6 +27,13 @@ extern "C" { #define DLL_EXPORT extern #endif +#ifdef __linux__ +#include +#else +#define __bswap_16(a) __builtin_bswap16(a) +#define __bswap_32(a) __builtin_bswap32(a) +#define __bswap_64(a) __builtin_bswap64(a) +#endif #include #include #include @@ -36,42 +43,141 @@ extern "C" { #include #include #include - +#include /** * \defgroup DSP Digital Signal Processing API * +* The DSP API is a collection of essential routines used in astronomy signal processing
+* * The DSP API is used for processing monodimensional or multidimensional buffers,
+* generating, tranforming, stack, processing buffers, aligning, convoluting arrays,
* converting array element types, generate statistics, extract informations from buffers, convolute or
* cross-correlate different single or multi dimensional streams, rotate, scale, crop images.
* * \author Ilia Platone +* \version 1.0.0 +* \date 2017-2022 +* \copyright GNU Lesser GPL3 Public License. */ -/*@{*/ - +/**\{*/ /** * \defgroup DSP_Defines DSP API defines */ -/*@{*/ +/**\{*/ #define DSP_MAX_STARS 200 #define dsp_t double -#define dsp_t_max pow(2, sizeof(dsp_t)*4) +#define dsp_t_max 255 #define dsp_t_min -dsp_t_max -#define DSP_MAX_THREADS 4 +/** +* \brief get/set the maximum number of threads allowed +* \param value if greater than 1, set a maximum number of threads allowed +* \return The current or new number of threads allowed during runtime +*/ +DLL_EXPORT unsigned long int dsp_max_threads(unsigned long value); + +#ifndef DSP_DEBUG +#define DSP_DEBUG +/** +* \brief set the debug level +* \param value the debug level +*/ +DLL_EXPORT void dsp_set_debug_level(int value); +/** +* \brief get the debug level +* \return The current debug level +*/ +DLL_EXPORT int dsp_get_debug_level(); +/** +* \brief set the application name +* \param name the application name to be printed on logs +*/ +DLL_EXPORT void dsp_set_app_name(char* name); +/** +* \brief get the application name +* \return The current application name printed on logs +*/ +DLL_EXPORT char* dsp_get_app_name(); +/** +* \brief set the output log streeam +* \param f The FILE stream pointer to set as standard output +*/ +DLL_EXPORT void dsp_set_stdout(FILE *f); +/** +* \brief set the error log streeam +* \param f The FILE stream pointer to set as standard error +*/ +DLL_EXPORT void dsp_set_stderr(FILE *f); + +/** +* \brief log a message to the error or output streams +* \param x The log level +* \param str The string to print +*/ +DLL_EXPORT void dsp_print(int x, char* str); + +#define DSP_DEBUG_INFO 0 +#define DSP_DEBUG_ERROR 1 +#define DSP_DEBUG_WARNING 2 +#define DSP_DEBUG_DEBUG 3 +#define pdbg(x, ...) ({ \ +char str[500]; \ +struct timespec ts; \ +time_t t = time(NULL); \ +struct tm tm = *localtime(&t); \ +clock_gettime(CLOCK_REALTIME, &ts); \ +sprintf(str, "[%04d-%02d-%02dT%02d:%02d:%02d.%03ld ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec/1000000); \ +switch(x) { \ + case DSP_DEBUG_ERROR: \ + sprintf(&str[strlen(str)], "ERRO]"); \ + break; \ + case DSP_DEBUG_WARNING: \ + sprintf(&str[strlen(str)], "WARN]"); \ + break; \ + case DSP_DEBUG_DEBUG: \ + sprintf(&str[strlen(str)], "DEBG]"); \ + break; \ + default: \ + sprintf(&str[strlen(str)], "INFO]"); \ + break; \ +} \ +if(dsp_get_app_name() != NULL) \ + sprintf(&str[strlen(str)], "[%s]", dsp_get_app_name()); \ +sprintf(&str[strlen(str)], " "); \ +sprintf(&str[strlen(str)], __VA_ARGS__); \ +dsp_print(x, str); \ +}) +#define pinfo(...) pdbg(DSP_DEBUG_INFO, __VA_ARGS__) +#define perr(...) pdbg(DSP_DEBUG_ERROR, __VA_ARGS__) +#define pwarn(...) pdbg(DSP_DEBUG_WARNING, __VA_ARGS__) +#define pgarb(...) pdbg(DSP_DEBUG_DEBUG, __VA_ARGS__) +#define pfunc pgarb("%s\n", __func__) +#define start_gettime +#define end_gettime +#else +#define pinfo(...) +#define perr(...) +#define pwarn(...) +#define pgarb(...) +#define pfunc(...) +#define start_gettime(...) +#define end_gettime(...) +#endif + ///if min() is not present you can use this one #ifndef Min #define Min(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (a) _b = (b); \ + ({ __typeof (a) _a = (a); \ + __typeof (a) _b = (b); \ _a < _b ? _a : _b; }) #endif ///if max() is not present you can use this one #ifndef Max #define Max(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (a) _b = (b); \ + ({ __typeof (a) _a = (a); \ + __typeof (a) _b = (b); \ _a > _b ? _a : _b; }) #endif ///Logarithm of a with arbitrary base b @@ -79,11 +185,27 @@ extern "C" { #define Log(a,b) \ ( log(a) / log(b) ) #endif -/*@}*/ +#ifndef DSP_ALIGN_TRANSLATED +///The stream is translated by the reference +#define DSP_ALIGN_TRANSLATED 1 +#endif +#ifndef DSP_ALIGN_SCALED +///The stream is scaled by the reference +#define DSP_ALIGN_SCALED 2 +#endif +#ifndef DSP_ALIGN_ROTATED +///The stream is rotated by the reference +#define DSP_ALIGN_ROTATED 4 +#endif +#ifndef DSP_ALIGN_NO_MATCH +///No matches were found during comparison +#define DSP_ALIGN_NO_MATCH 8 +#endif +/**\}*/ /** * \defgroup DSP_Types DSP API types */ -/*@{*/ +/**\{*/ /** * \brief Indicates a dot or line inside a dsp_stream @@ -91,9 +213,9 @@ extern "C" { */ typedef struct dsp_point_t { -/// Center of the point + /// Center of the point double* location; -/// Dimensions limit of the point + /// Dimensions limit of the point int dims; } dsp_point; @@ -102,40 +224,89 @@ typedef struct dsp_point_t */ typedef struct dsp_offset_t { -/// Center of the point + /// Center of the point double* offset; -/// Dimensions limit of the point + /// Dimensions limit of the point int dims; } dsp_offset; +/** +* \brief A star or object contained into a buffer +*/ +typedef struct dsp_star_t +{ + /// The center of the star + dsp_point center; + /// The diameter of the star + double diameter; + /// The name of the star + char name[150]; +} dsp_star; + +/** +* \brief A star or object contained into a buffer +*/ +typedef struct dsp_triangle_t +{ + /// The index of the triangle + double index; + /// The dimensions of the triangle + int dims; + /// The inclination of the triangle + double theta; + /// The sizes of the triangle + double *sizes; + /// The sizes of the triangle + double *ratios; + /// The stars of the triangle + dsp_star *stars; +} dsp_triangle; + /** * \brief Alignment informations needed */ typedef struct dsp_align_info_t { - /// Traslation offset + /// Translation offset double* offset; /// Center of rotation coordinates double* center; /// Rotational offset double* radians; /// Scaling factor - double factor; + double* factor; /// Dimensions limit int dims; + /// Reference triangles + dsp_triangle triangles[2]; + /// Triangles quantity + int triangles_count; + /// Match score + double score; + /// Decimals + double decimals; + /// Errors + int err; } dsp_align_info; /** -* \brief Complex number, used in Fourier Transform functions +* \brief Complex number array struct, used in Fourier Transform functions * \sa dsp_fourier_dft -* \sa dsp_fourier_complex_to_magnitude */ -typedef struct dsp_complex_t +typedef union { -/// Real part of the complex number - double real; -/// Imaginary part of the complex number - double imaginary; + /// Complex struct type array + struct + { + /// Real part of the complex number + double real; + /// Imaginary part of the complex number + double imaginary; + } *complex; + /// Complex number type array used with libFFTW + fftw_complex *fftw; + /// Linear double array containing complex numbers + double *buf; } dsp_complex; /** @@ -143,22 +314,34 @@ typedef struct dsp_complex_t */ typedef struct dsp_region_t { -/// Starting point within the buffer + /// Starting point within the buffer int start; -/// Length of the region + /// Length of the region int len; } dsp_region; /** -* \brief A star or object contained into a buffer +* \brief The location type */ -typedef struct dsp_star_t +typedef union dsp_location_t { -/// The center of the star - dsp_point center; -/// The diameter of the star - double diameter; -} dsp_star; + /// The location in xyz coordinates + struct + { + double x; + double y; + double z; + } xyz; + /// The location in geographic coordinates + struct + { + double lon; + double lat; + double el; + } geographic; + /// A 3d double array containing the location + double coordinates[3]; +} dsp_location; /** * \brief Multi-dimensional processing delegate function @@ -168,107 +351,120 @@ typedef void *(*dsp_func_t) (void *, ...); /** * \brief Contains a set of informations and data relative to a buffer and how to use it * \sa dsp_stream_new -* \sa dsp_stream_free * \sa dsp_stream_add_dim * \sa dsp_stream_del_dim +* \sa dsp_stream_alloc_buffer +* \sa dsp_stream_copy +* \sa dsp_stream_free_buffer +* \sa dsp_stream_free */ typedef struct dsp_stream_t { -/// The buffers length + /// Friendly name of the stream + char name[128]; + /// Increments by one on the copied stream + int is_copy; + /// The buffers length int len; -/// Number of dimensions of the buffers + /// Number of dimensions of the buffers int dims; -/// Sizes of each dimension + /// Sizes of each dimension int* sizes; -/// buffer + /// buffer dsp_t* buf; -/// Optional argument for the func() callback + /// Fourier transform + dsp_complex dft; + /// Optional argument for the func() callback void *arg; -/// The stream this one is child of + /// The parent stream struct dsp_stream_t* parent; -/// Children streams of the current one + /// Children streams struct dsp_stream_t** children; -/// Children streams count + /// Children streams count int child_count; -/// Location coordinates - double* location; -/// Target coordinates + /// Location coordinates pointer, can be extended to the main buffer size as location companion + dsp_location* location; + /// Target coordinates double* target; -/// Time at the beginning of the stream + /// Time at the beginning of the stream struct timespec starttimeutc; -/// Wavelength observed, used as reference with signal generators or filters + /// Wavelength observed, used as reference with signal generators or filters double wavelength; -/// Focal ratio + /// Focal ratio double focal_ratio; -/// Diameter + /// Diameter double diameter; -/// SNR + /// SNR double SNR; -/// Red pixel (Bayer) + /// Red pixel (Bayer) int red; -/// Sensor size + /// Sensor size double *pixel_sizes; -/// Sample rate of the buffers + /// Sample rate of the buffers double samplerate; -/// Thread type for future usage + /// Thread type for future usage pthread_t thread; -/// Callback function + /// Callback function dsp_func_t func; -/// Regions of interest for each dimension + /// Fourier transform magnitude + struct dsp_stream_t *magnitude; + /// Fourier transform phase + struct dsp_stream_t *phase; + /// Regions of interest for each dimension dsp_region *ROI; -/// Stars or objects identified into the buffers - TODO + /// Stars or objects identified into the buffers - TODO dsp_star *stars; -/// Stars or objects quantity + /// Stars or objects quantity int stars_count; -/// Align/scale/rotation settings + /// Triangles of stars or objects + dsp_triangle *triangles; + /// Triangles of stars or objects quantity + int triangles_count; + /// Align/scale/rotation settings dsp_align_info align_info; -/// Frame number (if part of a series) + /// Frame number (if part of a series) int frame_number; } dsp_stream, *dsp_stream_p; -/*@}*/ +/**\}*/ /** * \defgroup dsp_FourierTransform DSP API Fourier transform related functions */ -/*@{*/ +/**\{*/ /** * \brief Perform a discrete Fourier Transform of a dsp_stream * \param stream the inout stream. +* \param exp the exponent (recursivity) of the fourier transform. */ -DLL_EXPORT dsp_complex* dsp_fourier_dft(dsp_stream_p stream); +DLL_EXPORT void dsp_fourier_dft(dsp_stream_p stream, int exp); /** * \brief Perform an inverse discrete Fourier Transform of a dsp_stream * \param stream the inout stream. */ -DLL_EXPORT dsp_t* dsp_fourier_idft(dsp_stream_p stream); +DLL_EXPORT void dsp_fourier_idft(dsp_stream_p stream); /** -* \brief Perform a fast Fourier Transform of a dsp_stream +* \brief Fill the magnitude and phase buffers with the current data in stream->dft * \param stream the inout stream. */ -DLL_EXPORT void dsp_fourier_fft(dsp_stream_p stream); +DLL_EXPORT void dsp_fourier_2dsp(dsp_stream_p stream); /** -* \brief Perform an inverse fast Fourier Transform of a dsp_stream +* \brief Obtain the complex fourier tranform from the current magnitude and phase buffers * \param stream the inout stream. */ -DLL_EXPORT void dsp_fourier_ifft(dsp_stream_p stream); +DLL_EXPORT void dsp_fourier_2fftw(dsp_stream_p stream); /** -* \brief Obtain a complex number's magnitude -* \param n the input complex. -* \return the magnitude of the given number +* \brief Obtain a complex array from phase and magnitude arrays +* \param mag the input magnitude array. +* \param phi the input phase array. +* \param len the input arrays length. +* \return the array filled with the complex numbers */ -DLL_EXPORT double dsp_fourier_complex_get_magnitude(dsp_complex n); - -/** -* \brief Obtain a complex number's phase -* \param n the input complex. -* \return the phase of the given number -*/ -DLL_EXPORT double dsp_fourier_complex_get_phase(dsp_complex n); +DLL_EXPORT dsp_complex dsp_fourier_phase_mag_array_get_complex(double* mag, double* phi, int len); /** * \brief Obtain a complex number's array magnitudes @@ -276,7 +472,7 @@ DLL_EXPORT double dsp_fourier_complex_get_phase(dsp_complex n); * \param len the input array length. * \return the array filled with the magnitudes */ -DLL_EXPORT double* dsp_fourier_complex_array_get_magnitude(dsp_complex* in, int len); +DLL_EXPORT double* dsp_fourier_complex_array_get_magnitude(dsp_complex in, int len); /** * \brief Obtain a complex number's array phases @@ -284,37 +480,13 @@ DLL_EXPORT double* dsp_fourier_complex_array_get_magnitude(dsp_complex* in, int * \param len the input array length. * \return the array filled with the phases */ -DLL_EXPORT double* dsp_fourier_complex_array_get_phase(dsp_complex* in, int len); - -/** -* \brief Perform a discrete Fourier Transform of a dsp_stream and obtain the complex magnitudes -* \param stream the input stream. -*/ -DLL_EXPORT void dsp_fourier_dft_magnitude(dsp_stream_p stream); - -/** -* \brief Perform a discrete Fourier Transform of a dsp_stream and obtain the complex phases -* \param stream the input stream. -*/ -DLL_EXPORT void dsp_fourier_dft_phase(dsp_stream_p stream); +DLL_EXPORT double* dsp_fourier_complex_array_get_phase(dsp_complex in, int len); -/** -* \brief Perform an inverse discrete Fourier Transform of a dsp_stream and obtain the complex magnitudes -* \param stream the input stream. -*/ -DLL_EXPORT void dsp_fourier_idft_magnitude(dsp_stream_p stream); - -/** -* \brief Perform an inverse discrete Fourier Transform of a dsp_stream and obtain the complex phases -* \param stream the input stream. -*/ -DLL_EXPORT void dsp_fourier_idft_phase(dsp_stream_p stream); - -/*@}*/ +/**\}*/ /** * \defgroup dsp_Filters DSP API Linear buffer filtering functions */ -/*@{*/ +/**\{*/ /** * \brief A square law filter * \param stream the input stream. @@ -324,55 +496,61 @@ DLL_EXPORT void dsp_filter_squarelaw(dsp_stream_p stream); /** * \brief A low pass filter * \param stream the input stream. -* \param samplingfrequency the sampling frequency of the input stream. -* \param frequency the cutoff frequency of the filter. +* \param frequency the cutoff frequency of the filter in radians. */ -DLL_EXPORT void dsp_filter_lowpass(dsp_stream_p stream, double samplingfrequency, double frequency); +DLL_EXPORT void dsp_filter_lowpass(dsp_stream_p stream, double frequency); /** * \brief A high pass filter * \param stream the input stream. -* \param samplingfrequency the sampling frequency of the input stream. -* \param frequency the cutoff frequency of the filter. +* \param frequency the cutoff frequency of the filter in radians. */ -DLL_EXPORT void dsp_filter_highpass(dsp_stream_p stream, double samplingfrequency, double frequency); +DLL_EXPORT void dsp_filter_highpass(dsp_stream_p stream, double frequency); /** * \brief A band pass filter * \param stream the input stream. -* \param samplingfrequency the sampling frequency of the input stream. -* \param LowFrequency the high-pass cutoff frequency of the filter. -* \param HighFrequency the low-pass cutoff frequency of the filter. +* \param LowFrequency the high-pass cutoff frequency of the filter in radians. +* \param HighFrequency the low-pass cutoff frequency of the filter in radians. */ -DLL_EXPORT void dsp_filter_bandpass(dsp_stream_p stream, double samplingfrequency, double LowFrequency, double HighFrequency); +DLL_EXPORT void dsp_filter_bandpass(dsp_stream_p stream, double LowFrequency, + double HighFrequency); /** * \brief A band reject filter * \param stream the input stream. -* \param samplingfrequency the sampling frequency of the input stream. -* \param LowFrequency the high-pass cutoff frequency of the filter. +* \param LowFrequency the high-pass cutoff frequency of the filter in radians. * \param HighFrequency the low-pass cutoff frequency of the filter. */ -DLL_EXPORT void dsp_filter_bandreject(dsp_stream_p stream, double samplingfrequency, double LowFrequency, double HighFrequency); +DLL_EXPORT void dsp_filter_bandreject(dsp_stream_p stream, double LowFrequency, + double HighFrequency); -/*@}*/ +/**\}*/ /** * \defgroup dsp_Convolution DSP API Convolution and cross-correlation functions */ -/*@{*/ +/**\{*/ /** * \brief A cross-convolution processor -* \param stream1 the first input stream. -* \param stream2 the second input stream. +* \param stream the input stream. +* \param matrix the convolution matrix stream. */ -DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_stream_p stream2); +DLL_EXPORT void dsp_convolution_convolution(dsp_stream_p stream, dsp_stream_p matrix); -/*@}*/ +/** +* \brief A cross-correlation processor +* \param stream the input stream. +* \param matrix the correlation matrix stream. +*/ +DLL_EXPORT void dsp_convolution_correlation(dsp_stream_p stream, dsp_stream_p matrix); + +/**\}*/ /** * \defgroup dsp_Stats DSP API Buffer statistics functions */ -/*@{*/ +/**\{*/ +#ifndef dsp_stats_min /** * \brief Gets the minimum value of the input stream * \param buf the input buffer @@ -382,13 +560,15 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st #define dsp_stats_min(buf, len)\ ({\ int i;\ - __typeof__(buf[0]) min = (__typeof__(buf[0]))buf[0];\ + __typeof(buf[0]) min = (__typeof(buf[0]))buf[0];\ for(i = 0; i < len; i++) {\ min = Min(buf[i], min);\ }\ min;\ }) +#endif +#ifndef dsp_stats_max /** * \brief Gets the maximum value of the input stream * \param buf the input buffer @@ -398,13 +578,15 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st #define dsp_stats_max(buf, len)\ ({\ int i;\ - __typeof__(buf[0]) max = (__typeof__(buf[0]))buf[0];\ + __typeof(buf[0]) max = (__typeof(buf[0]))buf[0];\ for(i = 0; i < len; i++) {\ max = Max(buf[i], max);\ }\ max;\ }) +#endif +#ifndef dsp_stats_mid /** * \brief Gets the middle value of the input stream * \param buf the input buffer @@ -414,10 +596,12 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st #define dsp_stats_mid(buf, len)\ ({\ int i;\ - __typeof__(buf[0]) min = dsp_stats_min(buf, len);\ - (__typeof__(buf[0]))(min - dsp_stats_max(buf, len)) / 2.0 + min;\ + __typeof(buf[0]) min = dsp_stats_min(buf, len);\ + (__typeof(buf[0]))(min - dsp_stats_max(buf, len)) / 2.0 + min;\ }) +#endif +#ifndef dsp_stats_maximum_index /** * \brief Gets minimum value's position into the buffer * \param buf the input buffer @@ -427,13 +611,15 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st #define dsp_stats_minimum_index(buf, len)\ ({\ int i;\ - __typeof__(buf[0]) min = dsp_stats_min(buf, len);\ + __typeof(buf[0]) min = dsp_stats_min(buf, len);\ for(i = 0; i < len; i++) {\ if(buf[i] == min) break;\ }\ i;\ }) +#endif +#ifndef dsp_stats_maximum_index /** * \brief Gets maximum value's position into the buffer * \param buf the input buffer @@ -443,13 +629,15 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st #define dsp_stats_maximum_index(buf, len)\ ({\ int i;\ - __typeof__(buf[0]) max = dsp_stats_max(buf, len);\ + __typeof(buf[0]) max = dsp_stats_max(buf, len);\ for(i = 0; i < len; i++) {\ if(buf[i] == max) break;\ }\ i;\ }) +#endif +#ifndef dsp_stats_stddev /** * \brief A mean calculator * \param buf the input buffer @@ -458,15 +646,36 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st */ #define dsp_stats_mean(buf, len)\ ({\ - int i;\ - __typeof__(buf[0]) mean = 0;\ - for(i = 0; i < len; i++) {\ - mean += buf[i];\ + int __dsp__i;\ + double __dsp__mean = 0;\ + for(__dsp__i = 0; __dsp__i < len; __dsp__i++) {\ + __dsp__mean += buf[__dsp__i];\ + }\ + __dsp__mean /= len;\ + __dsp__mean;\ + }) +#endif + +#ifndef dsp_stats_stddev +/** +* \brief Standard deviation of the inut stream +* \param buf the inout buffer +* \param len the length of the buffer +*/ +#define dsp_stats_stddev(buf, len)\ +({\ + double __dsp__mean = dsp_stats_mean(buf, len);\ + int __dsp__x;\ + double __dsp__stddev = 0;\ + for(__dsp__x = 0; __dsp__x < len; __dsp__x++) {\ + __dsp__stddev += fabs(buf[__dsp__x] - __dsp__mean);\ }\ - mean /= len;\ - mean;\ + __dsp__stddev /= len;\ + __dsp__stddev;\ }) +#endif +#ifndef dsp_stats_val_count /** * \brief Counts value occurrences into stream * \param buf the input buffer @@ -484,14 +693,35 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st }\ count;\ }) +#endif +#ifndef dsp_stats_val_sum /** -* \brief Counts value occurrences into stream +* \brief Cumulative sum of all the values on the stream * \param buf the input buffer * \param len the length in elements of the buffer. -* \param val the value to count. * \return the count of the value of the stream. */ +#define dsp_stats_val_sum(buf, len) \ +({\ + int x;\ + double sum = 0;\ + for(x = 0; x < len; x++) {\ + sum += buf[x];\ + }\ + sum;\ + }) +#endif + +#ifndef dsp_stats_range_count +/** +* \brief Counts value ranging occurrences into stream +* \param buf the input buffer +* \param len the length in elements of the buffer. +* \param lo the bottom margin value. +* \param hi the upper margin value. +* \return the count of the values ranging between the margins of the stream. +*/ #define dsp_stats_range_count(buf, len, lo, hi) \ ({\ int x;\ @@ -502,9 +732,11 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st }\ count;\ }) +#endif +#ifndef dsp_stats_compare /** -* \brief Compare two streams +* \brief Compare two buffers * \param in1 the first input buffer * \param in2 the second input buffer * \param len the length in elements of the buffer. @@ -512,12 +744,13 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st */ #define dsp_stats_compare(in1, in2, len)\ ({\ - __typeof__(in1[0]) out = 0;\ + __typeof(in1[0]) out = 0;\ for(int i = 0; i < len; i++) {\ - out += in1[i] - (__typeof__(in1[0]))in2[i];\ + out += in1[i] - (__typeof(in1[0]))in2[i];\ }\ out;\ }) +#endif /** * \brief Histogram of the inut stream @@ -528,11 +761,11 @@ DLL_EXPORT dsp_stream_p dsp_convolution_convolution(dsp_stream_p stream1, dsp_st */ DLL_EXPORT double* dsp_stats_histogram(dsp_stream_p stream, int size); -/*@}*/ +/**\}*/ /** * \defgroup dsp_Buffers DSP API Buffer editing functions */ -/*@{*/ +/**\{*/ /** * \brief Shift a stream on each dimension @@ -546,50 +779,53 @@ DLL_EXPORT void dsp_buffer_shift(dsp_stream_p stream); */ DLL_EXPORT void dsp_buffer_removemean(dsp_stream_p stream); +#ifndef dsp_buffer_stretch /** * \brief Stretch minimum and maximum values of the input stream * \param buf the input buffer * \param len the length in elements of the buffer. -* \param min the desired minimum value. -* \param max the desired maximum value. +* \param _mn the desired minimum value. +* \param _mx the desired maximum value. */ - #define dsp_buffer_stretch(buf, len, _mn, _mx)\ ({\ int k;\ - __typeof__(buf[0]) __mn = dsp_stats_min(buf, len);\ - __typeof__(buf[0]) __mx = dsp_stats_max(buf, len);\ + __typeof(buf[0]) __mn = dsp_stats_min(buf, len);\ + __typeof(buf[0]) __mx = dsp_stats_max(buf, len);\ double oratio = (_mx - _mn);\ double iratio = (__mx - __mn);\ if(iratio == 0) iratio = 1;\ for(k = 0; k < len; k++) {\ buf[k] -= __mn;\ - buf[k] = (__typeof__(buf[0]))((double)buf[k] * oratio / iratio);\ + buf[k] = (__typeof(buf[0]))((double)buf[k] * oratio / iratio);\ buf[k] += _mn;\ }\ }) +#endif +#ifndef dsp_buffer_set /** -* \brief Place the given value on each element of the buffer +* \brief Fill the buffer with the passed value * \param buf the input buffer * \param len the length in elements of the buffer. -* \param val the desired value. +* \param _val the desired value. */ - #define dsp_buffer_set(buf, len, _val)\ ({\ int k;\ for(k = 0; k < len; k++) {\ - buf[k] = (__typeof__(buf[0]))(_val);\ + buf[k] = (__typeof(buf[0]))(_val);\ }\ }) +#endif +#ifndef dsp_buffer_normalize /** * \brief Normalize the input stream to the minimum and maximum values * \param buf the input buffer * \param len the length in elements of the buffer. -* \param min the clamping minimum value. -* \param max the clamping maximum value. +* \param mn the clamping bottom value. +* \param mx the clamping upper value. */ #define dsp_buffer_normalize(buf, len, mn, mx)\ ({\ @@ -598,6 +834,7 @@ DLL_EXPORT void dsp_buffer_removemean(dsp_stream_p stream); buf[k] = Max(mn, Min(mx, buf[k]));\ }\ }) +#endif /** * \brief Subtract elements of one stream from another's @@ -668,21 +905,21 @@ DLL_EXPORT void dsp_buffer_log(dsp_stream_p stream, dsp_t* in, int len); * \param stream the stream on which execute * \param val the value to be subtracted. */ -DLL_EXPORT void dsp_buffer_sub1(dsp_stream_p stream, double val); +DLL_EXPORT void dsp_buffer_sub1(dsp_stream_p stream, dsp_t val); /** * \brief Subtract each element of the input stream a value * \param stream the stream on which execute * \param val the value to be subtracted. */ -DLL_EXPORT void dsp_buffer_1sub(dsp_stream_p stream, double val); +DLL_EXPORT void dsp_buffer_1sub(dsp_stream_p stream, dsp_t val); /** * \brief Sum elements of the input stream to a value * \param stream the stream on which execute * \param val the value used for this operation. */ -DLL_EXPORT void dsp_buffer_sum1(dsp_stream_p stream, double val); +DLL_EXPORT void dsp_buffer_sum1(dsp_stream_p stream, dsp_t val); /** * \brief Divide elements of the input stream to a value @@ -720,13 +957,20 @@ DLL_EXPORT void dsp_buffer_pow1(dsp_stream_p stream, double val); DLL_EXPORT void dsp_buffer_log1(dsp_stream_p stream, double val); /** -* \brief Median elements of the inut stream +* \brief Median elements of the input stream * \param stream the stream on which execute * \param size the length of the median. * \param median the location of the median value. */ DLL_EXPORT void dsp_buffer_median(dsp_stream_p stream, int size, int median); +/** +* \brief Standard deviation of each element of the input stream within the given size +* \param stream the stream on which execute +* \param size the reference size. +*/ +DLL_EXPORT void dsp_buffer_sigma(dsp_stream_p stream, int size); + /** * \brief Deviate forward the first input stream using the second stream as indexing reference * \param stream the stream on which execute @@ -736,17 +980,17 @@ DLL_EXPORT void dsp_buffer_median(dsp_stream_p stream, int size, int median); */ DLL_EXPORT void dsp_buffer_deviate(dsp_stream_p stream, dsp_t* deviation, dsp_t mindeviation, dsp_t maxdeviation); +#ifndef dsp_buffer_reverse /** * \brief Reverse the order of the buffer elements -* \param buf the input stream. -* \param len the length of the first input stream. +* \param buf the inout stream. +* \param len the length of the input stream. */ -#ifndef dsp_buffer_reverse #define dsp_buffer_reverse(buf, len) \ ({ \ int i = (len - 1) / 2; \ int j = i + 1; \ - __typeof__(buf[0]) _x; \ + __typeof(buf[0]) _x; \ while(i >= 0) \ { \ _x = buf[j]; \ @@ -759,26 +1003,28 @@ DLL_EXPORT void dsp_buffer_deviate(dsp_stream_p stream, dsp_t* deviation, dsp_t #endif #ifndef dsp_buffer_swap +/** +* \brief Change the in buffer elements endianness +* \param in the inout stream. +* \param len the length of the input stream. +*/ #define dsp_buffer_swap(in, len) \ ({ \ int k; \ - switch(sizeof(((__typeof__ (in[0])*)in)[0])) { \ + switch(sizeof(((__typeof (in[0])*)in)[0])) { \ case 2: \ for(k = 0; k < len; k++) \ - ((__typeof__ (in[0])*)in)[k] = __bswap_16(((__typeof__ (in[0])*)in)[k]); \ + ((__typeof (in[0])*)in)[k] = __bswap_16(((__typeof (in[0])*)in)[k]); \ break; \ case 3: \ for(k = 0; k < len; k++) \ - ((__typeof__ (in[0])*)in)[k] = __bswap_32(((__typeof__ (in[0])*)in)[k]); \ - break; \ - case 4: \ - for(k = 0; k < len; k++) \ - ((__typeof__ (in[0])*)in)[k] = __bswap_64(((__typeof__ (in[0])*)in)[k]); \ + ((__typeof (in[0])*)in)[k] = __bswap_32(((__typeof (in[0])*)in)[k]); \ break; \ } \ }) #endif +#ifndef dsp_buffer_copy /** * \brief Fill the output buffer with the values of the * elements of the input stream by casting them to the @@ -787,42 +1033,42 @@ DLL_EXPORT void dsp_buffer_deviate(dsp_stream_p stream, dsp_t* deviation, dsp_t * \param out the output stream. * \param len the length of the first input stream. */ -#ifndef dsp_buffer_copy #define dsp_buffer_copy(in, out, len) \ ({ \ int k; \ for(k = 0; k < len; k++) { \ - ((__typeof__ (out[0])*)out)[k] = (__typeof__ (out[0]))((__typeof__ (in[0])*)in)[k]; \ + ((__typeof (out[0])*)out)[k] = (__typeof (out[0]))((__typeof (in[0])*)in)[k]; \ } \ }) #endif +#ifndef dsp_buffer_copy_stepping /** * \brief Fill the output buffer with the values of the * elements of the input stream by casting them to the * output buffer element type * \param in the input stream. * \param out the output stream. -* \param len the length of the first input stream. +* \param inlen the length of the input stream. +* \param outlen the length of the output stream. * \param instep copy each instep elements of in into each outstep elements of out. * \param outstep copy each instep elements of in into each outstep elements of out. */ -#ifndef dsp_buffer_copy_stepping #define dsp_buffer_copy_stepping(in, out, inlen, outlen, instep, outstep) \ ({ \ int k; \ int t; \ for(k = 0, t = 0; k < inlen && t < outlen; k+=instep, t+=outstep) { \ - ((__typeof__ (out[0])*)out)[t] = (__typeof__ (out[0]))((__typeof__ (in[0])*)in)[k]; \ + ((__typeof (out[0])*)out)[t] = (__typeof (out[0]))((__typeof (in[0])*)in)[k]; \ } \ }) #endif -/*@}*/ +/**\}*/ /** * \defgroup dsp_DSPStream DSP API Stream type management functions */ -/*@{*/ +/**\{*/ /** * \brief Allocate a buffer with length len on the stream passed as argument @@ -857,7 +1103,7 @@ DLL_EXPORT void dsp_stream_free_buffer(dsp_stream_p stream); * \return the newly created DSP stream type * \sa dsp_stream_free */ -DLL_EXPORT dsp_stream_p dsp_stream_new(); +DLL_EXPORT dsp_stream_p dsp_stream_new(void); /** * \brief Free the DSP stream passed as argument @@ -874,13 +1120,6 @@ DLL_EXPORT void dsp_stream_free(dsp_stream_p stream); */ DLL_EXPORT dsp_stream_p dsp_stream_copy(dsp_stream_p stream); -/** -* \brief Add a star into the stream struct -* \param stream the target DSP stream. -* \param star the star to add to the stream. -*/ -DLL_EXPORT void dsp_stream_add_star(dsp_stream_p stream, dsp_star star); - /** * \brief Add a child to the DSP Stream passed as argument * \param stream the target DSP stream. @@ -893,29 +1132,55 @@ DLL_EXPORT void dsp_stream_add_child(dsp_stream_p stream, dsp_stream_p child); /** * \brief Add a star to the DSP Stream passed as argument * \param stream the target DSP stream. -* \param child the star to add to DSP stream. +* \param star the star to add to DSP stream. * \sa dsp_stream_new * \sa dsp_stream_del_star */ DLL_EXPORT void dsp_stream_add_star(dsp_stream_p stream, dsp_star star); /** -* \brief Remove the child with index n to a DSP stream +* \brief Remove the star with index n to a DSP stream * \param stream the target DSP stream. -* \param n the index of the child to remove +* \param n the index of the star to remove * \sa dsp_stream_new -* \sa dsp_stream_add_child +* \sa dsp_stream_add_star */ -DLL_EXPORT void dsp_stream_del_child(dsp_stream_p stream, int n); +DLL_EXPORT void dsp_stream_del_star(dsp_stream_p stream, int n); /** -* \brief Remove the star with index n to a DSP stream +* \brief Add a triangle to the DSP Stream passed as argument * \param stream the target DSP stream. -* \param n the index of the star to remove +* \param triangle the triangle to add to DSP stream. * \sa dsp_stream_new -* \sa dsp_stream_add_star +* \sa dsp_stream_del_triangle */ -DLL_EXPORT void dsp_stream_del_star(dsp_stream_p stream, int n); +DLL_EXPORT void dsp_stream_add_triangle(dsp_stream_p stream, dsp_triangle triangle); + +/** +* \brief Remove the triangle with index n to a DSP stream +* \param stream the target DSP stream. +* \param index the index of the triangle to remove +* \sa dsp_stream_new +* \sa dsp_stream_add_triangle +*/ +DLL_EXPORT void dsp_stream_del_triangle(dsp_stream_p stream, int index); + +/** +* \brief Calculate the triangles in the stream struct +* \param stream the target DSP stream. +* \sa dsp_stream_new +* \sa dsp_stream_add_triangle +*/ +DLL_EXPORT void dsp_stream_calc_triangles(dsp_stream_p stream); + +/** +* \brief Remove the child with index n to a DSP stream +* \param stream the target DSP stream. +* \param n the index of the child to remove +* \sa dsp_stream_new +* \sa dsp_stream_add_child +*/ +DLL_EXPORT void dsp_stream_del_child(dsp_stream_p stream, int n); /** * \brief Add a dimension with length len to a DSP stream @@ -926,6 +1191,16 @@ DLL_EXPORT void dsp_stream_del_star(dsp_stream_p stream, int n); */ DLL_EXPORT void dsp_stream_add_dim(dsp_stream_p stream, int len); +/** +* \brief Set a dimension size to a DSP stream +* \param stream the target DSP stream. +* \param dim the index of the dimension to modify +* \param size the size of the dimension to modify +* \sa dsp_stream_new +* \sa dsp_stream_add_dim +*/ +DLL_EXPORT void dsp_stream_set_dim(dsp_stream_p stream, int dim, int size); + /** * \brief Remove the dimension with index n to a DSP stream * \param stream the target DSP stream. @@ -962,6 +1237,7 @@ DLL_EXPORT int* dsp_stream_get_position(dsp_stream_p stream, int index); /** * \brief Execute the function callback pointed by the func field of the passed stream * \param stream the target DSP stream. +* \param args The arguments list to be passed to the callback * \return callback return value * \sa dsp_stream_new * \sa dsp_stream_get_position @@ -971,17 +1247,33 @@ DLL_EXPORT void *dsp_stream_exec(dsp_stream_p stream, void *args, ...); /** * \brief Crop the buffers of the stream passed as argument by reading the ROI field. -* \param stream the target DSP stream. -* \return the cropped DSP stream. -* \sa dsp_stream_new +* \param stream The stream that will be cropped in-place */ DLL_EXPORT void dsp_stream_crop(dsp_stream_p stream); -/*@}*/ +/** +* \brief Rotate a stream around an axis and offset +* \param stream The stream that will be rotated in-place +*/ +DLL_EXPORT void dsp_stream_rotate(dsp_stream_p stream); + +/** +* \brief Translate a stream +* \param stream The stream that will be translated in-place +*/ +DLL_EXPORT void dsp_stream_translate(dsp_stream_p stream); + +/** +* \brief Scale a stream +* \param stream The stream that will be scaled in-place +*/ +DLL_EXPORT void dsp_stream_scale(dsp_stream_p stream); + +/**\}*/ /** * \defgroup dsp_SignalGen DSP API Signal generation functions */ -/*@{*/ +/**\{*/ /** * \brief Generate white noise @@ -1030,78 +1322,37 @@ DLL_EXPORT void dsp_modulation_frequency(dsp_stream_p stream, double samplefreq, */ DLL_EXPORT void dsp_modulation_amplitude(dsp_stream_p stream, double samplefreq, double freq); +/**\}*/ /** -* \brief Find stars into the stream -* \param stream The stream containing stars -* \param levels The level of thresholding -* \param min_size Minimum stellar size -* \param threshold Intensity treshold -* \param matrix The star shape -* \return The new dsp_stream_p structure pointer -*/ -DLL_EXPORT int dsp_align_find_stars(dsp_stream_p stream, int levels, int min_size, float threshold, dsp_stream_p matrix); - -/** -* \brief Limit search area to the radius around the first n stars and store those streams as children of the stream to be aligned -* \param reference The reference solved stream -* \param to_align The stream to be aligned -* \param n Stars count limit -* \param radius The search area -* \return The number of streams cropped and added + * \defgroup dsp_FileManagement DSP API File read/write functions */ -DLL_EXPORT int dsp_align_crop_limit(dsp_stream_p reference, dsp_stream_p to_align, int n, int radius); +/**\{*/ /** -* \brief Find offsets between 2 streams and extract align informations -* \param stream1 The first stream -* \param stream2 The second stream -* \param max_stars The maximum stars count allowed -* \param precision The precision used for comparison -* \param start_star Start compare from the start_star brigher star -* \return The new dsp_align_info structure pointer -*/ -DLL_EXPORT int dsp_align_get_offset(dsp_stream_p stream1, dsp_stream_p stream, int max_stars, int decimals); - -/** -* \brief Rotate a stream around an axis and offset -* \param stream The stream that need rotation -* \param info The dsp_align_info structure pointer containing the rotation informations -* \return The new dsp_stream_p structure pointer -*/ -DLL_EXPORT void dsp_stream_rotate(dsp_stream_p stream); - -/** -* \brief Traslate a stream -* \param stream The stream that need traslation -* \param info The dsp_align_info structure pointer containing the traslation informations -* \return The new dsp_stream_p structure pointer -*/ -DLL_EXPORT void dsp_stream_traslate(dsp_stream_p stream); - -/** -* \brief Scale a stream -* \param stream The stream that need scaling -* \param info The dsp_align_info structure pointer containing the scaling informations +* \brief Read a FITS file and fill a dsp_stream_p with its content +* \param filename the file name. +* \param channels will be filled with the number of components +* \param stretch 1 if the buffer intensities have to be stretched * \return The new dsp_stream_p structure pointer */ -DLL_EXPORT void dsp_stream_scale(dsp_stream_p stream); +DLL_EXPORT dsp_stream_p* dsp_file_read_fits(const char* filename, int *channels, int stretch); /** -* \brief Read a FITS file and fill a dsp_stream_p with its content +* \brief Write the dsp_stream_p into a FITS file, * \param filename the file name. -* \param stretch 1 if the buffer intensities have to be stretched -* \return The new dsp_stream_p structure pointer +* \param bpp the bit depth of the output FITS file. +* \param stream the input stream to be saved */ -DLL_EXPORT dsp_stream_p* dsp_file_read_fits(char *filename, int *channels, int stretch); +DLL_EXPORT void dsp_file_write_fits(const char* filename, int bpp, dsp_stream_p stream); /** -* \brief Write the components dsp_stream_p array into a FITS file, +* \brief Write the components dsp_stream_p array into a JPEG file, * \param filename the file name. * \param components the number of streams in the array to be used as components 1 or 3. * \param bpp the bit depth of the output JPEG file [8,16,32,64,-32,-64]. * \param stream the input stream to be saved */ -DLL_EXPORT void* dsp_file_write_fits(int bpp, size_t* memsize, dsp_stream_p stream); +DLL_EXPORT void dsp_file_write_fits_composite(const char* filename, int components, int bpp, dsp_stream_p* stream); /** * \brief Read a JPEG file and fill a array of dsp_stream_p with its content, @@ -1111,7 +1362,15 @@ DLL_EXPORT void* dsp_file_write_fits(int bpp, size_t* memsize, dsp_stream_p stre * \param stretch 1 if the buffer intensities have to be stretched * \return The new dsp_stream_p structure pointers array */ -DLL_EXPORT dsp_stream_p* dsp_file_read_jpeg(char *filename, int *channels, int stretch); +DLL_EXPORT dsp_stream_p* dsp_file_read_jpeg(const char* filename, int *channels, int stretch); + +/** +* \brief Write the stream into a JPEG file, +* \param filename the file name. +* \param quality the quality of the output JPEG file 0-100. +* \param stream the input stream to be saved +*/ +DLL_EXPORT void dsp_file_write_jpeg(const char* filename, int quality, dsp_stream_p stream); /** * \brief Write the components dsp_stream_p array into a JPEG file, @@ -1120,14 +1379,132 @@ DLL_EXPORT dsp_stream_p* dsp_file_read_jpeg(char *filename, int *channels, int s * \param quality the quality of the output JPEG file 0-100. * \param stream the input stream to be saved */ -DLL_EXPORT void dsp_file_write_jpeg_composite(char *filename, int components, int quality, dsp_stream_p* stream); +DLL_EXPORT void dsp_file_write_jpeg_composite(const char* filename, int components, int quality, dsp_stream_p* stream); +/** +* \brief Convert a bayer pattern dsp_t array into a grayscale array +* \param src the input buffer +* \param width the picture width +* \param height the picture height +* \return The new dsp_t array +*/ +DLL_EXPORT dsp_t* dsp_file_bayer_2_gray(dsp_t* src, int width, int height); + +/** +* \brief Convert a bayer pattern dsp_t array into a ordered 3 RGB array +* \param src the input buffer +* \param red the location of the red pixel within the bayer pattern +* \param width the picture width +* \param height the picture height +* \return The new dsp_t array +*/ +DLL_EXPORT dsp_t* dsp_file_bayer_2_rgb(dsp_t *src, int red, int width, int height); + +/** +* \brief Convert a color component dsp_t array into a dsp_stream_p array each element containing the single components +* \param buf the input buffer +* \param dims the number of dimension +* \param sizes the sizes of each dimension +* \param components the number of the color components +* \return The new dsp_stream_p array +*/ DLL_EXPORT dsp_stream_p *dsp_stream_from_components(dsp_t* buf, int dims, int *sizes, int components); + +/** +* \brief Convert an RGB color dsp_t array into a dsp_stream_p array each element containing the single components +* \param buf the input buffer +* \param dims the number of dimension +* \param sizes the sizes of each dimension +* \param components the number of the color components +* \param bpp the color depth of the color components +* \param stretch whether to stretch within 0 and dsp_t_max +* \return The new dsp_stream_p array +*/ DLL_EXPORT dsp_stream_p *dsp_buffer_rgb_to_components(void* buf, int dims, int *sizes, int components, int bpp, int stretch); + +/** +* \brief Convert a component dsp_stream_p array into an RGB dsp_t array +* \param stream the component dsp_stream_p array +* \param rgb the output buffer +* \param components the number of the color components +* \param bpp the color depth of the color components +*/ DLL_EXPORT void dsp_buffer_components_to_rgb(dsp_stream_p *stream, void* rgb, int components, int bpp); -/*@}*/ -/*@}*/ +/** +* \brief Convert a component dsp_stream_p array into a bayer dsp_t array +* \param src the component dsp_stream_p array +* \param red the red offset within the bayer quad +* \param width the width of the output array +* \param height the height of the output array +* \return The new dsp_stream_p array +*/ +DLL_EXPORT dsp_t* dsp_file_composite_2_bayer(dsp_stream_p *src, int red, int width, int height); + +/** +* \brief Write a FITS file from a dsp_stream_p array +* \param filename the output file name +* \param components the number of the color components +* \param bpp the color depth of the color components +* \param stream the component dsp_stream_p array +*/ +DLL_EXPORT void dsp_file_write_fits_bayer(const char* filename, int components, int bpp, dsp_stream_p* stream); + +/** +* \brief Convert a bayer pattern dsp_t array into a contiguos component array +* \param src the input buffer +* \param red the location of the red pixel within the bayer pattern +* \param width the picture width +* \param height the picture height +* \return The new dsp_t array +*/ +DLL_EXPORT dsp_t* dsp_file_bayer_2_composite(dsp_t *src, int red, int width, int height); + +/** +* \brief Calculate offsets, rotation and scaling of two streams giving reference alignment point +* \param ref the reference stream +* \param to_align the stream to be aligned +* \param tolerance number of decimals allowed +* \param target_score the minimum matching score to reach +* \return The alignment mask (bit1: translated, bit2: scaled, bit3: rotated) +*/ +DLL_EXPORT int dsp_align_get_offset(dsp_stream_p ref, dsp_stream_p to_align, double tolerance, double target_score); + +/** +* \brief Callback function for qsort for double type ascending ordering +* \param arg1 the first comparison element +* \param arg2 the second comparison element +* \return 1 if arg1 is greater than arg2, -1 if arg2 is greater than arg1 +*/ +DLL_EXPORT int dsp_qsort_double_asc (const void *arg1, const void *arg2); + +/** +* \brief Callback function for qsort for double type descending ordering +* \param arg1 the first comparison element +* \param arg2 the second comparison element +* \return 1 if arg2 is greater than arg1, -1 if arg1 is greater than arg2 +*/ +DLL_EXPORT int dsp_qsort_double_desc (const void *arg1, const void *arg2); + +/** +* \brief Callback function for qsort for dsp_star ascending ordering by their diameters +* \param arg1 the first comparison element +* \param arg2 the second comparison element +* \return 1 if arg1 diameter is greater than arg2, -1 if arg2 diameter is greater than arg1 +*/ +DLL_EXPORT int dsp_qsort_star_diameter_asc (const void *arg1, const void *arg2); + +/** +* \brief Callback function for qsort for dsp_star descending ordering by their diameters +* \param arg1 the first comparison element +* \param arg2 the second comparison element +* \return 1 if arg2 diameter is greater than arg1, -1 if arg1 diameter is greater than arg2 +*/ +DLL_EXPORT int dsp_qsort_star_diameter_desc (const void *arg1, const void *arg2); + +/**\}*/ +/// \defgroup dsp_FitsExtensions +#include #ifdef __cplusplus } diff --git a/libs/dsp/fft.c b/libs/dsp/fft.c index 1ec2a9ff46..a386d52820 100755 --- a/libs/dsp/fft.c +++ b/libs/dsp/fft.c @@ -1,90 +1,206 @@ /* - * libDSPAU - a digital signal processing library for astronoms usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" #include -double dsp_fourier_complex_get_magnitude(dsp_complex n) +static void dsp_fourier_dft_magnitude(dsp_stream_p stream) { - return sqrt (n.real * n.real + n.imaginary * n.imaginary); + if(stream == NULL) + return; + if(stream->magnitude) + stream->magnitude->buf = dsp_fourier_complex_array_get_magnitude(stream->dft, stream->len); } -double dsp_fourier_complex_get_phase(dsp_complex n) +static void dsp_fourier_dft_phase(dsp_stream_p stream) { - double out = 0; - if (n.real != 0) { - out = atan (n.imaginary / n.real); + if(stream == NULL) + return; + if(stream->phase) + stream->phase->buf = dsp_fourier_complex_array_get_phase(stream->dft, stream->len); +} + +void dsp_fourier_2dsp(dsp_stream_p stream) +{ + if(stream == NULL) + return; + int x, y; + fftw_complex *dft = (fftw_complex*)malloc(sizeof(fftw_complex) * stream->len); + memcpy(dft, stream->dft.fftw, sizeof(fftw_complex) * stream->len); + y = 0; + for(x = 0; x < stream->len && y < stream->len; x++) { + int *pos = dsp_stream_get_position(stream, x); + if(pos[0] <= stream->sizes[0] / 2) { + stream->dft.fftw[x][0] = dft[y][0]; + stream->dft.fftw[x][1] = dft[y][1]; + stream->dft.fftw[stream->len-1-x][0] = dft[y][0]; + stream->dft.fftw[stream->len-1-x][1] = dft[y][1]; + y++; + } + free(pos); + } + dsp_fourier_dft_magnitude(stream); + dsp_buffer_shift(stream->magnitude); + dsp_fourier_dft_phase(stream); + dsp_buffer_shift(stream->phase); +} + +void dsp_fourier_2fftw(dsp_stream_p stream) +{ + if(stream == NULL) + return; + int x, y; + if(!stream->phase || !stream->magnitude) return; + dsp_buffer_shift(stream->magnitude); + dsp_buffer_shift(stream->phase); + stream->dft = dsp_fourier_phase_mag_array_get_complex(stream->magnitude->buf, stream->phase->buf, stream->len); + fftw_complex *dft = (fftw_complex*)malloc(sizeof(fftw_complex) * stream->len); + memcpy(dft, stream->dft.fftw, sizeof(fftw_complex) * stream->len); + dsp_buffer_set(stream->dft.buf, stream->len*2, 0); + y = 0; + for(x = 0; x < stream->len; x++) { + int *pos = dsp_stream_get_position(stream, x); + if(pos[0] <= stream->sizes[0] / 2) { + stream->dft.fftw[y][0] = dft[x][0]; + stream->dft.fftw[y][1] = dft[x][1]; + y++; + } + free(pos); } - return out; } -double* dsp_fourier_complex_array_get_magnitude(dsp_complex* in, int len) +double* dsp_fourier_complex_array_get_magnitude(dsp_complex in, int len) { int i; double* out = (double*)malloc(sizeof(double) * len); for(i = 0; i < len; i++) { - out [i] = (double)dsp_fourier_complex_get_magnitude(in [i]); + double real = in.complex[i].real; + double imaginary = in.complex[i].imaginary; + out [i] = sqrt (pow(real, 2)+pow(imaginary, 2)); } return out; } -double* dsp_fourier_complex_array_get_phase(dsp_complex* in, int len) +double* dsp_fourier_complex_array_get_phase(dsp_complex in, int len) { int i; double* out = (double*)malloc(sizeof(double) * len); for(i = 0; i < len; i++) { - out [i] = (double)dsp_fourier_complex_get_phase(in [i]); + out [i] = 0; + if (in.complex[i].real != 0) { + double real = in.complex[i].real; + double imaginary = in.complex[i].imaginary; + double mag = sqrt(pow(real, 2)+pow(imaginary, 2)); + double rad = 0.0; + if(mag > 0.0) { + rad = acos (imaginary / (mag > 0.0 ? mag : 1.0)); + if(real < 0 && rad != 0) + rad = M_PI*2-rad; + } + out [i] = rad; + } + } + return out; +} + +dsp_complex dsp_fourier_phase_mag_array_get_complex(double* mag, double* phi, int len) +{ + int i; + dsp_complex out; + out.fftw = (fftw_complex*)malloc(sizeof(fftw_complex) * len); + dsp_buffer_set(out.buf, len*2, 0); + for(i = 0; i < len; i++) { + double real = sin(phi[i])*mag[i]; + double imaginary = cos(phi[i])*mag[i]; + out.complex[i].real = real; + out.complex[i].imaginary = imaginary; } return out; } -dsp_complex* dsp_fourier_dft(dsp_stream_p stream) +static void* dsp_stream_dft_th(void* arg) { - double* dft = (double*)malloc(sizeof(double) * stream->len); - dsp_complex* out = (dsp_complex*)malloc(sizeof(dsp_complex) * stream->len); - dsp_buffer_copy(stream->buf, dft, stream->len); + struct { + int exp; + dsp_stream_p stream; + } *arguments = arg; + dsp_fourier_dft(arguments->stream, arguments->exp); + return NULL; +} +void dsp_fourier_dft(dsp_stream_p stream, int exp) +{ + if(stream == NULL) + return; + if(exp < 1) + return; + double* buf = (double*)malloc(sizeof(double) * stream->len); + if(stream->phase == NULL) + stream->phase = dsp_stream_copy(stream); + if(stream->magnitude == NULL) + stream->magnitude = dsp_stream_copy(stream); + dsp_buffer_set(stream->dft.buf, stream->len * 2, 0); + dsp_buffer_copy(stream->buf, buf, stream->len); int *sizes = (int*)malloc(sizeof(int)*stream->dims); - memcpy (sizes, stream->sizes, sizeof(int)*stream->dims); dsp_buffer_reverse(sizes, stream->dims); - fftw_plan plan = fftw_plan_dft_r2c(stream->dims, sizes, dft, (fftw_complex*)out, FFTW_ESTIMATE); + fftw_plan plan = fftw_plan_dft_r2c(stream->dims, stream->sizes, buf, stream->dft.fftw, FFTW_ESTIMATE_PATIENT); fftw_execute(plan); fftw_free(plan); - fftw_free(dft); - return out; + free(sizes); + free(buf); + dsp_fourier_2dsp(stream); + if(exp > 1) { + exp--; + pthread_t th[2]; + struct { + int exp; + dsp_stream_p stream; + } thread_arguments[2]; + thread_arguments[0].exp = exp; + thread_arguments[0].stream = stream->phase; + pthread_create(&th[0], NULL, dsp_stream_dft_th, &thread_arguments[0]); + thread_arguments[1].exp = exp; + thread_arguments[1].stream = stream->magnitude; + pthread_create(&th[1], NULL, dsp_stream_dft_th, &thread_arguments[1]); + pthread_join(th[0], NULL); + pthread_join(th[1], NULL); + } } -dsp_t* dsp_fourier_idft(dsp_stream_p stream) +void dsp_fourier_idft(dsp_stream_p stream) { - dsp_complex* dft = (dsp_complex*)malloc(sizeof(dsp_complex) * stream->len); - double* out = (double*)malloc(sizeof(double) * stream->len); - int x; - for (x=0; xlen; x++) { - dft[x].real = stream->buf[x]; - dft[x].imaginary = stream->buf[x]; - } + if(stream == NULL) + return; + double *buf = (double*)malloc(sizeof(double)*stream->len); + dsp_t mn = dsp_stats_min(stream->buf, stream->len); + dsp_t mx = dsp_stats_max(stream->buf, stream->len); + dsp_buffer_set(buf, stream->len, 0); + free(stream->dft.buf); + dsp_fourier_2fftw(stream); int *sizes = (int*)malloc(sizeof(int)*stream->dims); - memcpy (sizes, stream->sizes, sizeof(int)*stream->dims); dsp_buffer_reverse(sizes, stream->dims); - fftw_plan plan = fftw_plan_dft_c2r(stream->dims, sizes, (fftw_complex*)dft, out, FFTW_ESTIMATE); + fftw_plan plan = fftw_plan_dft_c2r(stream->dims, stream->sizes, stream->dft.fftw, buf, FFTW_ESTIMATE_PATIENT); fftw_execute(plan); - dsp_buffer_copy(out, stream->buf, stream->len); fftw_free(plan); - free(dft); - free(out); - return stream->buf; + free(sizes); + dsp_buffer_stretch(buf, stream->len, mn, mx); + dsp_buffer_copy(buf, stream->buf, stream->len); + dsp_buffer_shift(stream->magnitude); + dsp_buffer_shift(stream->phase); + free(buf); } diff --git a/libs/dsp/file.c b/libs/dsp/file.c index 0f63c827cb..271d4057d6 100644 --- a/libs/dsp/file.c +++ b/libs/dsp/file.c @@ -1,20 +1,21 @@ /* - * libDSPAU - a digital signal processing library for astronoms usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" #include @@ -23,17 +24,16 @@ #include #include -dsp_stream_p* dsp_file_read_fits(char *filename, int *channels, int stretch) +dsp_stream_p* dsp_file_read_fits(const char* filename, int *channels, int stretch) { - fitsfile *fptr = (fitsfile*)malloc(sizeof(fitsfile)); - memset(fptr, 0, sizeof(fitsfile)); + fitsfile *fptr; int bpp = 16; int status = 0; char value[150]; char comment[150]; char error_status[64]; - fits_open_file(&fptr, filename, READONLY_FILE, &status); + fits_open_file(&fptr, filename, READONLY, &status); if (status) { @@ -53,14 +53,14 @@ dsp_stream_p* dsp_file_read_fits(char *filename, int *channels, int stretch) { goto fail; } - + bpp = fmax(16, bpp); int dim, nelements = 1; for(dim = 0; dim < dims; dim++) { nelements *= naxes[dim]; } - void *array = malloc((unsigned int)(abs(bpp) * nelements / 8)); + void *array = malloc(((size_t)abs(bpp) * nelements / 8)); int anynul = 0; - dsp_t* buf = (dsp_t*)malloc(sizeof(dsp_t)*(unsigned int)nelements); + dsp_t* buf = (dsp_t*)malloc(sizeof(dsp_t)*(size_t)(nelements+1)); switch(bpp) { case BYTE_IMG: fits_read_img(fptr, TBYTE, 1, (long)nelements, NULL, array, &anynul, &status); @@ -69,43 +69,43 @@ dsp_stream_p* dsp_file_read_fits(char *filename, int *channels, int stretch) break; case SHORT_IMG: fits_read_img(fptr, TUSHORT, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) - dsp_buffer_stretch(((short*)(array)), (long)nelements, 0, dsp_t_max); - dsp_buffer_copy(((short*)array), buf, nelements); + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) + dsp_buffer_stretch(((unsigned short*)(array)), (long)nelements, 0, dsp_t_max); + dsp_buffer_copy(((unsigned short*)array), buf, nelements); break; case USHORT_IMG: fits_read_img(fptr, TUSHORT, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((unsigned short*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((unsigned short*)array), buf, nelements); break; case LONG_IMG: fits_read_img(fptr, TULONG, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((int*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((int*)array), buf, nelements); break; case ULONG_IMG: fits_read_img(fptr, TULONG, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((unsigned int*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((unsigned int*)array), buf, nelements); break; case LONGLONG_IMG: fits_read_img(fptr, TLONGLONG, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((long*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((long*)array), buf, nelements); break; case FLOAT_IMG: fits_read_img(fptr, TFLOAT, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((float*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((float*)array), buf, nelements); break; case DOUBLE_IMG: fits_read_img(fptr, TDOUBLE, 1, (long)nelements, NULL, array, &anynul, &status); - if(abs(bpp) > 8*(int)sizeof(dsp_t)) + if((size_t)abs(bpp) > 8*sizeof(dsp_t)) dsp_buffer_stretch(((double*)(array)), (long)nelements, 0, dsp_t_max); dsp_buffer_copy(((double*)array), buf, nelements); break; @@ -113,53 +113,69 @@ dsp_stream_p* dsp_file_read_fits(char *filename, int *channels, int stretch) free(array); if(status||anynul) goto fail; - if(stretch) - dsp_buffer_stretch(buf, nelements, 0, dsp_t_max); - int red = -1; ffgkey(fptr, "XBAYROFF", value, comment, &status); if (!status) { red = atoi(value); } - + status = 0; ffgkey(fptr, "YBAYROFF", value, comment, &status); if (!status) { red |= atoi(value)<<1; } + status = 0; fits_close_file(fptr, &status); if(status) goto fail; - int sizes[3] = { (int)naxes[0], (int)naxes[1], (int)naxes[2] }; - *channels = (int)naxes[2]; - return dsp_stream_from_components(buf, dims, sizes, sizes[2]); + dsp_stream_p* stream; + int x; + void* rgb = NULL; + int sizes[2] = { naxes[0], naxes[1] }; + if(red > -1) { + *channels = 3; + rgb = dsp_file_bayer_2_rgb(buf, red, naxes[0], naxes[1]); + stream = dsp_buffer_rgb_to_components(rgb, dims, sizes, *channels, 32, 0); + } else { + *channels = naxes[2]; + dims = 2; + stream = dsp_stream_from_components(buf, dims, sizes, *channels); + } + free(buf); + if(stream) { + if(stretch) { + for (x = 0; x < *channels; x++) { + dsp_buffer_pow1(stream[x], 0.5); + dsp_buffer_stretch(stream[x]->buf, stream[x]->len, 0, dsp_t_max); + } + } + return stream; + } fail: if(status) { - fits_report_error(stderr, status); /* print out any error messages */ fits_get_errstatus(status, error_status); - fprintf(stderr, "FITS Error: %s\n", error_status); + perr("FITS Error: %s\n", error_status); } return NULL; } -void* dsp_file_write_fits(int bpp, size_t* memsize, dsp_stream_p stream) +void dsp_file_write_fits(const char* filename, int bpp, dsp_stream_p stream) { dsp_stream_p tmp = dsp_stream_copy(stream); int img_type = USHORT_IMG; int byte_type = TUSHORT; char bit_depth[64] = "16 bits per sample"; - void* buf = malloc((unsigned int)(tmp->len * abs(bpp) / 8 + 512)); - void *memfile = NULL; + void* buf = malloc((size_t)(tmp->len * (size_t)abs(bpp) / 8 + 512)); int status = 0; int naxis = tmp->dims; - long *naxes = (long*)malloc(sizeof(long) * (unsigned int)tmp->dims); + long *naxes = (long*)malloc(sizeof(long) * (size_t)tmp->dims); long nelements = tmp->len; char error_status[64]; - unsigned int i; - - for (i = 0; i < (unsigned int)tmp->dims; i++) + int i; + dsp_buffer_stretch(tmp->buf, tmp->len, 0, dsp_t_max); + for (i = 0; i < tmp->dims; i++) naxes[i] = tmp->sizes[i]; switch (bpp) { @@ -206,14 +222,13 @@ void* dsp_file_write_fits(int bpp, size_t* memsize, dsp_stream_p stream) break; default: - fprintf(stderr, "Unsupported bits per sample value %d", bpp); + perr("Unsupported bits per sample value %d", bpp); goto fail; } - fitsfile *fptr = NULL; - size_t len = 5760; - memfile = malloc(len); - fits_create_memfile(&fptr, &memfile, &len, 2880, realloc, &status); + unlink(filename); + fitsfile *fptr; + fits_create_file(&fptr, filename, &status); if (status) { @@ -236,28 +251,271 @@ void* dsp_file_write_fits(int bpp, size_t* memsize, dsp_stream_p stream) fits_close_file(fptr, &status); - *memsize = len; - fail_fptr: if(status) { - fits_report_error(stderr, status); fits_get_errstatus(status, error_status); - fprintf(stderr, "FITS Error: %s\n", error_status); - free(memfile); + perr("FITS Error: %s\n", error_status); } fail: dsp_stream_free_buffer(tmp); dsp_stream_free(tmp); free(naxes); - free(buf); - return memfile; + free (buf); } -dsp_stream_p* dsp_file_read_jpeg(char *filename, int *channels, int stretch) +void dsp_file_write_fits_composite(const char* filename, int components, int bpp, dsp_stream_p* stream) +{ + int x; + dsp_stream_p tmp = stream[components]; + int img_type = USHORT_IMG; + int byte_type = TUSHORT; + char bit_depth[64] = "16 bits per sample"; + void* buf = malloc((size_t)(tmp->len * components * (size_t)abs(bpp) / 8 + 512)); + int status = 0; + int naxis = tmp->dims + 1; + long *naxes = (long*)malloc(sizeof(long) * (size_t)(tmp->dims + 1)); + long nelements = tmp->len * components; + char error_status[64]; + int i; + for (i = 0; i < tmp->dims; i++) + naxes[i] = tmp->sizes[i]; + naxes[i] = components; + dsp_t max = (1<<(size_t)abs(bpp))/2-1; + for(x = 0; x < components; x++) { + tmp = dsp_stream_copy(stream[x]); + dsp_buffer_stretch(tmp->buf, tmp->len, 0, (dsp_t)max); + switch (bpp) + { + case 8: + byte_type = TBYTE; + img_type = BYTE_IMG; + dsp_buffer_copy(tmp->buf, ((unsigned char*)&((unsigned char*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "8 bits unsigned integer per sample"); + break; + + case 16: + byte_type = TUSHORT; + img_type = USHORT_IMG; + dsp_buffer_copy(tmp->buf, ((unsigned short*)&((unsigned short*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "16 bits unsigned integer per sample"); + break; + + case 32: + byte_type = TULONG; + img_type = ULONG_IMG; + dsp_buffer_copy(tmp->buf, ((unsigned int*)&((unsigned int*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "32 bits unsigned integer per sample"); + break; + + case 64: + byte_type = TLONGLONG; + img_type = LONGLONG_IMG; + dsp_buffer_copy(tmp->buf, ((unsigned long*)&((unsigned long*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "64 bits unsigned integer per sample"); + break; + + case -32: + byte_type = TFLOAT; + img_type = FLOAT_IMG; + dsp_buffer_copy(tmp->buf, ((float*)&((float*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "32 bits floating point per sample"); + break; + + case -64: + byte_type = TDOUBLE; + img_type = DOUBLE_IMG; + dsp_buffer_copy(tmp->buf, ((double*)&((double*)buf)[tmp->len*x]), tmp->len); + strcpy(bit_depth, "64 bits floating point per sample"); + break; + + default: + perr("Unsupported bits per sample value %d", bpp); + break; + } + dsp_stream_free_buffer(tmp); + dsp_stream_free(tmp); + } + + unlink(filename); + fitsfile *fptr; + fits_create_file(&fptr, filename, &status); + + if (status) + { + goto fail_fptr; + } + + fits_create_img(fptr, img_type, naxis, naxes, &status); + + if (status) + { + goto fail_fptr; + } + + fits_write_img(fptr, byte_type, 1, nelements, buf, &status); + + if (status) + { + goto fail_fptr; + } + + fits_close_file(fptr, &status); + +fail_fptr: + if(status) { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s\n", error_status); + } + free(naxes); + free (buf); +} + + +void dsp_file_write_fits_bayer(const char* filename, int components, int bpp, dsp_stream_p* stream) +{ + int red = 0; + int x; + dsp_stream_p tmp = dsp_stream_copy(stream[components]); + int img_type = USHORT_IMG; + int byte_type = TUSHORT; + char bit_depth[64] = "16 bits per sample"; + int len = tmp->len; + void* data = malloc((size_t)(len * (size_t)abs(bpp) / 8 + 512)); + int status = 0; + int naxis = tmp->dims; + long *naxes = (long*)malloc(sizeof(long) * (size_t)(tmp->dims)); + long nelements = tmp->len; + char error_status[64]; + int i; + for (i = 0; i < tmp->dims; i++) + naxes[i] = tmp->sizes[i]; + dsp_t *buf = dsp_file_composite_2_bayer(stream, red, tmp->sizes[0], tmp->sizes[1]); + dsp_stream_free_buffer(tmp); + dsp_stream_free(tmp); + for(x = 0; x < components; x++) { + dsp_buffer_stretch(buf, stream[components]->len, 0, (dsp_t)(1<<(size_t)abs(bpp))-1); + switch (bpp) + { + case 8: + byte_type = TBYTE; + img_type = BYTE_IMG; + dsp_buffer_copy(buf, ((unsigned char*)((unsigned char*)data)), stream[components]->len); + strcpy(bit_depth, "8 bits unsigned integer per sample"); + break; + + case 16: + byte_type = TUSHORT; + img_type = USHORT_IMG; + dsp_buffer_copy(buf, ((unsigned short*)((unsigned short*)data)), stream[components]->len); + strcpy(bit_depth, "16 bits unsigned integer per sample"); + break; + + case 32: + byte_type = TULONG; + img_type = ULONG_IMG; + dsp_buffer_copy(buf, ((unsigned int*)((unsigned int*)data)), stream[components]->len); + strcpy(bit_depth, "32 bits unsigned integer per sample"); + break; + + case 64: + byte_type = TLONGLONG; + img_type = LONGLONG_IMG; + dsp_buffer_copy(buf, ((unsigned long*)((unsigned long*)data)), stream[components]->len); + strcpy(bit_depth, "64 bits unsigned integer per sample"); + break; + + case -32: + byte_type = TFLOAT; + img_type = FLOAT_IMG; + dsp_buffer_copy(buf, ((float*)((float*)data)), stream[components]->len); + strcpy(bit_depth, "32 bits floating point per sample"); + break; + + case -64: + byte_type = TDOUBLE; + img_type = DOUBLE_IMG; + dsp_buffer_copy(buf, ((double*)((double*)data)), stream[components]->len); + strcpy(bit_depth, "64 bits floating point per sample"); + break; + + default: + perr("Unsupported bits per sample value %d", bpp); + break; + } + } + + unlink(filename); + fitsfile *fptr; + status = 0; + fits_create_file(&fptr, filename, &status); + + if (status) + { + goto fail_fptr; + } + + fits_create_img(fptr, img_type, naxis, naxes, &status); + + if (status) + { + goto fail_fptr; + } + + int redx = red&1; + int redy = (red>>1)&1; + + fits_write_key(fptr, TINT, "XBAYROFF", &redx, "X Bayer Offset", &status); + if (status) + { + goto fail_fptr; + } + + fits_write_key(fptr, TINT, "YBAYROFF", &redy, "Y Bayer Offset", &status); + if (status) + { + goto fail_fptr; + } + switch (red) { + case 0: + fits_write_key(fptr, TSTRING, "BAYERPAT", "RGGB", "Y Bayer Offset", &status); + break; + case 1: + fits_write_key(fptr, TSTRING, "BAYERPAT", "GRGB", "Y Bayer Offset", &status); + break; + case 2: + fits_write_key(fptr, TSTRING, "BAYERPAT", "GBRG", "Y Bayer Offset", &status); + break; + case 3: + fits_write_key(fptr, TSTRING, "BAYERPAT", "BGGR", "Y Bayer Offset", &status); + break; + } + if (status) + { + goto fail_fptr; + } + + fits_write_img(fptr, byte_type, 1, nelements, data, &status); + + if (status) + { + goto fail_fptr; + } + + fits_close_file(fptr, &status); + +fail_fptr: + if(status) { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s\n", error_status); + } + free(naxes); + free (data); +} +dsp_stream_p* dsp_file_read_jpeg(const char* filename, int *channels, int stretch) { int width, height; - unsigned int components; - unsigned int bpp = 8; + int components; + int bpp = 8; unsigned char * buf; struct jpeg_decompress_struct info; struct jpeg_error_mgr err; @@ -275,29 +533,80 @@ dsp_stream_p* dsp_file_read_jpeg(char *filename, int *channels, int stretch) jpeg_start_decompress(&info); width = (int)info.output_width; height = (int)info.output_height; - components = (unsigned int)info.num_components; + components = (int)info.num_components; - int row_stride = (int)components * (int)width; - buf = (unsigned char *)malloc((unsigned int)(width * height) * components); + int row_stride = (components * width); + buf = (unsigned char *)malloc((size_t)(width * height * components)); unsigned char *image = buf; - unsigned int row; - for (row = 0; row < (unsigned int)height; row++) + int row; + for (row = 0; row < height; row++) { jpeg_read_scanlines(&info, &image, 1); image += row_stride; } jpeg_finish_decompress(&info); - *channels = (int)components; - return dsp_buffer_rgb_to_components(buf, 2, (int[]){width, height}, (int)components, (int)bpp, stretch); + *channels = components; + return dsp_buffer_rgb_to_components(buf, 2, (int[]){width, height}, components, bpp, stretch); } -void dsp_file_write_jpeg_composite(char *filename, int components, int quality, dsp_stream_p* stream) +void dsp_file_write_jpeg(const char* filename, int quality, dsp_stream_p stream) +{ + int width = stream->sizes[0]; + int height = stream->sizes[1]; + int components = (stream->red>=0) ? 3 : 1; + void *buf = malloc((size_t)(stream->len*(stream->red>=0?3:1))); + unsigned char *image = (unsigned char *)buf; + dsp_t* data = stream->buf; + + if(components > 1) + data = dsp_file_bayer_2_rgb(stream->buf, stream->red, width, height); + dsp_buffer_stretch(data, stream->len*(stream->red>=0?3:1), 0, 255); + dsp_buffer_copy(data, image, stream->len*(stream->red>=0?3:1)); + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE * outfile; + int row_stride; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + if ((outfile = fopen(filename, "wb")) == NULL) { + perr("can't open %s\n", filename); + return; + } + jpeg_stdio_dest(&cinfo, outfile); + cinfo.image_width = (unsigned int)width; + cinfo.image_height = (unsigned int)height; + cinfo.in_color_space = (components == 1 ? JCS_GRAYSCALE : JCS_RGB); + cinfo.input_components = components; + jpeg_set_defaults(&cinfo); + cinfo.dct_method = JDCT_FLOAT; + cinfo.optimize_coding = TRUE; + cinfo.restart_in_rows = 1; + + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + row_stride = width * (stream->red>=0?3:1); + + int row; + for (row = 0; row < height; row++) + { + jpeg_write_scanlines(&cinfo, &image, 1); + image += row_stride; + } + + free(buf); + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); +} + +void dsp_file_write_jpeg_composite(const char* filename, int components, int quality, dsp_stream_p* stream) { int bpp = 8; unsigned int row_stride; - unsigned int width = (unsigned int)stream[0]->sizes[0]; - unsigned int height = (unsigned int)stream[0]->sizes[1]; - void *buf = malloc((unsigned int)(stream[0]->len*components*bpp/8)); + int width = stream[components]->sizes[0]; + int height = stream[components]->sizes[1]; + void *buf = malloc((size_t)(stream[components]->len*components)); unsigned char *image = (unsigned char *)buf; dsp_buffer_components_to_rgb(stream, buf, components, bpp); @@ -305,26 +614,26 @@ void dsp_file_write_jpeg_composite(char *filename, int components, int quality, struct jpeg_error_mgr jerr; FILE * outfile; cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); if ((outfile = fopen(filename, "wb")) == NULL) { - fprintf(stderr, "can't open %s\n", filename); + perr("can't open %s\n", filename); return; } + jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); - cinfo.image_width = width; - cinfo.image_height = height; + cinfo.image_width = (unsigned int)width; + cinfo.image_height = (unsigned int)height; cinfo.in_color_space = (components == 1 ? JCS_GRAYSCALE : JCS_RGB); cinfo.input_components = components; - jpeg_set_defaults(&cinfo); cinfo.dct_method = JDCT_FLOAT; cinfo.optimize_coding = TRUE; cinfo.restart_in_rows = 1; + jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); - row_stride = width * (unsigned int)components; + row_stride = (unsigned int)width * (unsigned int)components; int row; - for (row = 0; row < (int)height; row++) + for (row = 0; row < height; row++) { jpeg_write_scanlines(&cinfo, &image, 1); image += row_stride; @@ -336,10 +645,402 @@ void dsp_file_write_jpeg_composite(char *filename, int components, int quality, free(buf); } +dsp_t* dsp_file_bayer_2_gray(dsp_t *src, int width, int height) +{ + int i; + dsp_t *rawpt, *scanpt; + int size; + + dsp_t * dst = (dsp_t*)malloc(sizeof(dsp_t)*(size_t)(width*height)); + rawpt = src; + scanpt = dst; + size = width * height; + dsp_t val = 0; + for (i = 0; i < size; i++) + { + if ((i / width) % 2 == 0) + { + if ((i % 2) == 0) + { + /* B */ + if ((i > width) && ((i % width) > 0)) + { + val = + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* R */ + val += (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + width) + *(rawpt - width)) / 4; /* G */ + val += *rawpt; /* B */ + } + else + { + val = *(rawpt + width + 1); /* R */ + val += (*(rawpt + 1) + *(rawpt + width)) / 2; /* G */ + val += *rawpt; /* B */ + } + } + else + { + /* (B)G */ + if ((i > width) && ((i % width) < (width - 1))) + { + val = (*(rawpt + width) + *(rawpt - width)) / 2; /* R */ + val += *rawpt; /* G */ + val += (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */ + } + else + { + val = *(rawpt + width); /* R */ + val += *rawpt; /* G */ + val += *(rawpt - 1); /* B */ + } + } + } + else + { + if ((i % 2) == 0) + { + /* G(R) */ + if ((i < (width * (height - 1))) && ((i % width) > 0)) + { + val = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */ + val += *rawpt; /* G */ + val += (*(rawpt + width) + *(rawpt - width)) / 2; /* B */ + } + else + { + /* bottom line or left column */ + val = *(rawpt + 1); /* R */ + val += *rawpt; /* G */ + val += *(rawpt - width); /* B */ + } + } + else + { + /* R */ + if (i < (width * (height - 1)) && ((i % width) < (width - 1))) + { + val = *rawpt; /* R */ + val += (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - width) + *(rawpt + width)) / 4; /* G */ + val += + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* B */ + } + else + { + /* bottom line or right column */ + val = *rawpt; /* R */ + val += (*(rawpt - 1) + *(rawpt - width)) / 2; /* G */ + val += *(rawpt - width - 1); /* B */ + } + } + } + *scanpt++ = val; + rawpt++; + } + return dst; +} + + +dsp_t* dsp_file_composite_2_bayer(dsp_stream_p *src, int r, int width, int height) +{ + int i; + dsp_t *rawpt, *red, *green, *blue; + int size; + dsp_t *dst = (dsp_t *)malloc(sizeof(dsp_t)*(size_t)(width*height)); + rawpt = dst; + blue = src[0]->buf; + green = src[1]->buf; + red = src[2]->buf; + size = width * height; + for (i = 0; i < size; i++) + { + if ((i / width) % 2 == ((r&2)>>1)) + { + if ((i % 2) == (r&1)) + { + /* B */ + if ((i > width) && ((i % width) > 0)) + { + rawpt[i - width - 1] += red[i]; + rawpt[i - width + 1] += red[i]; + rawpt[i + width - 1] += red[i]; + rawpt[i + width + 1] += red[i]; + rawpt[i - 1] += green[i]; + rawpt[i + 1] += green[i]; + rawpt[i + width] += green[i]; + rawpt[i - width] += green[i]; + rawpt[i] += blue[i]; + } + else + { + rawpt[i + width + 1] += red[i]; + rawpt[i + 1] += green[i]; + rawpt[i + width] += green[i]; + rawpt[i] += blue[i]; + } + } + else + { + /* (B)G */ + if ((i > width) && ((i % width) < (width - 1))) + { + rawpt[i + width] += red[i]; + rawpt[i - width] += red[i]; + rawpt[i] += green[i]; + rawpt[i - 1] += blue[i]; + rawpt[i + 1] += blue[i]; + } + else + { + rawpt[i + width] += red[i]; + rawpt[i] += green[i]; + rawpt[i - 1] += blue[i]; + } + } + } + else + { + if ((i % 2) == (r&1)) + { + /* G(R) */ + if ((i < (width * (height - 1))) && ((i % width) > 0)) + { + rawpt[i - 1] += red[i]; + rawpt[i + 1] += red[i]; + rawpt[i] += green[i]; + rawpt[i + width] += blue[i]; + rawpt[i - width] += blue[i]; + } + else + { + rawpt[i + 1] += red[i]; + rawpt[i] += green[i]; + rawpt[i - width] += blue[i]; + } + } + else + { + if (i < (width * (height - 1)) && ((i % width) < (width - 1))) + { + rawpt[i] = red[i]; + rawpt[i - 1] += green[i]; + rawpt[i + 1] += green[i]; + rawpt[i - width] += green[i]; + rawpt[i + width] += green[i]; + rawpt[i - width - 1] += blue[i]; + rawpt[i - width + 1] += blue[i]; + rawpt[i + width + 1] += blue[i]; + rawpt[i + width + 1] += blue[i]; + } + else + { + /* bottom line or right column */ + rawpt[i] += red[i]; + rawpt[i - 1] += green[i]; + rawpt[i - width] += green[i]; + rawpt[i - width - 1] += blue[i]; + } + } + } + } + return dst; +} + + +dsp_t* dsp_file_bayer_2_composite(dsp_t *src, int r, int width, int height) +{ + int i; + dsp_t *rawpt, *red, *green, *blue; + int size; + + dsp_t *dst = (dsp_t *)malloc(sizeof(dsp_t)*(size_t)(width*height*3)); + rawpt = src; + blue = &dst[0]; + green = &dst[width*height]; + red = &dst[width*height*2]; + size = width * height; + for (i = 0; i < size; i++) + { + if ((i / width) % 2 == ((r&2)>>1)) + { + if ((i % 2) == (r&1)) + { + /* B */ + if ((i > width) && ((i % width) > 0)) + { + *red++ = + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* R */ + *green++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + width) + *(rawpt - width)) / 4; /* G */ + *blue++ = *rawpt; /* B */ + } + else + { + *red++ = *(rawpt + width + 1); /* R */ + *green++ = (*(rawpt + 1) + *(rawpt + width)) / 2; /* G */ + *blue++ = *rawpt; /* B */ + } + } + else + { + /* (B)G */ + if ((i > width) && ((i % width) < (width - 1))) + { + *red++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* R */ + *green++ = *rawpt; /* G */ + *blue++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */ + } + else + { + *red++ = *(rawpt + width); /* R */ + *green++ = *rawpt; /* G */ + *blue++ = *(rawpt - 1); /* B */ + } + } + } + else + { + if ((i % 2) == (r&1)) + { + /* G(R) */ + if ((i < (width * (height - 1))) && ((i % width) > 0)) + { + *red++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */ + *green++ = *rawpt; /* G */ + *blue++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* B */ + } + else + { + /* bottom line or left column */ + *red++ = *(rawpt + 1); /* R */ + *green++ = *rawpt; /* G */ + *blue++ = *(rawpt - width); /* B */ + } + } + else + { + /* R */ + if (i < (width * (height - 1)) && ((i % width) < (width - 1))) + { + *red++ = *rawpt; /* R */ + *green++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - width) + *(rawpt + width)) / 4; /* G */ + *blue++ = + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* B */ + } + else + { + /* bottom line or right column */ + *red++ = *rawpt; /* R */ + *green++ = (*(rawpt - 1) + *(rawpt - width)) / 2; /* G */ + *blue++ = *(rawpt - width - 1); /* B */ + } + } + } + rawpt++; + } + return dst; +} + + +dsp_t* dsp_file_bayer_2_rgb(dsp_t *src, int red, int width, int height) +{ + int i; + dsp_t *rawpt, *scanpt; + int size; + + dsp_t * dst = (dsp_t*)malloc(sizeof(dsp_t)*(size_t)(width*height*3)); + rawpt = src; + scanpt = dst; + size = width * height; + (void)*scanpt++; + for (i = 0; i < size; i++) + { + if ((i / width) % 2 == ((red&2)>>1)) + { + if ((i % 2) == (red&1)) + { + /* B */ + if ((i > width) && ((i % width) > 0)) + { + *scanpt++ = + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* R */ + *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + width) + *(rawpt - width)) / 4; /* G */ + *scanpt++ = *rawpt; /* B */ + } + else + { + *scanpt++ = *(rawpt + width + 1); /* R */ + *scanpt++ = (*(rawpt + 1) + *(rawpt + width)) / 2; /* G */ + *scanpt++ = *rawpt; /* B */ + } + } + else + { + /* (B)G */ + if ((i > width) && ((i % width) < (width - 1))) + { + *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */ + } + else + { + *scanpt++ = *(rawpt + width); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt - 1); /* B */ + } + } + } + else + { + if ((i % 2) == (red&1)) + { + /* G(R) */ + if ((i < (width * (height - 1))) && ((i % width) > 0)) + { + *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* B */ + } + else + { + /* bottom line or left column */ + *scanpt++ = *(rawpt + 1); /* R */ + *scanpt++ = *rawpt; /* G */ + *scanpt++ = *(rawpt - width); /* B */ + } + } + else + { + /* R */ + if (i < (width * (height - 1)) && ((i % width) < (width - 1))) + { + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - width) + *(rawpt + width)) / 4; /* G */ + *scanpt++ = + (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / + 4; /* B */ + } + else + { + /* bottom line or right column */ + *scanpt++ = *rawpt; /* R */ + *scanpt++ = (*(rawpt - 1) + *(rawpt - width)) / 2; /* G */ + *scanpt++ = *(rawpt - width - 1); /* B */ + } + } + } + rawpt++; + } + return dst; +} + dsp_stream_p *dsp_stream_from_components(dsp_t* buf, int dims, int *sizes, int components) { int d, y, x; - dsp_stream_p* picture = (dsp_stream_p*) malloc(sizeof(dsp_stream_p)*(unsigned int)(components+1)); + dsp_stream_p* picture = (dsp_stream_p*) malloc(sizeof(dsp_stream_p)*(size_t)(components+1)); for(y = 0; y <= components; y++) { picture[y] = dsp_stream_new(); for(d = 0; d < dims; d++) @@ -357,50 +1058,51 @@ dsp_stream_p *dsp_stream_from_components(dsp_t* buf, int dims, int *sizes, int c } } } - free (buf); return picture; } dsp_stream_p *dsp_buffer_rgb_to_components(void* buf, int dims, int *sizes, int components, int bpp, int stretch) { - dsp_stream_p* picture = (dsp_stream_p*) malloc(sizeof(dsp_stream_p)*(unsigned int)(components+1)); + dsp_stream_p* picture = (dsp_stream_p*) malloc(sizeof(dsp_stream_p)*(size_t)(components+1)); int x, y, z, d; + dsp_stream_p channel; for(y = 0; y < components; y++) { - picture[y] = dsp_stream_new(); + channel = dsp_stream_new(); for(d = 0; d < dims; d++) - dsp_stream_add_dim(picture[y], sizes[d]); - dsp_stream_alloc_buffer(picture[y], picture[y]->len); + dsp_stream_add_dim(channel, sizes[d]); + dsp_stream_alloc_buffer(channel, channel->len); switch(bpp) { case 8: - dsp_buffer_copy_stepping(((unsigned char*)&((unsigned char*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((unsigned char*)&((unsigned char*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; case 16: - dsp_buffer_copy_stepping(((unsigned short*)&((unsigned short*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((unsigned short*)&((unsigned short*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; case 32: - dsp_buffer_copy_stepping(((unsigned int*)&((unsigned int*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((unsigned int*)&((unsigned int*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; case 64: - dsp_buffer_copy_stepping(((unsigned long*)&((unsigned long*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((unsigned long*)&((unsigned long*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; case -32: - dsp_buffer_copy_stepping(((float*)&((float*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((float*)&((float*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; case -64: - dsp_buffer_copy_stepping(((double*)&((double*)buf)[y]), picture[y]->buf, picture[y]->len*components, picture[y]->len, components, 1); + dsp_buffer_copy_stepping(((double*)&((double*)buf)[y]), channel->buf, channel->len*components, channel->len, components, 1); break; default: break; } if(stretch) { - dsp_buffer_stretch(picture[y]->buf, picture[y]->len, 0, dsp_t_max); + dsp_buffer_stretch(channel->buf, channel->len, 0, dsp_t_max); } + picture[y] = channel; } - picture[y] = dsp_stream_new(); + channel = dsp_stream_new(); for(d = 0; d < dims; d++) - dsp_stream_add_dim(picture[y], sizes[d]); - dsp_stream_alloc_buffer(picture[y], picture[y]->len); - for(x = 0; x < picture[y]->len; x++) { + dsp_stream_add_dim(channel, sizes[d]); + dsp_stream_alloc_buffer(channel, channel->len); + for(x = 0; x < channel->len; x++) { double v = 0; switch(bpp) { case 8: @@ -416,7 +1118,7 @@ dsp_stream_p *dsp_buffer_rgb_to_components(void* buf, int dims, int *sizes, int for(z = 0; z < y; z++) v += ((unsigned long*)buf)[x*y+z]; break; case -32: - for(z = 0; z < y; z++) v += (double)((float*)buf)[x*y+z]; + for(z = 0; z < y; z++) v += ((float*)buf)[x*y+z]; break; case -64: for(z = 0; z < y; z++) v += ((double*)buf)[x*y+z]; @@ -424,22 +1126,23 @@ dsp_stream_p *dsp_buffer_rgb_to_components(void* buf, int dims, int *sizes, int default: break; } - picture[y]->buf[x] = (dsp_t)(v/y); + channel->buf[x] = (dsp_t)(v/y); } if(stretch) { - dsp_buffer_stretch(picture[y]->buf, picture[y]->len, 0, dsp_t_max); + dsp_buffer_stretch(channel->buf, channel->len, 0, dsp_t_max); } + picture[y] = channel; free (buf); return picture; } void dsp_buffer_components_to_rgb(dsp_stream_p *stream, void* rgb, int components, int bpp) { - size_t y; + ssize_t y; int len = stream[0]->len * components; - dsp_t max = (dsp_t)((double)((1<buf, in->len, 0, max); switch(bpp) { diff --git a/libs/dsp/filters.c b/libs/dsp/filters.c index 082ac13a04..4e48ab0ad2 100644 --- a/libs/dsp/filters.c +++ b/libs/dsp/filters.c @@ -1,25 +1,28 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" void dsp_filter_squarelaw(dsp_stream_p stream) { + if(stream == NULL) + return; dsp_t* in = stream->buf; dsp_t *out = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); int len = stream->len; @@ -34,102 +37,106 @@ void dsp_filter_squarelaw(dsp_stream_p stream) free(out); } -void dsp_filter_calc_coefficients(double SamplingFrequency, double LowFrequency, double HighFrequency, double* CF, double* R, double *K) +void dsp_filter_lowpass(dsp_stream_p stream, double Frequency) { - double BW = (HighFrequency - LowFrequency) / SamplingFrequency; - *CF = 2.0 * cos((LowFrequency + HighFrequency) * M_PI / SamplingFrequency); - *R = 1.0 - 3.0 * BW; - *K = (1.0 - *R * *CF + *R * *R) / (2.0 - *CF); -} - -void dsp_filter_lowpass(dsp_stream_p stream, double SamplingFrequency, double Frequency) -{ - double *out = (double*)malloc(sizeof(double) * stream->len); - double CF = cos(Frequency / 2.0 * M_PI / SamplingFrequency); - int dim = -1, i; - out[0] = stream->buf[0]; - while (dim++ < stream->dims - 1) { - int size = (dim < 0 ? 1 : stream->sizes[dim]); - for(i = size; i < stream->len; i+=size) { - out[i] += stream->buf[i] + (out[i - size] - stream->buf[i]) * CF; + if(stream == NULL) + return; + int d, x; + double radius = 0.0; + for(d = 0; d < stream->dims; d++) { + radius += pow(stream->sizes[d]/2.0, 2); + } + radius = sqrt(radius); + dsp_fourier_dft(stream, 1); + for(x = 0; x < stream->len; x++) { + int* pos = dsp_stream_get_position(stream, x); + double dist = 0.0; + for(d = 0; d < stream->dims; d++) { + dist += pow(stream->sizes[d]/2.0-pos[d], 2); } + free(pos); + dist = sqrt(dist); + dist *= M_PI/radius; + if(dist>Frequency) + stream->magnitude->buf[x] = 0.0; } - memcpy(stream->buf, out, stream->len * sizeof(double)); - free(out); + dsp_fourier_idft(stream); } -void dsp_filter_highpass(dsp_stream_p stream, double SamplingFrequency, double Frequency) +void dsp_filter_highpass(dsp_stream_p stream, double Frequency) { - dsp_t *out = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); - double CF = cos(Frequency / 2.0 * M_PI / SamplingFrequency); - int dim = -1, i; - out[0] = stream->buf[0]; - while (dim++ < stream->dims - 1) { - int size = (dim < 0 ? 1 : stream->sizes[dim]); - for(i = size; i < stream->len; i+=size) { - out[i] += stream->buf[i] + (out[i - size] - stream->buf[i]) * CF; + if(stream == NULL) + return; + int d, x; + double radius = 0.0; + for(d = 0; d < stream->dims; d++) { + radius += pow(stream->sizes[d]/2.0, 2); + } + radius = sqrt(radius); + dsp_fourier_dft(stream, 1); + for(x = 0; x < stream->len; x++) { + int* pos = dsp_stream_get_position(stream, x); + double dist = 0.0; + for(d = 0; d < stream->dims; d++) { + dist += pow(stream->sizes[d]/2.0-pos[d], 2); } + free(pos); + dist = sqrt(dist); + dist *= M_PI/radius; + if(distmagnitude->buf[x] = 0.0; } - dsp_buffer_sub(stream, out, stream->len); - free(out); + dsp_fourier_idft(stream); } -void dsp_filter_bandreject(dsp_stream_p stream, double SamplingFrequency, double LowFrequency, double HighFrequency) { - dsp_t *out = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); - double R, K, CF; - dsp_filter_calc_coefficients(SamplingFrequency, LowFrequency, HighFrequency, &CF, &R, &K); - double R2 = R*R; - - double a[3] = { K, -K*CF, K }; - double b[2] = { R*CF, -R2 }; - - int dim = -1, i, x; - while (dim++ < stream->dims - 1) { - for(i = 0; i < stream->len; i++) { - int size = (dim < 0 ? 1 : stream->sizes[dim]); - out[i] = 0; - if(i < stream->len - 2 * size) { - for(x = 0; x < 3; x++) { - out[i] += (double)stream->buf[i + x * size] * a[2 - x]; - } - } - if(i > size) { - for(x = 0; x < 2; x++) { - out[i] -= out[i - 2 * size + x * size] * b[x]; - } - } +void dsp_filter_bandreject(dsp_stream_p stream, double LowFrequency, double HighFrequency) +{ + if(stream == NULL) + return; + int d, x; + double radius = 0.0; + for(d = 0; d < stream->dims; d++) { + radius += pow(stream->sizes[d]/2.0, 2); + } + radius = sqrt(radius); + dsp_fourier_dft(stream, 1); + for(x = 0; x < stream->len; x++) { + int* pos = dsp_stream_get_position(stream, x); + double dist = 0.0; + for(d = 0; d < stream->dims; d++) { + dist += pow(stream->sizes[d]/2.0-pos[d], 2); } + free(pos); + dist = sqrt(dist); + dist *= M_PI/radius; + if(distLowFrequency) + stream->magnitude->buf[x] = 0.0; } - memcpy(stream->buf, out, stream->len * sizeof(dsp_t)); - free(out); + dsp_fourier_idft(stream); } -void dsp_filter_bandpass(dsp_stream_p stream, double SamplingFrequency, double LowFrequency, double HighFrequency) { - dsp_t *out = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); - double R, K, CF; - dsp_filter_calc_coefficients(SamplingFrequency, LowFrequency, HighFrequency, &CF, &R, &K); - double R2 = R*R; - - double a[3] = { 1 - K, (K-R)*CF, R2 - K }; - double b[2] = { R*CF, -R2 }; - - int dim = -1, i, x; - while (dim++ < stream->dims - 1) { - for(i = 0; i < stream->len; i++) { - int size = (dim < 0 ? 1 : stream->sizes[dim]); - out[i] = 0; - if(i < stream->len - 2 * size) { - for(x = 0; x < 3; x++) { - out[i] += (double)stream->buf[i + x * size] * a[2 - x]; - } - } - if(i > size) { - for(x = 0; x < 2; x++) { - out[i] -= out[i - 2 * size + x * size] * b[x]; - } - } +void dsp_filter_bandpass(dsp_stream_p stream, double LowFrequency, double HighFrequency) +{ + if(stream == NULL) + return; + int d, x; + double radius = 0.0; + for(d = 0; d < stream->dims; d++) { + radius += pow(stream->sizes[d]/2.0, 2); + } + radius = sqrt(radius); + dsp_fourier_dft(stream, 1); + for(x = 0; x < stream->len; x++) { + int* pos = dsp_stream_get_position(stream, x); + double dist = 0.0; + for(d = 0; d < stream->dims; d++) { + dist += pow(stream->sizes[d]/2.0-pos[d], 2); } + free(pos); + dist = sqrt(dist); + dist *= M_PI/radius; + if(dist>HighFrequency||distmagnitude->buf[x] = 0.0; } - memcpy(stream->buf, out, stream->len * sizeof(dsp_t)); - free(out); + dsp_fourier_idft(stream); } diff --git a/libs/dsp/fits.c b/libs/dsp/fits.c new file mode 100644 index 0000000000..83bd8f7db3 --- /dev/null +++ b/libs/dsp/fits.c @@ -0,0 +1,466 @@ +/* +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "dsp.h" + +void dsp_fits_update_fits_key(fitsfile *fptr, int type, char* name, void *p, char* explanation, int *status) +{ + fits_update_key(fptr, type, name, p, explanation, status); +} + +long dsp_fits_alloc_fits_rows(fitsfile *fptr, unsigned long num_rows) +{ + int status = 0; + long nrows = 0; + fits_get_num_rows(fptr, &nrows, &status); + fits_insert_rows(fptr, nrows, num_rows, &status); + return nrows; +} + + +int dsp_fits_fill_fits_col(fitsfile *fptr, char* name, unsigned char *buf, int typecode, long num_elements, unsigned long rown) +{ + int status = 0; + int ncol = 0; + fits_get_colnum(fptr, CASESEN, (char*)(name), &ncol, &status); + if(status != COL_NOT_FOUND) + { + fits_write_col(fptr, typecode, ncol, rown, 1, num_elements, buf, &status); + } + return status; +} + +int dsp_fits_append_fits_col(fitsfile *fptr, char* name, char* format) +{ + int status = 0; + int ncols = 0; + fits_get_colnum(fptr, CASESEN, (char*)(name), &ncols, &status); + if(status == COL_NOT_FOUND) + { + fits_get_num_cols(fptr, &ncols, &status); + fits_insert_col(fptr, ncols++, name, format, &status); + } + return ncols; +} + +void dsp_fits_delete_fits_col(fitsfile *fptr, char* name) +{ + int status = 0; + int ncol = 0; + fits_get_colnum(fptr, CASESEN, (char*)(name), &ncol, &status); + while(status != COL_NOT_FOUND) + fits_delete_col(fptr, ncol, &status); +} + +fitsfile* dsp_fits_create_fits(size_t *size, void **buf) +{ + fitsfile *fptr = NULL; + + size_t memsize; + int status = 0; + char error_status[64]; + + // Now we have to send fits format data to the client + memsize = 5760; + void* memptr = malloc(memsize); + if (!memptr) + { + perr("Error: failed to allocate memory: %lu", (unsigned long)(memsize)); + } + + fits_create_memfile(&fptr, &memptr, &memsize, 2880, realloc, &status); + + if (status) + { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s", error_status); + if(memptr != NULL) + free(memptr); + return NULL; + } + if (status) + { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s", error_status); + if(memptr != NULL) + free(memptr); + return NULL; + } + + if (status) + { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s", error_status); + if(memptr != NULL) + free(memptr); + return NULL; + } + + *size = memsize; + *buf = memptr; + + return fptr; +} + +int dsp_fits_close_fits(fitsfile *fptr) +{ + int status = 0; + fits_close_file(fptr, &status); + + return status; +} + +int dsp_fits_get_value(fitsfile *fptr, char* column, long rown, void **retval) +{ + int err = 1, n = 0, anynul = 0, status = 0, typecode; + long repeat = 1; + long width; + char name[64]; + if(column == NULL) + goto err_return; + fits_get_colname(fptr, 0, column, name, &n, &status); + if(status) + goto err_return; + fits_get_coltype(fptr, n, &typecode, &repeat, &width, &status); + void *value = malloc(dsp_fits_get_element_size(typecode)*(size_t)(repeat*width)); + fits_read_col(fptr, typecode, n, rown, 1, repeat, NULL, value, &anynul, &status); + *retval = value; +err_return: + return err; +} + +int dsp_fits_check_column(fitsfile *fptr, char* column, char **expected, long rown) +{ + int err = 1, n = 0, anynul = 0, status = 0, x, y, typecode; + long repeat = 1; + long width; + char name[64]; + if(column == NULL || expected == NULL) + goto err_return; + fits_get_colname(fptr, 0, column, name, &n, &status); + if(status) + goto err_return; + fits_get_coltype(fptr, n, &typecode, &repeat, &width, &status); + if(typecode != TSTRING) + goto err_return; + char **value = (char **)malloc(sizeof(char*)*(size_t)repeat); + for(x = 0; x < repeat; x++) { + value[x] = (char*) malloc((size_t)width); + fits_read_col_str(fptr, n, rown, 1, 1, NULL, value, &anynul, &status); + for(y = 0; strcmp(expected[y], ""); y++) { + if(!strcmp(value[x], expected[y])) { + err &= 1; + break; + } + } + if(y == 0) + err = 0; + } + for(x = 0; x < repeat; x++) + free(value[x]); + free(value); +err_return: + return err; +} + +int dsp_fits_check_key(fitsfile *fptr, char* keyname, char **expected) +{ + int err = 1, status = 0, y; + char value[64]; + if(keyname == NULL || expected == NULL) + goto err_return; + fits_read_key_str(fptr, keyname, value, NULL, &status); + if(status) + goto err_return; + for(y = 0; strcmp(expected[y], ""); y++) { + if(!strcmp(value, expected[y])) { + err &= 1; + break; + } + } + if(y == 0) + err = 0; +err_return: + return err; +} + +int dsp_fits_read_typecode(char* typestr, int *typecode, long *width, long *repeat) +{ + int w, r, t; + char c; + sscanf(typestr, "%d%c%d", &w, &c, &r); + t = (int)c; + if (t == EXTFITS_ELEMENT_BIT.typestr[0]) + t = EXTFITS_ELEMENT_BIT.typecode; + if (t == EXTFITS_ELEMENT_STRING.typestr[0]) + t = EXTFITS_ELEMENT_STRING.typecode; + if (t == EXTFITS_ELEMENT_LOGICAL.typestr[0]) + t = EXTFITS_ELEMENT_LOGICAL.typecode; + if (t == EXTFITS_ELEMENT_BYTE.typestr[0]) + t = EXTFITS_ELEMENT_BYTE.typecode; + if (t == EXTFITS_ELEMENT_SBYTE.typestr[0]) + t = EXTFITS_ELEMENT_SBYTE.typecode; + if (t == EXTFITS_ELEMENT_SHORT.typestr[0]) + t = EXTFITS_ELEMENT_SHORT.typecode; + if (t == EXTFITS_ELEMENT_USHORT.typestr[0]) + t = EXTFITS_ELEMENT_USHORT.typecode; + if (t == EXTFITS_ELEMENT_INT.typestr[0]) + t = EXTFITS_ELEMENT_INT.typecode; + if (t == EXTFITS_ELEMENT_UINT.typestr[0]) + t = EXTFITS_ELEMENT_UINT.typecode; + if (t == EXTFITS_ELEMENT_LONG.typestr[0]) + t = EXTFITS_ELEMENT_LONG.typecode; + if (t == EXTFITS_ELEMENT_FLOAT.typestr[0]) + t = EXTFITS_ELEMENT_FLOAT.typecode; + if (t == EXTFITS_ELEMENT_DOUBLE.typestr[0]) + t = EXTFITS_ELEMENT_DOUBLE.typecode; + if (t == EXTFITS_ELEMENT_COMPLEX.typestr[0]) + t = EXTFITS_ELEMENT_COMPLEX.typecode; + if (t == EXTFITS_ELEMENT_DBLCOMPLEX.typestr[0]) + t = EXTFITS_ELEMENT_DBLCOMPLEX.typecode; + else return -1; + *typecode = t; + *width = w; + *repeat = r; + return 0; +} + +size_t dsp_fits_get_element_size(int typecode) +{ + size_t typesize = 1; + + switch(typecode) + { + case TSHORT: + case TUSHORT: + typesize *= 2; + break; + case TINT: + case TUINT: + case TFLOAT: + typesize *= 4; + break; + case TLONG: + case TULONG: + case TDOUBLE: + case TCOMPLEX: + typesize *= 8; + break; + case TDBLCOMPLEX: + typesize *= 16; + break; + default: + break; + } + + return typesize; +} + +int dsp_fits_append_table(fitsfile* fptr, dsp_fits_column *columns, int ncols, char* tablename) +{ + int status = 0; + int x = 0; + fits_update_key(fptr, TSTRING, "EXTNAME", tablename, "", &status); + for(x = 0; x < ncols; x++) { + dsp_fits_append_fits_col(fptr, columns[x].name, columns[x].format); + } + return status; +} + +dsp_fits_row* dsp_fits_read_sdfits(char *filename, long *num_rows, long *maxes, long **maxis) +{ + fitsfile *fptr = (fitsfile*)malloc(sizeof(fitsfile)); + memset(fptr, 0, sizeof(fitsfile)); + int status = 0; + int sdfits_hdu = 0; + long nrows = 0; + long r = 0; + long nmatrix = 0; + int ncols = 0; + int typecode = 0; + long width = 0; + long repeat = 0; + int k = 0; + int i = 0; + int n = 0; + int dim; + int anynul = 0; + long naxes[3] = { 1, 1, 1 }; + dsp_fits_column* columns = (dsp_fits_column*)malloc(sizeof(dsp_fits_column)); + dsp_fits_row* rows = (dsp_fits_row*)malloc(sizeof(dsp_fits_row)); + char value[150]; + char comment[150]; + char error_status[64]; + + fits_open_file(&fptr, filename, READONLY, &status); + if (status) + { + goto fail; + } + + ffgkey(fptr, FITS_KEYWORD_EXTEND.name, value, comment, &status); + if(status || strcmp(value, FITS_KEYWORD_EXTEND.value)) + { + goto fail; + } + + ffgkey(fptr, SDFITS_KEYWORD_TELESCOP.name, value, comment, &status); + if (!status) + { + } + status = 0; + + ffgkey(fptr, SDFITS_KEYWORD_OBSERVER.name, value, comment, &status); + if (!status) + { + } + status = 0; + + ffgkey(fptr, SDFITS_KEYWORD_DATE_OBS.name, value, comment, &status); + if (!status) + { + } + status = 0; + + ffgkey(fptr, SDFITS_KEYWORD_DATAMAX.name, value, comment, &status); + if (!status) + { + } + status = 0; + + ffgkey(fptr, SDFITS_KEYWORD_DATAMIN.name, value, comment, &status); + if (!status) + { + } + status = 0; + + fits_movabs_hdu(fptr, 1, &sdfits_hdu, &status); + if(status || sdfits_hdu != BINARY_TBL) + { + goto fail; + } + + fits_read_key_str(fptr, "EXTNAME", value, comment, &status); + if(status || strcmp(value, FITS_TABLE_SDFITS)) + { + goto fail; + } + + fits_read_key_str(fptr, EXTFITS_KEYWORD_NMATRIX.name, value, NULL, &status); + if(status || strcmp(value, EXTFITS_KEYWORD_NMATRIX.value)) { + goto fail; + } + + fits_get_num_rows(fptr, &nrows, &status); + if(status) + { + goto fail; + } + + fits_get_num_cols(fptr, &ncols, &status); + if(status) + { + goto fail; + } + + fits_read_key_lng(fptr, EXTFITS_KEYWORD_NMATRIX.name, &nmatrix, NULL, &status); + if(status || nmatrix < 1) + { + goto fail; + } + + columns = (dsp_fits_column*)realloc(columns, sizeof(dsp_fits_column)*((size_t)ncols+1)); + rows = (dsp_fits_row*)realloc(rows, sizeof(dsp_fits_row)*((size_t)nrows+1)); + + for(r = 0; r < nrows; r++) { + for(k = 0; k < ncols; k++) { + columns[k].name = (char*)malloc(150); + columns[k].format = (char*)malloc(150); + columns[k].unit = (char*)malloc(150); + columns[k].value = (char*)malloc(150); + columns[k].comment = (char*)malloc(150); + + status = 0; + fits_get_colname(fptr, 0, SDFITS_TABLE_MAIN[i].name, value, &n, &status); + strcpy(columns[k].name, value); + if(!dsp_fits_check_key(fptr, EXTFITS_KEYWORD_TMATX(k).name, &EXTFITS_KEYWORD_TMATX(k).value)) { + int max_dims = 5; + int dims; + long *sizes =(long*)malloc(sizeof(long)*(size_t)max_dims); + fits_read_tdim(fptr, k, max_dims, &dims, sizes, &status); + if(dims < 2) { + long d = 0; + fits_read_key_lng(fptr, EXTFITS_KEYWORD_MAXIS().name, &d, NULL, &status); + sizes = (long*)malloc(sizeof(long)*(size_t)dims); + for(dim = 0; dim < d; dim++) + fits_read_key_lng(fptr, EXTFITS_KEYWORD_MAXIS(dim).name, &sizes[dim], NULL, &status); + dims = (int)d; + } + if(dims > 0) { + void *tcs = NULL; + dsp_fits_get_value(fptr, EXTFITS_KEYWORD_TMATX(k).axes_definition.format.name, r, &tcs); + strcpy(columns[k].format, tcs); + dsp_fits_get_value(fptr, EXTFITS_KEYWORD_TMATX(k).axes_definition.unit.name, r, &tcs); + strcpy(columns[k].unit, tcs); + if (!dsp_fits_read_typecode((char*)tcs, &typecode, &width, &repeat)) { + size_t element_size = dsp_fits_get_element_size(typecode); + long nelements = 1; + for(dim = 0; dim < dims; dim++) { + nelements *= naxes[dim]; + } + columns[k].value = (char*)malloc(element_size*(size_t)nelements); + fits_read_col(fptr, typecode, k, r, 1, nelements, NULL, columns->value, &anynul, &status); + if(!anynul && !status) { + *maxis = (long*)malloc(sizeof(long)*(size_t)dims); + for(dim = 0; dim < dims; dim++) + *maxis[dim] = naxes[dim]; + *maxes = dims; + } + } + } + } else { + int typecode; + long repeat, width; + fits_get_eqcoltype(fptr, n, &typecode, &repeat, &width, &status); + if(status) continue; + if(dsp_fits_check_column(fptr, columns[k].name, columns[k].expected, r)) + continue; + void *val = &columns[k].value; + dsp_fits_get_value(fptr, columns[k].name, r, &val); + } + } + rows[r].columns = (dsp_fits_column*)malloc(sizeof(dsp_fits_column)*rows[r].num_columns); + rows[r].num_columns = (size_t)ncols; + } + *num_rows = nrows; + status = 0; + fits_close_file(fptr, &status); + if(status) + goto fail; + return rows; +fail: + free(rows); + free(columns); + if(status) + { + fits_get_errstatus(status, error_status); + perr("FITS Error: %s\n", error_status); + } + return NULL; +} diff --git a/libs/dsp/fits.h b/libs/dsp/fits.h new file mode 100644 index 0000000000..9f905f7dd9 --- /dev/null +++ b/libs/dsp/fits.h @@ -0,0 +1,335 @@ +/* +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _DSP_FITS_H +#define _DSP_FITS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLL_EXPORT +#define DLL_EXPORT extern +#endif + +#include + +/** + * \defgroup dsp_FitsExtensions DSP API FITS Extensions functions +*/ +/**\{*/ +///FITS format +typedef struct +{ + ///String format + char typestr[8]; + ///FITSIO typecode + int typecode; + ///Number of repetitions + long repeat; + ///Width of each element + long width; +} dsp_fits_format; + +///FITS keyword +typedef struct +{ + ///Name of the keyword + char *name; + ///Format of the content of the keyword + char *format; + ///Measure unit of the value + char *unit; + ///Value + char *value; + ///Description of the keyword or value + char *comment; + ///Expected value if checking when read + char ** expected; +} dsp_fits_keyword; + +///Binary table FITS extension column +typedef struct +{ + ///Name of the column (title, TTYPE) + char *name; + ///Format string of the content of the column (TFORM) + char *format; + ///Measure unit of the column elements (TUNIT) + char *unit; + ///Default initial value + char *value; + ///Description of the column or data + char *comment; + ///Expected values if checking when read + char ** expected; +} dsp_fits_column; + +///Binary table FITS extension row +typedef struct +{ + ///Columns array + dsp_fits_column* columns; + ///Columns data + size_t num_columns; +} dsp_fits_row; + +///Binary table FITS Matrix axis +typedef struct +{ + ///Axis name + char *name; + ///Axis format string + char *format; + ///Axis measure unit string + char *unit; + ///Axis default value + char *value; + ///Axis description + char *comment; + ///Data definition + struct + { + ///Data name + dsp_fits_keyword name; + ///Data increment step + dsp_fits_keyword increment; + ///Data reference pixel + dsp_fits_keyword refpix; + ///Data reference pixel value + dsp_fits_keyword value; + } definition; +} dsp_fits_axis; + +///Binary table FITS Matrix +typedef struct +{ + ///Matrix name + char *name; + ///Matrix format string + char *format; + ///Matrix measure unit string + char *value; + ///Matrix description + char *comment; + ///Axes definition + struct + { + ///Axes name + dsp_fits_keyword name; + ///Axes format + dsp_fits_keyword format; + ///Axes measure unit + dsp_fits_keyword unit; + ///Axes quantity + dsp_fits_keyword dims; + } axes_definition; +} dsp_fits_matrix; + +///Returns non-zero decimal conversion of integer into string +#ifndef itostr +#define its(x) #x +#define itostr(x) its(x) +#endif + +///FITS element types +#define EXTFITS_ELEMENT_STRING (dsp_fits_format){"A", TSTRING, 0, 0} +#define EXTFITS_ELEMENT_LOGICAL (dsp_fits_format){"L", TLOGICAL, 0, 0} +#define EXTFITS_ELEMENT_BIT (dsp_fits_format){"X", TBIT, 0, 0} +#define EXTFITS_ELEMENT_BYTE (dsp_fits_format){"B", TBYTE, 0, 0} +#define EXTFITS_ELEMENT_SBYTE (dsp_fits_format){"S", TSBYTE, 0, 0} +#define EXTFITS_ELEMENT_SHORT (dsp_fits_format){"I", TSHORT, 0, 0} +#define EXTFITS_ELEMENT_USHORT (dsp_fits_format){"U", TUSHORT, 0, 0} +#define EXTFITS_ELEMENT_INT (dsp_fits_format){"J", TINT, 0, 0} +#define EXTFITS_ELEMENT_UINT (dsp_fits_format){"V", TUINT, 0, 0} +#define EXTFITS_ELEMENT_LONG (dsp_fits_format){"K", TLONG, 0, 0} +#define EXTFITS_ELEMENT_FLOAT (dsp_fits_format){"E", TFLOAT, 0, 0} +#define EXTFITS_ELEMENT_DOUBLE (dsp_fits_format){"D", TDOUBLE, 0, 0} +#define EXTFITS_ELEMENT_COMPLEX (dsp_fits_format){"C", TCOMPLEX, 0, 0} +#define EXTFITS_ELEMENT_DBLCOMPLEX (dsp_fits_format){"M", TDBLCOMPLEX, 0, 0} + +///FITS Measure units +#define EXTFITS_MEASURE_UNIT_HZ "Hz" +#define EXTFITS_MEASURE_UNIT_SECOND "sec" +#define EXTFITS_MEASURE_UNIT_MINUTE "min" +#define EXTFITS_MEASURE_UNIT_HOUR "hour" +#define EXTFITS_MEASURE_UNIT_DAY "day" +#define EXTFITS_MEASURE_UNIT_MONTH "month" +#define EXTFITS_MEASURE_UNIT_YEAR "year" +#define EXTFITS_MEASURE_UNIT_JANSKY "Jy" +#define EXTFITS_MEASURE_UNIT_KELVIN "K" +#define EXTFITS_MEASURE_UNIT_ANGSTROM "Angstrom" +#define EXTFITS_MEASURE_UNIT_ARCSEC "arcsec" +#define EXTFITS_MEASURE_UNIT_ARCMIN "arcmin" +#define EXTFITS_MEASURE_UNIT_DEGREE "degree" +#define EXTFITS_MEASURE_UNIT_PERCENT "percent" +#define EXTFITS_MEASURE_UNIT_METER "meter" +#define EXTFITS_MEASURE_UNIT_MILLIBAR "millibar" + +///Set to 'FLUX' or 'DATA' for matrix buffers +#define EXTFITS_KEYWORD_TTYPE(n) (dsp_fits_keyword){"TTYPE" itostr(n), "8A", "", "", "Set to 'FLUX'", (char*[]){"FLUX", "DATA", ""}} +///shall have the value 'K', 'JY' or 'UNCALIB' +#define EXTFITS_KEYWORD_TUNIT(n) (dsp_fits_keyword){"TUNIT" itostr(n), "8A", "", "", "Shall have the value 'JY' or 'UNCALIB'", (char*[]){""}} +///Size in pixels of data buffer +#define EXTFITS_KEYWORD_TDIM(n) (dsp_fits_keyword){"TDIM" itostr(n), "8A", "", "", "Size in pixels of data buffer", (char*[]){""}} +///shall have the format of the column +#define EXTFITS_KEYWORD_TFORM(n) (dsp_fits_keyword){"TFORM" itostr(n), "8A", "", "", "Shall be a character string", (char*[]){""}} + +///Name of regular axis m = 1 to M +#define EXTFITS_KEYWORD_CTYPE(m) (dsp_fits_keyword){"CTYPE" itostr(m), EXTFITS_ELEMENT_STRING.typestr, "", "", "Name of regular axis m = 1 to M", (char*[]){""}} +///Coordinate increment on axis m = 1 to M +#define EXTFITS_KEYWORD_CDELT(m) (dsp_fits_keyword){"CDELT" itostr(m), EXTFITS_ELEMENT_FLOAT.typestr, "", "", "Coordinate increment on axis m = 1 to M", (char*[]){""}} +///Reference pixel on axis m = 1 to M +#define EXTFITS_KEYWORD_CRPIX(m) (dsp_fits_keyword){"CRPIX" itostr(m), EXTFITS_ELEMENT_FLOAT.typestr, "", "", "Reference pixel on axis m = 1 to M", (char*[]){""}} +///Coordinate value at reference pixel on axis m = 1 to M +#define EXTFITS_KEYWORD_CRVAL(m) (dsp_fits_keyword){"CRVAL" itostr(m), EXTFITS_ELEMENT_FLOAT.typestr, "", "", "Coordinate value at reference pixel on axis m = 1 to M", (char*[]){""}} + +///NMATRIX shall be present with the value 1 +#define EXTFITS_KEYWORD_NMATRIX (dsp_fits_keyword){"NMATRIX", EXTFITS_ELEMENT_SHORT.typestr, "", "1", "NMATRIX shall be present with the value 1", (char*[]){"1", ""}} +///Set to 'T' — column n contains the visibility matrix +#define EXTFITS_KEYWORD_TMATX(n) (dsp_fits_matrix){"TMATX" itostr(n), "8A", "T", "Set to 'T'", {EXTFITS_KEYWORD_TTYPE(n), EXTFITS_KEYWORD_TFORM(n), EXTFITS_KEYWORD_TUNIT(n), EXTFITS_KEYWORD_TDIM(n)}} +///M = number axes in regular matrix, Number pixels on axis m = 1 to M +#define EXTFITS_KEYWORD_MAXIS(m) (dsp_fits_axis){"MAXIS" itostr(m), EXTFITS_ELEMENT_SHORT.typestr, "", "", "M = number axes in regular matrix, Number pixels on axis m = 1 to M", {EXTFITS_KEYWORD_CTYPE(m), EXTFITS_KEYWORD_CDELT(m), EXTFITS_KEYWORD_CRPIX(m), EXTFITS_KEYWORD_CRVAL(m)}} + +///Target right ascension coordinate +#define EXTFITS_KEYWORD_OBJCTRA (dsp_fits_column){"OBJCTRA", EXTFITS_ELEMENT_STRING.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Target right ascension coordinate", (char*[]){""}} +///Target declination coordinate +#define EXTFITS_KEYWORD_OBJCTDEC (dsp_fits_column){"OBJCTDEC", EXTFITS_ELEMENT_STRING.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Target declination coordinate", (char*[]){""}} + +#define FITS_KEYWORD_EXTEND (dsp_fits_keyword){"EXTEND", "A", "", "T", "", (char*[]){""}} +#define FITS_KEYWORD_EXTNAME (dsp_fits_keyword){"EXTNAME", "", "", "", "", (char*[]){""}} + +/** +* \brief Create or update a new fits header key +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param type The typecode of the value +* \param name The keyword to be updated +* \param value The new value of the specified keyword +* \param comment The keyword or assigned value description or explanation +* \param status This variable will be updated with the status of the update operation +*/ +void dsp_fits_update_fits_key(fitsfile *fptr, int type, char* name, void *value, char* comment, int *status); + +/** +* \brief Convert an RGB color dsp_t array into a dsp_stream_p array each element containing the single components +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param num_rows The number of rows to be allocated +* \return The number of rows incremented by the allocated ones +* \sa dsp_fits_create_fits +*/ +long dsp_fits_alloc_fits_rows(fitsfile *fptr, unsigned long num_rows); + +/** +* \brief Fill a column at the given row position with the valued buffer +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param name The name of the column +* \param buf The buffer that will be copied into the selected field. +* \param typecode The element type size +* \param num_elements The total field size in elements, this should take into account the width and repeat multipliers +* \param rown The row number where the field is located +* \return non-zero if any error occured +* \sa dsp_fits_create_fits +*/ +int dsp_fits_fill_fits_col(fitsfile *fptr, char* name, unsigned char *buf, int typecode, long num_elements, + unsigned long rown); + +/** +* \brief Add a column to the binary table +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param name The name of the column +* \param format This field should indicate the element size, width of each element and repetition eventually +* \return non-zero if any error occured +*/ +int dsp_fits_append_fits_col(fitsfile *fptr, char* name, char* format); + +/** +* \brief Delete a column from the binary table +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param name The name of the column +*/ +void dsp_fits_delete_fits_col(fitsfile *fptr, char* name); + +/** +* \brief Obtain the single element size in bytes +* \param typecode The typecode of each single element +* \return the size of the single element +*/ +size_t dsp_fits_get_element_size(int typecode); + +/** +* \brief Decode a typecode format string +* \param typestr The element format string +* \param typecode This function will return the typecode to this variable +* \param width This function will return the width to this variable +* \param repeat This function will return the repeatition count to this variable +* \return non-zero if any error occured +*/ +int dsp_fits_read_typecode(char* typestr, int *typecode, long *width, long *repeat); + +/** +* \brief Obtain the value of the specified field +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param column The column name of the selected field +* \param rown The row position of the field +* \param retval A preallocated buffer where the field value will be stored into +* \return non-zero if any error occured +*/ +int dsp_fits_get_value(fitsfile *fptr, char* column, long rown, void **retval); + +/** +* \brief Check if the value of the specified field corresponds to a subset of values +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \param column The column name of the selected field +* \param expected A buffer array containing expected values, terminating with an empty value +* \param rown The row position of the field +* \return zero if any of the values was matched +*/ +int dsp_fits_check_column(fitsfile *fptr, char* column, char **expected, long rown); + +/** +* \brief Create an open fits file pointer to be updated later +* \param size This variable will contain the initial size of the fits file pointer +* \param buf This buffer will contain the fits memfile +* \return fitsfile the fits file pointer +*/ +fitsfile* dsp_fits_create_fits(size_t *size, void **buf); + +/** +* \brief Add a binary table extension into a fits file +* \param fptr Pointer to a fits file +* \param columns An array of dsp_fits_column structs +* \param ncols The dsp_fits_column array length +* \param tablename The extension table name +* \return non-zero if any error occured +*/ +int dsp_fits_add_table(fitsfile* fptr, dsp_fits_column *columns, int ncols, const char* tablename); + +/** +* \brief Close a fits file pointer +* \param fptr The fits file pointer created by dsp_fits_create_fits +* \return non-zero if any error occured +*/ +int dsp_fits_close_fits(fitsfile *fptr); +/**\}*/ + +#ifdef __cplusplus +} +#endif + +#endif //_DSP_FITS_H diff --git a/libs/dsp/fits_extensions.h b/libs/dsp/fits_extensions.h new file mode 100644 index 0000000000..a10c851e4d --- /dev/null +++ b/libs/dsp/fits_extensions.h @@ -0,0 +1,45 @@ +/* +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _FITS_EXTENSIONS_H +#define _FITS_EXTENSIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLL_EXPORT +#define DLL_EXPORT extern +#endif + +/** + * \defgroup dsp_FitsExtensions DSP API FITS Extensions functions +*/ +/**\{*/ +/// \defgroup dsp_FitsExtensionSDFITS DSP API SDFITS Extension +#include +/// \defgroup dsp_FitsExtensionFITSIDI DSP API FITSIDI Extension +#include +/**\}*/ + +#ifdef __cplusplus +} +#endif + +#endif //_FITS_EXTENSIONS_H diff --git a/libs/dsp/fitsidi.h b/libs/dsp/fitsidi.h new file mode 100644 index 0000000000..42f91efd45 --- /dev/null +++ b/libs/dsp/fitsidi.h @@ -0,0 +1,840 @@ +/* +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _FITS_EXTENSION_FITSIDI_H +#define _FITS_EXTENSION_FITSIDI_H + +#ifdef __cplusplus +extern "C" { +#endif +#include + +/// \defgroup dsp_FitsExtensionFITSIDI DSP API FITSIDI Extension +/**\{*/ +///Antenna polarizations +///I +#define EXTFITS_STOKE_I "1" +///Q +#define EXTFITS_STOKE_Q "2" +///U +#define EXTFITS_STOKE_U "3" +///V +#define EXTFITS_STOKE_V "4" +///RR +#define EXTFITS_STOKE_RR "-1" +///LL +#define EXTFITS_STOKE_LL "-2" +///RL +#define EXTFITS_STOKE_RL "-3" +///LR +#define EXTFITS_STOKE_LR "-4" +///XX +#define EXTFITS_STOKE_XX "-5" +///YY +#define EXTFITS_STOKE_YY "-6" +///XY +#define EXTFITS_STOKE_XY "-7" +///YX +#define EXTFITS_STOKE_YX "-8" + +///FITS-IDI Convention Tables +///Antenna polarization information +#define FITS_TABLE_FITSIDI_ANTENNA "ANTENNA" +///Time system information and antenna coordinates +#define FITS_TABLE_FITSIDI_ARRAY_GEOMETRY "ARRAY_GEOMETRY" +///Channel-dependent complex gains +#define FITS_TABLE_FITSIDI_BANDPASS "BANDPASS" +///Baseline-specific gain factors +#define FITS_TABLE_FITSIDI_BASELINE "BASELINE" +///Complex gains as a function of time +#define FITS_TABLE_FITSIDI_CALIBRATION "CALIBRATION" +///Information for flagging data +#define FITS_TABLE_FITSIDI_FLAG "FLAG" +///Frequency setups +#define FITS_TABLE_FITSIDI_FREQUENCY "FREQUENCY" +///Antenna gain curves +#define FITS_TABLE_FITSIDI_GAIN_CURVE "GAIN_CURVE" +///Correlator model parameters +#define FITS_TABLE_FITSIDI_INTERFEROMETER_MODEL "INTERFEROMETER_MODEL" +///Phase cal measurements +#define FITS_TABLE_FITSIDI_PHASE_CAL "PHASE-CAL" +///Information on sources observed +#define FITS_TABLE_FITSIDI_SOURCE "SOURCE" +///System and antenna temperatures +#define FITS_TABLE_FITSIDI_SYSTEM_TEMPERATURE "SYSTEM_TEMPERATURE" +///Visibility data +#define FITS_TABLE_FITSIDI_UV_DATA "UV_DATA" +///Meteorological data +#define FITS_TABLE_FITSIDI_WEATHER "WEATHER" + +///FITS-IDI global keywords +///Name/type of correlator +#define FITSIDI_COLUMN_CORRELAT (dsp_fits_column){"CORRELAT", EXTFITS_ELEMENT_STRING.typestr, "", "", "Name/type of correlator", (char*[]){""}} +///Version number of the correlator software that produced the file +#define FITSIDI_COLUMN_FXCORVER (dsp_fits_column){"FXCORVER", EXTFITS_ELEMENT_STRING.typestr, "", "", "Version number of the correlator software that produced the file", (char*[]){""}} + +///FITS-IDI common table keywords +///Revision number of the table definition +#define FITSIDI_KEYWORD_TABREV "TABREV" +///Observation identification +#define FITSIDI_KEYWORD_OBSCODE "OBSCODE" +///The number of Stokes parameters +#define FITSIDI_KEYWORD_NO_STKD "NO_STKD" +///The first Stokes parameter coordinate value +#define FITSIDI_KEYWORD_STK_1 "STK_1" +///The number of bands +#define FITSIDI_KEYWORD_NO_BAND "NO_BAND" +///The number of spectral channels per band +#define FITSIDI_KEYWORD_NO_CHAN "NO_CHAN" +///The file reference frequency in Hz +#define FITSIDI_KEYWORD_REF_FREQ "REF_FREQ" +///The channel bandwidth in Hz for the first band in the frequency setup with frequency ID number 1 +#define FITSIDI_KEYWORD_CHAN_BW "CHAN_BW" +///The reference pixel for the frequency axis +#define FITSIDI_KEYWORD_REF_PIXL "REF_PIXL" + +///Regular axes for the FITS-IDI UV_DATA table data matrix +///Real, imaginary, weight +#define FITSIDI_UV_DATA_AXIS_COMPLEX (dsp_fits_column){"COMPLEX", "", "", "", "Real, imaginary, weight", (char*[]){""}} +///Stokes parameter +#define FITSIDI_UV_DATA_AXIS_STOKES (dsp_fits_column){"STOKES", "", "", "", "Stokes parameter", (char*[]){""}} +///Frequency (spectral channel) +#define FITSIDI_UV_DATA_AXIS_FREQ (dsp_fits_column){"FREQ", "", "", EXTFITS_MEASURE_UNIT_HZ, "Frequency (spectral channel)", (char*[]){""}} +///Band number +#define FITSIDI_UV_DATA_AXIS_BAND (dsp_fits_column){"BAND", "", "", EXTFITS_MEASURE_UNIT_HZ, "Band number", (char*[]){""}} +///Right ascension of the phase center +#define FITSIDI_UV_DATA_AXIS_RA (dsp_fits_column){"RA", "", "", EXTFITS_MEASURE_UNIT_DEGREE, "Right ascension of the phase center", (char*[]){""}} +///Declination of the phase center +#define FITSIDI_UV_DATA_AXIS_DEC (dsp_fits_column){"DEC", "", "", EXTFITS_MEASURE_UNIT_DEGREE, "Declination of the phase center", (char*[]){""}} + +///Random parameters for the FITS-IDI UV_DATA table +///seconds u baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_UU (dsp_fits_column){"UU", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "u baseline coordinate (-SIN system)", (char*[]){""}} +///seconds v baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_VV (dsp_fits_column){"VV", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "v baseline coordinate (-SIN system)", (char*[]){""}} +///seconds w baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_WW (dsp_fits_column){"WW", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "w baseline coordinate (-SIN system)", (char*[]){""}} +///seconds u baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_UU_SIN (dsp_fits_column){"UU---SIN", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "u baseline coordinate (-SIN system)", (char*[]){""}} +///seconds v baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_VV_SIN (dsp_fits_column){"VV---SIN", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "v baseline coordinate (-SIN system)", (char*[]){""}} +///seconds w baseline coordinate (-SIN system) +#define FITSIDI_UV_DATA_COLUMN_WW_SIN (dsp_fits_column){"WW---SIN", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "w baseline coordinate (-SIN system)", (char*[]){""}} +///seconds u baseline coordinate (-NCP system) +#define FITSIDI_UV_DATA_COLUMN_UU_NCP (dsp_fits_column){"UU---NCP", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "u baseline coordinate (-NCP system)", (char*[]){""}} +///seconds v baseline coordinate (-NCP system) +#define FITSIDI_UV_DATA_COLUMN_VV_NCP (dsp_fits_column){"VV---NCP", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "v baseline coordinate (-NCP system)", (char*[]){""}} +///seconds w baseline coordinate (-NCP system) +#define FITSIDI_UV_DATA_COLUMN_WW_NCP (dsp_fits_column){"WW---NCP", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "w baseline coordinate (-NCP system)", (char*[]){""}} +///days Julian date at 0 hours +#define FITSIDI_UV_DATA_COLUMN_DATE (dsp_fits_column){"DATE", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Julian date at 0 hours", (char*[]){""}} +///days Time elapsed since 0 hours +#define FITSIDI_UV_DATA_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Time elapsed since 0 hours", (char*[]){""}} +///Baseline number +#define FITSIDI_UV_DATA_COLUMN_BASELINE (dsp_fits_column){"BASELINE", "1J", "", "", "Baseline number", (char*[]){""}} +///Array number +#define FITSIDI_UV_DATA_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Source ID number +#define FITSIDI_UV_DATA_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Frequency setup ID number +#define FITSIDI_UV_DATA_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup ID number", (char*[]){""}} +///seconds Integration time +#define FITSIDI_UV_DATA_COLUMN_INTTIM (dsp_fits_column){"INTTIM", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "Integration time", (char*[]){""}} +///Weights +#define FITSIDI_UV_DATA_COLUMN_WEIGHT(nstokes, nband) (dsp_fits_column){"WEIGHT", EXTFITS_ELEMENT_FLOAT.typestr itostr(nstokes) "," itostr(nband), "", "", "Weights", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI UV_DATA table +///2 +#define FITSIDI_UV_DATA_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "2", (char*[]){""}} + +///The number of Stokes parameters +#define FITSIDI_UV_DATA_KEYWORD_NO_STKD (dsp_fits_keyword){"NO_STKD", EXTFITS_ELEMENT_SHORT.typestr, "", "", "The number of Stokes parameters", (char*[]){""}} +///The first Stokes parameter coordinate value +#define FITSIDI_UV_DATA_KEYWORD_STK_1 (dsp_fits_keyword){"STK_1", EXTFITS_ELEMENT_SHORT.typestr, "", "", "The first Stokes parameter coordinate value", (char*[]){""}} +///The number of bands +#define FITSIDI_UV_DATA_KEYWORD_NO_BAND (dsp_fits_keyword){"NO_BAND", EXTFITS_ELEMENT_SHORT.typestr, "", "", "The number of bands", (char*[]){""}} +///The number of spectral channels per band +#define FITSIDI_UV_DATA_KEYWORD_NO_CHAN (dsp_fits_keyword){"NO_CHAN", EXTFITS_ELEMENT_SHORT.typestr, "", "", "The number of spectral channels per band", (char*[]){""}} +///The file reference frequency in Hz +#define FITSIDI_UV_DATA_KEYWORD_REF_FREQ (dsp_fits_keyword){"REF_FREQ", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "The file reference frequency in Hz", (char*[]){""}} +///The channel bandwidth in Hz for the first band in the frequency setup with frequency ID number 1 +#define FITSIDI_UV_DATA_KEYWORD_CHAN_BW (dsp_fits_keyword){"CHAN_BW", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "The channel bandwidth in Hz for the first band in the frequency setup with frequency ID number 1", (char*[]){""}} +///The reference pixel for the frequency axis +#define FITSIDI_UV_DATA_KEYWORD_REF_PIXL (dsp_fits_keyword){"REF_PIXL", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "The reference pixel for the frequency axis", (char*[]){""}} +///Mean equinox +#define FITSIDI_UV_DATA_KEYWORD_EQUINOX (dsp_fits_keyword){"EQUINOX", "8A", "", "", "Mean equinox", (char*[]){""}} +///Type of data weights +#define FITSIDI_UV_DATA_KEYWORD_WEIGHTYP (dsp_fits_keyword){"WEIGHTYP", "8A", "", "", "Type of data weights", (char*[]){""}} + +///Columns for the FITS-IDI ARRAY_GEOMETRY table +///Antenna name +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_ANNAME (dsp_fits_column){"ANNAME", "8A", "", "", "Antenna name", (char*[]){""}} +///meters Antenna station coordinates (x, y, z) +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_STABXYZ (dsp_fits_column){"STABXYZ", "3D", EXTFITS_MEASURE_UNIT_METER, "", "Antenna station coordinates (x, y, z)", (char*[]){""}} +///meters/s First-order derivatives of the station coordinates with respect to time +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_DERXYZ (dsp_fits_column){"DERXYZ", "3E", "meters/s", "", "First-order derivatives of the station coordinates with respect to time", (char*[]){""}} +///Orbital parameters +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_ORBPARM(norb) (dsp_fits_column){"ORBPARM", EXTFITS_ELEMENT_DOUBLE.typestr itostr(norb), "", "", "Orbital parameters", (char*[]){""}} +///Antenna number +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_NOSTA (dsp_fits_column){"NOSTA", "1I", "", "", "Antenna number", (char*[]){""}} +///Mount type +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_MNTSTA (dsp_fits_column){"MNTSTA", "1J", "", "", "Mount type", (char*[]){""}} +///meters Axis offset +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_STAXOF (dsp_fits_column){"STAXOF", "3E", EXTFITS_MEASURE_UNIT_METER, "", "Axis offset", (char*[]){""}} +///meters Antenna diameter +#define FITSIDI_ARRAY_GEOMETRY_COLUMN_DIAMETER (dsp_fits_column){"DIAMETER", "1E", EXTFITS_MEASURE_UNIT_METER, "", "Antenna diameter", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI ARRAY_GEOMETRY table +///1 +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Array number +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_EXTVER (dsp_fits_keyword){"EXTVER", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Array number", (char*[]){""}} +///Array name +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_ARRNAM (dsp_fits_keyword){"ARRNAM", EXTFITS_ELEMENT_STRING.typestr, "", "", "Array name", (char*[]){""}} +///Coordinate frame +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_FRAME (dsp_fits_keyword){"FRAME", EXTFITS_ELEMENT_STRING.typestr, "", "", "Coordinate frame", (char*[]){""}} +///x coordinate of array center (m) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_ARRAYX (dsp_fits_keyword){"ARRAYX", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "x coordinate of array center (m)", (char*[]){""}} +///y coordinate of array center (m) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_ARRAYY (dsp_fits_keyword){"ARRAYY", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "y coordinate of array center (m)", (char*[]){""}} +///z coordinate of array center (m) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_ARRAYZ (dsp_fits_keyword){"ARRAYZ", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "z coordinate of array center (m)", (char*[]){""}} +///norb= number orbital parameters in table +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_NUMORB (dsp_fits_keyword){"NUMORB", EXTFITS_ELEMENT_SHORT.typestr, "", "", "norb= number orbital parameters in table", (char*[]){""}} +///Reference frequency (Hz) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_FREQ (dsp_fits_keyword){"FREQ", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "Reference frequency (Hz)", (char*[]){""}} +///Time system +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_TIMESYS (dsp_fits_keyword){"TIMESYS", EXTFITS_ELEMENT_STRING.typestr, "", "", "Time system", (char*[]){""}} +///Reference date +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_RDATE (dsp_fits_keyword){"RDATE", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Reference date", (char*[]){""}} +///GST at 0h on reference date (degrees) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_GSTIA0 (dsp_fits_keyword){"GSTIA0", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "GST at 0h on reference date (degrees)", (char*[]){""}} +///Earth's rotation rate (degrees/day) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_DEGPDY (dsp_fits_keyword){"DEGPDY", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "Earth's rotation rate (degrees/day)", (char*[]){""}} +///UT1 - UTC (sec) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_UT1UTC (dsp_fits_keyword){"UT1UTC", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "UT1 - UTC (sec)", (char*[]){""}} +///IAT - UTC (sec) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_IATUTC (dsp_fits_keyword){"IATUTC", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "IAT - UTC (sec)", (char*[]){""}} +///x coordinate of North Pole (arc seconds) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_POLARX (dsp_fits_keyword){"POLARX", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "x coordinate of North Pole (arc seconds)", (char*[]){""}} +///y coordinate of North Pole (arc seconds) +#define FITSIDI_ARRAY_GEOMETRY_KEYWORD_POLARY (dsp_fits_keyword){"POLARY", EXTFITS_ELEMENT_FLOAT.typestr, "", "", "y coordinate of North Pole (arc seconds)", (char*[]){""}} + +///Columns for the FITS-IDI ANTENNA table +///days Central time of period covered by record +#define FITSIDI_ANTENNA_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of period covered by record", (char*[]){""}} +///days Duration of period covered by record +#define FITSIDI_ANTENNA_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of period covered by record", (char*[]){""}} +///Antenna name +#define FITSIDI_ANTENNA_COLUMN_ANNAME (dsp_fits_column){"ANNAME", "8A", "", "", "Antenna name", (char*[]){""}} +///Antenna number +#define FITSIDI_ANTENNA_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_ANTENNA_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_ANTENNA_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Number of digitizer levels +#define FITSIDI_ANTENNA_COLUMN_NO_LEVELS (dsp_fits_column){"NO_LEVELS", "1J", "", "", "Number of digitizer levels", (char*[]){""}} +///Feed A polarization label +#define FITSIDI_ANTENNA_COLUMN_POLTYA (dsp_fits_column){"POLTYA", "1A", "Feed A polarization label", (char*[]){""}} +///degrees Feed A orientation +#define FITSIDI_ANTENNA_COLUMN_POLAA(nband) (dsp_fits_column){"POLAA", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_DEGREE, "", "Feed A orientation", (char*[]){""}} +///Feed A polarization parameters +#define FITSIDI_ANTENNA_COLUMN_POLCALA(npcal, nband) (dsp_fits_column){"POLCALA", EXTFITS_ELEMENT_FLOAT.typestr itostr(npcal) "," itostr(nband), "", "", "Feed A polarization parameters", (char*[]){""}} +///Feed B polarization label +#define FITSIDI_ANTENNA_COLUMN_POLTYB (dsp_fits_column){"POLTYB", "1A", "Feed B polarization label", (char*[]){""}} +///degrees Feed B orientation +#define FITSIDI_ANTENNA_COLUMN_POLAB(nband) (dsp_fits_column){"POLAB", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_DEGREE, "", "Feed B orientation", (char*[]){""}} +///Feed B polarization parameters +#define FITSIDI_ANTENNA_COLUMN_POLCALB(npcal, nband) (dsp_fits_column){"POLCALB", EXTFITS_ELEMENT_FLOAT.typestr itostr(npcal) "," itostr(nband), "", "", "Feed B polarization parameters", (char*[]){""}} +///degrees / m Antenna beam fwhm +#define FITSIDI_ANTENNA_COLUMN_BEAMFWHM(nband) (dsp_fits_column){"BEAMFWHM", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_DEGREE, "", "/ m Antenna beam fwhm", (char*[]){""}} + +///Polarization parameters +///Linear approximation for circular feeds +#define FITSIDI_ANTENNA_POLPARM_APPROX "APPROX" +///Linear approximation for linear feeds +#define FITSIDI_ANTENNA_POLPARM_LIN "X-Y LIN" +///Orientation and ellipticity +#define FITSIDI_ANTENNA_POLPARM_ORI_ELP "ORI-ELP" + +///Mandatory keywords for the FITS-IDI ANTENNA table +///1 +#define FITSIDI_ANTENNA_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///npcal = 0 or 2, number of polarization calibration constants +#define FITSIDI_ANTENNA_KEYWORD_NOPCAL (dsp_fits_keyword){"NOPCAL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "npcal = 0 or 2, number of polarization calibration constants", (char*[]){""}} +///The feed polarization parameterization +#define FITSIDI_ANTENNA_KEYWORD_POLTYPE (dsp_fits_keyword){"POLTYPE", EXTFITS_ELEMENT_STRING.typestr, "", "", "The feed polarization parameterization", (char*[]){""}} + +///Columns for the FITS-IDI FREQUENCY table +///Frequency setup number +#define FITSIDI_FREQUENCY_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Hz Frequency offsets +#define FITSIDI_FREQUENCY_COLUMN_BANDFREQ(nband) (dsp_fits_column){"BANDFREQ", EXTFITS_ELEMENT_DOUBLE.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Frequency offsets", (char*[]){""}} +///Hz Individual channel widths +#define FITSIDI_FREQUENCY_COLUMN_CH_WIDTH(nband) (dsp_fits_column){"CH_WIDTH", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Individual channel widths", (char*[]){""}} +///Hz Total bandwidths of bands +#define FITSIDI_FREQUENCY_COLUMN_TOTAL_BANDWIDTH(nband) (dsp_fits_column){"TOTAL_BANDWIDTH", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Total bandwidths of bands", (char*[]){""}} +///Sideband flag +#define FITSIDI_FREQUENCY_COLUMN_SIDEBAND(nband) (dsp_fits_column){"SIDEBAND", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Sideband flag", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI FREQUENCY table +///1 +#define FITSIDI_FREQUENCY_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} + +///Frames of reference for VELTYP +///Local standard of rest +#define FITSIDI_SOURCE_VELTYP_LSR "LSR" +///Solar system barycenter +#define FITSIDI_SOURCE_VELTYP_BARYCENT "BARYCENT" +///Center of mass of the Earth +#define FITSIDI_SOURCE_VELTYP_GEOCENTR "GEOCENTR" +///Uncorrected +#define FITSIDI_SOURCE_VELTYP_TOPOCENT "TOPOCENT" + +///Columns for the FITS-IDI SOURCE table +///Source ID number +#define FITSIDI_SOURCE_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Source name +#define FITSIDI_SOURCE_COLUMN_SOURCE (dsp_fits_column){"SOURCE", "16A", "", "", "Source name", (char*[]){""}} +///Source name numeric qualifier +#define FITSIDI_SOURCE_COLUMN_QUAL (dsp_fits_column){"QUAL", "1J", "", "", "Source name numeric qualifier", (char*[]){""}} +///Calibrator code +#define FITSIDI_SOURCE_COLUMN_CALCODE (dsp_fits_column){"CALCODE", "4A", "", "", "Calibrator code", (char*[]){""}} +///Frequency setup number +#define FITSIDI_SOURCE_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Jy Stokes I flux density +#define FITSIDI_SOURCE_COLUMN_IFLUX(nband) (dsp_fits_column){"IFLUX", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Jy", "", "Stokes I flux density", (char*[]){""}} +///Jy Stokes Q flux density +#define FITSIDI_SOURCE_COLUMN_QFLUX(nband) (dsp_fits_column){"QFLUX", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Jy", "", "Stokes Q flux density", (char*[]){""}} +///Jy Stokes U flux density +#define FITSIDI_SOURCE_COLUMN_UFLUX(nband) (dsp_fits_column){"UFLUX", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Jy", "", "Stokes U flux density", (char*[]){""}} +///Jy Stokes V flux density +#define FITSIDI_SOURCE_COLUMN_VFLUX(nband) (dsp_fits_column){"VFLUX", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Jy", "", "Stokes V flux density", (char*[]){""}} +///Jy Spectral index for each band +#define FITSIDI_SOURCE_COLUMN_ALPHA(nband) (dsp_fits_column){"ALPHA", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Jy", "", "Spectral index for each band", (char*[]){""}} +///Hz Frequency offset for each band +#define FITSIDI_SOURCE_COLUMN_FREQOFF(nband) (dsp_fits_column){"FREQOFF", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Frequency offset for each band", (char*[]){""}} +///degrees Right ascension at mean equinox +#define FITSIDI_SOURCE_COLUMN_RAEPO (dsp_fits_column){"RAEPO", "1D", EXTFITS_MEASURE_UNIT_DEGREE, "", "Right ascension at mean equinox", (char*[]){""}} +///degrees Declination at mean equinox +#define FITSIDI_SOURCE_COLUMN_DECEPO (dsp_fits_column){"DECEPO", "1D", EXTFITS_MEASURE_UNIT_DEGREE, "", "Declination at mean equinox", (char*[]){""}} +///Mean equinox +#define FITSIDI_SOURCE_COLUMN_EQUINOX (dsp_fits_column){"EQUINOX", "8A", "", "", "Mean equinox", (char*[]){""}} +///degrees Apparent right ascension +#define FITSIDI_SOURCE_COLUMN_RAAPP (dsp_fits_column){"RAAPP", "1D", EXTFITS_MEASURE_UNIT_DEGREE, "", "Apparent right ascension", (char*[]){""}} +///degrees Apparent declination +#define FITSIDI_SOURCE_COLUMN_DECAPP (dsp_fits_column){"DECAPP", "1D", EXTFITS_MEASURE_UNIT_DEGREE, "", "Apparent declination", (char*[]){""}} +///meters/sec Systemic velocity for each band +#define FITSIDI_SOURCE_COLUMN_SYSVEL(nband) (dsp_fits_column){"SYSVEL", EXTFITS_ELEMENT_DOUBLE.typestr itostr(nband), "meters/sec", "", "Systemic velocity for each band", (char*[]){""}} +///Velocity type +#define FITSIDI_SOURCE_COLUMN_VELTYP (dsp_fits_column){"VELTYP", "8A", "", "", "Velocity type", (char*[]){""}} +///Velocity definition +#define FITSIDI_SOURCE_COLUMN_VELDEF (dsp_fits_column){"VELDEF", "8A", "", "", "Velocity definition", (char*[]){""}} +///Hz Line rest frequency for each band +#define FITSIDI_SOURCE_COLUMN_RESTFREQ(nband) (dsp_fits_column){"RESTFREQ", EXTFITS_ELEMENT_DOUBLE.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Line rest frequency for each band", (char*[]){""}} +///degrees/day Proper motion in right ascension +#define FITSIDI_SOURCE_COLUMN_PMRA (dsp_fits_column){"PMRA", "1D", "degrees/day", "", "Proper motion in right ascension", (char*[]){""}} +///degrees/day Proper motion in declination +#define FITSIDI_SOURCE_COLUMN_PMDEC (dsp_fits_column){"PMDEC", "1D", "degrees/day", "", "Proper motion in declination", (char*[]){""}} +///arcseconds Parallax of source +#define FITSIDI_SOURCE_COLUMN_PARALLAX (dsp_fits_column){"PARALLAX", "1E", EXTFITS_MEASURE_UNIT_ARCSEC, "", "Parallax of source", (char*[]){""}} +///years Epoch of observation +#define FITSIDI_SOURCE_COLUMN_EPOCH (dsp_fits_column){"EPOCH", "1D", EXTFITS_MEASURE_UNIT_YEAR, "", "Epoch of observation", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI SOURCE table +///1 +#define FITSIDI_SOURCE_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} + +///Columns for the FITS-IDI INTERFEROMETER_MODEL table +///days Starting time of interval +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Starting time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///rad m−2 Ionospheric Faraday rotation +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_I_FAR_ROT (dsp_fits_column){"I.FAR.ROT", "1E", "rad m−2", "", "Ionospheric Faraday rotation", (char*[]){""}} +///Hz Time variable frequency offsets +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_FREQ_VAR(nband) (dsp_fits_column){"FREQ.VAR", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Time variable frequency offsets", (char*[]){""}} +///turns Phase delay polynomials for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_PDELAY_1(npoly, nband) (dsp_fits_column){"PDELAY_1", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), "turns", "", "Phase delay polynomials for polarization 1", (char*[]){""}} +///seconds Group delay polynomials for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_GDELAY_1(npoly, nband) (dsp_fits_column){"GDELAY_1", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), EXTFITS_MEASURE_UNIT_SECOND, "", "Group delay polynomials for polarization 1", (char*[]){""}} +///Hz Phase delay rate polynomials for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_PRATE_1(npoly, nband) (dsp_fits_column){"PRATE_1", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Phase delay rate polynomials for polarization 1", (char*[]){""}} +///sec/sec Group delay rate polynomials for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_GRATE_1(npoly, nband) (dsp_fits_column){"GRATE_1", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), "sec/sec", "", "Group delay rate polynomials for polarization 1", (char*[]){""}} +///sec m−2 Dispersive delay for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_DISP_1 (dsp_fits_column){"DISP_1", "1E", EXTFITS_MEASURE_UNIT_SECOND, "", "Dispersive delay for polarization 1", (char*[]){""}} +///sec m−2/sec Rate of change of dispersive delay for polarization 1 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_DDISP_1 (dsp_fits_column){"DDISP_1", "1E", "sec m−2/sec", "", " Rate of change of dispersive delay for polarization 1", (char*[]){""}} +///turns Phase delay polynomials for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_PDELAY_2(npoly, nband) (dsp_fits_column){"PDELAY_2", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), "turns", "", "Phase delay polynomials for polarization 2", (char*[]){""}} +///seconds Group delay polynomials for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_GDELAY_2(npoly, nband) (dsp_fits_column){"GDELAY_2", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), EXTFITS_MEASURE_UNIT_SECOND, "", "Group delay polynomials for polarization 2", (char*[]){""}} +///Hz Phase delay rate polynomials for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_PRATE_2(npoly, nband) (dsp_fits_column){"PRATE_2", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Phase delay rate polynomials for polarization 2", (char*[]){""}} +///sec/sec Group delay rate polynomials for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_GRATE_2(npoly, nband) (dsp_fits_column){"GRATE_2", EXTFITS_ELEMENT_DOUBLE.typestr itostr(npoly) "," itostr(nband), "sec/sec", "", "Group delay rate polynomials for polarization 2", (char*[]){""}} +///sec m−2 Dispersive delay for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_DISP_2 (dsp_fits_column){"DISP_2", "1E", EXTFITS_MEASURE_UNIT_SECOND, "", "Dispersive delay for polarization 2", (char*[]){""}} +///sec m−2/sec Rate of change of dispersive delay for polarization 2 +#define FITSIDI_INTERFEROMETER_MODEL_COLUMN_DDISP_2 (dsp_fits_column){"DDISP_2", "1E", "sec m−2/sec", "", " Rate of change of dispersive delay for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI INTERFEROMETER_MODEL table +///2 +#define FITSIDI_INTERFEROMETER_MODEL_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "2", (char*[]){""}} +///Number of polynomial terms npoly +#define FITSIDI_INTERFEROMETER_MODEL_KEYWORD_NPOLY (dsp_fits_keyword){"NPOLY", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polynomial terms npoly", (char*[]){""}} +///Number of polarizations +#define FITSIDI_INTERFEROMETER_MODEL_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations", (char*[]){""}} + +///Columns for the FITS-IDI SYSTEM_TEMPERATURE table +///days Central time of interval +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Kelvin System temperatures for polarization 1 +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TSYS_1(nband) (dsp_fits_column){"TSYS_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "System temperatures for polarization 1", (char*[]){""}} +///Kelvin Antenna temperatures for polarization 1 +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TANT_1(nband) (dsp_fits_column){"TANT_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "Antenna temperatures for polarization 1", (char*[]){""}} +///Kelvin System temperatures for polarization 2 +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TSYS_2(nband) (dsp_fits_column){"TSYS_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "System temperatures for polarization 2", (char*[]){""}} +///Kelvin Antenna temperatures for polarization 2 +#define FITSIDI_SYSTEM_TEMPERATURE_COLUMN_TANT_2(nband) (dsp_fits_column){"TANT_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "Antenna temperatures for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI SYSTEM_TEMPERATURE table +///1 +#define FITSIDI_SYSTEM_TEMPERATURE_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_SYSTEM_TEMPERATURE_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} + +///Types for x and y values +///None +#define XY_None "0" +///Elevation in degrees +#define XY_Elevation_in_degrees "1" +///Zenith angle in degrees +#define XY_Zenith_angle_in_degrees "2" +///Hour angle in degrees +#define XY_Hour_angle_in_degrees "3" +///Declination in degrees +#define XY_Declination_in_degrees "4" +///Co-declination in degrees +#define XY_Codeclination_in_degrees "5" + +///Spherical harmonic coefficients in GAIN_1 and GAIN 2 +///A00 +#define spherical_harmonic_coefficients_A00 "1" +///A10 +#define spherical_harmonic_coefficients_A10 "2" +///A11E +#define spherical_harmonic_coefficients_A11E "3" +///A110 +#define spherical_harmonic_coefficients_A110 "4" +///A20 +#define spherical_harmonic_coefficients_A20 "5" +///A21E +#define spherical_harmonic_coefficients_A21E "6" +///A210 +#define spherical_harmonic_coefficients_A210 "7" +///A22E +#define spherical_harmonic_coefficients_A22E "8" +///A220 +#define spherical_harmonic_coefficients_A220 "9" +///A30 +#define spherical_harmonic_coefficients_A30 "10" + +///Columns for the FITS-IDI GAIN_CURVE table +///Antenna number +#define FITSIDI_GAIN_CURVE_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_GAIN_CURVE_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_GAIN_CURVE_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Gain curve types for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_TYPE_1(nband) (dsp_fits_column){"TYPE_1", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Gain curve types for polarization 1", (char*[]){""}} +///Number of terms or entries for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_NTERM_1(nband) (dsp_fits_column){"NTERM_1", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Number of terms or entries for polarization 1", (char*[]){""}} +///x value types for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_X_TYP_1(nband) (dsp_fits_column){"X_TYP_1", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "x value types for polarization 1", (char*[]){""}} +///y value types for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_Y_TYP_1(nband) (dsp_fits_column){"Y_TYP_1", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "y value types for polarization 1", (char*[]){""}} +///x values for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_X_VAL_1(nband) (dsp_fits_column){"X_VAL_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "x values for polarization 1", (char*[]){""}} +///y values for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_Y_VAL_1(ntab, nband) (dsp_fits_column){"Y_VAL_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntab) "," itostr(nband), "", "", "y values for polarization 1", (char*[]){""}} +///Relative gain values for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_GAIN_1(ntab, nband) (dsp_fits_column){"GAIN_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntab) "," itostr(nband), "", "", "Relative gain values for polarization 1", (char*[]){""}} +///K/Jy Sensitivities for polarization 1 +#define FITSIDI_GAIN_CURVE_COLUMN_SENS_1(nband) (dsp_fits_column){"SENS_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "K/Jy", "", " Sensitivities for polarization 1", (char*[]){""}} +///Gain curve types for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_TYPE_2(nband) (dsp_fits_column){"TYPE_2", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Gain curve types for polarization 2", (char*[]){""}} +///Number of terms or entries for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_NTERM_2(nband) (dsp_fits_column){"NTERM_2", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Number of terms or entries for polarization 2", (char*[]){""}} +///x value types for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_X_TYP_2(nband) (dsp_fits_column){"X_TYP_2", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "x value types for polarization 2", (char*[]){""}} +///y value types for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_Y_TYP_2(nband) (dsp_fits_column){"Y_TYP_2", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "y value types for polarization 2", (char*[]){""}} +///x values for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_X_VAL_2(nband) (dsp_fits_column){"X_VAL_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "x values for polarization 2", (char*[]){""}} +///y values for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_Y_VAL_2(ntab, nband) (dsp_fits_column){"Y_VAL_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntab) "," itostr(nband), "", "", "y values for polarization 2", (char*[]){""}} +///Relative gain values for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_GAIN_2(ntab, nband) (dsp_fits_column){"GAIN_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntab) "," itostr(nband), "", "", "Relative gain values for polarization 2", (char*[]){""}} +///K/Jy Sensitivities for polarization 2 +#define FITSIDI_GAIN_CURVE_COLUMN_SENS_2(nband) (dsp_fits_column){"SENS_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "K/Jy", "", " Sensitivities for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI GAIN_CURVE table +///1 +#define FITSIDI_GAIN_CURVE_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_GAIN_CURVE_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} +///Number of tabulated values ntab +#define FITSIDI_GAIN_CURVE_KEYWORD_NO_TABS (dsp_fits_keyword){"NO_TABS", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of tabulated values ntab", (char*[]){""}} + +///Columns for the FITS-IDI PHASE-CAL table +///days Central time of interval +#define FITSIDI_PHASE_CAL_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_PHASE_CAL_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_PHASE_CAL_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_PHASE_CAL_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_PHASE_CAL_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_PHASE_CAL_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///seconds Cable calibration measurement +#define FITSIDI_PHASE_CAL_COLUMN_CABLE_CAL (dsp_fits_column){"CABLE_CAL", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "Cable calibration measurement", (char*[]){""}} +///percent State counts for polarization 1 +#define FITSIDI_PHASE_CAL_COLUMN_STATE_1(nband) (dsp_fits_column){"STATE_1", "E4,", nband), EXTFITS_MEASURE_UNIT_PERCENT, "", "State counts for polarization 1", (char*[]){""}} +///Hz Phase-cal tone frequencies for polarization 1 +#define FITSIDI_PHASE_CAL_COLUMN_PC_FREQ_1(ntone, nband) (dsp_fits_column){"PC_FREQ_1", EXTFITS_ELEMENT_DOUBLE.typestr itostr(ntone) "," itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Phase-cal tone frequencies for polarization 1", (char*[]){""}} +///Real parts of phase-cal measurements for polarization 1 +#define FITSIDI_PHASE_CAL_COLUMN_PC_REAL_1(ntone, nband) (dsp_fits_column){"PC_REAL_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "", "", "Real parts of phase-cal measurements for polarization 1", (char*[]){""}} +///Imaginary parts of phase-cal measurements for polarization 1 +#define FITSIDI_PHASE_CAL_COLUMN_PC_IMAG_1(ntone, nband) (dsp_fits_column){"PC_IMAG_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "", "", "Imaginary parts of phase-cal measurements for polarization 1", (char*[]){""}} +///sec/sec Phase-cal rates for polarization 1 +#define FITSIDI_PHASE_CAL_COLUMN_PC_RATE_1(ntone, nband) (dsp_fits_column){"PC_RATE_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "sec/sec", "", "Phase-cal rates for polarization 1", (char*[]){""}} +///percent State counts for polarization 2 +#define FITSIDI_PHASE_CAL_COLUMN_STATE_2(nband) (dsp_fits_column){"STATE_2", "E4,", nband), EXTFITS_MEASURE_UNIT_PERCENT, "", "State counts for polarization 2", (char*[]){""}} +///Hz Phase-cal tone frequencies for polarization 2 +#define FITSIDI_PHASE_CAL_COLUMN_PC_FREQ_2(ntone, nband) (dsp_fits_column){"PC_FREQ_2", EXTFITS_ELEMENT_DOUBLE.typestr itostr(ntone) "," itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Phase-cal tone frequencies for polarization 2", (char*[]){""}} +///Real parts of phase-cal measurements for polarization 2 +#define FITSIDI_PHASE_CAL_COLUMN_PC_REAL_2(ntone, nband) (dsp_fits_column){"PC_REAL_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "", "", "Real parts of phase-cal measurements for polarization 2", (char*[]){""}} +///Imaginary parts of phase-cal measurements for polarization 2 +#define FITSIDI_PHASE_CAL_COLUMN_PC_IMAG_2(ntone, nband) (dsp_fits_column){"PC_IMAG_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "", "", "Imaginary parts of phase-cal measurements for polarization 2", (char*[]){""}} +///sec/sec Phase-cal rates for polarization 2 +#define FITSIDI_PHASE_CAL_COLUMN_PC_RATE_2(ntone, nband) (dsp_fits_column){"PC_RATE_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(ntone) "," itostr(nband), "sec/sec", "", "Phase-cal rates for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI PHASE-CAL table +///2 +#define FITSIDI_PHASE_CAL_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "2", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_PHASE_CAL_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} +///Number of tones ntone +#define FITSIDI_PHASE_CAL_KEYWORD_NO_TABS (dsp_fits_keyword){"NO_TABS", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of tones ntone", (char*[]){""}} + +///Recommended SEVERITY codes +///No severity level assigned +#define severity_No_severity_level_assigned "-1" +///Data are known to be useless +#define severity_Data_are_known_to_be_useless "0" +///Data are probably useless +#define severity_Data_are_probably_useless "1" +///Data may be useless +#define severity_Data_may_be_useless "2" + +///Columns for the FITS-IDI FLAG table +///Source ID number +#define FITSIDI_FLAG_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Array number +#define FITSIDI_FLAG_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Antenna numbers +#define FITSIDI_FLAG_COLUMN_ANTS (dsp_fits_column){"ANTS", "2J", "", "", "Antenna numbers", (char*[]){""}} +///Frequency setup number +#define FITSIDI_FLAG_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///days Time range +#define FITSIDI_FLAG_COLUMN_TIMERANG (dsp_fits_column){"TIMERANG", "2E", EXTFITS_MEASURE_UNIT_DAY, "", "Time range", (char*[]){""}} +///Band flags +#define FITSIDI_FLAG_COLUMN_BANDS(nband) (dsp_fits_column){"BANDS", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Band flags", (char*[]){""}} +///Channel range +#define FITSIDI_FLAG_COLUMN_CHANS (dsp_fits_column){"CHANS", "2J", "", "", "Channel range", (char*[]){""}} +///Polarization flags +#define FITSIDI_FLAG_COLUMN_PFLAGS (dsp_fits_column){"PFLAGS", "4J", "", "", "Polarization flags", (char*[]){""}} +///Reason for flag +#define FITSIDI_FLAG_COLUMN_REASON(n) (dsp_fits_column){"REASON" itostr(n), EXTFITS_ELEMENT_STRING.typestr, "", "", "Reason for flag", (char*[]){""}} +///Severity code +#define FITSIDI_FLAG_COLUMN_SEVERITY (dsp_fits_column){"SEVERITY", "1J", "", "", "Severity code", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI FLAG table +///2 +#define FITSIDI_FLAG_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "2", (char*[]){""}} + +///Columns for the FITS-IDI WEATHER table +///days Central time of interval +#define FITSIDI_WEATHER_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_WEATHER_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Antenna number +#define FITSIDI_WEATHER_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Centigrade Surface air temperature +#define FITSIDI_WEATHER_COLUMN_TEMPERATURE (dsp_fits_column){"TEMPERATURE", "1E", "", "", "Centigrade Surface air temperature", (char*[]){""}} +///millibar Surface air pressure +#define FITSIDI_WEATHER_COLUMN_PRESSURE (dsp_fits_column){"PRESSURE", "1E", "millibar", "", "Surface air pressure", (char*[]){""}} +///Centigrade Dewpoint temperature +#define FITSIDI_WEATHER_COLUMN_DEWPOINT (dsp_fits_column){"DEWPOINT", "1E", "", "", "Centigrade Dewpoint temperature", (char*[]){""}} +///m s−1 Wind velocity +#define FITSIDI_WEATHER_COLUMN_WIND_VELOCITY (dsp_fits_column){"WIND_VELOCITY", "1E", "m s−1", "", " Wind velocity", (char*[]){""}} +///degrees Wind direction East from North +#define FITSIDI_WEATHER_COLUMN_WIND_DIRECTION (dsp_fits_column){"WIND_DIRECTION", "1E", EXTFITS_MEASURE_UNIT_DEGREE, "", "Wind direction East from North", (char*[]){""}} +///m−2 Water column +#define FITSIDI_WEATHER_COLUMN_WVR_H2O (dsp_fits_column){"WVR_H2O", "1E", "m−2", "", "Water column", (char*[]){""}} +///m−2 Electron column +#define FITSIDI_WEATHER_COLUMN_IONOS_ELECTRON (dsp_fits_column){"IONOS_ELECTRON", "1E", "m−2", "", "Electron column", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI WEATHER table +///2 +#define FITSIDI_WEATHER_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "2", (char*[]){""}} +///Reference date +#define FITSIDI_WEATHER_KEYWORD_RDATE (dsp_fits_keyword){"RDATE", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Reference date", (char*[]){""}} + +///Columns for the FITS-IDI BASELINE table +///days Central time of interval +#define FITSIDI_BASELINE_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_BASELINE_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Array number +#define FITSIDI_BASELINE_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Antenna numbers forming baseline +#define FITSIDI_BASELINE_COLUMN_ANTENNA_NOS (dsp_fits_column){"ANTENNA_NOS.", "2J", "", "", "Antenna numbers forming baseline", (char*[]){""}} +///Frequency setup number +#define FITSIDI_BASELINE_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Real part of multiplicative correction +#define FITSIDI_BASELINE_COLUMN_REAL_M(nstokes, nband) (dsp_fits_column){"REAL_M", EXTFITS_ELEMENT_FLOAT.typestr itostr(nstokes) "," itostr(nband), "", "", "Real part of multiplicative correction", (char*[]){""}} +///Imaginary part of multiplicative correction +#define FITSIDI_BASELINE_COLUMN_IMAG_M(nstokes, nband) (dsp_fits_column){"IMAG_M", EXTFITS_ELEMENT_FLOAT.typestr itostr(nstokes) "," itostr(nband), "", "", "Imaginary part of multiplicative correction", (char*[]){""}} +///Real part of additive correction +#define FITSIDI_BASELINE_COLUMN_REAL_A(nstokes, nband) (dsp_fits_column){"REAL_A", EXTFITS_ELEMENT_FLOAT.typestr itostr(nstokes) "," itostr(nband), "", "", "Real part of additive correction", (char*[]){""}} +///Imaginary part of additive correction +#define FITSIDI_BASELINE_COLUMN_IMAG_A(nstokes, nband) (dsp_fits_column){"IMAG_A", EXTFITS_ELEMENT_FLOAT.typestr itostr(nstokes) "," itostr(nband), "", "", "Imaginary part of additive correction", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI BASELINE table +///1 +#define FITSIDI_BASELINE_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Maximum antenna number in the table +#define FITSIDI_BASELINE_KEYWORD_NO_ANT (dsp_fits_keyword){"NO_ANT", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Maximum antenna number in the table", (char*[]){""}} + +///Columns for the FITS-IDI BANDPASS table +///days Central time of interval +#define FITSIDI_BANDPASS_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_BANDPASS_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_BANDPASS_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_BANDPASS_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_BANDPASS_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_BANDPASS_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Hz Channel bandwidth +#define FITSIDI_BANDPASS_COLUMN_BANDWIDTH (dsp_fits_column){"BANDWIDTH", "1E", EXTFITS_MEASURE_UNIT_HZ, "", "Channel bandwidth", (char*[]){""}} +///Hz Frequency of each band +#define FITSIDI_BANDPASS_COLUMN_BAND_FREQ(nband) (dsp_fits_column){"BAND_FREQ", EXTFITS_ELEMENT_DOUBLE.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "Frequency of each band", (char*[]){""}} +///Reference antenna for polarization 1 +#define FITSIDI_BANDPASS_COLUMN_REFANT_1 (dsp_fits_column){"REFANT_1", "1J", "", "", "Reference antenna for polarization 1", (char*[]){""}} +///Real part of bandpass correction for polarization 1 +#define FITSIDI_BANDPASS_COLUMN_BREAL_1(nbach, nband) (dsp_fits_column){"BREAL_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nbach) "," itostr(nband), "", "", "Real part of bandpass correction for polarization 1", (char*[]){""}} +///Imaginary part of bandpass correction for polarization 1 +#define FITSIDI_BANDPASS_COLUMN_BIMAG_1(nbach, nband) (dsp_fits_column){"BIMAG_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nbach) "," itostr(nband), "", "", "Imaginary part of bandpass correction for polarization 1", (char*[]){""}} +///Reference antenna for polarization 2 +#define FITSIDI_BANDPASS_COLUMN_REFANT_2 (dsp_fits_column){"REFANT_2", "1J", "", "", "Reference antenna for polarization 2", (char*[]){""}} +///Real part of bandpass correction for polarization 2 +#define FITSIDI_BANDPASS_COLUMN_BREAL_2(nbach, nband) (dsp_fits_column){"BREAL_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nbach) "," itostr(nband), "", "", "Real part of bandpass correction for polarization 2", (char*[]){""}} +///Imaginary part of bandpass correction for polarization 2 +#define FITSIDI_BANDPASS_COLUMN_BIMAG_2(nbach, nband) (dsp_fits_column){"BIMAG_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nbach) "," itostr(nband), "", "", "Imaginary part of bandpass correction for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI BANDPASS table +///1 +#define FITSIDI_BANDPASS_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Maximum antenna number in the table +#define FITSIDI_BANDPASS_KEYWORD_NO_ANT (dsp_fits_keyword){"NO_ANT", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Maximum antenna number in the table", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_BANDPASS_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} +///Number of spectral channels in the table +#define FITSIDI_BANDPASS_KEYWORD_NO_BACH (dsp_fits_keyword){"NO_BACH", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of spectral channels in the table", (char*[]){""}} +///Data channel number for first channel in the table +#define FITSIDI_BANDPASS_KEYWORD_STRT_CHN (dsp_fits_keyword){"STRT_CHN", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Data channel number for first channel in the table", (char*[]){""}} + +///Columns for the FITS-IDI CALIBRATION table +///days Central time of interval +#define FITSIDI_CALIBRATION_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///days Duration of interval +#define FITSIDI_CALIBRATION_COLUMN_TIME_INTERVAL (dsp_fits_column){"TIME_INTERVAL", "1E", EXTFITS_MEASURE_UNIT_DAY, "", "Duration of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_CALIBRATION_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_CALIBRATION_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_CALIBRATION_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_CALIBRATION_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///Kelvin System temperature for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_TSYS_1(nband) (dsp_fits_column){"TSYS_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "System temperature for polarization 1", (char*[]){""}} +///Kelvin Antenna temperature for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_TANT_1(nband) (dsp_fits_column){"TANT_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "Antenna temperature for polarization 1", (char*[]){""}} +///Kelvin/Jy Sensitivity at polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_SENSITIVITY_1(nband) (dsp_fits_column){"SENSITIVITY_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Kelvin/Jy", "", "Sensitivity at polarization 1", (char*[]){""}} +///radians Phase at polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_PHASE_1(nband) (dsp_fits_column){"PHASE_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_RAD, "", "Phase at polarization 1", (char*[]){""}} +///sec/sec Rate of change of delay of polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_RATE_1(nband) (dsp_fits_column){"RATE_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "sec/sec", "", "Rate of change of delay of polarization 1", (char*[]){""}} +///seconds Delay of polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_DELAY_1(nband) (dsp_fits_column){"DELAY_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_SECOND, "", "Delay of polarization 1", (char*[]){""}} +///Complex gain real part for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_REAL_1(nband) (dsp_fits_column){"REAL_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Complex gain real part for polarization 1", (char*[]){""}} +///Complex gain imaginary part for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_IMAG_1(nband) (dsp_fits_column){"IMAG_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Complex gain imaginary part for polarization 1", (char*[]){""}} +///Reliability weight of complex gain for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_WEIGHT_1(nband) (dsp_fits_column){"WEIGHT_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Reliability weight of complex gain for polarization 1", (char*[]){""}} +///Reference antenna for polarization 1 +#define FITSIDI_CALIBRATION_COLUMN_REFANT_1(nband) (dsp_fits_column){"REFANT_1", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Reference antenna for polarization 1", (char*[]){""}} +///Kelvin System temperature for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_TSYS_2(nband) (dsp_fits_column){"TSYS_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "System temperature for polarization 2", (char*[]){""}} +///Kelvin Antenna temperature for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_TANT_2(nband) (dsp_fits_column){"TANT_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_KELVIN, "", "Antenna temperature for polarization 2", (char*[]){""}} +///Kelvin/Jy Sensitivity at polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_SENSITIVITY_2(nband) (dsp_fits_column){"SENSITIVITY_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Kelvin/Jy", "", "Sensitivity at polarization 2", (char*[]){""}} +///radians Phase at polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_PHASE_2(nband) (dsp_fits_column){"PHASE_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_RAD, "", "Phase at polarization 2", (char*[]){""}} +///sec/sec Rate of change of delay of polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_RATE_2(nband) (dsp_fits_column){"RATE_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "sec/sec", "", "Rate of change of delay of polarization 2", (char*[]){""}} +///seconds Delay of polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_DELAY_2(nband) (dsp_fits_column){"DELAY_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_SECOND, "", "Delay of polarization 2", (char*[]){""}} +///Complex gain real part for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_REAL_2(nband) (dsp_fits_column){"REAL_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Complex gain real part for polarization 2", (char*[]){""}} +///Complex gain imaginary part for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_IMAG_2(nband) (dsp_fits_column){"IMAG_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Complex gain imaginary part for polarization 2", (char*[]){""}} +///Reliability weight of complex gain for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_WEIGHT_2(nband) (dsp_fits_column){"WEIGHT_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "", "", "Reliability weight of complex gain for polarization 2", (char*[]){""}} +///Reference antenna for polarization 2 +#define FITSIDI_CALIBRATION_COLUMN_REFANT_2(nband) (dsp_fits_column){"REFANT_2", EXTFITS_ELEMENT_INT.typestr itostr(nband), "", "", "Reference antenna for polarization 2", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI CALIBRATION table +///1 +#define FITSIDI_CALIBRATION_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Maximum antenna number in the table +#define FITSIDI_CALIBRATION_KEYWORD_NO_ANT (dsp_fits_keyword){"NO_ANT", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Maximum antenna number in the table", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_CALIBRATION_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} + +///Columns for the FITS-IDI MODEL_COMPS table +///days Central time of interval +#define FITSIDI_MODEL_COMPS_COLUMN_TIME (dsp_fits_column){"TIME", "1D", EXTFITS_MEASURE_UNIT_DAY, "", "Central time of interval", (char*[]){""}} +///Source ID number +#define FITSIDI_MODEL_COMPS_COLUMN_SOURCE_ID (dsp_fits_column){"SOURCE_ID", "1J", "", "", "Source ID number", (char*[]){""}} +///Antenna number +#define FITSIDI_MODEL_COMPS_COLUMN_ANTENNA_NO (dsp_fits_column){"ANTENNA_NO", "1J", "", "", "Antenna number", (char*[]){""}} +///Array number +#define FITSIDI_MODEL_COMPS_COLUMN_ARRAY (dsp_fits_column){"ARRAY", "1J", "", "", "Array number", (char*[]){""}} +///Frequency setup number +#define FITSIDI_MODEL_COMPS_COLUMN_FREQID (dsp_fits_column){"FREQID", "1J", "", "", "Frequency setup number", (char*[]){""}} +///sec Atmospheric delay +#define FITSIDI_MODEL_COMPS_COLUMN_ATMOS (dsp_fits_column){"ATMOS", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "Atmospheric delay", (char*[]){""}} +///sec/sec Time derivative of atmospheric delay +#define FITSIDI_MODEL_COMPS_COLUMN_DATMOS (dsp_fits_column){"DATMOS", "1D", "sec/sec", "", "Time derivative of atmospheric delay", (char*[]){""}} +///sec Group delay +#define FITSIDI_MODEL_COMPS_COLUMN_GDELAY (dsp_fits_column){"GDELAY", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "Group delay", (char*[]){""}} +///sec/sec Rate of change of group delay +#define FITSIDI_MODEL_COMPS_COLUMN_GRATE (dsp_fits_column){"GRATE", "1D", "sec/sec", "", "Rate of change of group delay", (char*[]){""}} +///sec 'Clock' epoch error +#define FITSIDI_MODEL_COMPS_COLUMN_CLOCK_1 (dsp_fits_column){"CLOCK_1", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "'Clock' epoch error", (char*[]){""}} +///sec/sec Time derivative of clock error +#define FITSIDI_MODEL_COMPS_COLUMN_DCLOCK_1 (dsp_fits_column){"DCLOCK_1", "1D", "sec/sec", "", "Time derivative of clock error", (char*[]){""}} +///Hz LO offset +#define FITSIDI_MODEL_COMPS_COLUMN_LO_OFFSET_1(nband) (dsp_fits_column){"LO_OFFSET_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "LO offset", (char*[]){""}} +///Hz/sec Time derivative of LO offset +#define FITSIDI_MODEL_COMPS_COLUMN_DLO_OFFSET_1(nband) (dsp_fits_column){"DLO_OFFSET_1", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Hz/sec", "", "Time derivative of LO offset", (char*[]){""}} +///sec m−2 Dispersive delay +#define FITSIDI_MODEL_COMPS_COLUMN_DISP_1 (dsp_fits_column){"DISP_1", "1E", EXTFITS_MEASURE_UNIT_SECOND, "", "Dispersive delay", (char*[]){""}} +///sec m−2/sec Time derivative of dispersive delay +#define FITSIDI_MODEL_COMPS_COLUMN_DDISP_1 (dsp_fits_column){"DDISP_1", "1E", "sec m−2/sec", "", " Time derivative of dispersive delay", (char*[]){""}} +///sec 'Clock' epoch error +#define FITSIDI_MODEL_COMPS_COLUMN_CLOCK_2 (dsp_fits_column){"CLOCK_2", "1D", EXTFITS_MEASURE_UNIT_SECOND, "", "'Clock' epoch error", (char*[]){""}} +///sec/sec Time derivative of clock error +#define FITSIDI_MODEL_COMPS_COLUMN_DCLOCK_2 (dsp_fits_column){"DCLOCK_2", "1D", "sec/sec", "", "Time derivative of clock error", (char*[]){""}} +///Hz LO offset +#define FITSIDI_MODEL_COMPS_COLUMN_LO_OFFSET_2(nband) (dsp_fits_column){"LO_OFFSET_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), EXTFITS_MEASURE_UNIT_HZ, "", "LO offset", (char*[]){""}} +///Hz/sec Time derivative of LO offset +#define FITSIDI_MODEL_COMPS_COLUMN_DLO_OFFSET_2(nband) (dsp_fits_column){"DLO_OFFSET_2", EXTFITS_ELEMENT_FLOAT.typestr itostr(nband), "Hz/sec", "", "Time derivative of LO offset", (char*[]){""}} +///sec m−2 Dispersive delay +#define FITSIDI_MODEL_COMPS_COLUMN_DISP_2 (dsp_fits_column){"DISP_2", "1E", EXTFITS_MEASURE_UNIT_SECOND, "", "Dispersive delay", (char*[]){""}} +///sec m−2/sec Time derivative of dispersive delay +#define FITSIDI_MODEL_COMPS_COLUMN_DDISP_2 (dsp_fits_column){"DDISP_2", "1E", "sec m−2/sec", "", "Time derivative of dispersive delay", (char*[]){""}} + +///Mandatory keywords for the FITS-IDI MODEL_COMPS table +///1 +#define FITSIDI_MODEL_COMPS_KEYWORD_TABREV (dsp_fits_keyword){"TABREV", EXTFITS_ELEMENT_SHORT.typestr, "", "", "1", (char*[]){""}} +///Reference date +#define FITSIDI_MODEL_COMPS_KEYWORD_RDATE (dsp_fits_keyword){"RDATE", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Reference date", (char*[]){""}} +///Number of polarizations in the table +#define FITSIDI_MODEL_COMPS_KEYWORD_NO_POL (dsp_fits_keyword){"NO_POL", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Number of polarizations in the table", (char*[]){""}} +///FFT size +#define FITSIDI_MODEL_COMPS_KEYWORD_FFT_SIZE (dsp_fits_keyword){"FFT_SIZE", EXTFITS_ELEMENT_SHORT.typestr, "", "", "FFT size", (char*[]){""}} +///Oversampling factor +#define FITSIDI_MODEL_COMPS_KEYWORD_OVERSAMP (dsp_fits_keyword){"OVERSAMP", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Oversampling factor", (char*[]){""}} +///Zero padding factor +#define FITSIDI_MODEL_COMPS_KEYWORD_ZERO_PAD (dsp_fits_keyword){"ZERO_PAD", EXTFITS_ELEMENT_SHORT.typestr, "", "", "Zero padding factor", (char*[]){""}} +///Tapering function ('HANNING' or 'UNIFORM') +#define FITSIDI_MODEL_COMPS_KEYWORD_TAPER_FN (dsp_fits_keyword){"TAPER_FN", EXTFITS_ELEMENT_STRING.typestr, "", "", "Tapering function ('HANNING' or 'UNIFORM')", (char*[]){""}} + +/** +* \brief read a fits file containing a FITS-IDI Extension +* \param filename The file name of the fits to read +* \param nstreams The number of streams of the data matrix passed by reference +* \param maxes The number of dimensions of the data matrix passed by reference +* \param maxis The sizes of the data matrix +* \return dsp_fits_row pointer describing the fits file content +*/ +dsp_fits_row *dsp_fits_read_fitsidi(char *filename, long *nstreams, long *maxes, long **maxis); +/**\}*/ + +#ifdef __cplusplus +} +#endif + +#endif //_FITS_EXTENSION_FITSIDI_H diff --git a/libs/dsp/sdfits.h b/libs/dsp/sdfits.h new file mode 100644 index 0000000000..8c90ef7508 --- /dev/null +++ b/libs/dsp/sdfits.h @@ -0,0 +1,304 @@ +/* +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _FITS_EXTENSION_SDFITS_H +#define _FITS_EXTENSION_SDFITS_H + +#ifdef __cplusplus +extern "C" { +#endif +#include + +/// \defgroup dsp_FitsExtensionSDFITS DSP API SDFITS Extension +/**\{*/ +///SDFITS Convention Table +#define FITS_TABLE_SDFITS "SINGLE DISH" + +///SDFITS columns +///common FITS usage +#define SDFITS_COLUMN_OBJECT (dsp_fits_column){"OBJECT", "8A", "", "", "common FITS usage", (char*[]){""}} +///common FITS keyword +#define SDFITS_COLUMN_TELESCOP (dsp_fits_column){"TELESCOP", "8A", "", "", "common FITS keyword", (char*[]){""}} +///resolution may differ from spacing of backend, not one channel +#define SDFITS_COLUMN_FREQRES (dsp_fits_column){"FREQRES", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_HZ, "", "resolution may differ from spacing of backend, not one channel", (char*[]){""}} +#define SDFITS_COLUMN_BANDWID (dsp_fits_column){"BANDWID", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_HZ, "", "", (char*[]){""}} +///common FITS usage; JD preferable? +#define SDFITS_COLUMN_DATE_OBS (dsp_fits_column){"DATE-OBS", "8A", "", "", "common FITS usage; JD preferable?", (char*[]){""}} +///UT time of day; UT seconds since Oh UT +#define SDFITS_COLUMN_TIME (dsp_fits_column){"TIME", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_SECOND, "", "UT time of day; UT seconds since Oh UT", (char*[]){""}} +///effective integration time +#define SDFITS_COLUMN_EXPOSURE (dsp_fits_column){"EXPOSURE", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_SECOND, "", "effective integration time", (char*[]){""}} +///system, not receiver, temperature +#define SDFITS_COLUMN_TSYS (dsp_fits_column){"TSYS", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "system, not receiver, temperature", (char*[]){""}} +///Target right ascension coordinate +#define SDFITS_COLUMN_OBJCTRA (dsp_fits_column){"OBJCTRA", EXTFITS_ELEMENT_STRING.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Target right ascension coordinate", (char*[]){""}} +///Target declination coordinate +#define SDFITS_COLUMN_OBJCTDEC (dsp_fits_column){"OBJCTDEC", EXTFITS_ELEMENT_STRING.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Target declination coordinate", (char*[]){""}} +///Data buffer +#define SDFITS_COLUMN_DATA (dsp_fits_column){"DATA", "", "", "", "", (char*[]){""}} + +///OBSMODE +///average +#define OBSTYPE_LINE "LINE" +///continuum +#define OBSTYPE_CONT "CONT" +///pulses +#define OBSTYPE_PULS "PULS" + +///position switch +#define OBSMODE_PSSW "PSSW" +///frequency switch +#define OBSMODE_FQSW "FQSW" +///beam switch +#define OBSMODE_BMSW "BMSW" +///phase-lock switch +#define OBSMODE_PLSW "PLSW" +///load switch +#define OBSMODE_LDSW "LDSW" +///total power +#define OBSMODE_TLPW "TLPW" + +///average +#define OBSMODE_LINE_PSSW OBSTYPE_LINE OBSMODE_PSSW +///frequency switch +#define OBSMODE_LINE_FQSW OBSTYPE_LINE OBSMODE_FQSW +///beam switch +#define OBSMODE_LINE_BMSW OBSTYPE_LINE OBSMODE_BMSW +///phase-lock switch +#define OBSMODE_LINE_PLSW OBSTYPE_LINE OBSMODE_PLSW +///load switch +#define OBSMODE_LINE_LDSW OBSTYPE_LINE OBSMODE_LDSW +///total power +#define OBSMODE_LINE_TLPW OBSTYPE_LINE OBSMODE_TLPW + +///continuum +///position switch +#define OBSMODE_CONT_PSSW OBSTYPE_CONT OBSMODE_PSSW +///frequency switch +#define OBSMODE_CONT_FQSW OBSTYPE_CONT OBSMODE_FQSW +///beam switch +#define OBSMODE_CONT_BMSW OBSTYPE_CONT OBSMODE_BMSW +///phase-lock switch +#define OBSMODE_CONT_PLSW OBSTYPE_CONT OBSMODE_PLSW +///load switch +#define OBSMODE_CONT_LDSW OBSTYPE_CONT OBSMODE_LDSW +///total power +#define OBSMODE_CONT_TLPW OBSTYPE_CONT OBSMODE_TLPW + +///pulses +///position switch +#define OBSMODE_PULS_PSSW OBSTYPE_PULS OBSMODE_PSSW +///frequency switch +#define OBSMODE_PULS_FQSW OBSTYPE_PULS OBSMODE_FQSW +///beam switch +#define OBSMODE_PULS_BMSW OBSTYPE_PULS OBSMODE_BMSW +///phase-lock switch +#define OBSMODE_PULS_PLSW OBSTYPE_PULS OBSMODE_PLSW +///load switch +#define OBSMODE_PULS_LDSW OBSTYPE_PULS OBSMODE_LDSW +///total power +#define OBSMODE_PULS_TLPW OBSTYPE_PULS OBSMODE_TLPW + +///TEMPSCAL +#define TEMPSCAL_TB "TB" +#define TEMPSCAL_TA "TA" +#define TEMPSCAL_TA_TR "TA*TR" +#define TEMPSCAL_TR "TR*" + +///VELDEF +#define VELDEF_RADI "*RADI" +#define VELDEF_OPTI "OPTI" +#define VELDEF_RELA "RELA" +#define VELDEF_LSR "LSR" +#define VELDEF_HELO "HELO" +#define VELDEF_EART "EART" +#define VELDEF_BARI "BARI" +#define VELDEF_OBS "-OBS" + +///SDFITS columns +///Observer name +#define SDFITS_COLUMN_OBSERVER (dsp_fits_column){"OBSERVER", "8A", "", "", "Observer name", (char*[]){""}} +///Observer & operator initials; +#define SDFITS_COLUMN_OBSID (dsp_fits_column){"OBSID", "8A", "", "", "Observer & operator initials", (char*[]){""}} +///Project ID; +#define SDFITS_COLUMN_PROJID (dsp_fits_column){"PROJID", "8A", "", "", "Project ID", (char*[]){""}} +///Scan number +#define SDFITS_COLUMN_SCAN (dsp_fits_column){"SCAN", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Scan number", (char*[]){""}} +///Type of data, observing mode; +#define SDFITS_COLUMN_OBSMODE (dsp_fits_column){"OBSMODE", "8A", "", "", "Type of data, observing mode", (char*[]){OBSMODE_LINE_PSSW, OBSMODE_LINE_FQSW, OBSMODE_LINE_BMSW, OBSMODE_LINE_PLSW, OBSMODE_LINE_LDSW, OBSMODE_LINE_TLPW, OBSMODE_CONT_PSSW, OBSMODE_CONT_FQSW, OBSMODE_CONT_BMSW, OBSMODE_CONT_PLSW, OBSMODE_CONT_LDSW, OBSMODE_CONT_TLPW, OBSMODE_PULS_PSSW, OBSMODE_PULS_FQSW, OBSMODE_PULS_BMSW, OBSMODE_PULS_PLSW, OBSMODE_PULS_LDSW, OBSMODE_PULS_TLPW}} +///Molecule observed or detected; +#define SDFITS_COLUMN_MOLECULE (dsp_fits_column){"MOLECULE", "8A", "", "", "Molecule observed or detected", (char*[]){""}} +///As appropriate; +#define SDFITS_COLUMN_TRANSITI (dsp_fits_column){"TRANSITI", "8A", "", "", "As appropriate", (char*[]){""}} +///Normalization of TA; +#define SDFITS_COLUMN_TEMPSCAL (dsp_fits_column){"TEMPSCAL", "8A", "", "", "Normalization of TA", (char*[]){""}} +/// +#define SDFITS_COLUMN_FRONTEND (dsp_fits_column){"FRONTEND", "8A", "", "", "", (char*[]){""}} +///Calibration Temp (K) +#define SDFITS_COLUMN_TCAL (dsp_fits_column){"TCAL", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Calibration Temp", (char*[]){""}} +///Hot load temperature (K) +#define SDFITS_COLUMN_THOT (dsp_fits_column){"THOT", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Hot load temperature", (char*[]){""}} +///Cold load temperature (K) +#define SDFITS_COLUMN_TCOLD (dsp_fits_column){"TCOLD", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Cold load temperature", (char*[]){""}} +///Receiver Temp (K), Float +#define SDFITS_COLUMN_TRX (dsp_fits_column){"TRX", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Receiver Temp, Float", (char*[]){""}} +///Velocity definition & frame; +#define SDFITS_COLUMN_VELDEF (dsp_fits_column){"VELDEF", "8A", "", "", "Velocity definition & frame", (char*[]){VELDEF_RADI, VELDEF_OPTI, VELDEF_RELA, VELDEF_LSR, VELDEF_HELO, VELDEF_EART, VELDEF_BARI, VELDEF_OBS, ""}} +///radial velocity correction; Vref - Vtel +#define SDFITS_COLUMN_VCORR (dsp_fits_column){"VCORR", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "radial velocity correction; Vref - Vtel", (char*[]){""}} +///Observed Frequency (Hz) +#define SDFITS_COLUMN_OBSFREQ (dsp_fits_column){"OBSFREQ", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_HZ, "", "Observed Frequency", (char*[]){""}} +///Image sideband freq (Hz) +#define SDFITS_COLUMN_IMAGFREQ (dsp_fits_column){"IMAGFREQ", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_HZ, "", "Image sideband freq", (char*[]){""}} +///LST (seconds) at start of scan +#define SDFITS_COLUMN_LST (dsp_fits_column){"LST", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_SECOND, "", "LST at start of scan", (char*[]){""}} +///LST (seconds) at start of scan +#define SDFITS_COLUMN_LST (dsp_fits_column){"LST", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_SECOND, "", "LST at start of scan", (char*[]){""}} +///Commanded Azimuth (Degrees) +#define SDFITS_COLUMN_AZIMUTH (dsp_fits_column){"AZIMUTH", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Commanded Azimuth", (char*[]){""}} +///Commanded Elevation (Degrees) +#define SDFITS_COLUMN_ELEVATIO (dsp_fits_column){"ELEVATIO", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Commanded Elevation", (char*[]){""}} +///Opacity at signal freq +#define SDFITS_COLUMN_TAU (dsp_fits_column){"TAU", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_PERCENT, "", "Opacity at signal freq", (char*[]){""}} +///Opacity at image freq +#define SDFITS_COLUMN_TAUIMAGE (dsp_fits_column){"TAUIMAGE", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_PERCENT, "", "Opacity at image freq", (char*[]){""}} +///Opacity per unit air mass +#define SDFITS_COLUMN_TAUZENIT (dsp_fits_column){"TAUZENIT", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_PERCENT, "", "Opacity per unit air mass", (char*[]){""}} +///Decimal fraction 0..1 +#define SDFITS_COLUMN_HUMIDITY (dsp_fits_column){"HUMIDITY", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Decimal fraction 0..1", (char*[]){""}} +///Ambient Temp (K) +#define SDFITS_COLUMN_TAMBIENT (dsp_fits_column){"TAMBIENT", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Ambient Temp (K)", (char*[]){""}} +///Barometer reading mm Hg +#define SDFITS_COLUMN_PRESSURE (dsp_fits_column){"PRESSURE", EXTFITS_ELEMENT_DOUBLE.typestr, "mm Hg", "", "Barometer reading ", (char*[]){""}} +///Dew point (K) +#define SDFITS_COLUMN_DEWPOINT (dsp_fits_column){"DEWPOINT", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_KELVIN, "", "Dew point", (char*[]){""}} +///Wind speed m/s +#define SDFITS_COLUMN_WINDSPEE (dsp_fits_column){"WINDSPEE", EXTFITS_ELEMENT_DOUBLE.typestr, "m/s", "", "Wind speed", (char*[]){""}} +///Degrees West of North +#define SDFITS_COLUMN_WINDDIRE (dsp_fits_column){"WINDDIRE", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Degrees West of North", (char*[]){""}} +///Main-beam efficiency +#define SDFITS_COLUMN_BEAMEFF (dsp_fits_column){"BEAMEFF", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_PERCENT, "", "Main-beam efficiency", (char*[]){""}} +///Antenna Aperature Efficiency +#define SDFITS_COLUMN_APEREFF (dsp_fits_column){"APEREFF", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_PERCENT, "", "Antenna Aperature Efficiency", (char*[]){""}} +///Rear spillover +#define SDFITS_COLUMN_ETAL (dsp_fits_column){"ETAL", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Rear spillover", (char*[]){""}} +///Accounts for forward loss +#define SDFITS_COLUMN_ETAFSS (dsp_fits_column){"ETAFSS", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Accounts for forward loss", (char*[]){""}} +///K per Jy +#define SDFITS_COLUMN_ANTGAIN (dsp_fits_column){"ANTGAIN", EXTFITS_ELEMENT_DOUBLE.typestr, "K/Jy", "", "", (char*[]){""}} +///Large main-beam FWHM +#define SDFITS_COLUMN_BMAJ (dsp_fits_column){"BMAJ", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Large main-beam FWHM", (char*[]){""}} +///Small main-beam FWHM +#define SDFITS_COLUMN_BMIN (dsp_fits_column){"BMIN", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "Small main-beam FWHM", (char*[]){""}} +///Beam position angle, measured East of North +#define SDFITS_COLUMN_BPA (dsp_fits_column){"BPA", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Beam position angle", (char*[]){""}} +///Site longitude (Degrees) +#define SDFITS_COLUMN_SITELONG (dsp_fits_column){"SITELONG", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Site longitude", (char*[]){""}} +///Site latitude (Degrees) +#define SDFITS_COLUMN_SITELAT (dsp_fits_column){"SITELAT", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_DEGREE, "", "Site latitude", (char*[]){""}} +///site elevation in meters +#define SDFITS_COLUMN_SITEELEV (dsp_fits_column){"SITEELEV", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_METER, "", "site elevation", (char*[]){""}} +///Epoch of observation (year) +#define SDFITS_COLUMN_EPOCH (dsp_fits_column){"EPOCH", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_YEAR, "", "Epoch of observation", (char*[]){""}} +///Equinox of coords (year) +#define SDFITS_COLUMN_EQUINOX (dsp_fits_column){"EQUINOX", EXTFITS_ELEMENT_DOUBLE.typestr, EXTFITS_MEASURE_UNIT_YEAR, "", "Equinox of coords", (char*[]){""}} + +#define SDFITS_TABLE_MAIN (dsp_fits_column[]){\ +SDFITS_COLUMN_OBJECT,\ +SDFITS_COLUMN_TELESCOP,\ +SDFITS_COLUMN_FREQRES,\ +SDFITS_COLUMN_BANDWID,\ +SDFITS_COLUMN_DATE_OBS,\ +SDFITS_COLUMN_TIME,\ +SDFITS_COLUMN_EXPOSURE,\ +SDFITS_COLUMN_TSYS,\ +SDFITS_COLUMN_DATA,\ +SDFITS_COLUMN_OBSERVER, \ +SDFITS_COLUMN_OBSID, \ +SDFITS_COLUMN_PROJID, \ +SDFITS_COLUMN_SCAN, \ +SDFITS_COLUMN_OBSMODE, \ +SDFITS_COLUMN_MOLECULE, \ +SDFITS_COLUMN_TRANSITI, \ +SDFITS_COLUMN_TEMPSCAL, \ +SDFITS_COLUMN_FRONTEND, \ +SDFITS_COLUMN_TCAL, \ +SDFITS_COLUMN_THOT, \ +SDFITS_COLUMN_TCOLD, \ +SDFITS_COLUMN_TRX, \ +SDFITS_COLUMN_VELDEF, \ +SDFITS_COLUMN_VCORR, \ +SDFITS_COLUMN_OBSFREQ, \ +SDFITS_COLUMN_IMAGFREQ, \ +SDFITS_COLUMN_LST, \ +SDFITS_COLUMN_LST, \ +SDFITS_COLUMN_AZIMUTH, \ +SDFITS_COLUMN_ELEVATIO, \ +SDFITS_COLUMN_TAU, \ +SDFITS_COLUMN_TAUIMAGE, \ +SDFITS_COLUMN_TAUZENIT, \ +SDFITS_COLUMN_HUMIDITY, \ +SDFITS_COLUMN_TAMBIENT, \ +SDFITS_COLUMN_PRESSURE, \ +SDFITS_COLUMN_DEWPOINT, \ +SDFITS_COLUMN_WINDSPEE, \ +SDFITS_COLUMN_WINDDIRE, \ +SDFITS_COLUMN_BEAMEFF, \ +SDFITS_COLUMN_APEREFF, \ +SDFITS_COLUMN_ETAL, \ +SDFITS_COLUMN_ETAFSS, \ +SDFITS_COLUMN_ANTGAIN, \ +SDFITS_COLUMN_BMAJ, \ +SDFITS_COLUMN_BMIN, \ +SDFITS_COLUMN_BPA, \ +SDFITS_COLUMN_SITELONG, \ +SDFITS_COLUMN_SITELAT, \ +SDFITS_COLUMN_SITEELEV, \ +SDFITS_COLUMN_EPOCH, \ +SDFITS_COLUMN_EQUINOX, \ +} + +///Global keywords for the SDFITS SINGLE DISH table +///Designation of Telescope. +#define SDFITS_KEYWORD_TELESCOP (dsp_fits_keyword){"TELESCOP", "8A", "", "", "", (char*[]){""}} +///Name of observer. +#define SDFITS_KEYWORD_OBSERVER (dsp_fits_keyword){"OBSERVER", "8A", "", "", "", (char*[]){""}} +///UT date of observation (dd/mm/yy) . +#define SDFITS_KEYWORD_DATE_OBS (dsp_fits_keyword){"DATE-OBS", "8A", "", "", "", (char*[]){""}} +///Max spectral value (K) - for whole file. +#define SDFITS_KEYWORD_DATAMAX (dsp_fits_keyword){"DATAMAX", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "", (char*[]){""}} +///Min spectral value (K) - for whole file. +#define SDFITS_KEYWORD_DATAMIN (dsp_fits_keyword){"DATAMIN", EXTFITS_ELEMENT_DOUBLE.typestr, "", "", "", (char*[]){""}} + +/** +* \brief read a fits file containing a SDFITS Extension +* \param filename The file name of the fits to read +* \param nstreams The number of streams of the data matrix passed by reference +* \param maxes The number of dimensions of the data matrix passed by reference +* \param maxis The sizes of the data matrix +* \return dsp_fits_row pointer describing the fits file content +*/ +dsp_fits_row *dsp_fits_read_sdfits(char *filename, long *nstreams, long *maxes, long **maxis); +/**\}*/ + +#ifdef __cplusplus +} +#endif + +#endif //_FITS_EXTENSION_SDFITS_H diff --git a/libs/dsp/signals.c b/libs/dsp/signals.c index 7e8915a527..4e6650d59b 100644 --- a/libs/dsp/signals.c +++ b/libs/dsp/signals.c @@ -1,20 +1,21 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" @@ -55,7 +56,7 @@ void dsp_signals_sawtoothwave(dsp_stream_p stream, double samplefreq, double fre x = rad; while (x > 1.0) x -= 1.0; - stream->buf[k] = (double)(32768+32767*x); + stream->buf[k] = (dsp_t)(32768+32767*x); } } @@ -73,7 +74,7 @@ void dsp_signals_triwave(dsp_stream_p stream, double samplefreq, double freq) x -= 2.0; while (x > 1.0) x = 2.0 - x; - stream->buf[k] = (double)(32768+32767*x); + stream->buf[k] = (dsp_t)(32768+32767*x); } } @@ -86,10 +87,10 @@ void dsp_modulation_frequency(dsp_stream_p stream, double samplefreq, double fre double mx = dsp_stats_max(stream->buf, stream->len); double lo = mn * bandwidth * 1.5 / samplefreq; double hi = mx * bandwidth * 0.5 / samplefreq; - double *deviation = (double*)malloc(sizeof(double) * stream->len); + dsp_t *deviation = (dsp_t*)malloc(sizeof(dsp_t) * stream->len); dsp_buffer_copy(stream->buf, deviation, stream->len); dsp_buffer_deviate(carrier, deviation, hi, lo); - memcpy(stream->buf, carrier->buf, stream->len * sizeof(double)); + memcpy(stream->buf, carrier->buf, stream->len * sizeof(dsp_t)); dsp_stream_free(carrier); } diff --git a/libs/dsp/stats.c b/libs/dsp/stats.c index ce9258293b..80b310e50b 100755 --- a/libs/dsp/stats.c +++ b/libs/dsp/stats.c @@ -1,32 +1,44 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" double* dsp_stats_histogram(dsp_stream_p stream, int size) { + if(stream == NULL) + return NULL; int k; + long i = 0; double* out = (double*)malloc(sizeof(double)*size); - double mx = dsp_stats_max(stream->buf, stream->len); - double mn = dsp_stats_min(stream->buf, stream->len); - for(k = 1; k < size; k++) { - out[k] = dsp_stats_range_count(stream->buf, stream->len, mn + (k - 1) * (mx - mn / size), mn + k * (mx - mn / size)); + dsp_t* tmp = (dsp_t*)malloc(sizeof(dsp_t)*stream->len); + dsp_buffer_set(out, size, 0.0); + memcpy(tmp, stream->buf, sizeof(dsp_t)*stream->len); + dsp_buffer_stretch(tmp, stream->len, 0, size-1); + for(k = 0; k < stream->len; k++) { + i = (long)tmp[k]; + if(i > 0 && i < size) + out[i] ++; } + free(tmp); + dsp_t mn = dsp_stats_min(out, size); + dsp_t mx = dsp_stats_max(out, size); + if(mn < mx) + dsp_buffer_stretch(out, size, 0, size); return out; } - diff --git a/libs/dsp/stream.c b/libs/dsp/stream.c old mode 100644 new mode 100755 index 9639518973..737fe68530 --- a/libs/dsp/stream.c +++ b/libs/dsp/stream.c @@ -1,65 +1,157 @@ /* - * libDSPAU - a digital signal processing library for astronomy usage - * Copyright (C) 2017 Ilia Platone - * - * 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 3 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 . - */ +* DSP API - a digital signal processing library for astronomy usage +* Copyright © 2017-2022 Ilia Platone +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ #include "dsp.h" +static int dsp_debug = 0; +static char* dsp_app_name = NULL; + +static unsigned long MAX_THREADS = 1; + +static FILE *out = NULL; +static FILE *err = NULL; + +unsigned long int dsp_max_threads(unsigned long value) +{ + if(value>0) { + MAX_THREADS = value; + } + return MAX_THREADS; +} + +void dsp_set_stdout(FILE *f) +{ + out = f; +} + +void dsp_set_stderr(FILE *f) +{ + err = f; +} + +void dsp_print(int x, char* str) +{ + if(x == DSP_DEBUG_INFO && out != NULL) + fprintf(out, "%s", str); + else if(x <= dsp_get_debug_level() && err != NULL) + fprintf(err, "%s", str); +} + +void dsp_set_debug_level(int value) +{ + dsp_debug = value; +} + +void dsp_set_app_name(char* name) +{ + dsp_app_name = name; +} + +int dsp_get_debug_level() +{ + return dsp_debug; +} + +char* dsp_get_app_name() +{ + return dsp_app_name; +} void dsp_stream_alloc_buffer(dsp_stream_p stream, int len) { + if(stream == NULL) + return; if(stream->buf != NULL) { stream->buf = (dsp_t*)realloc(stream->buf, sizeof(dsp_t) * len); } else { stream->buf = (dsp_t*)malloc(sizeof(dsp_t) * len); } + if(stream->dft.buf != NULL) { + stream->dft.fftw = (fftw_complex*)realloc(stream->dft.buf, sizeof(fftw_complex) * len); + } else { + stream->dft.fftw = (fftw_complex*)malloc(sizeof(fftw_complex) * len); + } + if(stream->location != NULL) { + stream->location = (dsp_location*)realloc(stream->location, sizeof(dsp_location) * (stream->len)); + } else { + stream->location = (dsp_location*)malloc(sizeof(dsp_location) * (stream->len)); + } + if(stream->magnitude != NULL) + dsp_stream_alloc_buffer(stream->magnitude, len); + if(stream->phase != NULL) + dsp_stream_alloc_buffer(stream->phase, len); } void dsp_stream_set_buffer(dsp_stream_p stream, void *buffer, int len) { + if(stream == NULL) + return; stream->buf = (dsp_t*)buffer; stream->len = len; } dsp_t* dsp_stream_get_buffer(dsp_stream_p stream) { + if(stream == NULL) + return NULL; return stream->buf; } void dsp_stream_free_buffer(dsp_stream_p stream) { - if(stream->buf == NULL) + if(stream == NULL) return; - free(stream->buf); + if(stream->buf != NULL) + free(stream->buf); + if(stream->dft.buf != NULL) + free(stream->dft.buf); + if(stream->magnitude != NULL) + dsp_stream_free_buffer(stream->magnitude); + if(stream->phase != NULL) + dsp_stream_free_buffer(stream->phase); } +/** + * @brief dsp_stream_new + * @return + */ dsp_stream_p dsp_stream_new() { dsp_stream_p stream = (dsp_stream_p)malloc(sizeof(dsp_stream) * 1); - stream->buf = (dsp_t*)malloc(sizeof(dsp_t) * 1); + stream->is_copy = 0; + stream->buf = (dsp_t*)malloc(sizeof(dsp_t) * 0); + stream->dft.buf = (double*)malloc(sizeof(dsp_t) * 0); + stream->magnitude = NULL; + stream->phase = NULL; stream->sizes = (int*)malloc(sizeof(int) * 1); stream->pixel_sizes = (double*)malloc(sizeof(double) * 1); stream->children = (dsp_stream_p*)malloc(sizeof(dsp_stream_p) * 1); stream->ROI = (dsp_region*)malloc(sizeof(dsp_region) * 1); - stream->location = (double*)malloc(sizeof(double) * 3); + stream->location = (dsp_location*)malloc(sizeof(dsp_location) * 1); stream->target = (double*)malloc(sizeof(double) * 3); stream->stars = (dsp_star*)malloc(sizeof(dsp_star) * 1); + stream->triangles = (dsp_triangle*)malloc(sizeof(dsp_triangle) * 1); stream->align_info.offset = (double*)malloc(sizeof(double)*1); stream->align_info.center = (double*)malloc(sizeof(double)*1); stream->align_info.radians = (double*)malloc(sizeof(double)*1); + stream->align_info.factor = (double*)malloc(sizeof(double)*1); stream->stars_count = 0; + stream->triangles_count = 0; stream->child_count = 0; stream->frame_number = 0; stream->parent = NULL; @@ -73,43 +165,85 @@ dsp_stream_p dsp_stream_new() return stream; } +/** + * @brief dsp_stream_free + * @param stream + */ void dsp_stream_free(dsp_stream_p stream) { if(stream == NULL) return; - free(stream->sizes); - free(stream->pixel_sizes); - free(stream->children); - free(stream->ROI); - free(stream->location); - free(stream->target); + if(stream->sizes != NULL) + free(stream->sizes); + if(stream->magnitude != NULL) + dsp_stream_free(stream->magnitude); + if(stream->phase != NULL) + dsp_stream_free(stream->phase); + if(stream->is_copy == 0) { + if(stream->pixel_sizes != NULL) + free(stream->pixel_sizes); + if(stream->children != NULL) + free(stream->children); + if(stream->ROI != NULL) + free(stream->ROI); + if(stream->location != NULL) + free(stream->location); + if(stream->target != NULL) + free(stream->target); + if(stream->stars != NULL) + free(stream->stars); + if(stream->triangles != NULL) + free(stream->triangles); + } free(stream); } +/** + * @brief dsp_stream_copy + * @param stream + * @return + */ dsp_stream_p dsp_stream_copy(dsp_stream_p stream) { + if(stream == NULL) + return NULL; dsp_stream_p dest = dsp_stream_new(); int i; for(i = 0; i < stream->dims; i++) dsp_stream_add_dim(dest, abs(stream->sizes[i])); + for(i = 0; i < stream->stars_count; i++) + dsp_stream_add_star(dest, stream->stars[i]); + for(i = 0; i < stream->triangles_count; i++) + dsp_stream_add_triangle(dest, stream->triangles[i]); + dest->is_copy = stream->is_copy + 1; dsp_stream_alloc_buffer(dest, dest->len); dest->wavelength = stream->wavelength; dest->samplerate = stream->samplerate; - dest->stars_count = stream->stars_count; dest->diameter = stream->diameter; dest->focal_ratio = stream->focal_ratio; - dest->starttimeutc = stream->starttimeutc; - dest->align_info = stream->align_info; + memcpy(&dest->starttimeutc, &stream->starttimeutc, sizeof(struct timespec)); + memcpy(&dest->align_info, &stream->align_info, sizeof(dsp_align_info)); memcpy(dest->ROI, stream->ROI, sizeof(dsp_region) * stream->dims); memcpy(dest->pixel_sizes, stream->pixel_sizes, sizeof(double) * stream->dims); memcpy(dest->target, stream->target, sizeof(double) * 3); - memcpy(dest->location, stream->location, sizeof(double) * 3); - memcpy(dest->buf, stream->buf, sizeof(dsp_t) * stream->len); + if(dest->location != NULL) + memcpy(dest->location, stream->location, sizeof(dsp_location) * stream->len); + if(dest->buf != NULL) + memcpy(dest->buf, stream->buf, sizeof(dsp_t) * stream->len); + if(dest->dft.buf != NULL) + memcpy(dest->dft.buf, stream->dft.buf, sizeof(fftw_complex) * stream->len); return dest; } +/** + * @brief dsp_stream_add_dim + * @param stream + * @param size + */ void dsp_stream_add_dim(dsp_stream_p stream, int size) { + if(stream == NULL) + return; stream->sizes[stream->dims] = size; stream->len *= size; stream->dims ++; @@ -120,11 +254,45 @@ void dsp_stream_add_dim(dsp_stream_p stream, int size) stream->align_info.offset = (double*)realloc(stream->align_info.offset, sizeof(double)*stream->dims); stream->align_info.center = (double*)realloc(stream->align_info.center, sizeof(double)*stream->dims); stream->align_info.radians = (double*)realloc(stream->align_info.radians, sizeof(double)*(stream->dims-1)); - stream->align_info.factor = 0.0; + stream->align_info.factor = (double*)realloc(stream->align_info.factor, sizeof(double)*stream->dims); + if(stream->magnitude != NULL) + dsp_stream_add_dim(stream->magnitude, size); + if(stream->phase != NULL) + dsp_stream_add_dim(stream->phase, size); +} + +/** + * @brief dsp_stream_set_dim + * @param stream + * @param dim + * @param size + */ +void dsp_stream_set_dim(dsp_stream_p stream, int dim, int size) +{ + if(stream == NULL) + return; + int d = 0; + if(dim < stream->dims) { + stream->sizes[dim] = size; + stream->len = 1; + for(d = 0; d < stream->dims; d++) + stream->len *= stream->sizes[d]; + if(stream->magnitude != NULL) + dsp_stream_set_dim(stream->magnitude, dim, size); + if(stream->phase != NULL) + dsp_stream_set_dim(stream->phase, dim, size); + } } +/** + * @brief dsp_stream_del_dim + * @param stream + * @param index + */ void dsp_stream_del_dim(dsp_stream_p stream, int index) { + if(stream == NULL) + return; int* sizes = (int*)malloc(sizeof(int) * stream->dims); int dims = stream->dims; memcpy(sizes, stream->sizes, sizeof(int) * stream->dims); @@ -136,18 +304,36 @@ void dsp_stream_del_dim(dsp_stream_p stream, int index) dsp_stream_add_dim(stream, abs(sizes[i])); } } + if(stream->magnitude != NULL) + dsp_stream_del_dim(stream->magnitude, index); + if(stream->phase != NULL) + dsp_stream_del_dim(stream->phase, index); } +/** + * @brief dsp_stream_add_child + * @param stream + * @param child + */ void dsp_stream_add_child(dsp_stream_p stream, dsp_stream_p child) { + if(stream == NULL) + return; child->parent = stream; stream->children[stream->child_count] = child; stream->child_count++; - stream->children = realloc(stream->children, sizeof(dsp_stream_p) * (stream->child_count + 1)); + stream->children = (dsp_stream_p*)realloc(stream->children, sizeof(dsp_stream_p) * (stream->child_count + 1)); } +/** + * @brief dsp_stream_del_child + * @param stream + * @param index + */ void dsp_stream_del_child(dsp_stream_p stream, int index) { + if(stream == NULL) + return; dsp_stream_p* children = (dsp_stream_p*)malloc(sizeof(dsp_stream_p) * stream->child_count); int child_count = stream->child_count; memcpy(children, stream->children, sizeof(dsp_stream_p*) * stream->child_count); @@ -161,17 +347,35 @@ void dsp_stream_del_child(dsp_stream_p stream, int index) } } +/** + * @brief dsp_stream_add_star + * @param stream + * @param star + */ void dsp_stream_add_star(dsp_stream_p stream, dsp_star star) { + if(stream == NULL) + return; + int d; stream->stars = (dsp_star*)realloc(stream->stars, sizeof(dsp_star)*(stream->stars_count+1)); - stream->stars[stream->stars_count].center.dims = star.center.dims; - stream->stars[stream->stars_count].center.location = star.center.location; + strcpy(stream->stars[stream->stars_count].name, star.name); stream->stars[stream->stars_count].diameter = star.diameter; + stream->stars[stream->stars_count].center.dims = star.center.dims; + stream->stars[stream->stars_count].center.location = (double*)malloc(sizeof(double)*star.center.dims); + for(d = 0; d < star.center.dims; d++) + stream->stars[stream->stars_count].center.location[d] = star.center.location[d]; stream->stars_count++; } +/** + * @brief dsp_stream_del_star + * @param stream + * @param index + */ void dsp_stream_del_star(dsp_stream_p stream, int index) { + if(stream == NULL) + return; dsp_star* stars = (dsp_star*)malloc(sizeof(dsp_star) * stream->stars_count); int stars_count = stream->stars_count; memcpy(stars, stream->stars, sizeof(dsp_star*) * stream->stars_count); @@ -185,7 +389,71 @@ void dsp_stream_del_star(dsp_stream_p stream, int index) } } +/** + * @brief dsp_stream_add_triangle + * @param stream + * @param triangle + */ +void dsp_stream_add_triangle(dsp_stream_p stream, dsp_triangle triangle) +{ + if(stream == NULL) + return; + int s; + int d; + stream->triangles = (dsp_triangle*)realloc(stream->triangles, sizeof(dsp_triangle)*(stream->triangles_count+1)); + stream->triangles[stream->triangles_count].dims = triangle.dims; + stream->triangles[stream->triangles_count].theta = triangle.theta; + stream->triangles[stream->triangles_count].ratios = (double*)malloc(sizeof(double)*triangle.dims); + stream->triangles[stream->triangles_count].sizes = (double*)malloc(sizeof(double)*triangle.dims); + stream->triangles[stream->triangles_count].stars = (dsp_star*)malloc(sizeof(dsp_star)*triangle.dims); + stream->triangles[stream->triangles_count].ratios[0] = 1.0; + triangle.index = triangle.index; + for (s = 0; s < triangle.dims; s++) { + stream->triangles[stream->triangles_count].sizes[s] = triangle.sizes[s]; + if(s > 0) { + stream->triangles[stream->triangles_count].ratios[s] = fabs(triangle.sizes[s]/triangle.sizes[0]); + } + stream->triangles[stream->triangles_count].stars[s].center.dims = triangle.stars[s].center.dims; + stream->triangles[stream->triangles_count].stars[s].diameter = triangle.stars[s].diameter; + stream->triangles[stream->triangles_count].stars[s].center.location = (double*)malloc(sizeof(double)*triangle.stars[s].center.dims); + for(d = 0; d < triangle.stars[s].center.dims; d++) + stream->triangles[stream->triangles_count].stars[s].center.location[d] = triangle.stars[s].center.location[d]; + } + stream->triangles[stream->triangles_count].index = triangle.index; + stream->triangles_count++; +} + +/** + * @brief dsp_stream_del_triangle + * @param stream + * @param index + */ +void dsp_stream_del_triangle(dsp_stream_p stream, int index) +{ + if(stream == NULL) + return; + dsp_triangle* triangles = (dsp_triangle*)malloc(sizeof(dsp_triangle) * stream->triangles_count); + int triangles_count = stream->triangles_count; + memcpy(triangles, stream->triangles, sizeof(dsp_triangle*) * stream->triangles_count); + free(stream->triangles); + stream->triangles_count = 0; + int i; + for(i = 0; i < triangles_count; i++) { + if(i != index) { + dsp_stream_add_triangle(stream, triangles[i]); + } + } +} + +/** + * @brief dsp_stream_get_position + * @param stream + * @param index + * @return + */ int* dsp_stream_get_position(dsp_stream_p stream, int index) { + if(stream == NULL) + return NULL; int dim = 0; int y = 0; int m = 1; @@ -199,7 +467,15 @@ int* dsp_stream_get_position(dsp_stream_p stream, int index) { return pos; } +/** + * @brief dsp_stream_set_position + * @param stream + * @param pos + * @return + */ int dsp_stream_set_position(dsp_stream_p stream, int* pos) { + if(stream == NULL) + return -1; int dim = 0; int index = 0; int m = 1; @@ -210,8 +486,14 @@ int dsp_stream_set_position(dsp_stream_p stream, int* pos) { return index; } +/** + * @brief dsp_stream_crop + * @param in + */ void dsp_stream_crop(dsp_stream_p in) { + if(in == NULL) + return; dsp_stream_p stream = dsp_stream_new(); int dim, d; for(dim = 0; dim < in->dims; dim++) { @@ -247,27 +529,36 @@ void dsp_stream_crop(dsp_stream_p in) dsp_buffer_copy(stream->buf, in->buf, stream->len); dsp_stream_free_buffer(stream); dsp_stream_free(stream); + } -void dsp_stream_traslate(dsp_stream_p in) +void dsp_stream_translate(dsp_stream_p in) { + if(in == NULL) + return; dsp_stream_p stream = dsp_stream_copy(in); int* offset = (int*)malloc(sizeof(int)*stream->dims); - dsp_buffer_copy(stream->align_info.offset, offset, stream->dims); + dsp_buffer_copy(in->align_info.offset, offset, in->dims); int z = dsp_stream_set_position(stream, offset); free(offset); int k = -z; z = Max(0, z); k = Max(0, k); int len = stream->len-z-k; - dsp_t *buf = &stream->buf[k]; - dsp_t *data = &in->buf[z]; + dsp_t *buf = &stream->buf[z]; + dsp_t *data = &in->buf[k]; memset(in->buf, 0, sizeof(dsp_t)*in->len); memcpy(data, buf, sizeof(dsp_t)*len); dsp_stream_free_buffer(stream); dsp_stream_free(stream); + } +/** + * @brief dsp_stream_scale_th + * @param arg + * @return + */ static void* dsp_stream_scale_th(void* arg) { struct { @@ -277,21 +568,24 @@ static void* dsp_stream_scale_th(void* arg) dsp_stream_p stream = arguments->stream; dsp_stream_p in = stream->parent; int cur_th = arguments->cur_th; - int start = cur_th * stream->len / DSP_MAX_THREADS; - int end = start + stream->len / DSP_MAX_THREADS; + int start = cur_th * stream->len / dsp_max_threads(0); + int end = start + stream->len / dsp_max_threads(0); end = Min(stream->len, end); int y, d; for(y = start; y < end; y++) { int* pos = dsp_stream_get_position(stream, y); + double factor = 0.0; for(d = 0; d < stream->dims; d++) { - pos[d] -= stream->sizes[d]; - pos[d] /= stream->align_info.factor; - pos[d] += stream->sizes[d]; + pos[d] -= stream->align_info.center[d]; + pos[d] /= stream->align_info.factor[d]; + pos[d] += stream->align_info.center[d]; + factor += pow(stream->align_info.factor[d], 2); } + factor = sqrt(factor); int x = dsp_stream_set_position(in, pos); if(x >= 0 && x < in->len) - stream->buf[y] += in->buf[x]/(stream->align_info.factor*stream->dims); + stream->buf[y] += in->buf[x]/(factor*stream->dims); free(pos); } return NULL; @@ -299,28 +593,31 @@ static void* dsp_stream_scale_th(void* arg) void dsp_stream_scale(dsp_stream_p in) { - int y; + if(in == NULL) + return; + long unsigned int y; dsp_stream_p stream = dsp_stream_copy(in); dsp_buffer_set(stream->buf, stream->len, 0); stream->parent = in; - pthread_t *th = malloc(sizeof(pthread_t)*DSP_MAX_THREADS); + pthread_t *th = malloc(sizeof(pthread_t)*dsp_max_threads(0)); struct { int cur_th; dsp_stream_p stream; - } thread_arguments[DSP_MAX_THREADS]; - for(y = 0; y < DSP_MAX_THREADS; y++) + } thread_arguments[dsp_max_threads(0)]; + for(y = 0; y < dsp_max_threads(0); y++) { thread_arguments[y].cur_th = y; thread_arguments[y].stream = stream; pthread_create(&th[y], NULL, dsp_stream_scale_th, &thread_arguments[y]); } - for(y = 0; y < DSP_MAX_THREADS; y++) + for(y = 0; y < dsp_max_threads(0); y++) pthread_join(th[y], NULL); free(th); stream->parent = NULL; dsp_buffer_copy(stream->buf, in->buf, stream->len); dsp_stream_free_buffer(stream); dsp_stream_free(stream); + } static void* dsp_stream_rotate_th(void* arg) @@ -332,8 +629,8 @@ static void* dsp_stream_rotate_th(void* arg) dsp_stream_p stream = arguments->stream; dsp_stream_p in = stream->parent; int cur_th = arguments->cur_th; - int start = cur_th * stream->len / DSP_MAX_THREADS; - int end = start + stream->len / DSP_MAX_THREADS; + int start = cur_th * stream->len / dsp_max_threads(0); + int end = start + stream->len / dsp_max_threads(0); end = Min(stream->len, end); int y; for(y = start; y < end; y++) @@ -346,12 +643,12 @@ static void* dsp_stream_rotate_th(void* arg) double r = stream->align_info.radians[dim-1]; double x = pos[dim-1]; double y = pos[dim]; - pos[dim] = x*-cos(r-M_PI_2); + pos[dim] = x*-sin(r); pos[dim-1] = x*cos(r); pos[dim] += y*cos(r); + pos[dim-1] += y*sin(r); pos[dim] += stream->align_info.center[dim]; pos[dim-1] += stream->align_info.center[dim-1]; - pos[dim-1] += y*cos(r-M_PI_2); } int x = dsp_stream_set_position(in, pos); free(pos); @@ -363,24 +660,27 @@ static void* dsp_stream_rotate_th(void* arg) void dsp_stream_rotate(dsp_stream_p in) { + if(in == NULL) + return; dsp_stream_p stream = dsp_stream_copy(in); dsp_buffer_set(stream->buf, stream->len, 0); stream->parent = in; - int y; - pthread_t *th = malloc(sizeof(pthread_t)*DSP_MAX_THREADS); + long unsigned int y; + pthread_t *th = malloc(sizeof(pthread_t)*dsp_max_threads(0)); struct { int cur_th; dsp_stream_p stream; - } thread_arguments[DSP_MAX_THREADS]; - for(y = 0; y < DSP_MAX_THREADS; y++) { + } thread_arguments[dsp_max_threads(0)]; + for(y = 0; y < dsp_max_threads(0); y++) { thread_arguments[y].cur_th = y; thread_arguments[y].stream = stream; pthread_create(&th[y], NULL, dsp_stream_rotate_th, &thread_arguments[y]); } - for(y = 0; y < DSP_MAX_THREADS; y++) + for(y = 0; y < dsp_max_threads(0); y++) pthread_join(th[y], NULL); free(th); dsp_buffer_copy(stream->buf, in->buf, stream->len); dsp_stream_free_buffer(stream); dsp_stream_free(stream); + } diff --git a/libs/indibase/dsp/convolution.cpp b/libs/indibase/dsp/convolution.cpp index ede1c79335..62980f0947 100644 --- a/libs/indibase/dsp/convolution.cpp +++ b/libs/indibase/dsp/convolution.cpp @@ -66,44 +66,43 @@ bool Convolution::ISNewBLOB(const char *dev, const char *name, int sizes[], int if(!strcmp(dev, getDeviceName())) { if(!strcmp(name, DownloadBP.name)) { IUUpdateBLOB(&DownloadBP, sizes, blobsizes, blobs, formats, names, n); - LOGF_INFO("Received convolution matrix BLOB for %s", getDeviceName()); - if(matrix) + LOGF_INFO("Received matrix BLOB for %s", getDeviceName()); + if(matrix != nullptr) { dsp_stream_free_buffer(matrix); - dsp_stream_free(matrix); + dsp_stream_free(matrix); + } matrix = loadFITS(blobs[0], sizes[0]); - if(matrix != nullptr) { - LOGF_INFO("Convolution matrix for %s loaded", getDeviceName()); + if (matrix != nullptr) { + LOGF_INFO("Matrix for %s loaded", getDeviceName()); matrix_loaded = true; - IDSetBLOB(&DownloadBP, nullptr); + return true; } } } - return true; + return false; } -uint8_t* Convolution::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool Convolution::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; + if(!matrix_loaded) return false; setStream(buf, dims, sizes, bits_per_sample); - Convolute(); - return getStream(); -} - -void Convolution::Convolute() -{ - if(matrix_loaded) - dsp_convolution_convolution(stream, matrix); + dsp_fourier_dft(stream, 1); + dsp_fourier_dft(matrix, 1); + dsp_convolution_convolution(stream, matrix); + return Interface::processBLOB(getStream(), stream->dims, stream->sizes, bits_per_sample); } -Wavelets::Wavelets(INDI::DefaultDevice *dev) : Interface(dev, DSP_CONVOLUTION, "WAVELETS", "Wavelets") +Wavelets::Wavelets(INDI::DefaultDevice *dev) : Interface(dev, DSP_WAVELETS, "WAVELETS", "Wavelets") { for(int i = 0; i < N_WAVELETS; i++) { char strname[MAXINDINAME]; char strlabel[MAXINDILABEL]; - sprintf(strname, "WAVELET%0d", i); + sprintf(strname, "WAVELET_%0d", i); sprintf(strlabel, "%d pixels Gaussian Wavelet", (i+1)*3); IUFillNumber(&WaveletsN[i], strname, strlabel, "%3.3f", -15.0, 255.0, 1.0, 0.0); } - IUFillNumberVector(&WaveletsNP, WaveletsN, N_WAVELETS, m_Device->getDeviceName(), "WAVELET", "Wavelets", DSP_TAB, IP_RW, 60, IPS_IDLE); + IUFillNumberVector(&WaveletsNP, WaveletsN, N_WAVELETS, m_Device->getDeviceName(), "WAVELETS", "Wavelets", DSP_TAB, IP_RW, 60, IPS_IDLE); } Wavelets::~Wavelets() @@ -131,8 +130,9 @@ bool Wavelets::ISNewNumber(const char *dev, const char *name, double *values, ch return true; } -uint8_t* Wavelets::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool Wavelets::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; setStream(buf, dims, sizes, bits_per_sample); double min = dsp_stats_min(stream->buf, stream->len); double max = dsp_stats_max(stream->buf, stream->len); @@ -149,6 +149,8 @@ uint8_t* Wavelets::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_pe matrix->buf[x + y * size] = sin(static_cast(x)*M_PI/static_cast(size))*sin(static_cast(y)*M_PI/static_cast(size)); } } + dsp_fourier_dft(tmp, 1); + dsp_fourier_dft(matrix, 1); dsp_convolution_convolution(tmp, matrix); dsp_buffer_sub(tmp, matrix->buf, matrix->len); dsp_buffer_mul1(tmp, WaveletsNP.np[i].value/8.0); @@ -162,6 +164,6 @@ uint8_t* Wavelets::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_pe dsp_stream_free_buffer(stream); dsp_stream_free(stream); stream = dsp_stream_copy(out); - return getStream(); + return Interface::processBLOB(getStream(), stream->dims, stream->sizes, bits_per_sample); } } diff --git a/libs/indibase/dsp/convolution.h b/libs/indibase/dsp/convolution.h index bfdbe6104b..8ad51b85d7 100644 --- a/libs/indibase/dsp/convolution.h +++ b/libs/indibase/dsp/convolution.h @@ -33,22 +33,19 @@ class Convolution : public Interface public: Convolution(INDI::DefaultDevice *dev); bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) override; + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~Convolution(); void Activated() override; void Deactivated() override; - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; - private: - dsp_stream_p matrix; - IBLOBVectorProperty DownloadBP; IBLOB DownloadB; + dsp_stream_p matrix; bool matrix_loaded { false }; - void Convolute(); }; class Wavelets : public Interface @@ -56,14 +53,13 @@ class Wavelets : public Interface public: Wavelets(INDI::DefaultDevice *dev); bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override; + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~Wavelets(); void Activated() override; void Deactivated() override; - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; - private: dsp_stream_p matrix; diff --git a/libs/indibase/dsp/dspinterface.cpp b/libs/indibase/dsp/dspinterface.cpp index fa04a1fac2..b2e64348e9 100644 --- a/libs/indibase/dsp/dspinterface.cpp +++ b/libs/indibase/dsp/dspinterface.cpp @@ -63,9 +63,9 @@ Interface::Interface(INDI::DefaultDevice *dev, Type type, const char *name, cons char activatestrname[MAXINDINAME]; char activatestrlabel[MAXINDILABEL]; sprintf(activatestrname, "DSP_ACTIVATE_%s", m_Name); - sprintf(activatestrlabel, "Activate %s", m_Label); - IUFillSwitch(&ActivateS[0], "DSP_ACTIVATE_ON", "Activate", ISState::ISS_OFF); - IUFillSwitch(&ActivateS[1], "DSP_ACTIVATE_OFF", "Deactivate", ISState::ISS_ON); + sprintf(activatestrlabel, "%s", m_Label); + IUFillSwitch(&ActivateS[0], "DSP_ACTIVATE_ON", "On", ISState::ISS_OFF); + IUFillSwitch(&ActivateS[1], "DSP_ACTIVATE_OFF", "Off", ISState::ISS_ON); IUFillSwitchVector(&ActivateSP, ActivateS, 2, getDeviceName(), activatestrname, activatestrlabel, DSP_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); @@ -73,11 +73,22 @@ Interface::Interface(INDI::DefaultDevice *dev, Type type, const char *name, cons IUFillBLOBVector(&FitsBP, &FitsB, 1, getDeviceName(), m_Name, m_Label, DSP_TAB, IP_RO, 60, IPS_IDLE); BufferSizes = nullptr; BufferSizesQty = 0; - strncpy (FitsB.format, ".fits", MAXINDIFORMAT); + setCaptureFileExtension("fits"); + //Create the dsp stream + stream = dsp_stream_new(); + stream->magnitude = dsp_stream_new(); + stream->phase = dsp_stream_new(); + buffer = malloc(1); } Interface::~Interface() { + if(buffer != nullptr) + free(buffer); + if(stream != nullptr) { + dsp_stream_free_buffer(stream); + dsp_stream_free(stream); + } } const char *Interface::getDeviceName() @@ -179,8 +190,9 @@ uint8_t* Interface::Callback(uint8_t* buf, uint32_t ndims, int* dims, int bits_p return nullptr; } -bool Interface::processBLOB(uint8_t* buf, uint32_t ndims, int* dims, int bits_per_sample) +bool Interface::processBLOB(uint8_t* buffer, uint32_t ndims, int* dims, int bits_per_sample) { + bool success = false; if(PluginActive) { bool sendCapture = (m_Device->getSwitch("UPLOAD_MODE")->sp[0].s == ISS_ON @@ -190,32 +202,29 @@ bool Interface::processBLOB(uint8_t* buf, uint32_t ndims, int* dims, int bits_pe if (sendCapture || saveCapture) { - setSizes(ndims, dims); - setBPS(bits_per_sample); - uint8_t* buffer = Callback(buf, ndims, dims, bits_per_sample); if (buffer) { - LOGF_INFO("%s processing done. Creating file..", m_Label); - if (!strcmp(FitsB.format, ".fits")) + setSizes(ndims, dims); + setBPS(bits_per_sample); + LOGF_INFO("%s processing done.", m_Label); + + long len = 1; + uint32_t i; + for (len = 1, i = 0; i < BufferSizesQty; len *= BufferSizes[i++]); + len *= getBPS() / 8; + + if (!strcmp(captureExtention, "fits")) { - sendFITS(buffer, sendCapture, saveCapture); + success = sendFITS(buffer, sendCapture, saveCapture); } else { - long len = 1; - uint32_t i; - for (len = 1, i = 0; i < BufferSizesQty; len *= BufferSizes[i++]); - len *= getBPS() / 8; - uploadFile(buffer, len, sendCapture, saveCapture, FitsB.format); + success = uploadFile(buffer, len, sendCapture, saveCapture, captureExtention); } - - if (sendCapture) - IDSetBLOB(&FitsBP, nullptr); } - free(buffer); } } - return true; + return success; } void Interface::Activated() @@ -266,7 +275,7 @@ void Interface::addFITSKeywords(fitsfile *fptr) char lon_str[MAXINDIFORMAT]; char el_str[MAXINDIFORMAT]; fs_sexa(lat_str, Lat, 2, 360000); - fs_sexa(lat_str, Lon, 2, 360000); + fs_sexa(lon_str, Lon, 2, 360000); snprintf(el_str, MAXINDIFORMAT, "%lf", El); fits_update_key_s(fptr, TSTRING, "LATITUDE", lat_str, "Location Latitude", &status); fits_update_key_s(fptr, TSTRING, "LONGITUDE", lon_str, "Location Longitude", &status); @@ -332,84 +341,28 @@ void Interface::fits_update_key_s(fitsfile *fptr, int type, std::string name, vo dsp_stream_p Interface::loadFITS(char* buffer, int len) { - dsp_stream_p loaded_stream = dsp_stream_new(); - long ndims; - long bits_per_sample; - int status; - off_t offset; - off_t head; - off_t end; - fitsfile *fptr; - void* buf; - char error_status[MAXINDINAME]; - char comment[MAXINDINAME]; - char filename[MAXINDIMESSAGE]; - sprintf(filename, "/tmp/%s_%s_%08X.fits", m_Label, getDeviceName(), rand()); - int fd = creat(filename, 0600); - if(fd >= 0) + dsp_stream_p loaded_stream = nullptr; + char filename[MAXINDINAME]; + sprintf(filename, "INDI_DSP_INTERFACE_XXXXXX"); + int fd = mkstemp(filename); + if(fd > 0) { int written = write(fd, buffer, len); if(written != len) return nullptr; close(fd); + int channels = 0; + dsp_stream_p *stream_arr = dsp_file_read_fits(filename, &channels, false); + if (channels > 0) { + loaded_stream = stream_arr[channels]; + for (int c = 0; c < channels; c++) { + dsp_stream_free_buffer(stream_arr[c]); + dsp_stream_free(stream_arr[c]); + } + free(stream_arr); + } + unlink(filename); } - fits_open_file(&fptr, filename, 0, &status); - if(status != 0) - goto load_err; - fits_read_key_lng(fptr, "BITPIX", &bits_per_sample, comment, &status); - if(status != 0) - goto load_err; - fits_read_key_lng(fptr, "NAXIS", &ndims, comment, &status); - if(status != 0) - goto load_err; - for (int d = 1; d <= ndims; d++) - { - char query[MAXINDINAME]; - long value; - sprintf(query, "NAXIS%d", d); - fits_read_key_lng(fptr, query, &value, comment, &status); - if(status != 0) - goto load_err; - dsp_stream_add_dim(loaded_stream, value); - } - dsp_stream_alloc_buffer(loaded_stream, loaded_stream->len); - fits_get_hduoff(fptr, &head, &offset, &end, &status); - buf = static_cast(&buffer[offset]); - switch (bits_per_sample) - { - case 8: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto err_free; - case 16: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto err_free; - case 32: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto err_free; - case 64: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto err_free; - case -32: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto err_free; - case -64: - dsp_buffer_copy((static_cast(buf)), loaded_stream->buf, loaded_stream->len); - goto dsp_err; - default: - break; - } -load_err: - fits_report_error(stderr, status); /* print out any error messages */ - fits_get_errstatus(status, error_status); - LOGF_ERROR("FITS Error: %s", error_status); -dsp_err: - //Destroy the dsp stream - dsp_stream_free_buffer(loaded_stream); - dsp_stream_free(loaded_stream); - return nullptr; -err_free: - fits_close_file(fptr, &status); - unlink(filename); return loaded_stream; } @@ -429,18 +382,18 @@ bool Interface::sendFITS(uint8_t *buf, bool sendCapture, bool saveCapture) case 16: byte_type = TUSHORT; img_type = USHORT_IMG; - bit_depth = "16 bits per sample"; + bit_depth = "16 bits per pixel"; break; case 32: - byte_type = TULONG; + byte_type = TUINT; img_type = ULONG_IMG; bit_depth = "32 bits per sample"; break; case 64: - byte_type = TLONGLONG; - img_type = LONGLONG_IMG; + byte_type = TLONG; + img_type = ULONG_IMG; bit_depth = "64 bits double per sample"; break; @@ -519,10 +472,10 @@ bool Interface::sendFITS(uint8_t *buf, bool sendCapture, bool saveCapture) LOGF_ERROR("FITS Error: %s", error_status); return false; } - fits_close_file(fptr, &status); - uploadFile(memptr, memsize, sendCapture, saveCapture, "fits"); + uploadFile(memptr, memsize, sendCapture, saveCapture, captureExtention); + free(memptr); return true; } @@ -533,8 +486,13 @@ bool Interface::uploadFile(const void *fitsData, size_t totalBytes, bool sendCap DEBUGF(INDI::Logger::DBG_DEBUG, "Uploading file. Ext: %s, Size: %d, sendCapture? %s, saveCapture? %s", format, totalBytes, sendCapture ? "Yes" : "No", saveCapture ? "Yes" : "No"); - FitsB.blob = const_cast(fitsData); + FitsB.blob = const_cast(fitsData); FitsB.bloblen = static_cast(totalBytes); + FitsB.size = totalBytes; + FitsBP.s = IPS_BUSY; + + snprintf(FitsB.format, MAXINDIBLOBFMT, ".%s", captureExtention); + if (saveCapture) { @@ -570,6 +528,8 @@ bool Interface::uploadFile(const void *fitsData, size_t totalBytes, bool sendCap prefix = std::regex_replace(prefix, std::regex("XXX"), prefixIndex); } + char processedFileName[MAXINDINAME]; + snprintf(processedFileName, MAXINDINAME, "%s/%s_%s.%s", m_Device->getText("UPLOAD_SETTINGS")->tp[0].text, prefix.c_str(), m_Name, format); @@ -580,17 +540,14 @@ bool Interface::uploadFile(const void *fitsData, size_t totalBytes, bool sendCap return false; } - size_t n = 0; - for (size_t nr = 0; nr < static_cast(FitsB.bloblen); nr += n) - n = fwrite((static_cast(FitsB.blob) + nr), 1, static_cast(FitsB.bloblen - nr), fp); + int n = 0; + for (int nr = 0; nr < static_cast(FitsB.bloblen); nr += n) + n = fwrite((static_cast(FitsB.blob) + nr), 1, FitsB.bloblen - nr, fp); fclose(fp); LOGF_INFO("File saved in %s.", processedFileName); } - FitsB.size = totalBytes; - FitsBP.s = IPS_OK; - if (sendCapture) { @@ -601,6 +558,7 @@ bool Interface::uploadFile(const void *fitsData, size_t totalBytes, bool sendCap LOGF_DEBUG("BLOB transfer took %g seconds", diff.count()); } + FitsBP.s = IPS_OK; DEBUG(INDI::Logger::DBG_DEBUG, "Upload complete"); @@ -662,9 +620,13 @@ int Interface::getFileIndex(const char *dir, const char *prefix, const char *ext return (maxIndex + 1); } -void Interface::setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool Interface::setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample) { - //Create the dsp stream + stream->sizes = (int*)realloc(stream->sizes, sizeof(int)); + stream->dims = 0; + stream->len = 1; + dsp_stream_free_buffer(stream); + dsp_stream_free(stream); stream = dsp_stream_new(); for(uint32_t dim = 0; dim < dims; dim++) dsp_stream_add_dim(stream, sizes[dim]); @@ -691,14 +653,163 @@ void Interface::setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sam break; default: dsp_stream_free_buffer(stream); - //Destroy the dsp stream dsp_stream_free(stream); + return false; + } + return true; +} + +bool Interface::setMagnitude(void *buf, uint32_t dims, int *sizes, int bits_per_sample) +{ + if(stream == nullptr) return false; + if(dims != (uint32_t)stream->dims) return false; + for(uint32_t d = 0; d < dims; d++) + if(sizes[d] != stream->sizes[d]) return false; + dsp_stream_free_buffer(stream->magnitude); + dsp_stream_free(stream->magnitude); + stream->magnitude = dsp_stream_copy(stream); + dsp_buffer_set(stream->magnitude->buf, stream->len, 0); + switch (bits_per_sample) + { + case 8: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 16: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 32: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 64: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case -32: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case -64: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + default: + dsp_stream_free_buffer(stream->magnitude); + dsp_stream_free(stream->magnitude); + return false; + } + return true; +} + +bool Interface::setPhase(void *buf, uint32_t dims, int *sizes, int bits_per_sample) +{ + if(stream == nullptr) return false; + if(dims != (uint32_t)stream->dims) return false; + for(uint32_t d = 0; d < dims; d++) + if(sizes[d] != stream->sizes[d]) return false; + dsp_stream_free_buffer(stream->magnitude); + dsp_stream_free(stream->magnitude); + stream->magnitude = dsp_stream_copy(stream); + dsp_buffer_set(stream->magnitude->buf, stream->len, 0); + switch (bits_per_sample) + { + case 8: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 16: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 32: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case 64: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case -32: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + case -64: + dsp_buffer_copy((static_cast(buf)), stream->magnitude->buf, stream->len); + break; + default: + dsp_stream_free_buffer(stream->magnitude); + dsp_stream_free(stream->magnitude); + return false; + } + return true; +} + +bool Interface::setReal(void *buf, uint32_t dims, int *sizes, int bits_per_sample) +{ + if(stream == nullptr) return false; + if(dims != (uint32_t)stream->dims) return false; + for(uint32_t d = 0; d < dims; d++) + if(sizes[d] != stream->sizes[d]) return false; + if(stream->dft.buf == nullptr) + stream->dft.buf = (double*)malloc(sizeof(double) * stream->len * 2); + else + stream->dft.buf = (double*)realloc(stream->dft.buf, sizeof(double) * stream->len * 2); + switch (bits_per_sample) + { + case 8: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + case 16: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + case 32: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + case 64: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + case -32: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + case -64: + dsp_buffer_copy_stepping((static_cast(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2); + break; + default: + return false; + } + return true; +} + +bool Interface::setImaginary(void *buf, uint32_t dims, int *sizes, int bits_per_sample) +{ + if(stream == nullptr) return false; + if(dims != (uint32_t)stream->dims) return false; + for(uint32_t d = 0; d < dims; d++) + if(sizes[d] != stream->sizes[d]) return false; + if(stream->dft.buf == nullptr) + stream->dft.buf = (double*)malloc(sizeof(double) * stream->len * 2); + else + stream->dft.buf = (double*)realloc(stream->dft.buf, sizeof(double) * stream->len * 2); + switch (bits_per_sample) + { + case 8: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + case 16: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + case 32: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + case 64: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + case -32: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + case -64: + dsp_buffer_copy_stepping((static_cast(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2); + break; + default: + return false; } + return true; } uint8_t* Interface::getStream() { - void *buffer = malloc(stream->len * getBPS() / 8); + buffer = realloc(buffer, stream->len * getBPS() / 8); switch (getBPS()) { case 8: @@ -723,9 +834,75 @@ uint8_t* Interface::getStream() free (buffer); break; } - //Destroy the dsp stream - dsp_stream_free_buffer(stream); - dsp_stream_free(stream); return static_cast(buffer); } + +uint8_t* Interface::getMagnitude() +{ + buffer = malloc(stream->len * getBPS() / 8); + switch (getBPS()) + { + case 8: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + case 16: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + case 32: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + case 64: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + case -32: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + case -64: + dsp_buffer_copy(stream->magnitude->buf, (static_cast(buffer)), stream->len); + break; + default: + free (buffer); + break; + } + return static_cast(buffer); +} + +uint8_t* Interface::getBuffer(dsp_stream_p in, uint32_t *dims, int **sizes) +{ + void *buffer = malloc(in->len * getBPS() / 8); + switch (getBPS()) + { + case 8: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + case 16: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + case 32: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + case 64: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + case -32: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + case -64: + dsp_buffer_copy(in->buf, (static_cast(buffer)), in->len); + break; + default: + free (buffer); + break; + } + *dims = in->dims; + *sizes = (int*)malloc(sizeof(int) * in->dims); + for(int d = 0; d < in->dims; d++) + *sizes[d] = in->sizes[d]; + return static_cast(buffer); +} + +void Interface::setCaptureFileExtension(const char *ext) +{ + snprintf(captureExtention, MAXINDIBLOBFMT, "%s", ext); +} } diff --git a/libs/indibase/dsp/dspinterface.h b/libs/indibase/dsp/dspinterface.h index 3f34ec1868..9475509fef 100644 --- a/libs/indibase/dsp/dspinterface.h +++ b/libs/indibase/dsp/dspinterface.h @@ -73,7 +73,9 @@ class Interface DSP_DFT, DSP_IDFT, DSP_CONVOLUTION, + DSP_WAVELETS, DSP_SPECTRUM, + DSP_HISTOGRAM, } Type; virtual void ISGetProperties(const char *dev); @@ -92,7 +94,7 @@ class Interface * @param bits_per_sample original bit depth of the input buffer * @return True if successful, false otherwise. */ - bool processBLOB(uint8_t* buf, uint32_t ndims, int* dims, int bits_per_sample); + virtual bool processBLOB(uint8_t* buf, uint32_t ndims, int* dims, int bits_per_sample); /** * @brief setSizes Set the returned file dimensions and corresponding sizes. @@ -120,6 +122,12 @@ class Interface */ int getBPS() { return BPS; } + /** + * @brief setIntegrationFileExtension Set the returned file extension. + * @param ext The extension suffix. + */ + void setCaptureFileExtension(const char *ext); + protected: /** @@ -173,16 +181,26 @@ class Interface const char *m_Name { nullptr }; const char *m_Label { nullptr }; Type m_Type { DSP_NONE }; - void setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample); + bool setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample); + bool setMagnitude(void *buf, uint32_t dims, int *sizes, int bits_per_sample); + bool setPhase(void *buf, uint32_t dims, int *sizes, int bits_per_sample); + bool setReal(void *buf, uint32_t dims, int *sizes, int bits_per_sample); + bool setImaginary(void *buf, uint32_t dims, int *sizes, int bits_per_sample); uint8_t *getStream(); + uint8_t *getMagnitude(); + uint8_t *getPhase(); + uint8_t *getReal(); + uint8_t *getImaginary(); + uint8_t* getBuffer(dsp_stream_p in, uint32_t *dims, int **sizes); dsp_stream_p stream; private: - uint32_t BufferSizesQty; - int *BufferSizes; - int BPS; + char captureExtention[MAXINDIBLOBFMT] { "fits" }; + void *buffer { nullptr }; + uint32_t BufferSizesQty {0 }; + int *BufferSizes { nullptr }; + int BPS { 16 }; - char processedFileName[MAXINDINAME]; void fits_update_key_s(fitsfile *fptr, int type, std::string name, void *p, std::string explanation, int *status); void addFITSKeywords(fitsfile *fptr); bool sendFITS(uint8_t *buf, bool sendCapture, bool saveCapture); diff --git a/libs/indibase/dsp/manager.cpp b/libs/indibase/dsp/manager.cpp index fc2e09ccfe..c4ceb5c910 100644 --- a/libs/indibase/dsp/manager.cpp +++ b/libs/indibase/dsp/manager.cpp @@ -139,5 +139,13 @@ bool Manager::processBLOB(uint8_t* buf, uint32_t ndims, int* dims, int bits_per_ r |= wavelets->processBLOB(buf, ndims, dims, bits_per_sample); return r; } - +void Manager::setCaptureFileExtension(const char *ext) +{ + convolution->setCaptureFileExtension(ext); + dft->setCaptureFileExtension(ext); + idft->setCaptureFileExtension(ext); + spectrum->setCaptureFileExtension(ext); + histogram->setCaptureFileExtension(ext); + wavelets->setCaptureFileExtension(ext); +} } diff --git a/libs/indibase/dsp/manager.h b/libs/indibase/dsp/manager.h index 425b58934d..06aca62c01 100644 --- a/libs/indibase/dsp/manager.h +++ b/libs/indibase/dsp/manager.h @@ -57,6 +57,8 @@ class Manager inline void setBPS(int bps) { BPS = bps; } inline int getBPS() { return BPS; } + void setCaptureFileExtension(const char *ext); + private: Convolution *convolution; FourierTransform *dft; diff --git a/libs/indibase/dsp/transforms.cpp b/libs/indibase/dsp/transforms.cpp index 376859167f..8a0c4ba9c4 100644 --- a/libs/indibase/dsp/transforms.cpp +++ b/libs/indibase/dsp/transforms.cpp @@ -40,30 +40,72 @@ FourierTransform::~FourierTransform() { } -uint8_t* FourierTransform::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool FourierTransform::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; setStream(buf, dims, sizes, bits_per_sample); - dsp_complex* dft = dsp_fourier_dft(stream); - for(int x = 0; x < stream->len; x++) - stream->buf[x] = sqrt(pow(dft[x].real, 2)+pow(dft[x].imaginary, 2)); - dsp_buffer_stretch(stream->buf, stream->len, 0.0, (bits_per_sample < 0 ? 1.0 : pow(2, bits_per_sample)-1)); - return getStream(); + + dsp_fourier_dft(stream, 1); + return Interface::processBLOB(getMagnitude(), stream->magnitude->dims, stream->magnitude->sizes, bits_per_sample); } InverseFourierTransform::InverseFourierTransform(INDI::DefaultDevice *dev) : Interface(dev, DSP_IDFT, "IDFT", "IDFT") { + IUFillBLOB(&DownloadB, "PHASE_DOWNLOAD", "Phase", ""); + IUFillBLOBVector(&DownloadBP, &FitsB, 1, m_Device->getDeviceName(), "PHASE", "Phase Data", DSP_TAB, IP_RW, 60, IPS_IDLE); } InverseFourierTransform::~InverseFourierTransform() { } -uint8_t* InverseFourierTransform::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +void InverseFourierTransform::Activated() +{ + m_Device->defineProperty(&DownloadBP); + Interface::Activated(); +} + +void InverseFourierTransform::Deactivated() +{ + m_Device->deleteProperty(DownloadBP.name); + Interface::Deactivated(); +} + +bool InverseFourierTransform::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; + if(!phase_loaded) return false; setStream(buf, dims, sizes, bits_per_sample); + if (phase->dims != stream->dims) return false; + for (int d = 0; d < stream->dims; d++) + if (phase->sizes[d] != stream->sizes[d]) + return false; + setMagnitude(buf, dims, sizes, bits_per_sample); + stream->phase = phase; + dsp_buffer_set(stream->buf, stream->len, 0); dsp_fourier_idft(stream); - dsp_buffer_stretch(stream->buf, stream->len, 0.0, (bits_per_sample < 0 ? 1.0 : pow(2, bits_per_sample)-1)); - return getStream(); + return Interface::processBLOB(getStream(), stream->dims, stream->sizes, bits_per_sample); +} + +bool InverseFourierTransform::ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + if(!strcmp(dev, getDeviceName())) { + if(!strcmp(name, DownloadBP.name)) { + IUUpdateBLOB(&DownloadBP, sizes, blobsizes, blobs, formats, names, n); + LOGF_INFO("Received phase BLOB for %s", getDeviceName()); + if(phase != nullptr) { + dsp_stream_free_buffer(phase); + dsp_stream_free(phase); + } + phase = loadFITS(blobs[0], sizes[0]); + if (phase != nullptr) { + LOGF_INFO("Phase for %s loaded", getDeviceName()); + phase_loaded = true; + return true; + } + } + } + return false; } Spectrum::Spectrum(INDI::DefaultDevice *dev) : Interface(dev, DSP_SPECTRUM, "SPECTRUM", "Spectrum") @@ -74,19 +116,18 @@ Spectrum::~Spectrum() { } -uint8_t* Spectrum::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool Spectrum::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; setStream(buf, dims, sizes, bits_per_sample); - dsp_fourier_idft(stream); - double *histo = dsp_stats_histogram(stream, 4096); - dsp_stream_free_buffer(stream); - dsp_stream_set_buffer(stream, histo, 4096); - setSizes(1, new int{4096}); - return getStream(); + + dsp_fourier_dft(stream, 1); + double *histo = dsp_stats_histogram(stream->magnitude, 4096); + return Interface::processBLOB(static_cast(static_cast(histo)), 1, new int{4096}, -64); } -Histogram::Histogram(INDI::DefaultDevice *dev) : Interface(dev, DSP_SPECTRUM, "HISTOGRAM", "Histogram") +Histogram::Histogram(INDI::DefaultDevice *dev) : Interface(dev, DSP_HISTOGRAM, "HISTOGRAM", "Histogram") { } @@ -94,13 +135,12 @@ Histogram::~Histogram() { } -uint8_t* Histogram::Callback(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) +bool Histogram::processBLOB(uint8_t *buf, uint32_t dims, int *sizes, int bits_per_sample) { + if(!PluginActive) return false; setStream(buf, dims, sizes, bits_per_sample); + double *histo = dsp_stats_histogram(stream, 4096); - dsp_stream_free_buffer(stream); - dsp_stream_set_buffer(stream, histo, 4096); - setSizes(1, new int{4096}); - return getStream(); + return Interface::processBLOB(static_cast(static_cast(histo)), 1, new int{4096}, -64); } } diff --git a/libs/indibase/dsp/transforms.h b/libs/indibase/dsp/transforms.h index e368cdaf19..7d18062a61 100644 --- a/libs/indibase/dsp/transforms.h +++ b/libs/indibase/dsp/transforms.h @@ -31,39 +31,49 @@ class FourierTransform : public Interface { public: FourierTransform(INDI::DefaultDevice *dev); + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~FourierTransform(); - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; }; class InverseFourierTransform : public Interface { public: InverseFourierTransform(INDI::DefaultDevice *dev); + bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) override; + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~InverseFourierTransform(); - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; + void Activated() override; + void Deactivated() override; + +private: + IBLOBVectorProperty DownloadBP; + IBLOB DownloadB; + + dsp_stream_p phase; + bool phase_loaded { false }; }; class Spectrum : public Interface { public: Spectrum(INDI::DefaultDevice *dev); + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~Spectrum(); - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; }; class Histogram : public Interface { public: Histogram(INDI::DefaultDevice *dev); + virtual bool processBLOB(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; protected: ~Histogram(); - uint8_t *Callback(uint8_t *out, uint32_t dims, int *sizes, int bits_per_sample) override; }; } diff --git a/libs/indibase/indicorrelator.cpp b/libs/indibase/indicorrelator.cpp index 65e476f374..fe16a56974 100644 --- a/libs/indibase/indicorrelator.cpp +++ b/libs/indibase/indicorrelator.cpp @@ -205,23 +205,24 @@ bool Correlator::StartIntegration(double duration) void Correlator::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) { - INumberVectorProperty *vp = nullptr; + INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); + INumberVectorProperty *nvp = nullptr; - if (!strcmp(property, CorrelatorSettingsNP.name)) { - vp = &FramedIntegrationNP; + if (!strcmp(property, CorrelatorSettingsNP.name)) + nvp = &CorrelatorSettingsNP; + else + return; - INumber *np = IUFindNumber(vp, element); - if (np) - { - np->min = min; - np->max = max; - np->step = step; + INumber *np = IUFindNumber(nvp, element); + if (np) + { + np->min = min; + np->max = max; + np->step = step; - if (sendToClient) - IUUpdateMinMax(vp); - } + if (sendToClient) + IUUpdateMinMax(nvp); } - INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); } } diff --git a/libs/indibase/indicorrelator.h b/libs/indibase/indicorrelator.h index 567e729d8a..5ae4eafe4b 100644 --- a/libs/indibase/indicorrelator.h +++ b/libs/indibase/indicorrelator.h @@ -247,7 +247,7 @@ class Correlator : public SensorInterface * @param sendToClient If true (default), the element limits are updated and is sent to the * client. If false, the element limits are updated without getting sent to the client. */ - void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient); + virtual void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) override; typedef enum { diff --git a/libs/indibase/indidetector.cpp b/libs/indibase/indidetector.cpp index 57897b6e2a..f158bc6a40 100644 --- a/libs/indibase/indidetector.cpp +++ b/libs/indibase/indidetector.cpp @@ -150,23 +150,24 @@ bool Detector::StartIntegration(double duration) void Detector::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) { - INumberVectorProperty *vp = nullptr; + INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); + INumberVectorProperty *nvp = nullptr; - if (!strcmp(property, DetectorSettingsNP.name)) { - vp = &FramedIntegrationNP; + if (!strcmp(property, DetectorSettingsNP.name)) + nvp = &DetectorSettingsNP; + else + return; - INumber *np = IUFindNumber(vp, element); - if (np) - { - np->min = min; - np->max = max; - np->step = step; + INumber *np = IUFindNumber(nvp, element); + if (np) + { + np->min = min; + np->max = max; + np->step = step; - if (sendToClient) - IUUpdateMinMax(vp); - } + if (sendToClient) + IUUpdateMinMax(nvp); } - INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); } void Detector::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) diff --git a/libs/indibase/indidetector.h b/libs/indibase/indidetector.h index 22b6302d5a..f0f3d38665 100644 --- a/libs/indibase/indidetector.h +++ b/libs/indibase/indidetector.h @@ -76,18 +76,18 @@ class Detector : public SensorInterface Detector(); virtual ~Detector(); - bool initProperties(); - bool updateProperties(); - void ISGetProperties(const char *dev); - bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n); - bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n); - bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n); - bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); - bool ISSnoopDevice(XMLEle *root); + bool initProperties() override; + bool updateProperties() override; + void ISGetProperties(const char *dev) override; + bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override; + bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override; + bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override; + bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) override; + bool ISSnoopDevice(XMLEle *root) override; - void addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len); + void addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) override; - virtual bool StartIntegration(double duration); + virtual bool StartIntegration(double duration) override; /** * @brief setResolution Set resolution of the detector in ns. @@ -151,7 +151,8 @@ class Detector : public SensorInterface * @param sendToClient If true (default), the element limits are updated and is sent to the * client. If false, the element limits are updated without getting sent to the client. */ - void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient); + virtual void setMinMaxStep(const char *property, const char *element, double min, double max, double step, + bool sendToClient = true) override; typedef enum { diff --git a/libs/indibase/indireceiver.cpp b/libs/indibase/indireceiver.cpp index 75ffdd6291..1da4742f54 100644 --- a/libs/indibase/indireceiver.cpp +++ b/libs/indibase/indireceiver.cpp @@ -174,23 +174,24 @@ bool Receiver::StartIntegration(double duration) void Receiver::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) { - INumberVectorProperty *vp = nullptr; + INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); + INumberVectorProperty *nvp = nullptr; - if (!strcmp(property, ReceiverSettingsNP.name)) { - vp = &FramedIntegrationNP; + if (!strcmp(property, ReceiverSettingsNP.name)) + nvp = &ReceiverSettingsNP; + else + return; - INumber *np = IUFindNumber(vp, element); - if (np) - { - np->min = min; - np->max = max; - np->step = step; + INumber *np = IUFindNumber(nvp, element); + if (np) + { + np->min = min; + np->max = max; + np->step = step; - if (sendToClient) - IUUpdateMinMax(vp); - } + if (sendToClient) + IUUpdateMinMax(nvp); } - INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); } void Receiver::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) diff --git a/libs/indibase/indireceiver.h b/libs/indibase/indireceiver.h index ce172d9345..c2ba97e447 100644 --- a/libs/indibase/indireceiver.h +++ b/libs/indibase/indireceiver.h @@ -174,8 +174,8 @@ class Receiver : public virtual SensorInterface * @param sendToClient If true (default), the element limits are updated and is sent to the * client. If false, the element limits are updated without getting sent to the client. */ - void setMinMaxStep(const char *property, const char *element, double min, double max, double step, - bool sendToClient = true); + virtual void setMinMaxStep(const char *property, const char *element, double min, double max, double step, + bool sendToClient = true) override; typedef enum { diff --git a/libs/indibase/indisensorinterface.cpp b/libs/indibase/indisensorinterface.cpp index eb8273402f..7af4b8867f 100644 --- a/libs/indibase/indisensorinterface.cpp +++ b/libs/indibase/indisensorinterface.cpp @@ -512,22 +512,22 @@ void SensorInterface::SetCapability(uint32_t cap) void SensorInterface::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) { - INumberVectorProperty *vp = nullptr; + INumberVectorProperty *nvp = nullptr; if (!strcmp(property, FramedIntegrationNP.name)) - { - vp = &FramedIntegrationNP; + nvp = &FramedIntegrationNP; + else + return; - INumber *np = IUFindNumber(vp, element); - if (np) - { - np->min = min; - np->max = max; - np->step = step; + INumber *np = IUFindNumber(nvp, element); + if (np) + { + np->min = min; + np->max = max; + np->step = step; - if (sendToClient) - IUUpdateMinMax(vp); - } + if (sendToClient) + IUUpdateMinMax(nvp); } } @@ -539,8 +539,10 @@ void SensorInterface::setBufferSize(int nbuf, bool allocMem) BufferSize = nbuf; // Reset size - if (HasStreaming()) - Streamer->setSize(BufferSize * 8 / getBPS()); + if(HasStreaming()) { + Streamer->setPixelFormat(INDI_MONO, getBPS()); + Streamer->setSize(getBufferSize() * 8 / abs(getBPS()), 1); + } // DSP if (HasDSP()) @@ -577,15 +579,13 @@ void SensorInterface::setIntegrationTime(double duration) const char *SensorInterface::getIntegrationStartTime() { - static char ts[32]; - - char iso8601[32]; + static char iso8601[32]; struct tm *tp; time_t t = (time_t)startIntegrationTime; tp = gmtime(&t); strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", tp); - return (ts); + return iso8601; } void SensorInterface::setIntegrationFailed() @@ -607,6 +607,8 @@ void SensorInterface::setNAxis(int value) void SensorInterface::setIntegrationFileExtension(const char *ext) { strncpy(integrationExtention, ext, MAXINDIBLOBFMT); + if(HasDSP()) + DSP->setCaptureFileExtension(ext); } @@ -671,6 +673,9 @@ void SensorInterface::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) } #endif + if (primaryAperture != -1) + fits_update_key_s(fptr, TDOUBLE, "APTDIA", &primaryAperture, "Diameter (mm)", &status); + if (primaryFocalLength != -1) fits_update_key_s(fptr, TDOUBLE, "FOCALLEN", &primaryFocalLength, "Focal Length (mm)", &status); @@ -685,7 +690,7 @@ void SensorInterface::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) char lon_str[MAXINDIFORMAT]; char el_str[MAXINDIFORMAT]; fs_sexa(lat_str, Latitude, 2, 360000); - fs_sexa(lat_str, Longitude, 2, 360000); + fs_sexa(lon_str, Longitude, 2, 360000); snprintf(el_str, MAXINDIFORMAT, "%lf", Elevation); fits_update_key_s(fptr, TSTRING, "SITELAT", lat_str, "Location Latitude", &status); fits_update_key_s(fptr, TSTRING, "SITELONG", lon_str, "Location Longitude", &status); diff --git a/libs/indibase/indisensorinterface.h b/libs/indibase/indisensorinterface.h index 5b5ebeaa0c..5a7fa6814e 100644 --- a/libs/indibase/indisensorinterface.h +++ b/libs/indibase/indisensorinterface.h @@ -180,7 +180,7 @@ class SensorInterface : public DefaultDevice * @param sendToClient If true (default), the element limits are updated and is sent to the * client. If false, the element limits are updated without getting sent to the client. */ - void setMinMaxStep(const char *property, const char *element, double min, double max, double step, + virtual void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient = true); /** @@ -269,6 +269,7 @@ class SensorInterface : public DefaultDevice /// Misc. ///////////////////////////////////////////////////////////////////////////// friend class StreamManager; + friend class StreamManagerPrivate; /** * @brief StartStreaming Start live video streaming * @return True if successful, false otherwise. diff --git a/libs/indibase/indispectrograph.cpp b/libs/indibase/indispectrograph.cpp index 8c11dc17fe..95282dd14e 100644 --- a/libs/indibase/indispectrograph.cpp +++ b/libs/indibase/indispectrograph.cpp @@ -161,23 +161,24 @@ bool Spectrograph::StartIntegration(double duration) void Spectrograph::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient) { - INumberVectorProperty *vp = nullptr; + INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); + INumberVectorProperty *nvp = nullptr; - if (!strcmp(property, SpectrographSettingsNP.name)) { - vp = &FramedIntegrationNP; + if (!strcmp(property, SpectrographSettingsNP.name)) + nvp = &SpectrographSettingsNP; + else + return; - INumber *np = IUFindNumber(vp, element); - if (np) - { - np->min = min; - np->max = max; - np->step = step; + INumber *np = IUFindNumber(nvp, element); + if (np) + { + np->min = min; + np->max = max; + np->step = step; - if (sendToClient) - IUUpdateMinMax(vp); - } + if (sendToClient) + IUUpdateMinMax(nvp); } - INDI::SensorInterface::setMinMaxStep(property, element, min, max, step, sendToClient); } void Spectrograph::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len) diff --git a/libs/indibase/indispectrograph.h b/libs/indibase/indispectrograph.h index eb599be7ec..a5e7425c2a 100644 --- a/libs/indibase/indispectrograph.h +++ b/libs/indibase/indispectrograph.h @@ -159,8 +159,8 @@ class Spectrograph : public virtual SensorInterface * @param sendToClient If true (default), the element limits are updated and is sent to the * client. If false, the element limits are updated without getting sent to the client. */ - void setMinMaxStep(const char *property, const char *element, double min, double max, double step, - bool sendToClient = true); + virtual void setMinMaxStep(const char *property, const char *element, double min, double max, double step, + bool sendToClient = true) override; typedef enum {