##// END OF EJS Templates
Switched to CMake, added a basic python test (with ctypes), simplified kcoef init function
chust -
r23:2e08872d5b98 tip TCH draft
parent child
Show More
@@ -0,0 +1,75
1 cmake_minimum_required(VERSION 3.6)
2 project(LFR-BasicParameters CXX C)
3
4 include(GNUInstallDirs)
5
6 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
7 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
8 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
9 OPTION (Coverage "Enables code coverage" OFF)
10
11
12 OPTION (Debug_tch "" OFF)
13 OPTION (LSB_FIRST_TCH "" ON)
14
15 if(Debug_tch)
16 add_definitions(-DDEBUG_TCH)
17 endif()
18 if(LSB_FIRST_TCH)
19 add_definitions(-DLSB_FIRST_TCH)
20 else()
21 add_definitions(-DMSB_FIRST_TCH)
22 endif()
23
24 set(CMAKE_CXX_STANDARD 17)
25
26 set(CMAKE_INCLUDE_CURRENT_DIR ON)
27
28 if(NOT CMAKE_BUILD_TYPE)
29 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
30 endif()
31
32
33 IF(CPPCHECK)
34 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
35 ENDIF(CPPCHECK)
36
37 IF(CLANG_TIDY)
38 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
39 ENDIF(CLANG_TIDY)
40
41 IF(IWYU)
42 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
43 ENDIF(IWYU)
44
45 file(GLOB sources src/*.c)
46 add_library(lfr_basic_params SHARED ${sources})
47
48 target_include_directories(lfr_basic_params
49 PUBLIC
50 $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/src>
51 )
52
53 IF(Coverage)
54 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage")
55 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -O0 -Wall -W -Wshadow -Wunused-variable \
56 -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers \
57 -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage")
58 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
59
60 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gcov.html
61 COMMAND gcovr --exclude='.*Test.*' --exclude='.*external.*' --object-directory ${CMAKE_BINARY_DIR} -r ${CMAKE_SOURCE_DIR} --html --html-details -o ${CMAKE_CURRENT_BINARY_DIR}/gcov.html
62 )
63 add_custom_target(gcovr
64 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gcov.html gcovr
65 )
66 add_custom_target(show_coverage
67 COMMAND xdg-open ${CMAKE_CURRENT_BINARY_DIR}/gcov.html
68 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gcov.html gcovr
69 )
70 ENDIF(Coverage)
71
72 enable_testing()
73 find_package (Python3 COMPONENTS Interpreter Development)
74 add_test(NAME init_k_coefficients COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/init_k_coefficients.py WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
75
@@ -0,0 +1,195
1 {
2 "cells": [
3 {
4 "cell_type": "code",
5 "execution_count": 1,
6 "metadata": {
7 "ExecuteTime": {
8 "end_time": "2019-11-08T17:24:20.336383Z",
9 "start_time": "2019-11-08T17:24:20.048293Z"
10 }
11 },
12 "outputs": [],
13 "source": [
14 "from ctypes import * \n",
15 "import matplotlib.pyplot as plt\n",
16 "import numpy as np\n",
17 "import os\n",
18 "import sys\n",
19 "\n",
20 "%matplotlib notebook"
21 ]
22 },
23 {
24 "cell_type": "code",
25 "execution_count": 2,
26 "metadata": {
27 "ExecuteTime": {
28 "end_time": "2019-11-08T17:24:20.382711Z",
29 "start_time": "2019-11-08T17:24:20.378601Z"
30 }
31 },
32 "outputs": [],
33 "source": [
34 "lib_basic_params = cdll.LoadLibrary('../build-LFR_basic-parameters-Desktop-Default/liblfr_basic_params.so')"
35 ]
36 },
37 {
38 "cell_type": "code",
39 "execution_count": null,
40 "metadata": {},
41 "outputs": [],
42 "source": []
43 },
44 {
45 "cell_type": "markdown",
46 "metadata": {},
47 "source": [
48 "Code C:\n",
49 "\n",
50 "```c\n",
51 "void init_k_coefficients_f0(float *k_coefficients, unsigned char nb_binscompressed_matrix )\n",
52 "```"
53 ]
54 },
55 {
56 "cell_type": "code",
57 "execution_count": 3,
58 "metadata": {
59 "ExecuteTime": {
60 "end_time": "2019-11-08T17:24:21.853368Z",
61 "start_time": "2019-11-08T17:24:21.554426Z"
62 }
63 },
64 "outputs": [
65 {
66 "data": {
67 "text/plain": [
68 "[<matplotlib.lines.Line2D at 0x7f466118c050>]"
69 ]
70 },
71 "execution_count": 3,
72 "metadata": {},
73 "output_type": "execute_result"
74 },
75 {
76 "data": {
77 "image/png": "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\n",
78 "text/plain": [
79 "<Figure size 432x288 with 1 Axes>"
80 ]
81 },
82 "metadata": {
83 "needs_background": "light"
84 },
85 "output_type": "display_data"
86 }
87 ],
88 "source": [
89 "nb_bins = 11\n",
90 "nb_binscompressed_matrix = c_char(nb_bins)\n",
91 "k_coefficients = (c_float * (32 * nb_bins))() \n",
92 "\n",
93 "for i in range(len(k_coefficients)):\n",
94 " k_coefficients[i] = 100.*np.random.random()\n",
95 " \n",
96 "plt.plot(k_coefficients)"
97 ]
98 },
99 {
100 "cell_type": "code",
101 "execution_count": 4,
102 "metadata": {
103 "ExecuteTime": {
104 "end_time": "2019-11-08T17:24:22.653016Z",
105 "start_time": "2019-11-08T17:24:22.406334Z"
106 }
107 },
108 "outputs": [
109 {
110 "data": {
111 "text/plain": [
112 "[<matplotlib.lines.Line2D at 0x7f4661137a90>]"
113 ]
114 },
115 "execution_count": 4,
116 "metadata": {},
117 "output_type": "execute_result"
118 },
119 {
120 "data": {
121 "image/png": "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\n",
122 "text/plain": [
123 "<Figure size 432x288 with 1 Axes>"
124 ]
125 },
126 "metadata": {
127 "needs_background": "light"
128 },
129 "output_type": "display_data"
130 }
131 ],
132 "source": [
133 "plt.figure()\n",
134 "lib_basic_params.init_k_coefficients(k_coefficients, nb_binscompressed_matrix)\n",
135 "plt.plot(k_coefficients)"
136 ]
137 },
138 {
139 "cell_type": "code",
140 "execution_count": 9,
141 "metadata": {
142 "ExecuteTime": {
143 "end_time": "2019-11-08T17:28:05.727737Z",
144 "start_time": "2019-11-08T17:28:05.720427Z"
145 }
146 },
147 "outputs": [
148 {
149 "data": {
150 "text/plain": [
151 "(array([ 2, 3, 34, 35, 66, 67, 98, 99, 130, 131, 162, 163, 194,\n",
152 " 195, 226, 227, 258, 259, 290, 291, 322, 323]),)"
153 ]
154 },
155 "execution_count": 9,
156 "metadata": {},
157 "output_type": "execute_result"
158 }
159 ],
160 "source": [
161 "\n",
162 "arr = np.array(k_coefficients)\n",
163 "np.where(arr == 0.)"
164 ]
165 },
166 {
167 "cell_type": "code",
168 "execution_count": null,
169 "metadata": {},
170 "outputs": [],
171 "source": []
172 }
173 ],
174 "metadata": {
175 "kernelspec": {
176 "display_name": "Python 3",
177 "language": "python",
178 "name": "python3"
179 },
180 "language_info": {
181 "codemirror_mode": {
182 "name": "ipython",
183 "version": 3
184 },
185 "file_extension": ".py",
186 "mimetype": "text/x-python",
187 "name": "python",
188 "nbconvert_exporter": "python",
189 "pygments_lexer": "ipython3",
190 "version": "3.7.4"
191 }
192 },
193 "nbformat": 4,
194 "nbformat_minor": 2
195 }
This diff has been collapsed as it changes many lines, (1002 lines changed) Show them Hide them
@@ -0,0 +1,1002
1 // In the frame of RPW LFR Sofware ICD Issue1 Rev8 (05/07/2013) => R2 FSW
2 // version 1.0: 31/07/2013
3 // version 1.1: 02/04/2014
4 // version 1.2: 30/04/2014
5 // version 1.3: 02/05/2014
6 // version 1.4: 16/05/2014
7 // version 1.5: 20/05/2014
8 // version 1.6: 19/12/2014
9 // version 1.7: 15/01/2015 (modifs de Paul + correction erreurs qui se compensaient (LSB <=> MSB + indices [0,2] <=> [1,3])
10 // version 1.8: 02/02/2015 (gestion des divisions par zéro)
11 // In the frame of RPW LFR Sofware ICD Issue3 Rev6 (27/01/2015) => R3 FSW
12 // version 2.0: 19/06/2015
13 // version 2.1: 22/06/2015 (modifs de Paul)
14 // version 2.2: 23/06/2015 (modifs de l'ordre de déclaration/définition de init_k_coefficients dans basic_parameters.c ... + maintien des declarations dans le .h)
15 // version 2.3: 01/07/2015 (affectation initiale des octets 7 et 9 dans les BP1 corrigée ...)
16 // version 2.4: 05/10/2018 (added GPL headers)
17 // version 2.5: 09/10/2018 (dans main.c #include "basic_parameters_utilities.h" est changé par les déclarations extern correspondantes ...!
18 // + delta mise en conformité LOGISCOPE)
19
20 /*------------------------------------------------------------------------------
21 -- Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
22 -- This file is a part of the LFR FSW
23 -- Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
24 --
25 -- This program is free software; you can redistribute it and/or modify
26 -- it under the terms of the GNU General Public License as published by
27 -- the Free Software Foundation; either version 2 of the License, or
28 -- (at your option) any later version.
29 --
30 -- This program is distributed in the hope that it will be useful,
31 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
32 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 -- GNU General Public License for more details.
34 --
35 -- You should have received a copy of the GNU General Public License
36 -- along with this program; if not, write to the Free Software
37 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 -------------------------------------------------------------------------------*/
39 /*-- Author : Thomas Chust
40 -- Contact : Thomas Chust
41 -- Mail : thomas.chust@lpp.polytechnique.fr
42 ----------------------------------------------------------------------------*/
43
44 #include <stdio.h>
45 #include <math.h>
46 #include <stdint.h>
47
48 #include "basic_parameters_params.h"
49
50 void init_k_coefficients(float *k_coefficients,
51 unsigned char nb_binscompressed_matrix )
52 {
53 uint8_t i; // 8 bits unsigned
54 uint8_t j;
55 for(i=0; i<nb_binscompressed_matrix; i++)
56 {
57 for (j=0;j<NB_K_COEFF_PER_BIN;j++) {
58 k_coefficients[i*NB_K_COEFF_PER_BIN+j] = 1.f;
59 }
60 k_coefficients[i*NB_K_COEFF_PER_BIN+K45_PE_RE] = 0.;
61 k_coefficients[i*NB_K_COEFF_PER_BIN+K45_PE_IM] = 0.;
62 }
63 }
64
65
66 void BP1_set(float *compressed_spec_mat, float *k_coeff_intercalib, uint8_t nb_bins_compressed_spec_mat, uint8_t *lfr_bp1){
67 float PSDB; // 32-bit floating point
68 float PSDE;
69 float tmp;
70 float NVEC_V0;
71 float NVEC_V1;
72 float NVEC_V2;
73 float aux;
74 float tr_SB_SB;
75 float e_cross_b_re;
76 float e_cross_b_im;
77 float n_cross_e_scal_b_re;
78 float n_cross_e_scal_b_im;
79 float ny;
80 float nz;
81 float bx_bx_star;
82 float vphi;
83 float significand;
84 int exponent; // 32-bit signed integer
85 float alpha_M;
86
87 uint8_t nbitexp; // 8-bit unsigned integer
88 uint8_t nbitsig;
89 uint8_t tmp_uint8;
90 uint8_t *pt_uint8; // pointer on unsigned 8-bit integer
91 int8_t expmin; // 8-bit signed integer
92 int8_t expmax;
93 uint16_t rangesig; // 16-bit unsigned integer
94 uint16_t psd;
95 uint16_t exp;
96 uint16_t tmp_uint16;
97 uint16_t i;
98
99 alpha_M = 45 * (3.1415927f/180);
100
101 #ifdef DEBUG_TCH
102 printf("BP1 : \n");
103 printf("Number of bins: %d\n", nb_bins_compressed_spec_mat);
104 #endif
105
106 // initialization for managing the exponents of the floating point data:
107 nbitexp = 6; // number of bits for the exponent
108 expmax = 32+5; // maximum value of the exponent
109 expmin = (expmax - (1 << nbitexp)) + 1; // accordingly the minimum exponent value
110 // for floating point data to be recorded on 16-bit words:
111 nbitsig = 16 - nbitexp; // number of bits for the significand
112 rangesig = (1 << nbitsig)-1; // == 2^nbitsig - 1
113
114 #ifdef DEBUG_TCH
115 printf("nbitexp : %d, expmax : %d, expmin : %d\n", nbitexp, expmax, expmin);
116 printf("nbitsig : %d, rangesig : %d\n", nbitsig, rangesig);
117 #endif
118
119 for(i=0; i<nb_bins_compressed_spec_mat; i++){
120 //==============================================
121 // BP1 PSDB == PA_LFR_SC_BP1_PB_F0 == 16 bits = 6 bits (exponent) + 10 bits (significand)
122 PSDB = compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] // S11
123 + compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9] // S22
124 + compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16]; // S33
125
126 significand = frexpf(PSDB, &exponent); // 0.5 <= significand < 1
127 // PSDB = significand * 2^exponent
128
129 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
130 exponent = expmin;
131 significand = 0.5; // min value that can be recorded
132 }
133 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
134 exponent = expmax;
135 significand = 1.0; // max value that can be recorded
136 }
137 if (significand == 0) { // in that case exponent == 0 too
138 exponent = expmin;
139 significand = 0.5; // min value that can be recorded
140 }
141
142 psd = (uint16_t) ((((significand*2) - 1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
143 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
144 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
145 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
146 tmp_uint16 = psd | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
147 // left place of the significand bits (nbitsig),
148 // making the 16-bit word to be recorded
149 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
150 #ifdef MSB_FIRST_TCH
151 lfr_bp1[(i*NB_BYTES_BP1)+2] = pt_uint8[0]; // Record MSB of tmp_uint16
152 lfr_bp1[(i*NB_BYTES_BP1)+3] = pt_uint8[1]; // Record LSB of tmp_uint16
153 #endif
154 #ifdef LSB_FIRST_TCH
155 lfr_bp1[(i*NB_BYTES_BP1)+2] = pt_uint8[1]; // Record MSB of tmp_uint16
156 lfr_bp1[(i*NB_BYTES_BP1)+3] = pt_uint8[0]; // Record LSB of tmp_uint16
157 #endif
158 #ifdef DEBUG_TCH
159 printf("\nBin number: %d\n", i);
160 printf("PSDB : %16.8e\n",PSDB);
161 printf("significand : %16.8e\n",significand);
162 printf("exponent : %d\n" ,exponent);
163 printf("psd for PSDB significand : %d\n",psd);
164 printf("exp for PSDB exponent : %d\n",exp);
165 printf("pt_uint8[1] for PSDB exponent + significand: %.3d or %.2x\n",pt_uint8[1], pt_uint8[1]);
166 printf("pt_uint8[0] for PSDB significand: %.3d or %.2x\n",pt_uint8[0], pt_uint8[0]);
167 printf("lfr_bp1[i*NB_BYTES_BP1+2] : %.3d or %.2x\n",lfr_bp1[i*NB_BYTES_BP1+2], lfr_bp1[i*NB_BYTES_BP1+2]);
168 printf("lfr_bp1[i*NB_BYTES_BP1+3] : %.3d or %.2x\n",lfr_bp1[i*NB_BYTES_BP1+3], lfr_bp1[i*NB_BYTES_BP1+3]);
169 #endif
170 //==============================================
171 // BP1 PSDE == PA_LFR_SC_BP1_PE_F0 == 16 bits = 6 bits (exponent) + 10 bits (significand)
172 PSDE = (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K44_PE]) // S44
173 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K55_PE]) // S55
174 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 22] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K45_PE_RE]) // S45 Re
175 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 23] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K45_PE_IM]); // S45 Im
176
177 significand = frexpf(PSDE, &exponent); // 0.5 <= significand < 1
178 // PSDE = significand * 2^exponent
179
180 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
181 exponent = expmin;
182 significand = 0.5; // min value that can be recorded
183 }
184 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
185 exponent = expmax;
186 significand = 1.0; // max value that can be recorded
187 }
188 if (significand == 0) {// in that case exponent == 0 too
189 exponent = expmin;
190 significand = 0.5; // min value that can be recorded
191 }
192
193 psd = (uint16_t) ((((significand*2)-1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
194 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
195 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
196 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
197 tmp_uint16 = psd | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
198 // left place of the significand bits (nbitsig),
199 // making the 16-bit word to be recorded
200 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
201 #ifdef MSB_FIRST_TCH
202 lfr_bp1[(i*NB_BYTES_BP1) + 0] = pt_uint8[0]; // Record MSB of tmp_uint16
203 lfr_bp1[(i*NB_BYTES_BP1) + 1] = pt_uint8[1]; // Record LSB of tmp_uint16
204 #endif
205 #ifdef LSB_FIRST_TCH
206 lfr_bp1[(i*NB_BYTES_BP1) + 0] = pt_uint8[1]; // Record MSB of tmp_uint16
207 lfr_bp1[(i*NB_BYTES_BP1) + 1] = pt_uint8[0]; // Record LSB of tmp_uint16
208 #endif
209 #ifdef DEBUG_TCH
210 printf("PSDE : %16.8e\n",PSDE);
211 printf("significand : %16.8e\n",significand);
212 printf("exponent : %d\n" ,exponent);
213 printf("psd for PSDE significand : %d\n",psd);
214 printf("exp for PSDE exponent : %d\n",exp);
215 printf("pt_uint8[1] for PSDE exponent + significand: %.3d or %.2x\n",pt_uint8[1], pt_uint8[1]);
216 printf("pt_uint8[0] for PSDE significand: %.3d or %.2x\n",pt_uint8[0], pt_uint8[0]);
217 printf("lfr_bp1[i*NB_BYTES_BP1+0] : %.3d or %.2x\n",lfr_bp1[i*NB_BYTES_BP1+0], lfr_bp1[i*NB_BYTES_BP1+0]);
218 printf("lfr_bp1[i*NB_BYTES_BP1+1] : %.3d or %.2x\n",lfr_bp1[i*NB_BYTES_BP1+1], lfr_bp1[i*NB_BYTES_BP1+1]);
219 #endif
220 //==============================================================================
221 // BP1 normal wave vector == PA_LFR_SC_BP1_NVEC_V0_F0 == 8 bits
222 // == PA_LFR_SC_BP1_NVEC_V1_F0 == 8 bits
223 // == PA_LFR_SC_BP1_NVEC_V2_F0 == 1 sign bit
224 tmp = sqrt( (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2] *compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2]) //Im S12
225 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4] *compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4]) //Im S13
226 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11]*compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11]) //Im S23
227 );
228 if (tmp != 0.) { // no division by 0.
229 NVEC_V0 = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11] / tmp; // S23 Im => n1
230 NVEC_V1 = (-compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4]) / tmp; // S13 Im => n2
231 NVEC_V2 = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2] / tmp; // S12 Im => n3
232 }
233 else
234 {
235 NVEC_V0 = 0.;
236 NVEC_V1 = 0.;
237 NVEC_V2 = 0.;
238 }
239 lfr_bp1[(i*NB_BYTES_BP1) + 4] = (uint8_t) ((NVEC_V0*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
240 lfr_bp1[(i*NB_BYTES_BP1) + 5] = (uint8_t) ((NVEC_V1*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
241 pt_uint8 = (uint8_t*) &NVEC_V2; // Affect an uint8_t pointer with the adress of NVEC_V2
242 #ifdef LSB_FIRST_TCH
243 lfr_bp1[(i*NB_BYTES_BP1) + 6] = pt_uint8[3] & 0x80; // Extract the sign bit of NVEC_V2 (32-bit float, sign bit in the 4th octet:PC convention)
244 // Record it at the 8th bit position (from the right to the left) of lfr_bp1[i*NB_BYTES_BP1+6]
245 #endif
246 #ifdef MSB_FIRST_TCH
247 lfr_bp1[(i*NB_BYTES_BP1) + 6] = pt_uint8[0] & 0x80; // Extract the sign bit of NVEC_V2 (32-bit float, sign bit in the 1th octet:SPARC convention)
248 // Record it at the 8th bit position (from the right to the left) of lfr_bp1[i*NB_BYTES_BP1+6]
249 #endif
250 #ifdef DEBUG_TCH
251 printf("NVEC_V0 : %16.8e\n",NVEC_V0);
252 printf("NVEC_V1 : %16.8e\n",NVEC_V1);
253 printf("NVEC_V2 : %16.8e\n",NVEC_V2);
254 printf("lfr_bp1[i*NB_BYTES_BP1+4] for NVEC_V0 : %u\n",lfr_bp1[i*NB_BYTES_BP1+4]);
255 printf("lfr_bp1[i*NB_BYTES_BP1+5] for NVEC_V1 : %u\n",lfr_bp1[i*NB_BYTES_BP1+5]);
256 printf("lfr_bp1[i*NB_BYTES_BP1+6] for NVEC_V2 : %u\n",lfr_bp1[i*NB_BYTES_BP1+6]);
257 #endif
258 //=======================================================
259 // BP1 ellipticity == PA_LFR_SC_BP1_ELLIP_F0 == 4 bits
260 if (PSDB != 0.) { // no division by 0.
261 aux = 2*tmp / PSDB; // Compute the ellipticity
262 }
263 else
264 {
265 aux = 0.;
266 }
267 tmp_uint8 = (uint8_t) ((aux*15) + 0.5); // Shift and cast into a 8-bit uint8_t with rounding
268 // where just the first 4 bits are used (0, ..., 15)
269 lfr_bp1[(i*NB_BYTES_BP1) + 6] = lfr_bp1[(i*NB_BYTES_BP1) + 6] | (tmp_uint8 << 3); // Put these 4 bits next to the right place
270 // of the sign bit of NVEC_V2 (recorded
271 // previously in lfr_bp1[i*NB_BYTES_BP1+6])
272 #ifdef DEBUG_TCH
273 printf("ellipticity : %16.8e\n",aux);
274 printf("tmp_uint8 for ellipticity : %u\n",tmp_uint8);
275 printf("lfr_bp1[i*NB_BYTES_BP1+6] for NVEC_V2 + ellipticity : %u\n",lfr_bp1[i*NB_BYTES_BP1+6]);
276 #endif
277 //==============================================================
278 // BP1 degree of polarization == PA_LFR_SC_BP1_DOP_F0 == 3 bits
279 tr_SB_SB = (compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] * compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX])
280 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9])
281 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16])
282 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 1] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 1])
283 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2])
284 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 3] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 3])
285 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4])
286 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 10]* compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 10])
287 + (2 * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11]* compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11]);
288 aux = PSDB*PSDB;
289 if (aux != 0.) { // no division by 0.
290 tmp = ( 3*tr_SB_SB - aux ) / ( 2 * aux ); // Compute the degree of polarisation
291 }
292 else
293 {
294 tmp = 0.;
295 }
296 tmp_uint8 = (uint8_t) ((tmp*7) + 0.5); // Shift and cast into a 8-bit uint8_t with rounding
297 // where just the first 3 bits are used (0, ..., 7)
298 lfr_bp1[(i*NB_BYTES_BP1) + 6] = lfr_bp1[(i*NB_BYTES_BP1) + 6] | tmp_uint8; // Record these 3 bits at the 3 first bit positions
299 // (from the right to the left) of lfr_bp1[i*NB_BYTES_BP1+6]
300 #ifdef DEBUG_TCH
301 printf("DOP : %16.8e\n",tmp);
302 printf("tmp_uint8 for DOP : %u\n",tmp_uint8);
303 printf("lfr_bp1[i*NB_BYTES_BP1+6] for NVEC_V2 + ellipticity + DOP : %u\n",lfr_bp1[i*NB_BYTES_BP1+6]);
304 #endif
305 //=======================================================================================
306 // BP1 X_SO-component of the Poynting flux == PA_LFR_SC_BP1_SX_F0 == 16 bits
307 // = 1 sign bit + 1 argument bit (two sectors)
308 // + 6 bits (exponent) + 8 bits (significand)
309 e_cross_b_re = (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_SX_RE]) //S34 Re
310 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_SX_RE]) //S35 Re
311 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 5] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K14_SX_RE]) //S14 Re
312 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 7] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K15_SX_RE]) //S15 Re
313 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_SX_RE]) //S24 Re
314 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_SX_RE]) //S25 Re
315 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_SX_IM]) //S34 Im
316 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_SX_IM]) //S35 Im
317 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 6] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K14_SX_IM]) //S14 Im
318 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 8] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K15_SX_IM]) //S15 Im
319 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_SX_IM]) //S24 Im
320 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_SX_IM]); //S25 Im
321 // Im(S_ji) = -Im(S_ij)
322 // k_ji = k_ij
323 e_cross_b_im = (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_SX_IM]) //S34 Re
324 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_SX_IM]) //S35 Re
325 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 5] *k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K14_SX_IM]) //S14 Re
326 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 7] *k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K15_SX_IM]) //S15 Re
327 + (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_SX_IM]) //S24 Re
328 + ((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_SX_IM]) //S25 Re
329 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_SX_RE]) //S34 Im
330 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_SX_RE]) //S35 Im
331 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 6] *k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K14_SX_RE]) //S14 Im
332 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 8] *k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K15_SX_RE]) //S15 Im
333 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_SX_RE]) //S24 Im
334 - (compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15]*k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_SX_RE])); //S25 Im
335 #ifdef DEBUG_TCH
336 printf("ReaSX : %16.8e\n",e_cross_b_re);
337 #endif
338 pt_uint8 = (uint8_t*) &e_cross_b_re; // Affect an uint8_t pointer with the adress of e_cross_b_re
339 #ifdef LSB_FIRST_TCH
340
341 lfr_bp1[(i*NB_BYTES_BP1) + 7] = (uint8_t) (pt_uint8[3] & 0x80); // Extract its sign bit (32-bit float, sign bit in the 4th octet:PC convention)
342 // Record it at the 8th bit position (from the right to the left)
343 // of lfr_bp1[i*NB_BYTES_BP1+7]
344 pt_uint8[3] = (pt_uint8[3] & 0x7f); // Make e_cross_b_re be positive in any case: |ReaSX|
345 #endif
346 #ifdef MSB_FIRST_TCH
347 lfr_bp1[(i*NB_BYTES_BP1) + 7] = (uint8_t) (pt_uint8[0] & 0x80); // Extract its sign bit (32-bit float, sign bit in the 1th octet:SPARC convention)
348 // Record it at the 8th bit position (from the right to the left)
349 // of lfr_bp1[i*NB_BYTES_BP1+7]
350 pt_uint8[0] = (pt_uint8[0] & 0x7f); // Make e_cross_b_re be positive in any case: |ReaSX|
351 #endif
352 significand = frexpf(e_cross_b_re, &exponent); // 0.5 <= significand < 1
353 // ReaSX = significand * 2^exponent
354 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
355 exponent = expmin;
356 significand = 0.5; // min value that can be recorded
357 }
358 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
359 exponent = expmax;
360 significand = 1.0; // max value that can be recorded
361 }
362 if (significand == 0) { // in that case exponent == 0 too
363 exponent = expmin;
364 significand = 0.5; // min value that can be recorded
365 }
366
367 lfr_bp1[(i*NB_BYTES_BP1) + 8] = (uint8_t) ((((significand*2)-1)*255) + 0.5); // Shift and cast into a 8-bit uint8_t with rounding
368 // where all bits are used (0, ..., 255)
369 tmp_uint8 = (uint8_t) (exponent-expmin); // Shift and cast into a 8-bit uint8_t where
370 // just the first nbitexp bits are used (0, ..., 2^nbitexp-1)
371 #ifdef DEBUG_TCH
372 printf("|ReaSX| : %16.8e\n",e_cross_b_re);
373 printf("significand : %16.8e\n",significand);
374 printf("exponent : %d\n" ,exponent);
375 printf("tmp_uint8 for ReaSX exponent : %d\n",tmp_uint8);
376 #endif
377 lfr_bp1[(i*NB_BYTES_BP1) + 7] = lfr_bp1[(i*NB_BYTES_BP1) + 7] | tmp_uint8; // Record these nbitexp bits in the nbitexp first bits
378 // (from the right to the left) of lfr_bp1[i*NB_BYTES_BP1+7]
379 #ifdef DEBUG_TCH
380 printf("lfr_bp1[i*NB_BYTES_BP1+7] for ReaSX sign + RealSX exponent : %u\n",lfr_bp1[i*NB_BYTES_BP1+7]);
381 printf("lfr_bp1[i*NB_BYTES_BP1+8] for ReaSX significand : %u\n",lfr_bp1[i*NB_BYTES_BP1+8]);
382 printf("ImaSX : %16.8e\n",e_cross_b_im);
383 #endif
384 pt_uint8 = (uint8_t*) &e_cross_b_im; // Affect an uint8_t pointer with the adress of e_cross_b_im
385 #ifdef LSB_FIRST_TCH
386 pt_uint8[3] = pt_uint8[3] & 0x7f; // Make e_cross_b_im be positive in any case: |ImaSX| (32-bit float, sign bit in the 4th octet:PC convention)
387 #endif
388 #ifdef MSB_FIRST_TCH
389 pt_uint8[0] = pt_uint8[0] & 0x7f; // Make e_cross_b_im be positive in any case: |ImaSX| (32-bit float, sign bit in the 1th octet:SPARC convention)
390 #endif
391 // Determine the sector argument of SX. If |Im| > |Re| affect
392 // an unsigned 8-bit char with 01000000; otherwise with null.
393 if (e_cross_b_im > e_cross_b_re) {
394 tmp_uint8 = 0x40;
395 }
396 else {
397 tmp_uint8 = 0x00;
398 }
399
400 lfr_bp1[(i*NB_BYTES_BP1) + 7] = lfr_bp1[(i*NB_BYTES_BP1) + 7] | tmp_uint8; // Record it as a sign bit at the 7th bit position (from the right
401 // to the left) of lfr_bp1[i*NB_BYTES_BP1+7], by simple logical addition.
402 #ifdef DEBUG_TCH
403 printf("|ImaSX| : %16.8e\n",e_cross_b_im);
404 printf("ArgSX sign : %u\n",tmp_uint8);
405 printf("lfr_bp1[i*NB_BYTES_BP1+7] for ReaSX & ArgSX signs + ReaSX exponent : %u\n",lfr_bp1[i*NB_BYTES_BP1+7]);
406 #endif
407 //======================================================================
408 // BP1 phase velocity estimator == PA_LFR_SC_BP1_VPHI_F0 == 16 bits
409 // = 1 sign bit + 1 argument bit (two sectors)
410 // + 6 bits (exponent) + 8 bits (significand)
411 ny = (sin(alpha_M)*NVEC_V1) + (cos(alpha_M)*NVEC_V2);
412 nz = NVEC_V0;
413 bx_bx_star = (cos(alpha_M)*cos(alpha_M)*compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9]) // S22 Re
414 + ((sin(alpha_M)*sin(alpha_M)*compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16]) // S33 Re
415 - (2*sin(alpha_M)*cos(alpha_M)*compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 10])); // S23 Re
416
417 n_cross_e_scal_b_re = (ny * ((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NY_RE]) //S24 Re
418 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NY_RE]) //S25 Re
419 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NY_RE]) //S34 Re
420 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NY_RE]) //S35 Re
421 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NY_IM]) //S24 Im
422 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NY_IM]) //S25 Im
423 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NY_IM]) //S34 Im
424 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NY_IM]))) //S35 Im
425 + (nz * ((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NZ_RE]) //S24 Re
426 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NZ_RE]) //S25 Re
427 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NZ_RE]) //S34 Re
428 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NZ_RE]) //S35 Re
429 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NZ_IM]) //S24 Im
430 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NZ_IM]) //S25 Im
431 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NZ_IM]) //S34 Im
432 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NZ_IM])));//S35 Im
433 // Im(S_ji) = -Im(S_ij)
434 // k_ji = k_ij
435 n_cross_e_scal_b_im = (ny * ((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NY_IM]) //S24 Re
436 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NY_IM]) //S25 Re
437 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NY_IM]) //S34 Re
438 +((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NY_IM]) //S35 Re
439 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NY_RE]) //S24 Im
440 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NY_RE]) //S25 Im
441 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NY_RE]) //S34 Im
442 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NY_RE])))) //S35 Im
443 + (nz * ((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NZ_IM]) //S24 Re
444 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NZ_IM]) //S25 Re
445 +(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NZ_IM] ) //S34 Re
446 +((compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NZ_IM]) //S35 Re
447 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K24_NZ_RE]) //S24 Im
448 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K25_NZ_RE]) //S25 Im
449 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K34_NZ_RE]) //S34 Im
450 -(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] * k_coeff_intercalib[(i*NB_K_COEFF_PER_BIN) + K35_NZ_RE]))));//S35 Im
451 #ifdef DEBUG_TCH
452 printf("n_cross_e_scal_b_re : %16.8e\n",n_cross_e_scal_b_re);
453 printf("n_cross_e_scal_b_im : %16.8e\n",n_cross_e_scal_b_im);
454 #endif
455 // vphi = n_cross_e_scal_b_re / bx_bx_star => sign(VPHI) = sign(n_cross_e_scal_b_re)
456 pt_uint8 = (uint8_t*) &n_cross_e_scal_b_re; // Affect an uint8_t pointer with the adress of n_cross_e_scal_b_re
457 #ifdef LSB_FIRST_TCH
458 lfr_bp1[(i*NB_BYTES_BP1) + 9] = (uint8_t) (pt_uint8[3] & 0x80); // Extract its sign bit (32-bit float, sign bit in the 4th octet:PC convention)
459 // Record it at the 8th bit position (from the right to the left)
460 // of lfr_bp1[i*NB_BYTES_BP1+9]
461 pt_uint8[3] = (pt_uint8[3] & 0x7f); // Make n_cross_e_scal_b_re be positive in any case: |n_cross_e_scal_b_re|
462 #endif
463 #ifdef MSB_FIRST_TCH
464 lfr_bp1[(i*NB_BYTES_BP1) + 9] = (uint8_t) (pt_uint8[0] & 0x80); // Extract its sign bit (32-bit float, sign bit in the 1th octet:SPARC convention)
465 // Record it at the 8th bit position (from the right to the left)
466 // of lfr_bp1[i*NB_BYTES_BP1+9]
467 pt_uint8[0] = (pt_uint8[0] & 0x7f); // Make n_cross_e_scal_b_re be positive in any case: |n_cross_e_scal_b_re|
468 #endif
469 if (bx_bx_star != 0.) { // no division by 0.
470 vphi = n_cross_e_scal_b_re / bx_bx_star; // Compute |VPHI|
471 }
472 else
473 {
474 vphi = 1.e+20; // Put a huge value
475 }
476 significand = frexpf(vphi, &exponent); // 0.5 <= significand < 1
477 // vphi = significand * 2^exponent
478 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
479 exponent = expmin;
480 significand = 0.5; // min value that can be recorded
481 }
482 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
483 exponent = expmax;
484 significand = 1.0; // max value that can be recorded
485 }
486 if (significand == 0) {// in that case exponent == 0 too
487 exponent = expmin;
488 significand = 0.5; // min value that can be recorded
489 }
490
491 lfr_bp1[(i*NB_BYTES_BP1) + 10] = (uint8_t) ((((significand*2)-1)*255) + 0.5); // Shift and cast into a 8-bit uint8_t with rounding
492 // where all the bits are used (0, ..., 255)
493 tmp_uint8 = (uint8_t) (exponent-expmin); // Shift and cast into a 8-bit uint8_t where
494 // just the first nbitexp bits are used (0, ..., 2^nbitexp-1)
495 #ifdef DEBUG_TCH
496 printf("|VPHI| : %16.8e\n",vphi);
497 printf("significand : %16.8e\n",significand);
498 printf("exponent : %d\n" ,exponent);
499 printf("tmp_uint8 for VPHI exponent : %d\n",tmp_uint8);
500 #endif
501 lfr_bp1[(i*NB_BYTES_BP1) + 9] = lfr_bp1[(i*NB_BYTES_BP1) + 9] | tmp_uint8; // Record these nbitexp bits in the nbitexp first bits
502 // (from the right to the left) of lfr_bp1[i*NB_BYTES_BP1+9]
503 #ifdef DEBUG_TCH
504 printf("lfr_bp1[i*NB_BYTES_BP1+9] for VPHI sign + VPHI exponent : %u\n",lfr_bp1[i*NB_BYTES_BP1+9]);
505 printf("lfr_bp1[i*NB_BYTES_BP1+10] for VPHI significand : %u\n",lfr_bp1[i*NB_BYTES_BP1+10]);
506 #endif
507 pt_uint8 = (uint8_t*) &n_cross_e_scal_b_im; // Affect an uint8_t pointer with the adress of n_cross_e_scal_b_im
508 #ifdef LSB_FIRST_TCH
509 pt_uint8[3] = pt_uint8[3] & 0x7f; // Make n_cross_e_scal_b_im be positive in any case: |ImaNEBX| (32-bit float, sign bit in the 4th octet:PC convention)
510 #endif
511 #ifdef MSB_FIRST_TCH
512 pt_uint8[0] = pt_uint8[0] & 0x7f; // Make n_cross_e_scal_b_im be positive in any case: |ImaNEBX| (32-bit float, sign bit in the 1th octet:SPARC convention)
513 #endif
514
515 // Determine the sector argument of NEBX. If |Im| > |Re| affect
516 // an unsigned 8-bit char with 01000000; otherwise with null.
517 if (n_cross_e_scal_b_im > n_cross_e_scal_b_re) {
518 tmp_uint8 = 0x40;
519 }
520 else {
521 tmp_uint8 = 0x00;
522 }
523
524 lfr_bp1[(i*NB_BYTES_BP1) + 9] = lfr_bp1[(i*NB_BYTES_BP1) + 9] | tmp_uint8; // Record it as a sign bit at the 7th bit position (from the right
525 // to the left) of lfr_bp1[i*NB_BYTES_BP1+9], by simple logical addition.
526 #ifdef DEBUG_TCH
527 printf("|n_cross_e_scal_b_im| : %16.8e\n",n_cross_e_scal_b_im);
528 printf("|n_cross_e_scal_b_im|/bx_bx_star : %16.8e\n",n_cross_e_scal_b_im/bx_bx_star);
529 printf("ArgNEBX sign : %u\n",tmp_uint8);
530 printf("lfr_bp1[i*NB_BYTES_BP1+9] for VPHI & ArgNEBX signs + VPHI exponent : %u\n",lfr_bp1[i*NB_BYTES_BP1+9]);
531 #endif
532 }
533 }
534
535 void BP2_set(float *compressed_spec_mat, uint8_t nb_bins_compressed_spec_mat, uint8_t *lfr_bp2)
536 {
537 float cross_re; // 32-bit floating point
538 float cross_im;
539 float aux;
540 float significand;
541 int exponent; // 32-bit signed integer
542 uint8_t nbitexp; // 8-bit unsigned integer
543 uint8_t nbitsig;
544 uint8_t *pt_uint8; // pointer on unsigned 8-bit integer
545 int8_t expmin; // 8-bit signed integer
546 int8_t expmax;
547 uint16_t rangesig; // 16-bit unsigned integer
548 uint16_t autocor;
549 uint16_t exp;
550 uint16_t tmp_uint16;
551 uint16_t i;
552
553 #ifdef DEBUG_TCH
554 printf("BP2 : \n");
555 printf("Number of bins: %d\n", nb_bins_compressed_spec_mat);
556 #endif
557
558 // For floating point data to be recorded on 16-bit words :
559 nbitexp = 6; // number of bits for the exponent
560 nbitsig = 16 - nbitexp; // number of bits for the significand
561 rangesig = (1 << nbitsig)-1; // == 2^nbitsig - 1
562 expmax = 32 + 5;
563 expmin = (expmax - (1 << nbitexp)) + 1;
564
565 #ifdef DEBUG_TCH
566
567 printf("nbitexp : %d, expmax : %d, expmin : %d\n", nbitexp, expmax, expmin);
568 printf("nbitsig : %d, rangesig : %d\n", nbitsig, rangesig);
569 #endif
570
571 for(i = 0; i<nb_bins_compressed_spec_mat; i++){
572 //==============================================
573 // BP2 normalized cross correlations == PA_LFR_SC_BP2_CROSS_F0 == 10 * (8+8) bits
574 // == PA_LFR_SC_BP2_CROSS_RE_0_F0 == 8 bits
575 // == PA_LFR_SC_BP2_CROSS_IM_0_F0 == 8 bits
576 // == PA_LFR_SC_BP2_CROSS_RE_1_F0 == 8 bits
577 // == PA_LFR_SC_BP2_CROSS_IM_1_F0 == 8 bits
578 // == PA_LFR_SC_BP2_CROSS_RE_2_F0 == 8 bits
579 // == PA_LFR_SC_BP2_CROSS_IM_2_F0 == 8 bits
580 // == PA_LFR_SC_BP2_CROSS_RE_3_F0 == 8 bits
581 // == PA_LFR_SC_BP2_CROSS_IM_3_F0 == 8 bits
582 // == PA_LFR_SC_BP2_CROSS_RE_4_F0 == 8 bits
583 // == PA_LFR_SC_BP2_CROSS_IM_4_F0 == 8 bits
584 // == PA_LFR_SC_BP2_CROSS_RE_5_F0 == 8 bits
585 // == PA_LFR_SC_BP2_CROSS_IM_5_F0 == 8 bits
586 // == PA_LFR_SC_BP2_CROSS_RE_6_F0 == 8 bits
587 // == PA_LFR_SC_BP2_CROSS_IM_6_F0 == 8 bits
588 // == PA_LFR_SC_BP2_CROSS_RE_7_F0 == 8 bits
589 // == PA_LFR_SC_BP2_CROSS_IM_7_F0 == 8 bits
590 // == PA_LFR_SC_BP2_CROSS_RE_8_F0 == 8 bits
591 // == PA_LFR_SC_BP2_CROSS_IM_8_F0 == 8 bits
592 // == PA_LFR_SC_BP2_CROSS_RE_9_F0 == 8 bits
593 // == PA_LFR_SC_BP2_CROSS_IM_9_F0 == 8 bits
594 // S12
595 aux = sqrt(compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9]);
596 if (aux != 0.) { // no division by 0.
597 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 1] / aux;
598 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 2] / aux;
599 }
600 else
601 {
602 cross_re = 0.;
603 cross_im = 0.;
604 }
605 lfr_bp2[(i*NB_BYTES_BP2) + 10] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
606 lfr_bp2[(i*NB_BYTES_BP2) + 20] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
607 #ifdef DEBUG_TCH
608 printf("\nBin number: %d\n", i);
609 printf("lfr_bp2[i*NB_BYTES_BP2+10] for cross12_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+10]);
610 printf("lfr_bp2[i*NB_BYTES_BP2+20] for cross12_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+20]);
611 #endif
612 // S13
613 aux = sqrt(compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16]);
614 if (aux != 0.) { // no division by 0.
615 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 3] / aux;
616 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 4] / aux;
617 }
618 else
619 {
620 cross_re = 0.;
621 cross_im = 0.;
622 }
623 lfr_bp2[(i*NB_BYTES_BP2) + 11] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
624 lfr_bp2[(i*NB_BYTES_BP2) + 21] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
625 #ifdef DEBUG_TCH
626 printf("lfr_bp2[i*NB_BYTES_BP2+11] for cross13_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+11]);
627 printf("lfr_bp2[i*NB_BYTES_BP2+21] for cross13_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+21]);
628 #endif
629 // S14
630 aux = sqrt(compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21]);
631 if (aux != 0.) { // no division by 0.
632 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 5] / aux;
633 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 6] / aux;
634 }
635 else
636 {
637 cross_re = 0.;
638 cross_im = 0.;
639 }
640 lfr_bp2[(i*NB_BYTES_BP2) + 12] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
641 lfr_bp2[(i*NB_BYTES_BP2) + 22] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
642 #ifdef DEBUG_TCH
643 printf("lfr_bp2[i*NB_BYTES_BP2+12] for cross14_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+12]);
644 printf("lfr_bp2[i*NB_BYTES_BP2+22] for cross14_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+22]);
645 #endif
646 // S15
647 aux = sqrt(compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24]);
648 if (aux != 0.) { // no division by 0.
649 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 7] / aux;
650 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 8] / aux;
651 }
652 else
653 {
654 cross_re = 0.;
655 cross_im = 0.;
656 }
657 lfr_bp2[(i*NB_BYTES_BP2) + 13] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
658 lfr_bp2[(i*NB_BYTES_BP2) + 23] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
659 #ifdef DEBUG_TCH
660 printf("lfr_bp2[i*NB_BYTES_BP2+13] for cross15_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+13]);
661 printf("lfr_bp2[i*NB_BYTES_BP2+23] for cross15_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+23]);
662 #endif
663 // S23
664 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16]);
665 if (aux != 0.) { // no division by 0.
666 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 10] / aux;
667 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 11] / aux;
668 }
669 else
670 {
671 cross_re = 0.;
672 cross_im = 0.;
673 }
674 lfr_bp2[(i*NB_BYTES_BP2) + 14] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
675 lfr_bp2[(i*NB_BYTES_BP2) + 24] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
676 #ifdef DEBUG_TCH
677 printf("lfr_bp2[i*NB_BYTES_BP2+14] for cross23_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+14]);
678 printf("lfr_bp2[i*NB_BYTES_BP2+24] for cross23_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+24]);
679 #endif
680 // S24
681 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21]);
682 if (aux != 0.) { // no division by 0.
683 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 12] / aux;
684 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 13] / aux;
685 }
686 else
687 {
688 cross_re = 0.;
689 cross_im = 0.;
690 }
691 lfr_bp2[(i*NB_BYTES_BP2) + 15] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
692 lfr_bp2[(i*NB_BYTES_BP2) + 25] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
693 #ifdef DEBUG_TCH
694 printf("lfr_bp2[i*NB_BYTES_BP2+15] for cross24_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+15]);
695 printf("lfr_bp2[i*NB_BYTES_BP2+25] for cross24_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+25]);
696 #endif
697 // S25
698 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24]);
699 if (aux != 0.) { // no division by 0.
700 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 14] / aux;
701 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 15] / aux;
702 }
703 else
704 {
705 cross_re = 0.;
706 cross_im = 0.;
707 }
708 lfr_bp2[(i*NB_BYTES_BP2) + 16] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
709 lfr_bp2[(i*NB_BYTES_BP2) + 26] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
710 #ifdef DEBUG_TCH
711 printf("lfr_bp2[i*NB_BYTES_BP2+16] for cross25_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+16]);
712 printf("lfr_bp2[i*NB_BYTES_BP2+26] for cross25_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+26]);
713 #endif
714 // S34
715 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21]);
716 if (aux != 0.) { // no division by 0.
717 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 17] / aux;
718 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 18] / aux;
719 }
720 else
721 {
722 cross_re = 0.;
723 cross_im = 0.;
724 }
725 lfr_bp2[(i*NB_BYTES_BP2) + 17] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
726 lfr_bp2[(i*NB_BYTES_BP2) + 27] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
727 #ifdef DEBUG_TCH
728 printf("lfr_bp2[i*NB_BYTES_BP2+17] for cross34_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+17]);
729 printf("lfr_bp2[i*NB_BYTES_BP2+27] for cross34_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+27]);
730 #endif
731 // S35
732 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16] * compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24]);
733 if (aux != 0.) { // no division by 0.
734 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 19] / aux;
735 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 20] / aux;
736 }
737 else
738 {
739 cross_re = 0.;
740 cross_im = 0.;
741 }
742 lfr_bp2[(i*NB_BYTES_BP2) + 18] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
743 lfr_bp2[(i*NB_BYTES_BP2) + 28] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
744 #ifdef DEBUG_TCH
745 printf("lfr_bp2[i*NB_BYTES_BP2+18] for cross35_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+18]);
746 printf("lfr_bp2[i*NB_BYTES_BP2+28] for cross35_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+28]);
747 #endif
748 // S45
749 aux = sqrt(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21]*compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24]);
750 if (aux != 0.) { // no division by 0.
751 cross_re = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 22] / aux;
752 cross_im = compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 23] / aux;
753 }
754 else
755 {
756 cross_re = 0.;
757 cross_im = 0.;
758 }
759 lfr_bp2[(i*NB_BYTES_BP2) + 19] = (uint8_t) ((cross_re*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
760 lfr_bp2[(i*NB_BYTES_BP2) + 29] = (uint8_t) ((cross_im*127.5) + 128); // Shift and cast into a 8-bit uint8_t (0, ..., 255) with rounding
761 #ifdef DEBUG_TCH
762 printf("lfr_bp2[i*NB_BYTES_BP2+19] for cross45_re (%16.8e) : %.3u\n",cross_re, lfr_bp2[i*NB_BYTES_BP2+19]);
763 printf("lfr_bp2[i*NB_BYTES_BP2+29] for cross45_im (%16.8e) : %.3u\n",cross_im, lfr_bp2[i*NB_BYTES_BP2+29]);
764 #endif
765 //==============================================
766 // BP2 auto correlations == PA_LFR_SC_BP2_AUTO_F0 == 5*16 bits = 5*[6 bits (exponent) + 10 bits (significand)]
767 // == PA_LFR_SC_BP2_AUTO_A0_F0 == 16 bits
768 // == PA_LFR_SC_BP2_AUTO_A1_F0 == 16 bits
769 // == PA_LFR_SC_BP2_AUTO_A2_F0 == 16 bits
770 // == PA_LFR_SC_BP2_AUTO_A3_F0 == 16 bits
771 // == PA_LFR_SC_BP2_AUTO_A4_F0 == 16 bits
772 // S11
773 significand = frexpf(compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX], &exponent); // 0.5 <= significand < 1
774 // S11 = significand * 2^exponent
775 #ifdef DEBUG_TCH
776 printf("S11 : %16.8e\n",compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX]);
777 printf("significand : %16.8e\n",significand);
778 printf("exponent : %d\n" ,exponent);
779 #endif
780 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
781 exponent = expmin;
782 significand = 0.5; // min value that can be recorded
783 }
784 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
785 exponent = expmax;
786 significand = 1.0; // max value that can be recorded
787 }
788 if (significand == 0) { // in that case exponent == 0 too
789 exponent = expmin;
790 significand = 0.5; // min value that can be recorded
791 }
792
793 autocor = (uint16_t) ((((significand*2)-1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
794 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
795 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
796 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
797 tmp_uint16 = autocor | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
798 // left place of the significand bits (nbitsig),
799 // making the 16-bit word to be recorded
800 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
801 #ifdef MSB_FIRST_TCH
802 lfr_bp2[(i*NB_BYTES_BP2) + 0] = pt_uint8[0]; // Record MSB of tmp_uint16
803 lfr_bp2[(i*NB_BYTES_BP2) + 1] = pt_uint8[1]; // Record LSB of tmp_uint16
804 #endif
805 #ifdef LSB_FIRST_TCH
806 lfr_bp2[(i*NB_BYTES_BP2) + 0] = pt_uint8[1]; // Record MSB of tmp_uint16
807 lfr_bp2[(i*NB_BYTES_BP2) + 1] = pt_uint8[0]; // Record LSB of tmp_uint16
808 #endif
809 #ifdef DEBUG_TCH
810 printf("autocor for S11 significand : %u\n",autocor);
811 printf("exp for S11 exponent : %u\n",exp);
812 printf("pt_uint8[1] for S11 exponent + significand : %.3d or %2x\n",pt_uint8[1], pt_uint8[1]);
813 printf("pt_uint8[0] for S11 significand : %.3d or %2x\n",pt_uint8[0], pt_uint8[0]);
814 printf("lfr_bp2[i*NB_BYTES_BP2+0] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+0], lfr_bp2[i*NB_BYTES_BP2+0]);
815 printf("lfr_bp2[i*NB_BYTES_BP2+1] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+1], lfr_bp2[i*NB_BYTES_BP2+1]);
816 #endif
817 // S22
818 significand = frexpf(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 9], &exponent); // 0.5 <= significand < 1
819 // S22 = significand * 2^exponent
820 #ifdef DEBUG_TCH
821 printf("S22 : %16.8e\n",compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX+9]);
822 printf("significand : %16.8e\n",significand);
823 printf("exponent : %d\n" ,exponent);
824 #endif
825 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
826 exponent = expmin;
827 significand = 0.5; // min value that can be recorded
828 }
829 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
830 exponent = expmax;
831 significand = 1.0; // max value that can be recorded
832 }
833 if (significand == 0) { // in that case exponent == 0 too
834 exponent = expmin;
835 significand = 0.5; // min value that can be recorded
836 }
837
838 autocor = (uint16_t) ((((significand*2)-1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
839 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
840 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
841 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
842 tmp_uint16 = autocor | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
843 // left place of the significand bits (nbitsig),
844 // making the 16-bit word to be recorded
845 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
846 #ifdef MSB_FIRST_TCH
847 lfr_bp2[(i*NB_BYTES_BP2) + 2] = pt_uint8[0]; // Record MSB of tmp_uint16
848 lfr_bp2[(i*NB_BYTES_BP2) + 3] = pt_uint8[1]; // Record LSB of tmp_uint16
849 #endif
850 #ifdef LSB_FIRST_TCH
851 lfr_bp2[(i*NB_BYTES_BP2) + 2] = pt_uint8[1]; // Record MSB of tmp_uint16
852 lfr_bp2[(i*NB_BYTES_BP2) + 3] = pt_uint8[0]; // Record LSB of tmp_uint16
853 #endif
854 #ifdef DEBUG_TCH
855 printf("autocor for S22 significand : %u\n",autocor);
856 printf("exp for S11 exponent : %u\n",exp);
857 printf("pt_uint8[1] for S22 exponent + significand : %.3d or %2x\n",pt_uint8[1], pt_uint8[1]);
858 printf("pt_uint8[0] for S22 significand : %.3d or %2x\n",pt_uint8[0], pt_uint8[0]);
859 printf("lfr_bp2[i*NB_BYTES_BP2+2] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+2], lfr_bp2[i*NB_BYTES_BP2+2]);
860 printf("lfr_bp2[i*NB_BYTES_BP2+3] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+3], lfr_bp2[i*NB_BYTES_BP2+3]);
861 #endif
862 // S33
863 significand = frexpf(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 16], &exponent); // 0.5 <= significand < 1
864 // S33 = significand * 2^exponent
865 #ifdef DEBUG_TCH
866 printf("S33 : %16.8e\n",compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX+16]);
867 printf("significand : %16.8e\n",significand);
868 printf("exponent : %d\n" ,exponent);
869 #endif
870 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
871 exponent = expmin;
872 significand = 0.5; // min value that can be recorded
873 }
874 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
875 exponent = expmax;
876 significand = 1.0; // max value that can be recorded
877 }
878 if (significand == 0) { // in that case exponent == 0 too
879 exponent = expmin;
880 significand = 0.5; // min value that can be recorded
881 }
882
883 autocor = (uint16_t) ((((significand*2)-1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
884 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
885 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
886 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
887 tmp_uint16 = autocor | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
888 // left place of the significand bits (nbitsig),
889 // making the 16-bit word to be recorded
890 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
891 #ifdef MSB_FIRST_TCH
892 lfr_bp2[(i*NB_BYTES_BP2) + 4] = pt_uint8[0]; // Record MSB of tmp_uint16
893 lfr_bp2[(i*NB_BYTES_BP2) + 5] = pt_uint8[1]; // Record LSB of tmp_uint16
894 #endif
895 #ifdef LSB_FIRST_TCH
896 lfr_bp2[(i*NB_BYTES_BP2) + 4] = pt_uint8[1]; // Record MSB of tmp_uint16
897 lfr_bp2[(i*NB_BYTES_BP2) + 5] = pt_uint8[0]; // Record LSB of tmp_uint16
898 #endif
899 #ifdef DEBUG_TCH
900 printf("autocor for S33 significand : %u\n",autocor);
901 printf("exp for S33 exponent : %u\n",exp);
902 printf("pt_uint8[1] for S33 exponent + significand : %.3d or %2x\n",pt_uint8[1], pt_uint8[1]);
903 printf("pt_uint8[0] for S33 significand : %.3d or %2x\n",pt_uint8[0], pt_uint8[0]);
904 printf("lfr_bp2[i*NB_BYTES_BP2+4] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+4], lfr_bp2[i*NB_BYTES_BP2+4]);
905 printf("lfr_bp2[i*NB_BYTES_BP2+5] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+5], lfr_bp2[i*NB_BYTES_BP2+5]);
906 #endif
907 // S44
908 significand = frexpf(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 21], &exponent); // 0.5 <= significand < 1
909 // S44 = significand * 2^exponent
910 #ifdef DEBUG_TCH
911 printf("S44 : %16.8e\n",compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX+21]);
912 printf("significand : %16.8e\n",significand);
913 printf("exponent : %d\n" ,exponent);
914 #endif
915
916 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
917 exponent = expmin;
918 significand = 0.5; // min value that can be recorded
919 }
920 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
921 exponent = expmax;
922 significand = 1.0; // max value that can be recorded
923 }
924 if (significand == 0) { // in that case exponent == 0 too
925 exponent = expmin;
926 significand = 0.5; // min value that can be recorded
927 }
928
929 autocor = (uint16_t) ((((significand*2)-1)*rangesig )+ 0.5); // Shift and cast into a 16-bit unsigned int with rounding
930 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
931 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
932 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
933 tmp_uint16 = autocor | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
934 // left place of the significand bits (nbitsig),
935 // making the 16-bit word to be recorded
936 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
937 #ifdef MSB_FIRST_TCH
938 lfr_bp2[(i*NB_BYTES_BP2) + 6] = pt_uint8[0]; // Record MSB of tmp_uint16
939 lfr_bp2[(i*NB_BYTES_BP2) + 7] = pt_uint8[1]; // Record LSB of tmp_uint16
940 #endif
941 #ifdef LSB_FIRST_TCH
942 lfr_bp2[(i*NB_BYTES_BP2) + 6] = pt_uint8[1]; // Record MSB of tmp_uint16
943 lfr_bp2[(i*NB_BYTES_BP2) + 7] = pt_uint8[0]; // Record LSB of tmp_uint16
944 #endif
945 #ifdef DEBUG_TCH
946 printf("autocor for S44 significand : %u\n",autocor);
947 printf("exp for S44 exponent : %u\n",exp);
948 printf("pt_uint8[1] for S44 exponent + significand : %.3d or %2x\n",pt_uint8[1], pt_uint8[1]);
949 printf("pt_uint8[0] for S44 significand : %.3d or %2x\n",pt_uint8[0], pt_uint8[0]);
950 printf("lfr_bp2[i*NB_BYTES_BP2+6] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+6], lfr_bp2[i*NB_BYTES_BP2+6]);
951 printf("lfr_bp2[i*NB_BYTES_BP2+7] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+7], lfr_bp2[i*NB_BYTES_BP2+7]);
952 #endif
953 // S55
954 significand = frexpf(compressed_spec_mat[(i*NB_VALUES_PER_SPECTRAL_MATRIX) + 24], &exponent); // 0.5 <= significand < 1
955 // S55 = significand * 2^exponent
956 #ifdef DEBUG_TCH
957 printf("S55 : %16.8e\n",compressed_spec_mat[i*NB_VALUES_PER_SPECTRAL_MATRIX+24]);
958 printf("significand : %16.8e\n",significand);
959 printf("exponent : %d\n" ,exponent);
960 #endif
961 if (exponent < expmin) { // value should be >= 0.5 * 2^expmin
962 exponent = expmin;
963 significand = 0.5; // min value that can be recorded
964 }
965 if (exponent > expmax) { // value should be < 0.5 * 2^(expmax+1)
966 exponent = expmax;
967 significand = 1.0; // max value that can be recorded
968 }
969 if (significand == 0) { // in that case exponent == 0 too
970 exponent = expmin;
971 significand = 0.5; // min value that can be recorded
972 }
973
974 autocor = (uint16_t) ((((significand*2)-1)*rangesig) + 0.5); // Shift and cast into a 16-bit unsigned int with rounding
975 // where just the first nbitsig bits are used (0, ..., 2^nbitsig-1)
976 exp = (uint16_t) (exponent-expmin); // Shift and cast into a 16-bit unsigned int where just
977 // the first nbitexp bits are used (0, ..., 2^nbitexp-1)
978 tmp_uint16 = autocor | (exp << nbitsig); // Put the exponent bits (nbitexp) next to the
979 // left place of the significand bits (nbitsig),
980 // making the 16-bit word to be recorded
981 pt_uint8 = (uint8_t*) &tmp_uint16; // Affect an uint8_t pointer with the adress of tmp_uint16
982 #ifdef MSB_FIRST_TCH
983 lfr_bp2[(i*NB_BYTES_BP2) + 8] = pt_uint8[0]; // Record MSB of tmp_uint16
984 lfr_bp2[(i*NB_BYTES_BP2) + 9] = pt_uint8[1]; // Record LSB of tmp_uint16
985 //printf("MSB:\n");
986 #endif
987 #ifdef LSB_FIRST_TCH
988 lfr_bp2[(i*NB_BYTES_BP2) + 8] = pt_uint8[1]; // Record MSB of tmp_uint16
989 lfr_bp2[(i*NB_BYTES_BP2) + 9] = pt_uint8[0]; // Record LSB of tmp_uint16
990 //printf("LSB:\n");
991 #endif
992 #ifdef DEBUG_TCH
993 printf("autocor for S55 significand : %u\n",autocor);
994 printf("exp for S55 exponent : %u\n",exp);
995 printf("pt_uint8[1] for S55 exponent + significand : %.3d or %2x\n",pt_uint8[1], pt_uint8[1]);
996 printf("pt_uint8[0] for S55 significand : %.3d or %2x\n",pt_uint8[0], pt_uint8[0]);
997 printf("lfr_bp2[i*NB_BYTES_BP2+8] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+8], lfr_bp2[i*NB_BYTES_BP2+8]);
998 printf("lfr_bp2[i*NB_BYTES_BP2+9] : %3u or %2x\n",lfr_bp2[i*NB_BYTES_BP2+9], lfr_bp2[i*NB_BYTES_BP2+9]);
999 #endif
1000 }
1001 }
1002
@@ -0,0 +1,61
1 // In the frame of RPW LFR Sofware ICD Issue1 Rev8 (05/07/2013) => R2 FSW
2 // version 1.0: 31/07/2013
3 // version 1.1: 02/04/2014
4 // version 1.2: 30/04/2014
5 // version 1.3: 02/05/2014
6 // version 1.4: 16/05/2014
7 // version 1.5: 20/05/2014
8 // version 1.6: 19/12/2014
9 // version 1.7: 15/01/2015 (modifs de Paul + correction erreurs qui se compensaient (LSB <=> MSB + indices [0,2] <=> [1,3])
10 // version 1.8: 02/02/2015 (gestion des divisions par zéro)
11 // In the frame of RPW LFR Sofware ICD Issue3 Rev6 (27/01/2015) => R3 FSW
12 // version 2.0: 19/06/2015
13 // version 2.1: 22/06/2015 (modifs de Paul)
14 // version 2.2: 23/06/2015 (modifs de l'ordre de déclaration/définition de init_k_coefficients dans basic_parameters.c ... + maintien des declarations dans le .h)
15 // version 2.3: 01/07/2015 (affectation initiale des octets 7 et 9 dans les BP1 corrigée ...)
16 // version 2.4: 05/10/2018 (mise en conformité LOGISCOPE)
17 // version 2.5: 09/10/2018 (dans main.c #include "basic_parameters_utilities.h" est changé par les déclarations extern correspondantes ...!
18 // + delta mise en conformité LOGISCOPE)
19
20 /*------------------------------------------------------------------------------
21 -- Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
22 -- This file is a part of the LFR FSW
23 -- Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
24 --
25 -- This program is free software; you can redistribute it and/or modify
26 -- it under the terms of the GNU General Public License as published by
27 -- the Free Software Foundation; either version 2 of the License, or
28 -- (at your option) any later version.
29 --
30 -- This program is distributed in the hope that it will be useful,
31 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
32 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 -- GNU General Public License for more details.
34 --
35 -- You should have received a copy of the GNU General Public License
36 -- along with this program; if not, write to the Free Software
37 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 -------------------------------------------------------------------------------*/
39 /*-- Author : Thomas Chust
40 -- Contact : Thomas Chust
41 -- Mail : thomas.chust@lpp.polytechnique.fr
42 ----------------------------------------------------------------------------*/
43
44 #ifndef BASIC_PARAMETERS_H_INCLUDED
45 #define BASIC_PARAMETERS_H_INCLUDED
46
47 #include <stdint.h>
48
49 #include "basic_parameters_params.h"
50
51 void init_k_coefficients( float *k_coeff_intercalib, unsigned char nb_binscompressed_matrix );
52
53 //***********************************
54 // STATIC INLINE FUNCTION DEFINITIONS
55
56 void BP1_set( float * compressed_spec_mat, float * k_coeff_intercalib, uint8_t nb_bins_compressed_spec_mat, uint8_t * lfr_bp1 );
57
58 void BP2_set( float * compressed_spec_mat, uint8_t nb_bins_compressed_spec_mat, uint8_t * lfr_bp2 );
59
60
61 #endif // BASIC_PARAMETERS_H_INCLUDED
@@ -0,0 +1,93
1 // In the frame of RPW LFR Sofware ICD Issue1 Rev8 (05/07/2013) => R2 FSW
2 // version 1.4: 16/05/2014
3 // version 1.5: 20/05/2014
4 // version 1.6: 19/12/2014
5 // version 1.7: 15/01/2015 (modifs de Paul + correction erreurs qui se compensaient (LSB <=> MSB + indices [0,2] <=> [1,3])
6 // version 1.8: 02/02/2015 (gestion des divisions par zéro)
7 // In the frame of RPW LFR Sofware ICD Issue3 Rev6 (27/01/2015) => R3 FSW
8 // version 2.0: 19/06/2015
9 // version 2.1: 22/06/2015 (modifs de Paul)
10 // version 2.2: 23/06/2015 (modifs de l'ordre de déclaration/définition de init_k_coefficients dans basic_parameters.c ... + maintien des declarations dans le .h)
11 // version 2.3: 01/07/2015 (affectation initiale des octets 7 et 9 dans les BP1 corrigée ...)
12 // version 2.4: 05/10/2018 (added GPL headers)
13 // version 2.5: 09/10/2018 (dans main.c #include "basic_parameters_utilities.h" est changé par les déclarations extern correspondantes ...!
14 // + delta mise en conformité LOGISCOPE)
15
16 /*------------------------------------------------------------------------------
17 -- Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
18 -- This file is a part of the LFR FSW
19 -- Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
20 --
21 -- This program is free software; you can redistribute it and/or modify
22 -- it under the terms of the GNU General Public License as published by
23 -- the Free Software Foundation; either version 2 of the License, or
24 -- (at your option) any later version.
25 --
26 -- This program is distributed in the hope that it will be useful,
27 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
28 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 -- GNU General Public License for more details.
30 --
31 -- You should have received a copy of the GNU General Public License
32 -- along with this program; if not, write to the Free Software
33 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 -------------------------------------------------------------------------------*/
35 /*-- Author : Thomas Chust
36 -- Contact : Thomas Chust
37 -- Mail : thomas.chust@lpp.polytechnique.fr
38 ----------------------------------------------------------------------------*/
39
40 #ifndef BASIC_PARAMETERS_PARAMS_H
41 #define BASIC_PARAMETERS_PARAMS_H
42
43 #define NB_VALUES_PER_SPECTRAL_MATRIX 25
44
45 #define NB_BINS_COMPRESSED_MATRIX_f0 11
46 #define NB_BINS_COMPRESSED_MATRIX_f1 13
47 #define NB_BINS_COMPRESSED_MATRIX_f2 12
48
49 #define NB_BYTES_BP1 11
50 #define NB_BYTES_BP2 30
51
52 //********************************************
53 // K-COEFFICIENTS FOR ONBOARD INTERCALIBRATION
54
55 #define NB_K_COEFF_PER_BIN 32
56
57 #define K44_PE 0
58 #define K55_PE 1
59 #define K45_PE_RE 2
60 #define K45_PE_IM 3
61
62 #define K14_SX_RE 4
63 #define K14_SX_IM 5
64 #define K15_SX_RE 6
65 #define K15_SX_IM 7
66 #define K24_SX_RE 8
67 #define K24_SX_IM 9
68 #define K25_SX_RE 10
69 #define K25_SX_IM 11
70 #define K34_SX_RE 12
71 #define K34_SX_IM 13
72 #define K35_SX_RE 14
73 #define K35_SX_IM 15
74
75 #define K24_NY_RE 16
76 #define K24_NY_IM 17
77 #define K25_NY_RE 18
78 #define K25_NY_IM 19
79 #define K34_NY_RE 20
80 #define K34_NY_IM 21
81 #define K35_NY_RE 22
82 #define K35_NY_IM 23
83
84 #define K24_NZ_RE 24
85 #define K24_NZ_IM 25
86 #define K25_NZ_RE 26
87 #define K25_NZ_IM 27
88 #define K34_NZ_RE 28
89 #define K34_NZ_IM 29
90 #define K35_NZ_RE 30
91 #define K35_NZ_IM 31
92
93 #endif // BASIC_PARAMETERS_PARAMS_H
@@ -0,0 +1,54
1 // In the frame of RPW LFR Sofware ICD Issue1 Rev8 (05/07/2013) => R2 FSW
2 // version 1.6: 19/12/2014
3 // version 1.7: 15/01/2015 (modifs de Paul + correction erreurs qui se compensaient (LSB <=> MSB + indices [0,2] <=> [1,3])
4 // version 1.8: 02/02/2015 (gestion des divisions par zéro)
5 // In the frame of RPW LFR Sofware ICD Issue3 Rev6 (27/01/2015) => R3 FSW
6 // version 2.0: 19/06/2015
7 // version 2.1: 22/06/2015 (modifs de Paul)
8 // version 2.2: 23/06/2015 (modifs de l'ordre de déclaration/définition de init_k_coefficients dans basic_parameters.c ... + maintien des declarations dans le .h)
9 // version 2.3: 01/07/2015 (affectation initiale des octets 7 et 9 dans les BP1 corrigée ...)
10 // version 2.4: 05/10/2018 (mise en conformité LOGISCOPE)
11 // version 2.5: 09/10/2018 (dans main.c #include "basic_parameters_utilities.h" est changé par les déclarations extern correspondantes ...!
12 // + delta mise en conformité LOGISCOPE)
13
14 /*------------------------------------------------------------------------------
15 -- Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
16 -- This file is a part of the LFR FSW
17 -- Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
18 --
19 -- This program is free software; you can redistribute it and/or modify
20 -- it under the terms of the GNU General Public License as published by
21 -- the Free Software Foundation; either version 2 of the License, or
22 -- (at your option) any later version.
23 --
24 -- This program is distributed in the hope that it will be useful,
25 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
26 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 -- GNU General Public License for more details.
28 --
29 -- You should have received a copy of the GNU General Public License
30 -- along with this program; if not, write to the Free Software
31 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 -------------------------------------------------------------------------------*/
33 /*-- Author : Thomas Chust
34 -- Contact : Thomas Chust
35 -- Mail : thomas.chust@lpp.polytechnique.fr
36 ----------------------------------------------------------------------------*/
37
38 #ifndef BASIC_PARAMETERS_UTILITIES_H
39 #define BASIC_PARAMETERS_UTILITIES_H
40
41 #include <stdio.h>
42 #include <malloc.h>
43
44 #include "basic_parameters_params.h"
45
46 float compressed_spectral_matrix_f0[NB_BINS_COMPRESSED_MATRIX_f0 * NB_VALUES_PER_SPECTRAL_MATRIX] = {0.0};
47 float k_coefficients_f0[NB_BINS_COMPRESSED_MATRIX_f0 * NB_K_COEFF_PER_BIN] = {0.0};
48 float k_coefficients_f1[NB_BINS_COMPRESSED_MATRIX_f1 * NB_K_COEFF_PER_BIN] = {0.0};
49 float k_coefficients_f2[NB_BINS_COMPRESSED_MATRIX_f2 * NB_K_COEFF_PER_BIN] = {0.0};
50
51 unsigned char LFR_BP1_f0[NB_BINS_COMPRESSED_MATRIX_f0*NB_BYTES_BP1] = {0};
52 unsigned char LFR_BP2_f0[NB_BINS_COMPRESSED_MATRIX_f0*NB_BYTES_BP2] = {0};
53
54 #endif // BASIC_PARAMETERS_UTILITIES_H
@@ -0,0 +1,27
1 from ctypes import *
2 import numpy as np
3 import os
4 import sys
5
6 import unittest
7
8 class init_k_coefficients(unittest.TestCase):
9 def setUp(self):
10 self.lib_basic_params = cdll.LoadLibrary(f'{os.path.dirname(os.path.realpath(__file__))}/../../build-LFR_basic-parameters-Desktop-Default/liblfr_basic_params.so')
11
12 def tearDown(self):
13 pass
14
15 def test_init_k_coefficients_f0(self):
16 nb_bins = 11
17 nb_binscompressed_matrix = c_char(nb_bins)
18 k_coefficients = (c_float * (32 * nb_bins))()
19
20 for i in range(len(k_coefficients)):
21 k_coefficients[i] = 100.*np.random.random()
22
23 self.lib_basic_params.init_k_coefficients(k_coefficients, nb_binscompressed_matrix)
24 self.assertTrue(all([ v==1. if i not in ( 2, 3, 34, 35, 66, 67, 98, 99, 130, 131, 162, 163, 194, 195, 226, 227, 258, 259, 290, 291, 322, 323) else v==0. for i,v in enumerate(k_coefficients) ]))
25
26 if __name__ == '__main__':
27 unittest.main()
@@ -1,2 +1,2
1 syntax: glob
1 syntax: glob
2 tab_test2_v1.3
2 *.user
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (1003 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now