MA350 Aethalometer
The MA350 is an advanced aethalometer that measures black carbon concentrations at multiple wavelengths and provides source apportionment between fossil fuel and biomass burning sources.
AeroViz.rawDataReader.script.MA350.Reader
Bases: AbstractReader
MA350 Aethalometer Data Reader
A specialized reader for MA350 Aethalometer data files, which measure black carbon at multiple wavelengths and provide source apportionment.
See docs/api/instruments/aethalometers/MA350.md for usage and
docs/guide/reader-reference.md for the
file layout, status codes and QC rules.
Attributes
ABS_COLUMNS
class-attribute
instance-attribute
ERROR_STATES
class-attribute
instance-attribute
STATUS_BITS
class-attribute
instance-attribute
STATUS_BITS = {1: 'Power Failure', 2: 'Start up', 4: 'Tape advance', 16: 'Optical saturation', 32: 'Sample timing error', 128: 'Flow unstable', 256: 'Pump drive limit', 2048: 'System busy', 8192: 'Tape jam', 16384: 'Tape at end', 32768: 'Tape not ready', 65536: 'Tape transport not ready', 262144: 'Invalid date/time', 524288: 'Tape error'}
Methods:
_raw_reader
Read and parse raw MA350 Aethalometer data files.
Returns all columns from the raw file. Column selection is deferred to _QC() and _process() stages.
_QC
Perform quality control on MA350 Aethalometer raw data.
QC Rules Applied (raw data only)
- Status Error : Invalid instrument status codes
- Invalid BC : BC concentration outside 0-20000 ng/m³
- Insufficient : Less than 50% hourly data completeness
Note: AAE validation is done in _process() after calculation.
Raw format
- File pattern:
*.csv. - Native frequency: 1 minute (the
meta['freq']fallback; the grid actually found in each file is reported asdf.attrs['raw_freq']). - Data structure:
- Datetime index from the
Date / time localcolumn - BC measurements at multiple wavelengths
- Source apportionment data (biomass / fossil-fuel split)
- Derived parameters (the vendor's own AAE and Delta-C)
- Datetime index from the
Parse recipe
read_csv(parse_dates=['Date / time local'], index_col='Date / time local').- Column renames (keys are matched exactly, double space before the unit
included):
UV BCc→BC1,Blue BCc→BC2,Green BCc→BC3,Red BCc→BC4,IR BCc→BC5,Biomass BCc (ng/m^3)→BB mass,Fossil fuel BCc (ng/m^3)→FF mass,Delta-C (ng/m^3)→Delta-C,AAE→AAE_ref,BB (%)→BB. - Rows with an unparseable or duplicated timestamp are removed.
- Every other source column is kept at L1 and through to the output.
Quirks
- The
Statuscolumn's presence has never been verified against a real export (there is no fixture);check_status_columnswarns at runtime if the firmware labels it differently.
Measurement Parameters
The MA350 provides black carbon measurements at five wavelengths:
| Column | Wavelength | Description |
|---|---|---|
| BC1 | 375 nm | UV channel |
| BC2 | 470 nm | Blue channel |
| BC3 | 528 nm | Green channel |
| BC4 | 625 nm | Red channel |
| BC5 | 880 nm | Near-IR channel (reference) |
Status & error codes
The Status column is tested in bitwise mode — a row is an error when any
non-whitelisted code in ERROR_STATES matches it bitwise; see
status modes.
A missing Status column is logged as a warning and the rule then passes
every row.
Codes treated as errors:
1— Power Failure2— Start up4— Tape advance16— Optical saturation32— Sample timing error128— Flow unstable256— Pump drive limit2048— System busy8192— Tape jam16384— Tape at end32768— Tape not ready65536— Tape transport not ready262144— Invalid date/time524288— Tape error
Every error code has a named row in the register below, so nothing is treated as an error without a name.
Status Condition Register
The Status column is a bitfield: the instrument OR-sums every
active condition and reports the sum, so one value can mean several things at
once. Reader.STATUS_BITS carries this table, and it is what turns a raw status
into df.attrs['status_conditions'] — a named condition instead of a number.
| Bit | Decimal | Condition |
|---|---|---|
| 19 | 524288 |
Tape error |
| 18 | 262144 |
Invalid date/time |
| 16 | 65536 |
Tape transport not ready |
| 15 | 32768 |
Tape not ready |
| 14 | 16384 |
Tape at end |
| 13 | 8192 |
Tape jam |
| 11 | 2048 |
System busy |
| 8 | 256 |
Pump drive limit |
| 7 | 128 |
Flow unstable |
| 5 | 32 |
Sample timing error |
| 4 | 16 |
Optical saturation |
| 2 | 4 |
Tape advance |
| 1 | 2 |
Start up |
| 0 | 1 |
Power Failure |
To stop treating one condition as an error, whitelist its decimal value:
QC rules
| Rule | Condition | Severity |
|---|---|---|
Status Error |
any non-whitelisted ERROR_STATES code set in Status |
error |
Invalid BC |
any of BC1–BC5 ≤ 0 or > 20 000 ng/m³ | error |
Insufficient |
an hour holds < 50 % of the BC points it could have held, given how much of that hour the read covers | advisory |
Invalid AAE |
AAE < 0.7 or AAE > 3.0 — added in _process, after AAE has been computed |
error |
Invalid AAE cannot be a _QC rule because AAE does not exist until
_process has derived it; it is raised there through update_qc_flag and
counted into the same QC summary. The upper bound of 3.0 is deliberately loose
so that BrC-rich biomass-burning and dust episodes, where bulk AAE runs 2–3,
survive. Insufficient is advisory because a sparse hour's readings are fine
in themselves — only an hourly average would misrepresent it; promote it with
flag_severity={'Insufficient': 'error'}.
Output
The processed data contains the following columns:
| Column | Unit | Description |
|---|---|---|
| BC1-BC5 | ng/m³ | Black carbon at 5 wavelengths |
| abs_375-880 | Mm⁻¹ | Absorption coefficients (abs_375, abs_470, abs_528, abs_625, abs_880) |
| abs_550 | Mm⁻¹ | Interpolated absorption at 550nm |
| AAE | - | Absorption Angstrom Exponent (positive by convention), computed by AeroViz |
| eBC | ng/m³ | Equivalent black carbon (= BC5, 880 nm) |
| AAE_ref | - | The vendor's own AAE from the raw file, preserved separately |
| BB mass | ng/m³ | Biomass-burning BC from the instrument's source apportionment |
| FF mass | ng/m³ | Fossil-fuel BC from the instrument's source apportionment |
| Delta-C | ng/m³ | The instrument's native Delta-C (UV − IR) |
| BB | % | Biomass-burning fraction |
| every other source column | as in the raw file | Status, flows, … are kept alongside the derived columns |
How the derived columns are made (_absCoe in core/pre_process.py):
abs_λ = BC_λ × MAE_λ × 10⁻³, where MAE is the published σ_ATN divided by C = 1.3 (see the cross-section note below).AAEis the slope of a log-log fit over all five bands, sign-flipped so it is positive.abs_550is not measured: it is extrapolated from the nearest measured band asabs(λ₂) = abs(λ₁)·(λ₂/λ₁)^(−AAE).- A row whose BC channels are all 0, or where any channel is NaN, gets NaN in every derived column.
Files written per read are listed in RawDataReader Reference §1.
Cross section
AethLabs publish σ_ATN — the attenuation cross section
(24.069, 19.070, 17.028, 14.091, 10.120 m²/g at 375–880 nm). BC × σ_ATN
gives the attenuation coefficient, not absorption: the filter scatters light
multiple times and inflates it by a factor C. AeroViz divides by C = 1.3
for the MA-series, so abs_* is a true absorption coefficient.
This matters when stations are compared. Uncorrected, the MA350 reads about
30% higher than an AE33 measuring the same air — invisible at a single site.
After the correction the three aethalometers agree at every shared
wavelength (MA350 375 nm = 18.5 vs AE33 370 nm = 18.5 m²/g, 880 nm = 7.8 vs
7.8), which test_ma350_cross_section_is_absorption_not_attenuation pins.
AAE is unaffected: it is the slope of a log-log fit, and dividing every
band by the same constant only shifts the intercept.
Notes
- Provides real-time source apportionment
- Distinguishes between fossil fuel and biomass burning
- Multi-wavelength measurement capability (5 channels)
- Advanced data quality control with QCFlagBuilder