"""E1b drift: does the clean-air baseline change from day to day, and does subtracting it help? python experiments/e1b_drift.py data/demo_calibration --gas ethanol --concentration 1.0 Compares, for the same standard solution measured on different days: raw steady value (what you would get without a baseline) relative change (r-b)/b (what features.py uses) A smaller day-to-day CV for the relative change means the baseline correction works. """ from __future__ import annotations import argparse import sys from pathlib import Path import pandas as pd sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from enose.common import output_dir, plt, save_figure # noqa: E402 from enose.features import _tail_mean # noqa: E402 def main() -> None: parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("folder", type=Path) parser.add_argument("--gas", default="ethanol") parser.add_argument("--concentration", type=float, default=1.0) parser.add_argument("--heater-step", type=int, default=2) arguments = parser.parse_args() raw = pd.read_csv(arguments.folder / "raw.csv") labels = pd.read_csv(arguments.folder / "labels.csv") results = output_dir(arguments.folder / "results") chosen = labels[(labels["label"] == arguments.gas) & (labels["concentration"] == arguments.concentration)] if "rh_level" in chosen: chosen = chosen[chosen["rh_level"] == "mid"] records = [] for sample in chosen.itertuples(): rows = raw[(raw["sample_id"] == sample.sample_id) & (raw["heater_step"] == arguments.heater_step)] baseline = _tail_mean(rows[rows["phase"] == "purge"], "gas_ohm") steady = _tail_mean(rows[rows["phase"] == "sample"], "gas_ohm") records.append({"date": sample.date, "baseline": baseline, "steady": steady, "relative_change": (steady - baseline) / baseline}) table = pd.DataFrame(records).sort_values("date") daily = table.groupby("date").mean() daily.to_csv(results / "e1b_daily.csv") cv_raw = 100 * daily["steady"].std() / daily["steady"].mean() cv_relative = 100 * daily["relative_change"].std() / abs(daily["relative_change"].mean()) print(daily.round(4).to_string()) print(f"\n跨日變異係數:原始穩定值 {cv_raw:.1f}% 相對變化量 {cv_relative:.1f}%") print("相對變化量的 CV 比較小 → 扣基準有效" if cv_relative < cv_raw else "扣基準沒有改善,請檢查採樣流程") figure, axes = plt.subplots(1, 2, figsize=(10, 3.6)) axes[0].plot(daily.index, daily["baseline"], "o-", label="乾淨空氣基準 b") axes[0].plot(daily.index, daily["steady"], "s-", label="樣本穩定值 r") axes[0].set_title("BME688 氣體電阻(Ω)") axes[0].legend() axes[1].plot(daily.index, daily["relative_change"], "o-") axes[1].set_title("相對變化量 (r − b) / b") for axis in axes: axis.tick_params(axis="x", rotation=45) save_figure(figure, results / "e1b_drift.png") if __name__ == "__main__": main()