eval-ac 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,185 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [0.3.1] - 2026-10-06
7
+
8
+ ### Added
9
+ - Documentation with Sphinx in `docs/` (theme furo, Markdown via
10
+ MyST): installation, user guide, Python interface with API reference
11
+ generated from the docstrings, description of the ABSCAL.HIS file format
12
+ (RPG manual, appendix A20, with byte offsets) and of the dataset, and the
13
+ changelog. The README sections are included, not copied, so that there
14
+ is only one source.
15
+ - `.readthedocs.yaml` for hosting on Read the Docs (warnings are errors).
16
+ - Extra `docs` in `pyproject.toml`; the extra `dev` contains the
17
+ documentation tools as well.
18
+ - CI job that builds the documentation with warnings as errors.
19
+ - Workflow `publish.yml`: a published GitHub release uploads the package
20
+ to PyPI, "Run workflow" uploads it to TestPyPI, both with trusted
21
+ publishing (no stored tokens). The workflow checks that the release tag
22
+ matches the package version.
23
+ - `MANIFEST.in`: the source distribution contains the tests, their
24
+ example data and the changelog, so that the tests can be run from it.
25
+ - Documentation page "Releasing" with the one-time setup of PyPI and the
26
+ release steps.
27
+ - README: badge of the documentation build.
28
+
29
+ ### Changed
30
+ - README: images as Markdown instead of HTML (needed for the
31
+ documentation; on GitHub they are now shown in full width), markers for
32
+ the sections included in the documentation, link to the documentation.
33
+ - README: images and the changelog link use absolute GitHub URLs, so that
34
+ they are also shown in the project description on PyPI.
35
+
36
+ ### Fixed
37
+ - Docstring of `calibration_drift()`: the return value was rendered as
38
+ return type in the API reference.
39
+
40
+ ## [0.3.0] - 2026-10-05
41
+
42
+ ### Added
43
+ - Selection of the calibration type: by default only calibrations with
44
+ liquid nitrogen (`cal_type` = 1) are plotted and analysed. Entries in
45
+ which no receiver was calibrated with liquid nitrogen are removed; if
46
+ only one receiver was, the values of the other receiver are set to NaN.
47
+ CLI option `--all-cal-types` disables the selection. Python:
48
+ `eval_ac.analysis.select_cal_type()`.
49
+ - Quality flags: channels with `calibration_flag` = 0 (not calibrated) are
50
+ marked with a red cross in the history plot, excluded from the drift
51
+ analysis and listed in the report if they belong to the latest
52
+ calibration. Python: `eval_ac.analysis.latest_not_calibrated()`.
53
+ - Drift analysis: the latest calibration of each receiver is compared with
54
+ the median of the `N` calibrations before it (deviation in percent).
55
+ Python: `eval_ac.analysis.calibration_drift()` and
56
+ `eval_ac.analysis.drift_exceedances()`. Default thresholds: gain 10 %,
57
+ noise diode temperature 2.5 %, system noise temperature 2.5 %,
58
+ non-linearity factor 0.5 % (about the 99th percentile of the example
59
+ data, adapt them to the instrument).
60
+ - Drift plot in the style of the history plot (`results_ln2_drift.png`),
61
+ Python: `eval_ac.plotting.plot_drift()`.
62
+ - CLI options `-d/--drift-plot`, `--n-reference`, `-t/--threshold
63
+ VARIABLE=PERCENT` (repeatable), `--max-age DAYS` and
64
+ `--fail-on-warning` (exit code 2 if the report contains a warning).
65
+ - CLI prints a quality report of the latest calibration of each receiver:
66
+ date and age, channels with flag 0, alpha out of range and drift.
67
+ - Age check: warning if the latest calibration of a receiver is older than
68
+ 183 days (RPG recommends an absolute calibration every 5 to 6 months,
69
+ manual section 3.1.3). The age is computed from `time_of_rec_1/2` of the
70
+ respective receiver. Python: `eval_ac.analysis.calibration_age()`.
71
+ - Range check of the non-linearity factor: warning if alpha of the latest
72
+ calibration is outside 0.9 <= alpha < 1 (manual section 3.1.3.1).
73
+ Python: `eval_ac.analysis.alpha_out_of_range()`.
74
+ - README section "Interpreting the results" based on the RPG manual
75
+ (RPG-MWR-STD-SW): meaning and operational use of G, Tsys, Tn and alpha,
76
+ typical patterns in the drift plot, what to do with a suspicious
77
+ calibration, how to adapt the thresholds and limitations.
78
+ - Tests with modified copies of the example file (other calibration
79
+ types, flag 0, time stamps, alpha); 47 tests in total. The tests do not
80
+ depend on the current date.
81
+
82
+ ### Changed
83
+ - History plot: latest and previous calibration are determined per
84
+ receiver, so a receiver that was not calibrated with liquid nitrogen in
85
+ the latest entry shows its own latest calibration.
86
+ - History plot: one legend per receiver below the panels instead of one in
87
+ every panel, so that the legend never hides data.
88
+ - `--no-plot` now suppresses both plots.
89
+ - The NetCDF file (`--netcdf`) still contains all calibration types.
90
+
91
+ ### Fixed
92
+ - `calibration_flag` comment: the flag is 0 = not calibrated,
93
+ 1 = calibrated per channel (RPG manual, appendix A20), not an 8 bit
94
+ array.
95
+ - `alpha`: comment with the detector model and the valid range added.
96
+
97
+ ## [0.2.0] - 2026-10-05
98
+
99
+ ### Added
100
+ - Command line interface `eval-ac` (also `python -m eval_ac`):
101
+ `eval-ac ABSCAL.HIS --netcdf abscal.nc --plot results_ln2_cal.png`.
102
+ Options `--no-plot`, `--show` and `--version`. Errors (missing file,
103
+ invalid file) are reported as one line on stderr with exit code 1.
104
+ - Functional API: `read_abscal_his()`, `write_netcdf()`, `read_raw()`,
105
+ `records_to_dataset()` in `eval_ac.convert_abscal_his` and
106
+ `plot_calibration_history()` in the new module `eval_ac.plotting`.
107
+ - Coordinate `time` (datetime of each calibration, decoded from
108
+ `time_of_rec_1`, seconds since 2001-01-01).
109
+ - Coordinate `receiver` (1 or 2) along `freq`, derived from the channel
110
+ numbers stored in the file.
111
+ - Validation of the input file: file code (39583209), length of every
112
+ record, truncated files, and identical channels in all entries.
113
+ - Tests (pytest) for reader, NetCDF output, plotting and CLI, including a
114
+ regression test against the output of version 0.1.0
115
+ (`example_data/abscal.nc`).
116
+ - `pyproject.toml` with the entry point `eval-ac` and the extras `test`
117
+ and `dev`.
118
+ - `CHANGELOG.md`.
119
+
120
+ ### Changed
121
+ - `HatproBinAbscalHis(filename, filename_out=None)`: the NetCDF file is
122
+ only written if `filename_out` is given. Before, the output file was
123
+ mandatory.
124
+ - `HatproBinAbscalHis.header` now holds plain integers
125
+ (`{'file_code': 39583209, 'n_samples': 16}`) instead of numpy arrays, and
126
+ the key `_n_samples` is renamed to `n_samples`. `HatproBinAbscalHis.data`
127
+ is now a list with one dictionary per calibration entry.
128
+ - The reader reads the file once into memory and parses it with explicit
129
+ little-endian types instead of calling `np.fromfile` for every value.
130
+ The values are identical to version 0.1.0 (checked by a test).
131
+ - Plot: the split into the two receivers is taken from the file instead of
132
+ fixed channel indices 0-6 / 7-13. The plot works for any number of
133
+ calibration entries (before, at least four were needed). The legend shows
134
+ the dates of the latest and previous calibration, the axes are labelled
135
+ with name and unit.
136
+ - `evaluate_absolute_calibration.py` no longer contains hard coded paths
137
+ and no longer runs on import. It now calls the CLI, i.e.
138
+ `python eval_ac/evaluate_absolute_calibration.py ABSCAL.HIS`.
139
+ - Global NetCDF attributes follow CF/ACDD names: `Conventions` (was
140
+ `conventions`), `date_created` in ISO 8601 (was `date of creation`), new
141
+ `title`. `history` contains time stamp, source file and eval_ac version.
142
+ The empty attribute `comments` was removed.
143
+ - CI: tests and a CLI run are executed on every push/PR, Python 3.9-3.12,
144
+ `actions/checkout@v4` and `actions/setup-python@v5`. Pylint checks
145
+ `eval_ac` and `tests`.
146
+ - Minimum Python version is 3.9 (was 3.8; Python 3.8 is end of life).
147
+ - The example plot moved to `docs/images/results_ln2_cal.png`.
148
+
149
+ ### Fixed
150
+ - The test called the class with one argument although two were required
151
+ and depended on the working directory; it was not run in CI.
152
+ - `long_name` of `cold_load_temp_1/2` said "hot load".
153
+ - Invalid CF `standard_name` "reveiver gain" of `gain` removed.
154
+ - Unit of the non-linearity factor `alpha` changed from `K` to `1`
155
+ (dimensionless).
156
+ - Typo "micorwave" in the `source` attribute.
157
+ - `datetime.utcnow()` (deprecated since Python 3.12) replaced.
158
+ - `datetime` removed from the dependencies (it is part of the standard
159
+ library); `netCDF4` added (needed to write NetCDF files).
160
+ - Version numbers were inconsistent (`setup.py`: 1.0, `__init__.py`:
161
+ 0.1.0); the version is now only defined in `eval_ac/__init__.py`.
162
+ - README: download badge pointed to a foreign repository.
163
+
164
+ ### Removed
165
+ - `setup.py` (replaced by `pyproject.toml`). Install with `pip install .`
166
+ instead of `python setup.py install`.
167
+ - Duplicate `results_ln2_cal.png` in the repository root and in the
168
+ package directory.
169
+
170
+ ### Migration from 0.1.0
171
+ | 0.1.0 | 0.2.0 |
172
+ | --- | --- |
173
+ | edit paths in `evaluate_absolute_calibration.py`, run it | `eval-ac ABSCAL.HIS --netcdf abscal.nc` |
174
+ | `python setup.py install` | `pip install .` |
175
+ | `HatproBinAbscalHis(f_in, f_out).xrdata` | `read_abscal_his(f_in)` (+ `write_netcdf(ds, f_out)`) |
176
+ | `obj.header['_n_samples'][0]` | `obj.header['n_samples']` |
177
+ | `ds.attrs['conventions']` | `ds.attrs['Conventions']` |
178
+
179
+ The distribution name changed from `evaluation-of-absolute-calibration-results`
180
+ to `eval-ac`; the import name `eval_ac` is unchanged.
181
+
182
+ ## [0.1.0]
183
+
184
+ - First version: reading of ABSCAL.HIS, conversion to NetCDF and plot of
185
+ the calibration history.
eval_ac-0.3.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Andreas Foth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ # files of the source distribution (sdist) in addition to the package,
2
+ # so that the tests can be run from the sdist
3
+ include CHANGELOG.md
4
+ recursive-include tests *.py
5
+ include example_data/ABSCAL.HIS example_data/abscal.nc
eval_ac-0.3.1/PKG-INFO ADDED
@@ -0,0 +1,306 @@
1
+ Metadata-Version: 2.4
2
+ Name: eval-ac
3
+ Version: 0.3.1
4
+ Summary: Read the ABSCAL.HIS file of RPG microwave radiometers (e.g. HATPRO) and visualize the history of the absolute calibration with liquid nitrogen.
5
+ Author-email: Andreas Foth <andreas.foth@uni-leipzig.de>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/WillyWallace/eval_ac
8
+ Project-URL: Documentation, https://eval-ac.readthedocs.io
9
+ Project-URL: Issues, https://github.com/WillyWallace/eval_ac/issues
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy
19
+ Requires-Dist: xarray
20
+ Requires-Dist: matplotlib
21
+ Requires-Dist: netCDF4
22
+ Provides-Extra: test
23
+ Requires-Dist: pytest; extra == "test"
24
+ Provides-Extra: docs
25
+ Requires-Dist: sphinx>=7; extra == "docs"
26
+ Requires-Dist: myst-parser>=2; extra == "docs"
27
+ Requires-Dist: furo; extra == "docs"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest; extra == "dev"
30
+ Requires-Dist: flake8; extra == "dev"
31
+ Requires-Dist: pylint; extra == "dev"
32
+ Requires-Dist: sphinx>=7; extra == "dev"
33
+ Requires-Dist: myst-parser>=2; extra == "dev"
34
+ Requires-Dist: furo; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ [![Python package](https://github.com/WillyWallace/eval_ac/actions/workflows/python-package.yml/badge.svg)](https://github.com/WillyWallace/eval_ac/actions/workflows/python-package.yml)
38
+ [![Pylint](https://github.com/WillyWallace/eval_ac/actions/workflows/pylint.yml/badge.svg)](https://github.com/WillyWallace/eval_ac/actions/workflows/pylint.yml)
39
+ [![Documentation Status](https://readthedocs.org/projects/eval-ac/badge/?version=latest)](https://eval-ac.readthedocs.io/en/latest/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+ [![Github all releases](https://img.shields.io/github/downloads/WillyWallace/eval_ac/total.svg)](https://github.com/WillyWallace/eval_ac/releases/)
42
+ [![Open Source? Yes!](https://badgen.net/badge/Open%20Source%20%3F/Yes%21/blue?icon=github)](https://github.com/Naereen/badges/)
43
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/WillyWallace/eval_ac/graphs/commit-activity)
44
+ ![Mastodon Follow](https://img.shields.io/mastodon/follow/109461236453474330?domain=https%3A%2F%2Fmeteo.social&logoColor=%230066cc&style=social)
45
+
46
+ <!-- [![Release][release-shield]][release-url] -->
47
+ <!-- [![PyPi version](https://badgen.net/pypi/v/pip/)](https://pypi.com/project/pip) -->
48
+
49
+ <!-- [![Twitter](https://img.shields.io/twitter/follow/RSAtmos_LIM?style=for-the-badge)](https://twitter.com/RSAtmos_LIM) -->
50
+
51
+ # Read the ABSCAL.HIS file and visualize the results of the absolute calibration with liquid nitrogen of an RPG microwave radiometer
52
+
53
+ <!-- TABLE OF CONTENTS -->
54
+ <details>
55
+ <summary>Table of Contents</summary>
56
+ <ol>
57
+ <li><a href="#Introduction">Introduction</a></li>
58
+ <li><a href="#getting-started">Getting Started</a></li>
59
+ <li><a href="#Usage">Usage</a></li>
60
+ <li><a href="#roadmap">Roadmap</a></li>
61
+ <!-- <li><a href="#contributing">Contributing</a></li> -->
62
+ <li><a href="#license">License</a></li>
63
+ <li><a href="#contact">Contact</a></li>
64
+ <li><a href="#acknowledgments">Acknowledgments</a></li>
65
+ </ol>
66
+ </details>
67
+
68
+ <!-- Introduction -->
69
+ ## Introduction
70
+
71
+ 📖 **Documentation:** https://eval-ac.readthedocs.io (user guide, Python API, ABSCAL.HIS file format)
72
+
73
+ This repository was created to display the results of the absolute calibration with liquid nitrogen of the microwave radiometer HATPRO manufactured by Radiometer Physics GmbH. For this purpose, the binary file ABSCAL.HIS is read in and converted into an xarray. Then the receiver gain, the temperature of the noise diode, the temperature of the system noise and the non-linearity factor are displayed in comparison to the previous and other prior calibrations.
74
+
75
+ <!-- GETTING STARTED -->
76
+ ## Getting Started
77
+
78
+ ### Installation
79
+
80
+ <!-- docs-installation-start -->
81
+ eval_ac requires Python 3.9 or newer. The dependencies (numpy, xarray, matplotlib, netCDF4) are installed automatically.
82
+
83
+ 1. Clone the repo
84
+ ```sh
85
+ git clone https://github.com/WillyWallace/eval_ac.git
86
+ cd eval_ac
87
+ ```
88
+
89
+ 2. Install the package
90
+ ```sh
91
+ pip install .
92
+ ```
93
+ For development (editable install with test and lint tools):
94
+ ```sh
95
+ pip install -e ".[dev]"
96
+ ```
97
+ <!-- docs-installation-end -->
98
+
99
+ <p align="right">(<a href="#top">back to top</a>)</p>
100
+
101
+ <!-- USAGE EXAMPLES -->
102
+ ## Usage
103
+
104
+ <!-- docs-usage-start -->
105
+ ### Command line
106
+
107
+ ```sh
108
+ eval-ac path/to/ABSCAL.HIS --netcdf abscal.nc
109
+ ```
110
+
111
+ This writes the NetCDF file, the history plot `results_ln2_cal.png`, the drift plot `results_ln2_drift.png` and prints a short quality report of the latest calibration:
112
+
113
+ ```text
114
+ read 16 calibration entries from path/to/ABSCAL.HIS
115
+ 16 of them are calibrations with liquid nitrogen
116
+ receiver 1: latest calibration 2026-04-29 (159 days ago)
117
+ receiver 2: latest calibration 2026-04-29 (159 days ago)
118
+ drift: all channels of the latest calibration are within the thresholds
119
+ ```
120
+
121
+ Lines starting with `warning:` point to something that should be checked, see [Quality checks](#quality-checks).
122
+
123
+ | Option | Description |
124
+ | --- | --- |
125
+ | `input` | path of the ABSCAL.HIS file (required) |
126
+ | `-n`, `--netcdf FILE` | write the converted data (all calibration types) to a NetCDF file |
127
+ | `-p`, `--plot FILE` | file name of the history plot (default: `results_ln2_cal.png`) |
128
+ | `-d`, `--drift-plot FILE` | file name of the drift plot (default: `results_ln2_drift.png`) |
129
+ | `--no-plot` | do not create any plot |
130
+ | `--show` | additionally show the plots in a window |
131
+ | `--all-cal-types` | use all calibrations instead of only those with liquid nitrogen |
132
+ | `--n-reference N` | number of calibrations before the latest one forming the drift reference (default: 5) |
133
+ | `-t`, `--threshold VAR=PERCENT` | drift threshold, e.g. `-t gain=8 -t temp_sys=2`; variables: `gain`, `temp_noise`, `temp_sys`, `alpha` |
134
+ | `--max-age DAYS` | warn if the latest calibration of a receiver is older (default: 183 days) |
135
+ | `--fail-on-warning` | exit with code 2 if the report contains a warning (e.g. for cron jobs) |
136
+ | `--version` | print the version |
137
+
138
+ `python -m eval_ac ...` works as well. Try it with the example file:
139
+
140
+ ```sh
141
+ eval-ac example_data/ABSCAL.HIS
142
+ ```
143
+
144
+ #### History plot
145
+
146
+ The plot shows the receiver gain, the noise diode temperature, the system noise temperature and the non-linearity factor of both receivers. The latest and the previous calibration of each receiver are highlighted with their dates, all older calibrations are drawn in grey. Channels that were not calibrated (`calibration_flag` = 0) are marked with a red cross. By default, only calibrations with liquid nitrogen are used (`cal_type` = 1); if only one receiver of an entry was calibrated with liquid nitrogen, only this receiver is used.
147
+
148
+ ![History plot of the example data](https://raw.githubusercontent.com/WillyWallace/eval_ac/main/docs/images/results_ln2_cal.png)
149
+
150
+ #### Drift plot
151
+
152
+ For each receiver, the latest calibration is compared with the median of the 5 calibrations before it (deviation in percent). Channels that were not calibrated are excluded. The dashed red lines are the thresholds, channels of the latest calibration exceeding them are circled and listed in the report. The grey lines show how far the older calibrations deviate from the same reference.
153
+
154
+ The y-axis is scaled to the thresholds and to the latest and previous calibration. Large outliers of older calibrations are therefore cut off at the edge of the panel; they are still visible in the history plot.
155
+
156
+ ![Drift plot of the example data](https://raw.githubusercontent.com/WillyWallace/eval_ac/main/docs/images/results_ln2_drift.png)
157
+
158
+ #### Quality checks
159
+
160
+ The report checks the latest calibration of each receiver (only calibrations with liquid nitrogen, unless `--all-cal-types` is given):
161
+
162
+ | Check | Warning if | Background |
163
+ | --- | --- | --- |
164
+ | Age | the latest calibration is older than `--max-age` days (default 183) | RPG recommends an absolute calibration every 5 to 6 months and after transport (manual, section 3.1.3). The age is computed from the calibration time of each receiver. |
165
+ | Flag | a channel has `calibration_flag` = 0 | The channel was not calibrated (manual, appendix A20). |
166
+ | Non-linearity factor | α is outside 0.9 ≤ α < 1 | Valid range of the detector model (manual, section 3.1.3.1, equation 1). Channels with flag 0 are not checked. |
167
+ | Drift | the deviation from the reference exceeds the threshold | See [Drift plot](#drift-plot) and [Interpreting the results](#interpreting-the-results). |
168
+
169
+ With `--fail-on-warning`, eval-ac exits with code 2 if any check gives a warning, e.g. to send an e-mail from a cron job:
170
+
171
+ ```sh
172
+ eval-ac /data/ABSCAL.HIS --no-plot --fail-on-warning || echo "check calibration" | mail -s "HATPRO" me@example.org
173
+ ```
174
+
175
+ ### Interpreting the results
176
+
177
+ The report and the drift plot point to calibrations that deserve a closer look; they do not decide whether a calibration is good or bad. That decision needs the knowledge of the instrument and of the calibration conditions. The background below is taken from the RPG manual *Principle of Operation & Software (standard radiometers)*, RPG-MWR-STD-SW (cited as "manual, section …").
178
+
179
+ #### What the absolute calibration determines
180
+
181
+ During the absolute calibration the radiometer looks at the internal ambient target and at the external liquid nitrogen cooled target, each with and without additional noise from the noise diode. From these four measurements it determines four parameters per channel (manual, section 3.1.3.1):
182
+
183
+ | Variable | Meaning | Use between two absolute calibrations |
184
+ | --- | --- | --- |
185
+ | `gain` (G) | receiver gain [V/K] | Very sensitive to small changes of the physical temperature of the receiver; it is recalibrated regularly with the ambient target (gain calibration, manual, section 3.3). |
186
+ | `temp_sys` (T<sub>sys</sub>) | system noise temperature [K] | Recalibrated together with G using the noise diode and the ambient target (manual, section 3.1.3.1). Changes of the temperature of the receiver optics (e.g. the feedhorn) change T<sub>sys</sub> (manual, section 3.1.3.2). |
187
+ | `temp_noise` (T<sub>n</sub>) | equivalent temperature of the noise diode [K] | Used as **secondary standard** for all automatic calibrations until the next absolute calibration; it is assumed to be stable (manual, section 3.1.3.1). In transparent channels it can also be recalibrated by sky tipping (manual, section 4.9.1). |
188
+ | `alpha` (α) | non-linearity factor of the detector, U = G·P<sup>α</sup> with 0.9 ≤ α < 1 | Assumed to be constant until the next absolute calibration (manual, section 3.1.3.1). |
189
+
190
+ **Consequences for the evaluation**
191
+
192
+ - Changes of **T<sub>n</sub>** and **α** are the most relevant: until the next absolute calibration, every automatic calibration builds on them. A real change of T<sub>n</sub> that is not captured by a new absolute calibration enters the measured brightness temperatures.
193
+ - Differences of the **gain** between absolute calibrations are expected, because the gain follows the receiver temperature and is recalibrated during operation anyway. Its default threshold is therefore larger. In the example data the gain varies much more than the other variables (standard deviation 1–3 % in the K-band and 5–18 % in the V-band, compared with below 2 % for T<sub>n</sub> and T<sub>sys</sub>).
194
+ - ABSCAL.HIS also contains successful sky tipping calibrations (manual, section 4.6). They use a different method and are only possible in transparent channels, so eval_ac compares only calibrations with liquid nitrogen by default.
195
+
196
+ #### Why the median of the previous calibrations?
197
+
198
+ A single failed calibration in the reference would shift a mean, but hardly the median. The previous calibration is part of the reference, so its deviation is usually small.
199
+
200
+ #### Typical patterns
201
+
202
+ These are rules of thumb, not statements of the manual:
203
+
204
+ | Pattern in the drift plot | Possible meaning |
205
+ | --- | --- |
206
+ | Latest within the thresholds, similar to the grey lines | Calibration consistent with the history. |
207
+ | Single channels of the latest calibration out of the thresholds, previous calibration normal | Possibly a problem during this calibration, e.g. with the cold target (filling, condensation; the manual asks to let the target dry before the V-band part, section 4.8). Check the calibration conditions and consider repeating the calibration. |
208
+ | All channels of a receiver shifted in the same direction | Rather a change of the receiver or of its noise diode than a single failed calibration, e.g. after maintenance or transport. |
209
+ | Latest and previous calibration deviate in the same way | The change is confirmed by two calibrations and is probably real; the reference (the 5 calibrations before) still describes the old state. |
210
+ | Channels marked as "not calibrated" (flag 0) | These channels were not calibrated in this entry (manual, appendix A20); they are not evaluated. |
211
+
212
+ #### What to do with a suspicious calibration
213
+
214
+ - Check that the absolute calibration was done after a warm-up of at least 30 minutes; it is recommended every 5 to 6 months and after transport (manual, section 3.1.3).
215
+ - Repeat the calibration if the conditions were doubtful.
216
+ - A bad calibration can be removed in the RPG host software: in the *Absolute Calibration History* menu, *Delete Last Entries* removes all entries after the marked one, and *Generate a new calibration file* creates an ABSCAL.CLB from selected calibrations of receiver 1 and 2 (manual, section 4.6).
217
+
218
+ #### Adapting the thresholds
219
+
220
+ The default thresholds are derived from a single HATPRO (2018–2026, 16 calibrations). Instruments, channels and sites differ, so:
221
+
222
+ 1. run `eval-ac` on the full history of your instrument,
223
+ 2. look at the spread of the grey lines in the drift plot,
224
+ 3. set thresholds slightly above the usual spread, e.g. `-t gain=6 -t temp_noise=1.5`.
225
+
226
+ #### Limitations
227
+
228
+ - With fewer than 5 earlier calibrations, the reference consists of fewer values (see `n_reference_used` in the result of `calibration_drift()`); with none, no drift can be computed.
229
+ - The drift is relative to the previous calibrations. A slow drift over many calibrations shifts the reference as well and is better seen in the history plot.
230
+
231
+ <!-- docs-usage-end -->
232
+ ### Python
233
+
234
+ <!-- docs-python-start -->
235
+ ```python
236
+ from eval_ac.convert_abscal_his import read_abscal_his, write_netcdf
237
+ from eval_ac.analysis import select_cal_type, calibration_drift, drift_exceedances
238
+ from eval_ac.plotting import plot_calibration_history, plot_drift
239
+
240
+ ds = read_abscal_his("ABSCAL.HIS") # xarray.Dataset, all calibration types
241
+ write_netcdf(ds, "abscal.nc")
242
+
243
+ ln2 = select_cal_type(ds) # only calibrations with liquid nitrogen
244
+ fig = plot_calibration_history(ln2, variables=["gain", "temp_sys"])
245
+ fig.savefig("gain_tsys.png")
246
+
247
+ drift = calibration_drift(ln2, n_reference=5)
248
+ for row in drift_exceedances(drift, thresholds={"gain": 8}):
249
+ print(row)
250
+ plot_drift(drift, thresholds={"gain": 8}).savefig("drift.png")
251
+ ```
252
+
253
+ The dataset has the dimensions `n_samples` (calibration entries, oldest first) and `freq` (channels). The coordinate `time` holds the date of each calibration, the coordinate `receiver` (1 or 2) assigns each channel to its receiver.
254
+
255
+ <!-- docs-python-end -->
256
+ ### Running the tests
257
+
258
+ <!-- docs-tests-start -->
259
+ ```sh
260
+ pip install -e ".[test]"
261
+ pytest
262
+ ```
263
+ <!-- docs-tests-end -->
264
+
265
+ <p align="right">(<a href="#top">back to top</a>)</p>
266
+
267
+ <!-- ROADMAP -->
268
+ ## Roadmap
269
+
270
+ - [x] add meaningful docstrings
271
+ - [x] make documentation with Sphinx (`docs/`)
272
+ - [x] host the documentation on readthedocs
273
+ - [x] enable pip install ...
274
+ - [ ] publish on PyPI
275
+ - [ ] Released version 1
276
+ - [x] Add Tests
277
+
278
+ See the [open issues](https://github.com/WillyWallace/eval_ac/issues) for a full list of proposed features (and known issues) and [CHANGELOG.md](https://github.com/WillyWallace/eval_ac/blob/main/CHANGELOG.md) for the changes of each version.
279
+
280
+ <p align="right">(<a href="#top">back to top</a>)</p>
281
+
282
+ <!-- LICENSE -->
283
+ ## License
284
+
285
+ Distributed under the MIT License. See `LICENSE` for more information.
286
+
287
+ <p align="right">(<a href="#top">back to top</a>)</p>
288
+
289
+ <!-- CONTACT -->
290
+ ## Contact
291
+
292
+ [Andreas Foth](https://www.uni-leipzig.de/personenprofil/mitarbeiter/dr-andreas-foth)
293
+
294
+
295
+ <p align="right">(<a href="#top">back to top</a>)</p>
296
+
297
+ <!-- ACKNOWLEDGMENTS -->
298
+ ## Acknowledgments
299
+
300
+ Special thanks for templates and help during implementation.
301
+
302
+ * [Readme Template](https://github.com/othneildrew/Best-README-Template)
303
+ * [cloudnetpy GitHub](https://github.com/actris-cloudnet/cloudnetpy.git)
304
+
305
+ <p align="right">(<a href="#top">back to top</a>)</p>
306
+