.. _programmers_notes: .. |br| raw:: html
.. index:: single: Programmers notes Programmers Notes ===================== CSV tables ----------- In some modules CSV tables may by imported (mk_master_cal). The implemented style is: .. csv-table:: :delim: , serial, chopper, f, a, p, stddev a, stddev p 1, 1, 1.232800e-01, 2.000200e-01, 8.823600e+01, 2.734738e-04, 2.734738e-04 1, 0, 1.000000e+00, 1.892500e-01, 1.112900e+02, 1.312173e-03, 1.312173e-03 .. code-block:: text serial, chopper, f, a, p, stddev a, stddev p 1, 1, 1.232800e-01, 2.000200e-01, 8.823600e+01, 2.734738e-04, 2.734738e-04 1, 0, 1.000000e+00, 1.892500e-01, 1.112900e+02, 1.312173e-03, 1.312173e-03 CVS tables are always TEXT. When performing actions based on tables, be aware that **1.0e+00** and **1.0E+00** are **NOT THE SAME** |br| Also in case of mathematics a string must be converted into a number and back: |br| .. 1.0e+00 -> double is ok, 1.0e+00 -> int is not ok; so internally we always go ``1.0e+00 -> double -> int`` (in case). |br| In case of string data we always compare lower case! |br| All frequencies you use have to be sorted from low to high. .. _ats_header: ATS header ----------- ats stands for advanced timeseries. |br| In languages such as C++ you do simlilar like (here with C++ & Qt) .. code-block:: c++ ATSHeader_80 bin_atsheader; //!< binaray header for read/write .... file.setFileName("myatsfile.ats"); file.open(QIODevice::ReadOnly)) QDataStream qds; qds.setDevice(file); qds.readRawData((char*) &bin_atsheader, sizeof(bin_atsheader)); qDebug() << "samples: " << bin_atsheader.uiSamples; In other languages reading a binary file is maybe similar. .. code-block:: c++ #ifndef ATSHEADER_80_DEF_H #define ATSHEADER_80_DEF_H #include // // // // array of chars are not NULL terminated ! // achChanType [2] = "Ex" is not NULL terminated // // #define C_ATS_CEA_NUM_HEADERS 1023 /*!< maximum number of 1023 headers of the ATS sliced file.*/ /*! \brief The ATSSliceHeader_s struct A sliced ats file ALWAYS contains a default header and C_ATS_CEA_NUM_HEADERS (1023) = 1024 total.
The FIRST and DEFAULT slice contains ALL information (total samples of all slices)
The 0 ... 1022 slices (= ATS_CEA_NUM_HEADERS ) contain the individual descriptions
start tsdata = 400h = 1024th byte
start of CEA data is 400h + 3FFh * 20h = 83E0h
1024 + 1023 * 32 = 33760
assuming 3 slices of 4096 iSamples will be 12,288 samples in the header, followed by 3 slice headers with 4096 iSamples each and 1019 empty slice headers
the data has to sorted out on/after 83E0h according to the slice info */ struct ATSSliceHeader_1080 { std::uint32_t uiSamples; //!< 000h number of samples for this slice std::uint32_t uiStartDateTime; //!< 004h startdate/time as UNIX timestamp (UTC) double dbDCOffsetCorrValue; //!< 008h DC offset correction value in mV float rPreGain; //!< 010h originally used pre-gain (GainStage1) - LSB is the same for all slices float rPostGain; //!< 014h originally used post-gain (GainStage2) - LSB is the same for all slices std::int8_t DCOffsetCorrOn; //!< 018h DC offset correction was on/off for this slice std::int8_t reserved[7]; //!< 020h reserved bytes to get to word / dword boundary }; /*! @todo TX info maybe UTM Zone number maybe UTM letter Tx times six double at least Tx base freq */ /*! \brief The ATSComments_80 struct for ats header 80,81 and 90
Some software will automatically convert to higher version
Some fields are external - the user has to set then; examples:
northing, easting, UTM Zone : these can be used for high density grids
*/ struct ATSComments_80 { char achClient [16]; //!< 000h UTF-8 storage, used in EDI char achContractor [16]; //!< 010h UTF-8 storage, used in EDI char achArea [16]; //!< 020h UTF-8 storage, used in EDI char achSurveyID [16]; //!< 030h UTF-8 storage, used in EDI char achOperator [16]; //!< 040h UTF-8 storage, used in EDI char achSiteName [112]; //!< 050h UTF-8 storage, no BOM at the beginning!; WORST case = 28 Chinese/Japanese chars (multibyte chars) char achXmlHeader [64]; //!< 0C0h UTF-8 storage points to the corresponding XML file, containing addtional information for this header; no PATH=XML file is in the same directory as the ats file // deleted September 2018 char achComments [512]; //!< 100h UTF-8 storage comment block starts (comment field can start with "weather:" but has no meaning // new September 2018 char achComments [288]; //!< 100h UTF-8 storage comment block starts (comment field can start with "weather:" but has no meaning char achSiteNameRR [112]; //!< 220h UTF-8 storage, no BOM at the beginning!; WORST case = 28 Chinese/Japanese chars (multibyte chars) char achSiteNameEMAP [112]; //!< 290h UTF-8 storage, no BOM at the beginning!; WORST case = 28 Chinese/Japanese chars (multibyte chars); INDICATES a default EMAP center station, where we expect the H (magnetic) }; /*! \brief The ATSHeader_80 struct
reference is lat and long; additional entries like northing and easting should be empty // not used
these entries can be overwritten by the user in case of high density grids
The site_name (site name, achSiteName, is in the comment field; the site_no, site_num, site_number, site number is nver stored; this is part of external numeration */ struct ATSHeader_80 { std::uint16_t uiHeaderLength; //!< 000h length of header in bytes (default 1024 and 33760 for CEA) std::int16_t siHeaderVers; //!< 002h 80 for ats, 81 for 64bit possible / metronix, 1080 for CEA / sliced header // This information can be found in the ChannelTS datastructure std::uint32_t uiSamples; //!< 004h amount of samples (each is a 32bit / 64bit int INTEL byte order little endian) in the file total of all slices; if uiSamples == UINT32_MAX, uiSamples64bit at address 0F0h will be used instead; uiSamples64bit replaces uiSamples in that case; do not add! //!< float rSampleFreq; //!< 008h sampling frequency in Hz std::uint32_t uiStartDateTime; //!< 00Ch unix TIMESTAMP (some computers will revert that to negative numbers if this number is grater than 32bit signed); 2106-02-07T06:28:14 is the END of this format double dblLSBMV; //!< 010h least significant bit in mV () std::int32_t iGMTOffset; //!< 018h not used, default 0; can be used as "UTC to GMT" float rOrigSampleFreq; //!< 01Ch sampling frequency in Hz as ORIGINALLY recorded; this value should NOT change (for example after filtering) //The required data could probably found in the HardwareConfig std::uint16_t uiADUSerNum; //!< 020h Serial number of the system (logger) std::uint16_t uiADCSerNum; //!< 022h Serial number of the ADC board (ADB) std::uint8_t uiChanNo; //!< 024h Channel number std::uint8_t uiChopper; //!< 025h Chopper On (1) / Off (0); e.g. chopper is on for 512Hz and lower // Data from XML Job-specification char achChanType [2]; //!< 026h (Ex, Ey, Ez, Hx, Hy, Hz, Jx, Jy, Jz, Px, Py, Pz, Rx, Ry, Rz and so on) char achSensorType [6]; //!< 028h (MFS06 MFS06e MFS07 MFS07e MFS10e SHFT02 SHF02e FGS02 FGS03 FGS03e etc. e.g. the "-" in MFS-06e is skipped) std::int16_t siSensorSerNum; //!< 02Eh Serial number of connected sensor float rPosX1; //!< 030h e.g. South negative [m] float rPosY1; //!< 034h e.g. West negative [m] float rPosZ1; //!< 038h e.g. top, sky [m] float rPosX2; //!< 03Ch e.g. North positive [m] float rPosY2; //!< 040h e.g. East positive [m] float rPosZ2; //!< 044h e.g. bottom, earth [m] // not used any more use pos values!!; GUI interfaces using Length and direction MUST calculate pos x,y,z and set above. float rDipLength; //!< 048h e.g. to be calculated; should not be used - my be over written in FUTURE // not used any more use pos values!! float rAngle; //!< 04Ch e.g. to be calculated; should not be used - my be over written in FUTURE // Data from Selftest float rProbeRes; //!< 050h [ohm] float rDCOffset; //!< 054h [mV] float rPreGain; //!< 058h e.g. Gain Stage 1 float rPostGain; //!< 05Ch e.g. Gain Stage 2 // Data from status information ? std::int32_t iLatitude; //!< 060h must be used, UNIT = milli seconds std::int32_t iLongitude; //!< 064h must be used, UNIT = milli seconds std::int32_t iElevation; //!< 068h must be used, UNIT = cm char byLatLongType; //!< 06Ch 'G' default, 'U' user, GPS should be used char byAddCoordType; //!< 06Dh 'U' = UTM, default empty std::int16_t siRefMeridian; //!< 06Eh default empty, should not be used (external) //!@todo can we store 64bit time and 64bit samples here ?? double dblNorthing; //!< 070h also xcoord should not be used, default 0 (external) double dblEasting; //!< 078h also ycoord should not be used default 0 (external) char byGPSStat; //!< 080h '-' unknown, 'N' no fix, 'C' full fix char byGPSAccuracy; //!< 081h '0' - not used, 1 in case GF4-Fix & Syrlinks was active (system was synced before Syrlinks took over) std::int16_t iUTCOffset; //!< 082h UTC + iUTCOffset = GPS time for example; can be used for other offsets, not used, default 0 char achSystemType[12]; //!< 084h MMS03e GMS05 ADU06 ADU07 ADU08 ADU09 SPAMMKV SPAMMKIII // Data from XML-Job specification char achSurveyHeaderName [12]; //!< 090h UTF-8 storage free for usage char achMeasType [4]; //!< 09Ch free for usage MT CSMT double DCOffsetCorrValue; //!< 0A0h DAC offset double std::int8_t DCOffsetCorrOn; //!< 0A8h DC offset was switched on (1) or off(0) std::int8_t InputDivOn; //!< 0A9h inputput divider on(1) off(0); e.g when coil was connected = 1 std::int16_t bit_indicator; //!< 0AAh 0 = 32bit int INTEL byte order, 1 = 64bit INTEL byte order, little endian; since atsheader version 81 char achSelfTestResult [2]; //!< 0ACh 'NO' or 'OK' std::uint16_t numslices; //!< 0AEh number of slices used (1....1024, 1 is the first, that is list.size() ) //std::int16_t calentries // max 128 entries // Were the following fields ever used ? std::int16_t siCalFreqs; //!< 0B0h not used (external) std::int16_t siCalEntryLength; //!< 0B2h not used (external) std::int16_t siCalVersion; //!< 0B4h not used (external) std::int16_t siCalStartAddress; //!< 0B6h not used, never used (external) char abyLFFilters [8]; //!< 0B8h is a bitfield char achUTMZone [12]; //!< 0C0h not used (external) (formerly abyADU06CalFilename) 32U or 01G, 32UMD7403 : alway NNC od NNCCNNNN std::uint32_t uiADUCalTimeDate; //!< 0CCh not used (external) char achSensorCalFilename [12]; //!< 0D0h not used ("SENSOR.CAL") (external) std::uint32_t uiSensorCalTimeDate; //!< 0DCh not used (external) float rPowerlineFreq1; //!< 0E0h e.g. empty (external) float rPowerlineFreq2; //!< 0E4h e.g. empty (external) char abyHFFilters[8]; //!< 0E8h is a bitfield // IF uiSamples == UINT32_MAX you find std::uint64_t uiSamples64bit; //!< 0F0h amount of samples (each is a 32bit /64bit int) in the file total of all slices; ONLY used in case uiSamples == UINT32_MAX; else 0; REPLACSES the uiSamples; do not add //double OriginalLSBMV; //!< 0F0h NOT USED ANYMORE! orig lsb from selftest without gains; used for ADC values float rExtGain; //!< 0F8h for external satellite box char achADBBoardType[4]; //!< 0FCh LF HF or MF or BB ATSComments_80 tscComment; //!< 100h // size if comments is total 100h + 100h data + (512byte comments = 200h) = 400h // start tsdata = 400h = 1024th byte // start of CEA header is 400h + 3FFh * 20h = 83E0h // 1024 + 1023 * 23 = 33760 }; #endif // ATSHEADER_80_DEF_H .. _dblLSBMV_programmer: LSB ^^^^^^ LSB == least significant bit **The dblLSBMV multiplied with the int32_t data values results in the measured values in mV** Gains and others are included in th LSB. |br| To scale the E field use rPosX1 ... rPosZ2 values and **NOT!** the rDipLength and rAngle; these values are obsolete |br| metronix software assumes for the magnetic field that in case all rPosX1 ... rPosZ2 are zero, that Hx is pointing North, Hy East and Hz down. |br| .. _atm_header: ATM header ^^^^^^^^^^^^^ That is the binary marker file .. code-block:: c++ struct atmheader { qint16 siHeaderLength; qint16 siHeaderVers; quint32 iSamples; }; Followed by booleans (for each sample); true = will be processed, false not. .. _calibration_file: Calibration File ------------------ E.g. the calibration file has to sections: "chopper on" and "chopper off". |br| First column indicateds frequency in Hz. |br| Second column amplitude in V/(nT * Hz) |br| Third phase in degree (0-360, not radians). |br| Be default the chopper should be ON for recordings with equal/less than 512 Hz. |br| For chopper on the lower frequencies can be extended by the theroretical function. For chopper off this is not possible. The amplitude is normalized by f (as you can see from the units). So for lower frequencies the amplitude of the MFS-06e converges agains 0.2 V/(nT*Hz) (and gives a horizontal line in a plot for the chopper on data). For usage in your software you may * multiply magnitude by f * make a complex number from magnitude and phase * if you take the mV data from the ats, multiply calibration by 1000 in case * interpolate the calibration data onto your nodes of the FFT * divide by the calibration .. code-block:: bash Calibration measurement with NumetriQ PSM 3750 - 0.1.100000.1.33 Metronix GmbH, Kocherstr. 3, 38120 Braunschweig Magnetometer: MFS06e#727 Date: 17/01/12 Time: 12:19:57 FREQUENCY MAGNITUDE PHASE Hz V/(nT*Hz) deg Chopper On +1.0000E-01 +1.9996E-01 +8.8589E+01 +1.2328E-01 +2.0008E-01 +8.8225E+01 +1.5199E-01 +2.0014E-01 +8.7796E+01 +1.8738E-01 +1.9987E-01 +8.7329E+01 +2.3101E-01 +1.9982E-01 +8.6762E+01 +2.8480E-01 +1.9984E-01 +8.5986E+01 +3.5111E-01 +1.9961E-01 +8.5047E+01 +4.3287E-01 +1.9919E-01 +8.3911E+01 +5.3367E-01 +1.9863E-01 +8.2537E+01 +6.5793E-01 +1.9767E-01 +8.0848E+01 +8.1113E-01 +1.9619E-01 +7.8796E+01 +1.0000E+00 +1.9432E-01 +7.6298E+01 +1.2329E+00 +1.9151E-01 +7.3290E+01 +1.5199E+00 +1.8781E-01 +6.9669E+01 +1.8738E+00 +1.8220E-01 +6.5470E+01 +2.3101E+00 +1.7438E-01 +6.0673E+01 +2.8480E+00 +1.6449E-01 +5.5318E+01 +3.5112E+00 +1.5217E-01 +4.9534E+01 +4.3288E+00 +1.3785E-01 +4.3570E+01 +5.3367E+00 +1.2226E-01 +3.7647E+01 +6.5793E+00 +1.0622E-01 +3.2028E+01 +8.1113E+00 +9.0622E-02 +2.6892E+01 +1.0000E+01 +7.6212E-02 +2.2313E+01 +1.2329E+01 +6.3445E-02 +1.8389E+01 +1.5199E+01 +5.2247E-02 +1.5069E+01 +1.8738E+01 +4.2964E-02 +1.2247E+01 +2.3101E+01 +3.5147E-02 +9.8945E+00 +2.8480E+01 +2.8661E-02 +8.0352E+00 +3.5112E+01 +2.3266E-02 +6.4090E+00 +4.3288E+01 +1.8976E-02 +5.1069E+00 +5.3367E+01 +1.5470E-02 +3.9140E+00 +6.5793E+01 +1.2495E-02 +3.0121E+00 +8.1113E+01 +1.0154E-02 +2.2737E+00 +1.0000E+02 +8.2466E-03 +1.5682E+00 +1.2329E+02 +6.6826E-03 +8.7741E-01 +1.5199E+02 +5.4120E-03 +3.2423E-01 +1.8738E+02 +4.3959E-03 -2.9814E-01 +2.3101E+02 +3.5657E-03 -8.7995E-01 +2.8480E+02 +2.8912E-03 -1.5233E+00 +3.5112E+02 +2.3408E-03 -2.1688E+00 +4.3288E+02 +1.9000E-03 -3.0046E+00 +5.3367E+02 +1.5399E-03 -3.9069E+00 +6.5793E+02 +1.2478E-03 -4.9982E+00 +8.1113E+02 +1.0105E-03 -6.2920E+00 +1.0000E+03 +8.1795E-04 -7.8551E+00 +1.2329E+03 +6.6137E-04 -9.7494E+00 +1.5199E+03 +5.3415E-04 -1.2052E+01 +1.8738E+03 +4.3092E-04 -1.4858E+01 +2.3101E+03 +3.4918E-04 -1.8440E+01 +2.8480E+03 +2.7656E-04 -2.3375E+01 +3.5112E+03 +2.1821E-04 -2.8876E+01 +4.3288E+03 +1.6854E-04 -3.6126E+01 +5.3367E+03 +1.2103E-04 -4.4781E+01 +6.5793E+03 +8.0732E-05 -4.5047E+01 +8.1113E+03 +6.6265E-05 -4.4906E+01 +1.0000E+04 +5.3269E-05 -5.2671E+01 FREQUENCY MAGNITUDE PHASE Hz V/(nT*Hz) deg Chopper Off +1.0000E+00 +1.8929E-01 +1.1098E+02 +1.2329E+00 +1.9877E-01 +1.0178E+02 +1.5199E+00 +2.0310E-01 +9.2408E+01 +1.8738E+00 +2.0205E-01 +8.2979E+01 +2.3101E+00 +1.9525E-01 +7.3551E+01 +2.8480E+00 +1.8380E-01 +6.4373E+01 +3.5112E+00 +1.6822E-01 +5.5546E+01 +4.3288E+00 +1.4990E-01 +4.7282E+01 +5.3367E+00 +1.3074E-01 +3.9765E+01 +6.5793E+00 +1.1170E-01 +3.3138E+01 +8.1113E+00 +9.4077E-02 +2.7353E+01 +1.0000E+01 +7.8347E-02 +2.2450E+01 +1.2329E+01 +6.4595E-02 +1.8346E+01 +1.5199E+01 +5.2931E-02 +1.4879E+01 +1.8738E+01 +4.3376E-02 +1.2120E+01 +2.3101E+01 +3.5403E-02 +9.7871E+00 +2.8480E+01 +2.8760E-02 +7.8304E+00 +3.5112E+01 +2.3408E-02 +6.1176E+00 +4.3288E+01 +1.8972E-02 +4.9934E+00 +5.3367E+01 +1.5398E-02 +4.0097E+00 +6.5793E+01 +1.2525E-02 +2.9188E+00 +8.1113E+01 +1.0166E-02 +2.1264E+00 +1.0000E+02 +8.2561E-03 +1.5565E+00 +1.2329E+02 +6.6903E-03 +8.5820E-01 +1.5199E+02 +5.4239E-03 +2.0043E-01 +1.8738E+02 +4.4025E-03 -3.0994E-01 +2.3101E+02 +3.5698E-03 -9.1526E-01 +2.8480E+02 +2.8946E-03 -1.5153E+00 +3.5112E+02 +2.3489E-03 -2.2518E+00 +4.3288E+02 +1.9026E-03 -2.9940E+00 +5.3367E+02 +1.5419E-03 -3.8998E+00 +6.5793E+02 +1.2494E-03 -4.9771E+00 +8.1113E+02 +1.0118E-03 -6.2748E+00 +1.0000E+03 +8.1898E-04 -7.8198E+00 +1.2329E+03 +6.6221E-04 -9.7244E+00 +1.5199E+03 +5.3482E-04 -1.2031E+01 +1.8738E+03 +4.3142E-04 -1.4824E+01 +2.3101E+03 +3.4914E-04 -1.8435E+01 +2.8480E+03 +2.7691E-04 -2.3267E+01 +3.5112E+03 +2.1863E-04 -2.8766E+01 +4.3288E+03 +1.6899E-04 -3.6023E+01 +5.3367E+03 +1.2149E-04 -4.4705E+01 +6.5793E+03 +8.1011E-05 -4.5075E+01 +8.1113E+03 +6.6395E-05 -4.4922E+01 +1.0000E+04 +5.3337E-05 -5.2637E+01 .. _sats_header: ATSS header -------------- sats stands for advanced timeseries stream. |br| The stream data itself is stored in *.atss* as *pure* binary data streams, 64 bit double IEEE 754 as most processor architectures use it. |br| The double is is used by default in Python/NumPy, MatLab, C++ and others. The JSON header is separated from the stream. This allows a continuous data transmission where the stream data *only* changes at the end. The sync client can use "rsync --append" in order to *resume* the data transfer. The JSON header can be transferred with the "rsync -z" option (compress) because it is an ASCII file. In addition a .sql3 (SQLite file version 3) is written into the data directory, containing the log data of the recording. The filename is splitted by the underscore tag _ with a default length of 3 and a letter bit_indicator 008_C01_R000_TEy_512H.sats ADU-08e data stream recorded with channel 1 as Ey with 512 Hz |br| 067_C00_R001_TEx_8s.sats ADU-08e data stream recorded with channel 0 as Ex with one sample every 4 seconds |br| .. csv-table:: :delim: , serial ADU, Channel 0 - N, Run 0 - N, Type (of channel), Sample Frequency or Sample Period, H(ertz) or S(econds), ext 008, C001, R000, TEy, 512, H, atss 067, C000, R001, TEx, 8, s, atss .