Artikel aus handwerk

  • Neun Monate Umwelt-CO₂, Teil II: Hochpass, Tiefpass, Spektrum

    Eher wolkiges grünes Wabern mit der Zeit auf der Abszisse und Frequenzen von 1/3 bis 3 pro Tag auf der Ordinate.  Dann und wann sind Strukturen bei ganzzahligen Frequenzen erkennbar.

    Am Ende des Posts verrate ich, welche Bewandnis es mit diesem hübschen, nachgerade frühlingshaften Muster hat. Und auch, wie mensch sowas selbst macht.

    Ich habe letztes Jahr neun Monate lang CO₂-Konzentrationen auf meinem Balkon gemessen, in der Hoffnung, ein wenig hinter die Gründe für die doch überraschend großen Konzentrationsschwankungen zu kommen, für die ich bei einer ersten Messung im November 2021 nur sehr spekulative Erklärungen gefunden habe (Stand Februar vor allem: die lokale Heizung und eventuell das Kraftwerk in Rheinau oder die Chemiefabriken in Ladenburg oder Ludwigshafen). Ich habe dann neulich an der Kalibration der Daten gespielt und bin zum Schluss gekommen, dass sie nach Maßstäben von KonsumentInnenelektronik recht ordentlich sein dürften.

    Jetzt möchte ich ein wenig in den Daten rumfummeln. „Explorative Datenanalyse“ nennen das Leute, die das mit dem Fummeln nicht zugeben wollen, und in der ernsthaften Wissenschaft wird zurecht etwas die Nase gerümpft, wenn jemand sowas macht: Es stecken in jedem hinreichend großen Datensatz fast beliebig viele Korrelationen, und wer sie sucht, wird sie auch finden. Leider sind (fast) alle davon Eigenschaften des Datensatzes bzw. der Messung, nicht aber des untersuchten Gegenstands.

    Andererseits: Ohne Induktion (was in normale Sprache übersetzt „Rumspielen, bis mensch einen Einfall hat“ heißt) gibt es, da muss ich Karl Popper ganz heftig widersprechen, keine Erkenntnis, und Deduktion kann mensch nachher immer noch machen (also, ich jetzt nicht, weil das hier mein Freizeitvergnügen ist und keine Wissenschaft).

    Erstmal glätten

    Meine ganz große Enttäuschung mit dem Datensatz war ja, dass sich fast kein Jahreszeiteneffekt gezeigt hat; natürlich werde ich hier, mitten im dichtbesiedelten Oberrheingraben, kein so hübsches Signal bekommen wie die Leute mit der klassischen Messung am Mauna Loa – davon, dass ich eine Schwingung von ein paar ppm nachvollziehen könnte, ganz zu schweigen. Aber ich hatte im September 2021 unter 300 ppm gemessen, während es im Herbst auf die global eher aktuellen 400 bis 500 ppm hochging. Ich hatte gehofft, den Weg zurück zu den 300 ppm im Laufe des Sommers beobachten zu können. Doch leider ist in den (Roh-) Daten erstmal nur Gekrakel:

    Plot: Kurve, die fast immer zwischen 400 und 500 ppm zittert. Auf der Abszisse die Zeit zwischen Ende Dezember 2021 und Mitte September 2022.

    Wenn in einem Datensatz nur Gekrakel ist, es aber einen langfristigen Effekt geben soll, hilft oft Glätten. Dabei ersetzt mensch jeden Punkt durch einen geeignet gebildeten Mittelwert über eine größere Umgebung dieses Punktes, wodurch kurzfristiges Gewackel wie in meinen Rohdaten stark unterdrückt wird und die langfristigen Trends besser sichtbar werden sollte. Es gibt noch einen zweiten Gewinn: Mensch kann das so gewonnene Mittel von den Daten abziehen und hat sozusagen destilliertes Gewackel (den „hochfrequenten Anteil“), der auf diese Weise auch ein klareres Signal zeigen mag.

    Im einfachsten Fall lässt sich so eine Glättung in ein paar Zeilen Python schreiben, und das auch noch relativ effizient als gleitendes Mittel unter Verwendung einer zweiendigen Queue aus Pythons großartigem Collections-Modul: Um das Mittel zu berechnen, addiere ich auf einen Akkumulator, und das, was ich da addiere, muss ich wieder abziehen, wenn der entsprechende Wert aus dem Fenster rausläuft. Dazu gibts noch die Subtilität, dass ich Zeit und Konzentration in der Mitte des Fensters zurückgeben will. Das führt auf so eine Funktion:

    def iter_naively_smoothed(in_file, smooth_over):
        queue = collections.deque()
        accum = 0
    
        for time, co2 in iter_co2(in_file):
            queue.append((time, co2))
            accum += co2
            while time-queue[0][0]>smooth_over:
                _, old = queue.popleft()
                accum -= old
            time, base_co2 = queue[len(queue)//2]
            yield time, accum/len(queue), base_co2-accum/len(queue)
    

    Als Plot sehen die über drei Tage[1] geglättete Konzentrationskurve und die Residuen so aus:

    Zwei Kurven, oben eine wellige Linie (die geglättete Kurve), unten eine sehr zackige Punktwolke.

    Die Ränder, vor allem der linke, sind dabei mit Vorsicht zu genießen, da dort fast nichts geglättet ist; die Funktion ist so geschrieben, dass dort die Fenster klein sind. So oder so: auch die geglättete Kurve hat keine nennenswerte Tendenz. Allenfalls die beiden großen Ausschläge bei den Tagen 80 und 110 könnten ein Signal sein.

    Zeitrechnungen

    „Tag 80” ist jetzt keine wirklich intuitive Angabe, aber ich wollte in den Plots nicht mit läsitgen Kalenderdaten operieren. Für die Interpretation wären sie jedoch schon ganz gut. Wie komme ich von Messtag auf ein bürgerliches Datum?

    Die Daten kommen original mit Unix-Timestamps, also der Zahl der Sekunden seit dem 1.1.1970, 0:00 Uhr UTC, und sie fangen mit 1640612194 an. Um ausgehend davon bürgerliche Daten auszurechnen, muss mensch wissen, dass ein Tag 86400 Sekunden hat. Pythons datetime-Modul liefert dann:

    >>> import datetime
    >>> datetime.datetime.fromtimestamp(1640612194+80*86400)
    datetime.datetime(2022, 3, 17, 14, 36, 34)
    >>> datetime.datetime.fromtimestamp(1640612194+110*86400)
    datetime.datetime(2022, 4, 16, 15, 36, 34)
    

    Mitte März und Mitte April ist also möglicherweise was Interessantes passiert. Da gucke ich nochmal drauf, wenn ich demnächst Wetterdaten einbeziehe.

    Die andere Seite, die Residuen, kann ich für eine saubere Fassung des Tagesplots aus Teil 1 verwenden. Weil längerfristige Schwankungen bei ihnen rausgerechnet sind, sollte ein regelmäßiger Tagesgang in den Residuen deutlicher herauskommen als im ganzen Signal. Dazu nehme ich wieder den Rest bei der Division durch 86400 (siehe oben), und die Warnungen wegen Zeitzonen aus dem Kalibrationspost gelten immer noch.

    Ein Dichteplot, der im Groben flach verläuft, aber zwischen 10'000 und 25'000 Sekunden auf der Abszisse deutlich fransig ist.

    Dass da „am Morgen” (15000 Sekunden sind etwa 4:15 Uhr UTC, also 5:15 MEZ und 6:15 MESZ) irgendwas passiert, dürfte ein robustes Signal sein, und es kommt ohne die niederfrequenten Signale deutlich besser raus. Mit etwas Wohlwollen könnte mensch vielleicht sogar zwei Berge im Abstand von einer Stunde sehen, was dann Normal- und Sommerzeit entspräche. Da der Sensor nicht weit von der Bundesstraße 3 stand, liegt als Erklärung zunächst Berufs- und Pendelverkehr nahe.

    Wenn der Tagesgang tatsächlich mit dem Berufsverkehr am Morgen zu tun hat, müsste sich eigentlich ein Signal im Wochenrhythmus zeigen, denn zumindest Sonntags ist es hier am Morgen deutlich ruhiger als an Werktagen. Die Projektion auf die Woche ist einfach: Statt den Rest bei der Division durch 86'400 nehme ich jetzt den Rest bei der Division durch 604'800, die Zahl der Sekunden in einer Woche. Das Ergebnis zeigt, vielleicht etwas überraschend, das Tagessignal eher deutlicher; ein Wochensignal hingegen ist weniger überzeugend erkennbar:

    Ein pinkes Siebengebirge mit grob gleichhohen Gipfeln.

    Vielleicht ist an den Tagen drei und vier etwas weniger los – welche Wochentage sind das? Nun, ich dividiere hier Unix-Timestamps; ihr erinnert euch: Die Sekunden seit dem 1.1.1970. Welcher Wochentag war dieser 1.1.?

    $ cal 1 1970
        January 1970
    Su Mo Tu We Th Fr Sa
                 1  2  3
     4  5  6  7  8  9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 31
    

    Weil die Unix-Epoche so eine große Rolle im heutigen Leben spielt[2], nehme das mal als erweiterte Kopfzahl: Er war ein Donnerstag. Und so sind die Tage 3 und 4 tatsächlich Samstag und Sonntag. Meine Autoabgas-These ist mir durch diese Prüfung etwas sympathischer geworden. Vermutlich fallen die Abgase nur bei wenig Wind und wenig Thermik (das ist praktisch die berüchtigte Dunkelflaute…) auf, so dass das dunkle Band mit hoher Punktdichte mehr oder minder bei der Null bleibt, jedoch immer wieder Spitzen mit bis zu 100 ppm extra in der Rush Hour auftreten. Wenn das hier Wissenschaft wäre, müsste ich mich jetzt auf die Suche nach Daten aus der Verkehrszählung machen.

    Und ich müsste überlegen, ob die Zacken im dunklen Band nicht doch ein echtes Signal sind. Speziell der Durchhänger so um die 180'000 Sekunden (also in der Nacht von Freitag auf Samstag) ist eigentlich kaum wegzudiskutieren. Aber was könnte gerade da plausiblerweise mehr frische Luft heranführen? Oder ist das, weil die Freitagnacht wegen Spätcorona noch besonders ruhig war?

    In Sachen Spitzen am Morgen hätte ich eine Alternativhypothese zu den Autoabgasen: Das könnte nämlich wieder der lokale Brenner sein. Dann wäre das, was da zu sehen ist, die Warmwasserbereitung zur Morgendusche. Attraktiv ist diese These schon allein, weil mir 6:15 eigentlich ein wenig früh vorkommt für das Einsetzen der Rush Hour nach Heidelberg rein; es ist ja nicht so, als seien da noch viele nennenswerte Industriebetriebe, in denen die Leute um sieben stechen müssten. Allerdings: in einem Wohnblock mit so vielen Studis wie meinem hier ist 6:15 auch keine plausible Zeit für massenhaftes Duschen…

    Spektralanalyse

    Was ich gerade gemacht habe, ist ein Spezialfall einer gerade für uns AstrophysikerInnen extrem wichtigen Technik – ich habe nämlich ein Signal nach Frequenzen aufgeteilt. Bis hierher hatte ich nur in zwei Bänder, ein hohes und ein tiefes. Mit der Fourieranalyse geht das viel allgemeiner: Mensch steckt ein Signal rein und bekommt ein Spektrum heraus, eine Kurve, die für jede Frequenz sagt, wie stark Schwingungen auf dieser Frequenz zum Signal beitragen.

    Mit dem Universal-Werkzeugkasten scipy kriegt mensch so ein Spektrum in anderthalb Zeilen Python:

    from scipy import signal
    f, power = signal.periodogram(samples[:,1], fs=86400/24/120)
    

    Dabei übergebe ich nur meine Konzentrationsmessungen, nicht die zugehörigen Zeiten, weil die periodogram-Funktion nur mit gleichmäßig gesampleten Daten zurechtkommt. Das sind meine Daten zum Glück: zwischen zwei Messungen liegen immer 30 Sekunden, und es sind auch keine Lücken in den Daten.

    Die halbe Minute Abstand zwischen zwei Punkten übergebe ich im Argument fs, allerdings als Frequenz (der Kehrwert der Periode) und umgerechnet in die Einheit „pro …

  • Neun Monate Umwelt-CO2, Teil I: Taugen die Daten?

    Im vergangenen Jahr habe ich meine CO₂-Messung am Balkon bis Mitte September laufen lassen, vor allem, weil ich sehen wollte, wie die Konzentrationen im Laufe der Zeit auf unter 300 ppm sinkt. So weit unten (relativ zum gegenwärtigen globalen Mittelwert von um die 400 ppm) lag zu meiner damaligen Überraschung die Konzentration mal ganz am Anfang meiner CO₂-Messungen, im September 2021. Ich hatte eigentlich erwartet, dass all das Grün im Sommer nach und nach auch in diesem Jahr dafür sorgen würde.

    Daraus ist nichts geworden. Im Groben ist die CO₂-Konzentration über Frühling und Sommer 2022 konstant geblieben:

    Plot: Kurve, die fast immer zwischen 400 und 500 ppm zittert. Auf der Abszisse die Zeit zwischen Ende Dezember 2021 und Mitte September 2022.

    (Alle Plots in diesem Post von TOPCAT). Mag sein, dass es einfach zu trocken war in diesem Jahr – mag aber auch sein, dass meine ersten Experimente einfach in besonders frischer Luft stattfanden. Schließlich kämen natürlich noch Kalibrationsprobleme in Betracht; ich habe nicht versucht, meine Messungen mit denen anderer zu abzugleichen.

    Der Negativbefund hat mich aber dazu gebracht, die Daten im Hinblick auf statistische und vor allem systematische Fehler genauer unter die Lupe zu nehmen. Darum geht es in diesem Post.

    Zunächst stellt sich die Frage, ob die generelle Zittrigkeit der Kurve eigentlich Rauschen des Sensors ist oder etwas anderes – von Anfang an haben mich ja die teils erheblichen Konzentrationsschwankungen verblüfft. Nun: angesichts der hohen Korrelation benachbarter Messwerte kommen diese jedenfalls nicht aus statistischen Fehlern im Sensor. Ich greife mal den 26. Mai (einen Donnerstag) heraus:

    Plot: Kurve, die ein wenig vor sich hin wackelt, bei der aber aber aufeinanderfolgende Punkte klar korreliert sind.

    Wenn das Wackeln ein statistischer Fehler wäre, dann wäre die Linie, die ich durch die Punkte gemalt habe, völliges Gekrakel und nicht erkennbarer Verlauf. Ich will gerne glauben, dass da ein Rauschen irgendwo unterhalb von 10 ppm drin ist. Der Rest ist irgendein Signal.

    Welcher Natur das Signal ist, ist eine Frage, die sich allenfalls mit dem ganzen Datensatz beantworten lässt. Angesichts der überragenden Bedeutung der Sonne für Physik und Leben auf der Erde geht der erste Blick auf der Suche nach systematischen Fehlern oder auch echter Physik bei solchen Zeitreihen erstmal auf die Tagesverläufe. Um da eine Idee des Verhaltens des ganzen Datensatzes zu bekommen, habe ich mir die Punktdichte in einem Plot von Tageszeit gegen CO₂-Konzentration angesehen (ich „falte auf den Tag“):

    Plot: Heatmap, die bei 1.5e4 und 5.5e4 auf der Abszisse Bäuche hat

    Die Abszisse hier verdient einen kurzen Kommentar: Sie zeigt den Rest bei der Division meiner Timestamps durch 84600, ausgedrückt in Stunden. Meine Timestamps sind in Sekunden, und 84600 ist einfach 24 mal 3600, also die Zahl der Sekunden an einem Tag. Mithin steht hier etwas wie eine Tageszeit.

    Ganz so einfach ist das aber nicht, weil meine Timestamps immer in UTC laufen, während die Umgebung der Willkür der Zeitzonen unterworfen ist; die 15 auf der Abszisse entspricht also manchmal 16 Uhr bürgerlicher Zeit (nämlich, wenn die Umgebung MEZ hatte) und manchmal 17 Uhr (wenn ihr Sommerzeit verordnet war). Aber schon rein optisch liegt nicht nahe, dass viel mehr zu sehen wäre, wenn ich die politischen Kapriolen nachvollziehen würde, um so weniger, als die Sonne die ja auch nicht nachvollzieht.

    Die Bäuche in der dunkleren Fläche, also einer besonders hohen Dichte von Punkten, entsprechen nun Tageszeiten, zu denen es häufiger mal hohe CO₂-Konzentrationen auf meinem Balkon gab. Das könnte ein Signal der Lüftung unserer Wohnung (oder vielleicht sogar der unserer Nachbarn) sein. Es ist aber auch plausibel, dass es der Reflex der Verkehrsdichte ist. Der Balkon befindet sich etwa 10 Meter über und 20 Meter neben einer recht viel befahrenen Straße, weshalb im September 2021 die Unsichtbarkeit der CO₂-Emissionen der Fahrzeuge mit meine größte Überraschung war. Mit hinreichend viel Statistik und Mitteln über hinreichend viele Wetterlagen zeigen sich die Autos (vielleicht) eben doch.

    Zwei Eisschachteln beschwert mit einem rostigen Stahlriegel

    Die Messanordnung; das wird für die Kalibration noch wichtig…

    Wenn Effekte so sehr auf zusammengekniffenen Augen beruhen wie hier beim Tagesverlauf, hilft es nichts: Da braucht es einen zweiten Blick auf innere Korrelationen der Daten, um zu sehen, ob sich da schlicht systematische Fehler zeigen oder ob es wirklich die Autos sind. Klar: besser wäre es natürlich, mit bekannten Konzentrationen oder einfacher einem bekannt guten Messgerät zu kalibrieren, also zu sehen, welche Anzeige das Gerät für welchen wahren Wert hat.

    Aber das ist aufwändig, und zumeist zeigen sich Systematiken mit ein paar plausiblen Annahmen („Modelle“) auch schon in den Daten selbst. Zur plausiblen Modellierung lohnt es sich, das Messprinzip des Geräts zu betrachten. Der Sensor ist im Groben eine Infrarot-Leuchtdiode, die in einem der Spektralbereiche sendet, in denen Kohlendioxid stark absorbiert (weswegen es ja den Treibhauseffekt macht). Das Signal wird dann von einer Fotodiode (oder etwas ähnlichem) aufgefangen, und die Schwächung des Signals ist ein Maß für die Konzentration von CO₂ zwischen LED und Fotodiode.

    Allerdings sind alle Halbleiter temperaturempfindlich, und irgendwas, das im Infrarotbereich empfängt, wird schon zwei Mal viel Kalibration brauchen, um Temperatursystematik wegzukriegen. Mit Sicherheit tut die eingebaute Software schon viel in der Richtung. Aber ein Dichteplot zwischen Temperatur und Konzentration zeigt durchaus einen ganzen Haufen Struktur:

    Dichtplot: Etwas wie Australien mit einem langen Schwanz nach Nordosten, dazu noch ein abgetrennter Schnips bei 50 Grad und 650 ppm.

    Manches davon ist ziemlich sicher Physik, so insbesondere, dass die ganz hohen Konzentrationen bei niedrigen Temperaturen auftreten – das ist ein Jahreszeiteneffekt. Anderes ist ganz klar Instrumentensignatur, am klarsten das abgetrennte Schwanzende jenseits von 50 Grad Sensortemperatur. Offenbar[1] ist die Kalibrationskurve (also: Welches Signal von der Fotodiode soll bei welcher Temperatur welche CO₂-Konzentration ausgeben?) abschnittsweise definiert, und beim Abschnitt über 50 Grad wird sich wohl wer bei den Hundertern vertippt haben. Im Tagesplot entspricht dieses Schwänzchen übrigens dem abgesetzten Häubchen am Nachmittag.

    Im Neunmonatsplot zeigen sich die Punkte dort in ein paar der Spitzen zwischen dem 18. Juli und dem 4. August, nur dass sie dort mit den „normalen“ Daten mit einer Linie verbunden sind und nicht als abgesetzt auffallen; Grundregel Nummer 312: Vorsicht beim Verbinden mit Linien. In einem Scatterplot, bei dem Punkte in dem abgetrennten Schwanzende rot gefärbt sind, sind die Unstetigkeiten (und mithin die Fehlkalibration des Geräts) offensichtlich:

    Eine grüne Kurve mit Lücken.  Die Lücken sind jeweils Hauben in rot, die 100 ppm über den Enden der Lücken schweben.

    In meinem Datensatz betrifft das 1027 von 724'424 Datenpunkten – eigentlich sollte ich die wegwerfen, aber wenn mensch einfach 100 von ihnen abzieht, kommen weitgehend glatte Kurven raus, und so wird das schon nicht völlig unvernünftig sein. Ich bin auch ganz glücklich mit meiner Erklärung des Vertippers bei der Hunderterstelle der abschnittsweise definierten Kalibrationskurve.

    Mir gefällt aber auch die offensichtliche Korrelation von Temperatur und CO₂ zwischen 30 und 50 Grad nicht[2], die sich in der „Fahne nach Nordosten“ im T-Kalibrationsplot zeigt. Mein, na ja, Modell würde da keine Korrelation[3], also einen ebenen Verlauf geradeaus „nach Osten“ erwarten lassen.

    Soweit das Modell zutrifft, ist die ganze Steigung nur eine weitere Fehlkalibration der Temperaturabhängigkeit der Photodiode. Mithin sollte mensch wahrscheinlich oberhalb von 30 Grad etwas wie (T − 30) ⁄ 20⋅50  ppm (weil: über die 20 Grad oberhalb von 30 Grad Celsius geht die Fahne um rund 50 ppm nach oben) abziehen. Gegen Ende des Posts erwähne ich, warum ich die Korrektur am Ende auf (T − 25) ⁄ 25⋅80  ppm erweitert habe.

    Zur näheren Untersuchung habe ich die Punkte aus der Fahne in einer normalen CO₂-Zeitreihe rosa eingefärbt, die Temperatur dazugeplottet und bin dabei zunächst auf ein Ereignis gestoßen, das mir sehr merkwürdig vorkam:

    Zwei Kurven.  Oben CO2, wo aus einer pinken Basis plötzlich ein grüner Gipfel rauswächst, unten die Temperatur, bei der sich nichts tut.

    Ich habe immer noch keine Ahnung, was hier passiert ist: Wenn nicht einfach nur das Instrument durchgedreht ist, dann muss von irgendwoher ein Schwung kohlendioxidreiche Luft gekommen sein, die aber an der Temperatur unter der Eisdose nichts geändert hat. Wenn der Spike von einer Wohnungslüftung käme, wäre das sehr seltsam, denn wenn die Leute die Fenster zu hatten – und nur dann hätte sich CO₂ anreichern können – wäre die Luft innen je nach Bauphysik fast sicher kühler oder wärmer gewesen als draußen. Hm. Mein bestes Angebot: Luft ist ein schlechter Wärmeleiter, und welches Lüftchen auch immer hier wehte, hat den sonnenbeschienenen Sensor einfach nicht kühlen können.

    Ach so: die Kurve ist beim Ergeignis grün, obwohl sich an der Temperatur nichts geändert hat, weil bei den hohen CO₂-Konzentrationen die ensprechenden Punkte aus der kleinen Nase über der Nordost-Fahne im T-Kalibrationsplot zu liegen kommen. Pink ist aber nur gemalt, was in der Fahne selbst ist.

    Fruchtbarer ist die Betrachtung des parallelen Verlaufs von CO₂ und Temperatur zwischen 13 und 16 Uhr. Diese Parallelität besteht tatsächlich nur für die pinken Punkte. Es gibt keine plausible Physik, die CO₂ und Temperatur (auf diesen Skalen) gleich schwingen lassen würde. Wenn ich mit meiner Augenmaß-Kalibrationsfunktion von oben korrigiere, verschwindet dieses Signal auch tatsächlich fast vollständig:

    Zwei Kurven wie eben, nur ist dieses Mal oben co2-(temp-30)/20*50 geplottet, und der parallele Verlauf der beiden Kurven ist auch wirklich fast weg.

    Beachtet die obere Achsenbeschriftung; das ist die Nachkalibration, die ich zunächst angebracht habe; mit meiner verbesserten Nachkalibration ab 25°C bleibt etwas mehr Signal übrig:

    Zwei Kurven wie eben; die rekalibrierte, die jetzt wieder irgendwas im Rhythmus der Temperatur macht.

    Dass die Flanken des „Störsignals“ jetzt steiler sind, finde ich eher beruhigend, denn ich glaube, dass das etwas mit direkter Sonneneinstrahlung zu tun hat (die die Infrarotdiode ganz bestimmt stört), und Licht und Schatten gehen natürlich viel schneller als die Erwärmung von Luft und Gerät. In der Tat würde Streulicht von der Sonne so tun, als käme etwas mehr Licht beim Sensor an, als wäre also etwas weniger CO₂ im Strahlengang. Wenn ihr scharf schaut: im Plot sieht es aus, als sei die CO₂-Schätzung niedriger, wenn die Temperatur ansteigt (also vermutlich die Sonne schien) und höher, wenn sie das nicht tat. Wäre das hier Wissenschaft, müsste ich dieser Spur genauer nachgehen. So, wie es ist, kann …

  • Gefrorener Nebel

    Foto: Ein Berg, unten wie von Schnee weiß überpudert, oben eher braun.

    Der Ölberg bei Dossenheim heute: Sieht zwar aus wie Inversionswetterlage, war aber überall kalt.

    Zu den großen Vorteilen des Lebens mit Bergblick[1] gehört, dass es immer wieder interessante Physik zu bestaunen gibt. Heute etwa zeigte sich der Ölberg – ein Teil des Aufstiegs zum Odenwald am östlichen Rand des Oberrheingrabens, das Foto entstand also von etwa 100 Metern über NN – wie im Foto oben. Berge, die oben braun und unten weiß sind, sind zunächst eher erstaunlich, denn „normal“ wirds nach oben hin kälter, und damit bleibt Schnee auf Bergen meistens viel länger liegen als im Tal, so wie etwa hier (Mai 2017):

    Foto: Viel Grün im Vordergrund, dahinter Schneeberge

    Eine wichtige Ausnahme von dieser Regel ergibt sich bei einer Inversionswetterlage, wenn sich warme Luft über kalte schiebt; der verlinkte Wikipedia-Artikel enthält in der Tat ein Bild ganz ähnlich wie das Eingangsfoto, also ein Berg mit weißem Fuß und braunem Kopf.

    Inversionswetterlagen sind von Dossenheim aus gut zu erkennen, wenn das Kraftwerk in Mannheim-Rheinau läuft, denn die Dampf-Fahne sieht dann etwas seltsam aus (Foto vom Dezember 2021):

    Foto: Himmel mit „Abgasfahne“, die auf halber Höhe abknickt und sich flach weiter ausbreitet.

    Wie das ohne Inversion aussieht, könnt ihr im kleinen GKM-Video im Kohlendioxid am Balkon-Post begutachten.

    Aber der Befund oben ist allenfalls indirekt auf eine Inversionswetterlage zurückzuführen. Es war gestern in der ganzen Luftsäule arschkalt – -8° Celsius ist für diese Gegend hier schon bitter – und dazu im Tal neblig. Bei diesen Tempraturen ist der Nebel ausgefroren, wie das heute morgen im Tal an vielen Stellen zu bewundern war, etwa an dieser Pflanze – also gut: an diesem Pflanzenrest:

    Foto: Myriaden von Eiskristallen an einem Pflanzentrieb in der Sonne

    Ich würde nennenswerte Summen verwetten, dass der Nebel gestern am Ölberg nur bis vielleicht 300 m über NN reichte und darüber strahlender Sonnenschein herrschte (diese obere Nebelgrenze mag an einer milden Inversion gelegen haben; ich bin nach den hiesigen Wetterverhältnissen der letzten Tage jedoch überzeugt, dass es auch bei Sonne nicht viel wärmer war dort oben).

    Es wäre bestimmt hinreißend gewesen, über die Nebel im Rheingraben zu blicken. Wenn mensch das nur immer so genau wüsste unten im Nebel… Andererseits: Es wäre mir wahrscheinlich so oder so zu kalt gewesen, und mein RSV (oder Influenza oder Parainfluenza oder Metapneumo oder hCoV oder was auch immer, also: meine blöde Erkältung gerade) hätte mich wohl eh drin gehalten.

    [1]Nein, ich will nichts darüber hören, dass Erhebungen von 350 Metern über die Umgebung – das ist die Größenordnung beim Ölberg – nicht als Berge, sondern allenfalls als Hügel zählen. Fahrt einfach mal mit dem Fahrrad rauf. Danach höre ich mir das Wort „Hügel“ auch aus eurem Mund an.
  • Kohlenstoff-Stoffwechsel des Menschen: Nur über Bande schlimm

    Foto einer Prozession mit viel Weihrauch

    Machen diese Priester, die da 2013 duch Barcolona prozedieren, mehr Treibhauseffekt durch ihren Qualm oder durch ihre Atemluft? Das zumindest rechne ich hier nicht aus.

    Mich hat neulich wer gefragt, wie viel CO2 ein durchschnittlicher Mensch so emittiert, und mit meiner Kopfzahl vom letzten Jahr, um die 35 Gigatonnen CO2-Äquivalent Gesamtemission weltweit, geteilt durch die geschätzten 8 Milliarden Menschen, die letzte Woche durch die Presse gingen, habe ich mal munter „vier Tonnen“ gesagt und anschließend die zweite Kopfzahl von damals, 2/3 Gt für die BRD mit 80 Millionen EinwohnerInnen zu „eher so acht Tonnen für dich und mich“ verarbeitet, „nicht zu vergessen ein paar Tonnen obendrauf für Fertigwaren und Futter, die wir importieren und die derzeit für oder gegen China, Brasilien oder Indonesien zählen.“

    Aber darum ging es ihm nicht. Er wollte wissen, was ein Mensch so ausatmet, was wir also einfach nur durch unseren Stoffwechsel emittieren. Dafür hatte ich spontan keine brauchbaren Kopfzahlen und habe (ahem: deshalb) erstmal eingewandt, dass das, wie unten ausgeführt, ziemlich irrelevant ist. Dennoch ist das keine per se schlechte Frage, und so habe ich meinen Post zur menschlichen Leistung hervorgekramt und daraus für mich und vergleichbare Menschen eine Wärmefreisetzung zwischen 8 und 16 MJ am Tag (also Megajoule, Millionen Joule) abgelesen. So ein Ärger: Das hatte ich eigentlich schon damals zur Kopfzahl erklärt, aber dann doch wieder vergessen.

    Vier Kilo pro Tag

    Zur CO2-Bilanz unserer Kohlenstoff-Verstoffwechselung hatte ich in meinen Überlegungen zur thermischen Leistung schon etwas geschrieben. Eine kurze Erinnerung daran: Tiere wie der Mensch betreiben sich vor allem, indem sie Phosphor von ATP abspalten, was ihnen für jedes Mol ATP 31 kJ Energie bringt. Für 30 Mol ATP atmen wir ungefähr sechs Mol CO2 aus, womit wir auf die Stoffmenge von CO2 bezogen am Ende

    31 ( kJ)/(mol ATP)(30  mol ATP)/(6  mol CO2) = 155  kJ ⁄ mol CO2

    an Wärme abgeben können. Das ist die untere Grenze der mit dem Ausatmen von einem Mol CO2 verbundenen Wärmefreisetzung; in Wahrheit werden auch die Prozesse zur Herstellung von ATP aus den verschiedenen Nahrungsbestandteilen Wärme freisetzen. Die obere Grenze ist – im zitierten Post diskutiert – die Reaktionsenthalpie von Verbrennung von Kohlenstoff, nämlich 394  kJ ⁄ mol. Die folgende Abschätzung aus der Abwärme liefert jedenfalls eine obere Grenze der Emission.

    Wenn wir die 155 kJ/mol mit der Leistung eines Durchschnittmenschen verrechnen – wir nehmen jetzt mal den Mittelwert der oben erwähnten Grenzen, also 12'000 kJ/d –, ergibt sich für die CO2-Emission eines Menschen aus dem Stoffwechsel

    (1.2⋅104 kJ ⁄ d)/(155  kJ ⁄ mol) ≈ 80  mol ⁄ d.

    Wer nun bei „Mol“ nur düstere Erinnerungen an den Chemieunterricht hat: Das ist einfach Abkürzung für „ungefähr 6⋅1023 Moleküle“, und diese krumme Zahl ist so gemacht, dass mensch im Groben nur die Nukleonenzahlen der beteiligten Atome zusammenaddieren muss, um das Mol („Stoffmenge“) in Gramm („Masse“) zu wandeln. Als Kopfzahlen taugen 12 Nukleonen für den Kohlenstoff und 16 Nukleonen für den Sauerstoff[1]. Für Kohlendioxid mit zwei Sauerstoff- und einem Kohlenstoffatom ergeben sich also 44 Gramm aufs Mol.

    Mithin atmen wir so auf einen Faktor zwei – Tour de France-FahrerInnen ausgenommen –

    80  mol ⁄ d⋅0.044  kg ⁄ mol ≈ 3.5  kg ⁄ d

    Kohlendioxid aus. Mit der Kopfzahl 1 Kubikmeter aufs Kilogramm für Luft (jaja, CO2 ist ist etwas dichter als N2, das ja die Luft dominiert, aber Faktoren von 1.5 spielen hier keine große Rolle) ist das ganz nebenher schnell in ein Volumen gewandelt: Wir atmen was zwischen zwei und acht Kubikmeter reines CO2 am Tag aus, genug, um eine Grube zu füllen, die groß genug ist, um reinzufallen. Ein Glück, dass unter normalen Umständen CO2 nicht in solchen Gruben bleibt, oder wir würden uns regelmäßig durch unsere eigene Atmung umbringen.

    Fürze und AfD-Debatten

    Völlig vernachlässigbar im Hinblick auf den Treibhauseffekt sind übrigens Fürze. Die Wikipedia beziffert die auf rund einen Liter am Tag. Angenommen, es handele sich um pures Methan (das geruchlos ist, was zeigt, dass wir hier eine nicht ganz zutreffende Annahme machen), wäre das in etwa ein Gramm davon und damit klimatisch verschwindend gegenüber dem CO2, selbst dann, wenn mensch die Treibhauswirkung von Methan mit etwas wie einem Faktor 20 gegenüber Kohlendioxid ansetzt.

    Aufs Jahr gerechnet haben wir also rund eine Tonne CO2-Äquivalent aus dem Stoffwechsel. Das schien mir verdächtig nahe an den fossilen Emissionen, die ich oben auf vier Tonnen pro Jahr geschätzt habe[2]. Dass wir im Schnitt lediglich vier Mal mehr fossile Energie verbraten sollten als wir durch unsere Nahrung zu uns nehmen, erschien mir auf Anhieb völlig unplausibel. Deswegen habe ich eine Suchmaschine mit etwas wie "CO2-Emission" "Atmung" angeworfen, und ich habe etwas über meinen Bekannten herausgefunden, das ich wirklich nicht wissen wollte.

    Per (übrigens ziemlich lahmen) Faktencheck der Tagesschau stellt sich nämlich raus, dass das Thema „Uh, Menschen in Afrika atmen und machen fast so viel CO2 wie unsere Autos” von einem, nun, intellektuell eher einfach gestrickten Menschen etabliert wurde, der für die AfD im Bundestag sitzt. Gut: solche „Diskurse“ können Menschen auch über Ecken erreichen – vielleicht ist der Bekannte ja gar nicht in AfD-Echokammern unterwegs. Ich nehme das jetzt einfach mal ganz fest an.

    Ziemlich irrelevant

    Lahm ist der Tagesschau-Faktencheck übrigens nicht nur, weil er nicht mal versucht, ein – ja wirklich nicht allzu kompliziertes – physikalisches Argument zu machen, sondern einfach nur irgendeine Autorität zitiert und dann mit völlig albernen Mantissenlängen arbeitet (von „168” bis „2040“, quasi aufs Promille genau), sondern auch, weil er viel zu wenig darauf eingeht, warum genau die Frage nach dem Stoffwechselbeitrag gleichzeitig völlig irrelevant und dramatisch ist.

    Irrelevant ist sie, weil: „Das vom Menschen ausgeatmete CO2 stammt aus dem eigenen Stoffwechsel, war also bereits im biologischen Kreislauf vorhanden“. Weder dieser noch die folgenden Sätze im Faktencheck machen hinreichend klar, was der entscheidende Unterschied ist zwischen Mensch und Betonmischer ist.

    Menschen nämlich essen nach wie vor praktisch nur Dinge, die ungefähr im Jahr vorher Pflanzen waren, oder jedenfalls im Jahrzehnt vorher. Das steht im Gegensatz zu fossilem Kohlenstoff, also Kohlenstoff, der vor vielen Millionen Jahren mal Pflanze war (oder anderweitig aus der Atmosphäre genommen wurde). Während nun Kohlenstoff, der letztes Jahr Pflanze war, plausiblerweise auch demnächst wieder Pflanze sein wird und sich kaum in den Atmosphäre anreichern wird, wird Kohlenstoff, den wir von vor (hunderten) Millionen Jahren in die Gegenwart transportieren, das eher nicht so schnell können – und in der Tat verbleiben jedenfalls große Mengen davon augenscheinlich sehr lange in der Atmosphäre.

    Eine Art, das zu sagen, wäre: „Solange wir weder Zeug aus Kohle noch aus Erdöl essen, sind wir unmittelbar nicht schlimmer als die Tiere, die wir verdrängt haben.“ Das „woher“ in der Überschrift deutet diesen Gedanken zwar an, aber es hätte schon sehr geholfen, ihn etwas klarer als über den doch recht abstrakten Verweis auf den „biologischen Kreislauf“ auszusprechen.

    Wir verstoffwechseln also direkt nur sehr wenig fossilen Kohlenstoff; ich denke, ein paar Aromastoffe und und andere Spuren in üblichen Lebensmitteln dürften direkt aus Öl und Gas erzeugt werden, aber selbst Analogkäse wird immer noch aus „Milch-, Soja- oder Bakterieneiweiß und Pflanzenfette als Grundstoffe, teils auch Stärke“ (Wikipedia) gemacht. Solange das so ist, sind wir mit dem Stoffwechsel selbst notwendig im CO2-Gleichgewicht mit unserer Landwirtschaft, die ja ständig den Kohlenstoff aus der Atmosphäre binden muss, der in der Folge wiederum in unseren Därmen landet – wie weit diese Produktions-Konsumptions-Logik noch als „biologischer Kreislauf“ durchgeht, dürft ihr selbst entscheiden.

    Trotzdem schlimm

    Allerdings: auch das Gegenargument ist in der Praxis ungültig, denn es gilt nur für die Sorte Subsistenzlandwirtschaft, die möglicherweise verbreitet bleibt in den Teilen des globalen Südens, die wir noch nicht „in den Weltmarkt integriert haben“: Sie findet ohne Beteiligung fossiler Energieträger statt, der Kohlenstoff, der da verhandelt wird, ist also tatsächlich vom letzten Jahr oder, wo die BäuerInnen mal roden, vielleicht vom letzten Jahrhundert.

    Die marktkonforme Lebensmittelproduktion hingegen hat, zwischen Trockenlegung von Feuchtgebieten, Treckern und Supermärkten, einen gewaltigen Anteil an der Emission (mehr oder, etwa im Fall von Mooren, minder) fossilen Kohlenstoffs, je nach Rechnung zwischen 10% und 30%. Und so ist schon richtig, dass das Wachstum dem Klima den Rest gibt. Das Wachstum der Bevölkerung jedoch hat darauf nur insoweit einen Einfluss, als es normalerweise Wirtschaftswachstum nach sich zieht. Es ist aber nicht die Subsistenzbäuerin, es ist die Produktion für den Weltmarkt, die fossiles CO2 freisetzt.

    Das spiegelt sich in den Abschätzungen der Pro-Kopf-Emission von Treibhausgasen in Our World In Data wider[3]. Während ein Weltmarktbürger wie dieser mangelinformierte AfD-Mensch um die acht Tonnen CO2-Äquivalent emittiert, sind Menschen in der komplett abgehängten Zentralafrikanischen Republik mit 40 Kilogramm im Jahr dabei. 200 Menschen dort haben den Fußabdruck dieses einen AfDlers. Ginge es nur um die Kohlenstoffemissionen, könnten wir „im Westen“ durch eine sehr mäßige Rate von Selbstentleibung noch jede Menge Bevölkerungswachstum im globalen Süden mehr als ausgleichen.

    Aber einerseits ist das nur Teil der Gleichung, und andererseits soll sich ja eigentlich niemand aufhängen. Es bleibt also nicht nur im …

  • 34 Monate Corona im Film

    Im Sommer 2021 habe ich in zwei Posts Filme zur Visualisierung der Corona-Inzidenzen und einer Art Alters-Scores aus den RKI-Daten der vorherigen anderthalb Jahren vorgestellt und ein wenig das Python-Programm diskutiert, das die generiert.

    Ich wollte das über den Sommer immer mal aktualisieren. Aber die Pandemie hat keine erkennbare Pause eingelegt, die eine gute Gelegenheit für eine Art Rückblick gewesen wäre. Jetzt aber ist wohl so in etwa der letzte Moment, in dem so ein Film noch nicht vollständige Clownerei ist, denn schon jetzt testet zumindest anekdotisch kaum mehr jemand. Wenn aber fast niemand PCR-Tests machen lässt, werden die Zahlen, die ich da visualisiere, weitgehend bedeutunglos (weil nicht small data).

    Bevor das Ganze zu einer Art aufwändigen Lavalampen-Simulation wird, habe ich die Programme genommen, dem Inzidenzfilm eine dynamische Colorbar gegönnt – angesichts von Inzidenzen von örtlich über 4000/100'000 im letzten Winter war das bisher feste Maximum von 250 nicht mehr sinnvoll – und habe die Filmchen nochmal mit aktuellen Daten gerendert.

    Hier also die Inzidenzen per Kreis (Hinweise dazu von vor einem Jahr):

    und hier die Alters-Scores (auch dazu Hinweise vom letzten Mal):

    Beide Filme sind mit -i 7 gebaut, jeder Tag ist also sieben Frames lang. Inzwischen wären die Filme zwar auch ohne Interpolation lang genug, aber sie hilft wenigstens dem Lavalampen-Effekt – und natürlich verletze ich gerne das Durchhörbarkeits-Zeitlimit von drei Minuten. Auch wenn die Filme gar keinen Ton machen.

    Ich habe die Gelegenheit genutzt, um den Code, der das macht – statt ihn nur hier zu verlinken, wo ihn niemand finden wird –, brav auf dem Codeberg abzuladen. Vielleicht hilft er dort ja Leuten, die irgendwann irgendwelche Daten in Kreispolygonen von matplotlib aus plotten wollen. Wenn es dafür bessere Standardverfahren geben sollte, habe ich die zumindest vor einem Jahr nicht gefunden.

  • (Un)verstandene Infektionsdynamik

    Ich habe vorhin einen Beitrag zu den Wirkungen nicht-pharmazeutischer Maßnahmen gehört, der in der Deutschlandfunk-Sendung Forschung aktuell am dritten Juni lief. Darin hieß es:

    Vielleicht sind die vielen Einflussfaktoren ein Grund, warum auf diesem Gebiet überhaupt wenig geforscht wird. Die Bessi-Collaboration zur Erforschung sozialer, Umwelt- und Verhaltens-Pandemiemaßnahmen zählt aktuell nur 18 veröffentlichte Studien aus diesem Bereich, aber 974 zu Impfstoffen oder Medikamenten.

    Das hat mich daran erinnert, dass ich spätestens seit Oktober 2021 eine ziemlich grundsätzliche Lücke bei unserem Verständnis der Epidemiologie von SARS-2 gewittert habe, und zwar ganz unabhängig von meinen misslungenen Vorhersagen im letzten Herbst. Ich habe nämlich bis genau heute aufgrund von, Fanfare, Unabhängigkeitsargumenten für sehr unplausibel gehalten, dass sich die Varianten gegenseitig verdrängen. Lasst mich spoilern: Mein Instinkt, dass da was nicht stimmen kann, war falsch, Mensch soll einfach nie die Exponentialfunktion unterschätzen.

    Aber langsam. Zunächst habe mir die R-Wert-Schätzungen des RKI vorgenommen. Zur Erinnerung: Der R-Wert soll sagen, wie viele Leute einE InfizierteR zu einer bestimmten Zeit im Mittel ansteckt; ist er konstant größer als eins, wächst die Inzidenz exponentiell, ist er konstant kleiner als eins, schrumpft sie exponentiell.

    Ich möchte auf der Basis der R-Werte den Pandemieverlauf nacherzählen, um der Variantenverdrängung auf die Spur zu kommen. Dabei nutze dabei die Kurvenfarbe als Indikator für die geschätzte Inzidenz – beachtet, dass sowohl die Skalen auf dieser Hilfsachse als auch auf der Ordinate von Bild zu Bild drastisch verschieden sind.

    Plausibler Anfang

    Dabei habe ich mir nacheinander ein paar Phasen vorgenommen. Von März bis Juli 2020 konnte mich mir alles prima zusammenreimen:

    Kurve mit einem Peak von über drei, die dann Richtung eins abfällt.

    Fig 1: R-Werte der ersten Welle

    Die unkontrollierte Infektion lief anfangs mit dem geschätzten R0 (also: wie groß ist das R ganz ohne Maßnahmen und Immunität?) der Wuhan-Variante (im Winter etwas wie 3) los, dann griffen die Maßnahmen, und wie sie nacheinander so griffen, fiel auch der R-Wert.

    Ich war damals mit dieser Interpretation soweit glücklich, auch wenn Leute immer mal wieder an den Zeitskalen rumgemäkelt haben: Reagiert das nicht schon vor den Maßnahmen? Hätte das nicht schneller auf Schul- und Betriebsschließungen reagieren müssen? Zu letzterem Punkt zumindest ist einzuwenden, dass es einerseits zwei, drei Wochen gedauert hat, bis die Leute wirklich im Coronamodus waren. Andererseits sind für die Mehrzahl der Fälle auch nur Melde-, nicht aber Infektionszeitpunkte bekannt. Da diese ohne Weiteres um ein oder zwei Wochen auseinanderliegen können, wäre selbst eine scharfe Stufe in R in den RKI-Schätzungen weich ausgeschmiert; ein weiteres Beispiel übrigens für die Gefahren von Big Data.

    Ein merkwürdiger Balanceakt

    Gegen Ende des ersten Coronasommers kam mir aber schon komisch vor, wie sehr sich das effektive R immer ziemlich genau um die Eins herum hielt. Bei sowas Kitzligem wie einem Infektionsprozess, der davon lebt, dass sich immer mal wieder ein ganzer Haufen Leute ansteckt, ist es alles andere als einfach, diese Sorte von Gleichgewicht (es stecken sich in jeder Zeiteinheit ungefähr genauso viele Leute an wie gesund werden) zu halten – die Überdispersion der Wuhan-Variante soll was wie 0.1 gewesen sein, so dass vermutlich überhaupt nur ein oder zwei von zehn Infizierten zur Ausbreitung der Krankheit beitrugen (dann aber auch gleich richtig, also mit mehreren Angesteckten).

    Unter diesen Umständen einen R-Wert von um die eins zu haben, ist ein Balanceakt ganz ähnlich der Steuerung eines AKW (das zudem nicht mit der Überdispersion zu kämpfen hat): mach ein bisschen zu wenig und die Infektion stirbt rapide aus (der Reaktor wird kalt); mach ein bisschen zu viel und du bist gleich wieder bei enormen Zahlen (der Reaktor geht durch). Dennoch hat sich der R-Wert (abgesehen vom Tönnies-Zacken Mitte Juni, der ganz gut demonstriert, was ich mit „kitzlig“ meine) im Sommer doch recht gut rund um 1 bewegt:

    Kurve, die um Eins rumzittert

    Fig 2: R-Werte im Sommer 2022

    Was hat R so (relativ) fein geregelt? Sind die Leute in Zeiten ansteigender R-Werte wirklich vorsichtiger geworden? Und waren sie unvorsichtiger, wenn die R-Werte niedrig waren? Erschwerend im Hinblick auf so eine Regelung kamen zumindest im Juli und August nennenswert viele Infektionen nicht durch Reproduktion im Land zustande, sondern kamen mit Rückreisenden aus Gegenden mit höheren Inzidenzen. Wie das genau lief, ist aber wieder schwierig zu quantifizieren.

    Mein erstes kleines Rätsel wäre also, warum die Inzidenz im Sommer 2020 über ein paar Monate hinweg im Wesentlichen konstant war. Im Herbst 2020 schien mir das eher wie eine Anekdote, zumal es recht erwartbar weiterging:

    Kurve mit einigen Peaks

    Fig 3: R-Werte der zweiten und dritten Wellen

    Die hohen R-Werte im Oktober sind überaus zwanglos durch Schulen, Betriebe und ganz kurz auch Unis mit allenfalls lockeren Maßnahmen bei lausig werdendem Wetter zu erklären. Der Abfall zum November hin wäre dann der „Lockdown Light“. Wieder mag mensch sich fragen, warum der Abstieg schon Mitte Oktober einsetzte, während der Lockdown Light ja erst Anfang November in Kraft trat, aber seis drum. Der nächste Buckel, hier schon in rot, weil mit für damalige Zeiten enormen Inzidenzen einhergehend, dürfte ganz grob Weihnachtsmärkte (Aufstieg) und deren Schließung (Abstieg; ok, es hat auch noch einige weitere Lockdown-Verstärkungen gegeben) im Dezember 2020 reflektieren.

    Verdrängt oder nicht verdrängt?

    Dass bei gleichbleibenden Maßnahmen der R-Wert ab Mitte Februar stieg, habe auch ich mir damals dadurch erklärt, dass die Alpha-Variante infektöser ist. Richtig schöne Grafiken dazu gibt es erst später, so etwa hier aus dem RKI-Wochenbericht vom 7.10 (der gerade nicht im RKI-Archiv zu finden ist):

    Farbig markierte Anteile verschiedener SARS-2-Varianten, die sich offenbar verdrängen

    Fig 4: Anteile der verschiedenen Varianten vom Oktober 2021 (Rechte: RKI)

    Während der, sagen wir, ersten 13 Kalenderwochen des Jahres 2021 hat also Alpha den Wuhan-Typ im Wesentlichen kompett, nun ja, verdrängt. Und das schien mir bis jezt sehr unplausibel. Anschaulich gesprochen nämlich kann Alpha den Wuhan-Typ nur dann verdrängen, wenn die Varianten „sich sehen“, also überhaupt nennenswert viele Menschen, die der Wuhan-Typ infizieren möchte, schon zuvor Alpha gehabt hätten[1].

    Das war im Frühling 2021 ganz klar nicht so. Der RKI-Bericht vom 16.4.2021 (in dem sich übrigens auch die damaligen Gedanken zu den Varianten spiegeln) spricht von rund 3 Millionen Infizierten. Plausible Dunkelziffern werden den Anteil der bereits mit SARS-2 (in der Regel noch nicht mal Alpha) Infizierten kaum über 10% heben. Die Wuhan-Variante kann also im Wesentlichen nichts von Alpha gesehen haben, und damit kann sie auch nicht verdrängt worden sein[2].

    Mit einem zweiten Blick stellt sich heraus, dass es das auch nicht brauchte, denn unter den recht drakonischen Maßnahmen vom Januar 2021 – wir reden hier von der Zeit nächtlicher Ausgangssperren – hatte der Wuhan-Typ so in etwa einen R-Wert von 0.9 (das lese ich jedenfalls aus Fig. 3). Nun rechnet(e) das RKI den R-Wert in etwa so, dass er das Verhältnis der Infektionen in einem Viertageszeitraum zum vorherigen Viertageszeitraum angibt; der Gedanke ist, dass es (die „Serienlänge”) von einer Infektion bis zur Ansteckung in der nächsten Generation bei SARS-2-Wuhan sowas wie eben die vier Tage dauern sollte[3].

    Unter der angesichts konstanter Maßnahmen wenigstens plausiblen Annahme eines konstanten R-Werts (gegen Ende des Zeitraums mag er wegen Wetter sogar noch weiter gefallen sein), kann mensch ausrechnen, dass nach 13 Wochen vom Wuhan-Typ nur noch

    0.913⋅7 ⁄ 4 ≈ 10%

    übrig waren, und weil bei hinreichend niedrigen Inzidenzen der Bestand eines im Wesentlichen ausbruchsgetriebenen Erregers wie der Wuhan-Variante eh schon prekär ist: Eigentlich reicht das schon, um das praktische Verschwinden der Wuhan-Variante ganz ohne Verdrängung durch Alpha zu erklären.

    Zero Covid vs. die vierte Welle

    Wenn das die Erklärung ist, wäre das in gewisser Weise eine gute Nachricht für die Zero Covid-Fraktion: Wir haben Corona schon mal ausgerottet, inzwischen sogar drei Mal, nämlich den Wuhan-Typ, Alpha und (wahrscheinlich) Delta. Die „Maßnahmen“ für die jeweils infektiösere Variante haben offenbar ausgereicht, ihre Vorgänger (praktisch) vollständig auszurotten. Damit wäre zwar immer noch nicht das Langfrist-Problem gelöst – denn global wird SARS-2 sicher nicht verschwinden –, so dass ich nach wie vor eifrig gegen Zero Covid argumentieren würde, aber ein lokales Ende von Corona haben wir offenbar schon mehrfach hinbekommen.

    Gehen wir weiter in der Zeit:

    Bunte Linie mit zwei ausgeprägten zweigipfeligen Höckern

    Fig 5: R-Werte während des Anlaufs zur vierten Welle.

    Im Anlauf zur vierten Welle wird es unübersichtlich, weil nennenswert viele Menschen geimpft waren. Es mag sein, dass der Wuhan-Typ etwas empfindlicher auf die Impfung reagiert als Alpha, so dass es vielleicht glaubhaft ist, dass der R-Wert des Wuhan-Typs nicht wieder auf das „gut 1“ aus dem Sommer 2020 zurückgeschnappt ist, nachdem die Beschränkungen aus dem Winter 20/21 nach und nach wegfielen; dann wäre zumindest klar, warum der Wuhan-Typ nicht wiederkam.

    Bei Alpha und Delta liegen die Verhältnisse wahrscheinlich komplizierter. Der Umschlag von Alpha auf Delta war noch schneller als der von Wuhan auf Alpha; abgeschätzt aus Fig. 4 vielleicht zwischen den Kalenderwochen 21 und 27. Davor, also im Juni, lag der R-Wert um 0.8, angesichts relativ entspannter Verhältnisse zu diesem Zeitpunkt vermutlich bereits eher durch Impfung als durch nichtpharamzeutische Maßnahmen bedingt. Sechs Wochen R = 0.8 bringen die Inzidenzen, immer noch unter der Annahme der Unabhängigkeit der konkurrierenden Infektionsprozesse, wiederum runter auf

    0.86⋅7 ⁄ 4 ≈ 10%

    – das Aussterben von Alpha kommt also erneut so in etwa hin, wenn …

  • Eine Sturmfront zieht durch

    Gestern am frühen Abend ist auch bei uns das als „Zeynep“ durch die Presse ziehende Sturmtief angekommen. Ich hatte überlegt, meine CO₂-Messapparatur auf dem Balkon –

    Zwei Eisschachteln beschwert mit einem rostigen Stahlriegel

    (unter der einen Eisschachtel ist ein Raspberry Pi, unter der anderen das zyTemp-Gerät, und die sind getrennt, weil der Raspi durch seine Abwärme die Temperaturmessung sehr stören würde – abzubauen, denn die zwei Eisschachteln, die da den Regenschutz machen, könnten bei hinreichend starkem Wind durchaus die Kraft entwickeln, den Stahlriegel[1], der sie über der Elektronik festhält, wegzuheben. Nun, ich habe die Installation stehen lassen und bin jetzt froh drum, denn so konnte ich den dramatischen Temperatursturz über die stürmische Kaltfront hinweg live beobachten:

    Graph: Ein starker Abfall von 15 auf 8 Grad

    (Die Zeit läuft in UTC, der Sturm begann hier also ziemlich genau um 18 Uhr MEZ).

    Sieben Kelvin Temperatursturz in einer guten halben Stunde finde ich schon ziemlich sportlich. Stickstoff siedet bei normalem Luftdruck bei 77 Kelvin (oder ungefähr minus 200 Grad Celsius angesichts des absoluten Nullpunkts bei -273 Grad Celsius). Wenn das so weitergegangen wäre mit dem Temperaturabfall um 15 Kelvin pro Stunde, würden sich 14 Stunden später, also ungefähr gerade jetzt, die ersten Stickstoffpfützen bilden. Whoa.

    Was mich zur Überlegung bringt, wie wohl die Atmosphäre ausfrieren würde; der Siedepunkt von Flüssigkeiten sinkt ja mit abnehmendem Druck, und weil die Erdatmosphäre Stickstoff plus ein bisschen was ist, wird der Druck sofort dramatisch fallen, wenn er kondensiert. Daher wird der Stickstoff wohl schön langsam nach und nach runterregnen, ganz wie kurz vorher schon der Sauerstoff (der bei 90 Kelvin siedet, aber weil niemand freiwillig mit flüssigem Sauerstoff hantiert, hat dieser Wert weniger Kopfzahl-Potenzial, und „ein wenig über Stickstoff“ ist alles, was ich mir merke), dessen 23% (nach Masse, nach Volumen sind es 21%) ja auch schon ordentlich zum Luftdruck beitragen.

    Das ist beim Kohlendioxid anders: Es würde ohne nennenswerte Änderungen beim Luftdruck ausfrieren und bei knapp 200 Kelvin (oder -70 Grad Celsius) mit etwas Glück hübsche Flocken bilden (es kann erst bei Drücken von über 5 bar überhaupt flüssig werden) und friedlich ausschneien. Ich bin nicht sicher, ob das schon mal wer für den Mars ausgerechnet hat: Schneit es dort CO₂ oder friert es eher wie Reif aus?

    Aber ich schweife ab. Um halb sieben hatte sich gestern abend der rasche Temperaturabfall gefangen, und das ist der zweite bemerkenswerte Punkt: an der Stelle, also nachdem die Front durch war, sank der CO₂-Gehalt der Luft ziemlich schlagartig um 20 ppm oder fünf Prozent. Das finde ich fast noch bemerkenswerter, denn es heißt, dass an der Front selbst nicht viel Materieaustausch stattfindet.

    Dass sich Wetterfronten so ähnlich zu Schockfronten verhalten, war mir bisher nicht klar, und ich habe aus dem Stand keine gute Erklärung, warum das so sein sollte. So eine Wetterfront ist ja doch recht turbulent (kann ich noch aus frischer Erinnerung sagen) und definitiv weit im Unterschallbereich, anders als die Schockfronten bei uns in der Astrophysik, wo sie meist aussehen wie die Filamente, die das HST im Cygnus Loop aufgenommen hat:

    Feine Filamente vor Himmelshintergrund

    Liebe GeophysikerInnen oder MeteorlogInnen: Ich bin dankbar für Lesetipps.

    [1]Wer sich fragt, was das mal war: Kioske hatten (oder haben?) solche Stahltrümmer zum Beschweren von Zeitschriften; wenn sie noch aktiv sind, ist da eine Kunststoffhülle mit Werbung drumrum. Also: Augen auf bei Sperrmüll nach Kioskauflösungen, die Dinger sind wirklich praktisch.
  • Kopfzahlen: Vulkane, Massen, Volumen

    Foto einer Fumarole

    Meine tatsächliche Erfahrung mit vulkanischem Schwefel geht nicht weit über die paar Gramm hinaus, die die Solfatara an dieser Fumarole abgelagert hat.

    In Forschung aktuell vom 18.1. ging es um den Ausbruch des Hunga Tonga Hunga Ha'apai (spätestens seit dem Ausbruch des Eyjafjallajökull ist klar, dass viele Vulkane großartige Namen haben). Darin hieß es, dass bei der Eruption wohl um die 400'000 Tonnen Schwefeldioxid entstanden sind, und dass das nicht viel sei, weil ein wirklich großer Vulkanausbruch – als Beispiel dient der Pinatubo-Ausbruch von 1991 – 20 Millionen Tonnen Schwefeldioxid emittiert.

    Bei dieser Gelegenheit ist mir aufgefallen, dass mir diese 20 Millionen Tonnen spontan alarmierend wenig sagten. Und drum dachte ich mir, ich sollte mal ein paar Kopfzahlen zu eher großen Massen und – weil ein Kubikmeter Wasser eine Masse von einer Tonne hat, hängt das eng zusammen – Volumen sammeln.

    Einfach war noch, die 20 Megatonnen mit meiner praktischen Kohlendioxid-Kopfzahl von neulich, 2/3 Gigatonnen CO₂ pro Jahr aus der BRD, zu vergleichen. Nun ist SO₂ eine ganz andere Nummer als CO₂ (ich erinnere mich an atemberaubende Vulkanbesuche und den weit größeren Schrecken des Chemiepraktikums), aber als Vorstellung finde ich es hilfreich, dass so ein ordentlicher Vulkanausbruch in etwa so viel Schwefeldioxid freisetzt wie die BRD in zehn Tagen (nämlich: ein dreißigstel Jahr) Kohlendioxid.

    Was SO₂-Emissionen selbst angeht, sieht das natürlich ganz anders aus; laut einer Grafik des Umweltbundesamts hat die BRD am Höhepunkt der Saure-Regen-Bekämpfung 1990 lediglich knapp 6 Megatonnen pro Jahr emittiert, also rund ein Viertel Pinatubo, und ist jetzt bei einer halben Megatonne, also in etwa einem Hunga Tonga Hunga Ha'apai (der Name begeistert mich erkennbar). In diesem Zusammenhang gar nicht erwartet hätte ich, dass laut einer IMO-Studie von 2016 der Schiffsverkehr weltweit nur 10 Mt Schwefeldioxid emittiert haben soll, also kaum doppelt so viel wie die BRD 1990, und inzwischen, im Rahmen einer in einschlägigen Kreisen offenbar besorgt beäugten Initiative namens IMO 2020, noch eine ganze Ecke weniger emittieren dürfte.

    Nur vorsorglich: Wer den DLF-Beitrag gelesen hat, mag sich erinnern, dass der Pinatubo das Weltklima um ein halbes Kelvin abgekühlt haben wird. Die sechs Megatonnen Schwefeldioxid aus der 1990er BRD haben jedoch sicher nicht ein achtel Kelvin ausgemacht, und zwar, weil sie fast ausschließlich bodennah entstanden sind. Damit Schwefeldioxid ordentlich klimawirksam wird, muss mensch es in die Stratosphäre bringen. Das ist für einen zünftigen Vulkan kein Problem. Und wäre leider auch für Menschen möglich.[1]

    Wenn sich der Schwefel des Pinatubo wie im Foto oben niederschlägt, wie viel ist das dann? Nun, erstmal ist der Masseanteil von Schwefel im SO₂ recht leicht auszurechnen, denn üblicher Schwefel hat Atommasse 32, während Sauerstoff bei 16 liegt, zwei davon also auch bei 32. Damit ist die Hälfte der Masse von Schwefeldioxid Schwefel, und der Pinatubo hat 10 Megatonnen Schwefel ausgespuckt. Bei einer Dichte von 2000  kg ⁄ m3 (hätte ich geringer eingeschätzt, muss ich sagen) macht das 5⋅106  m3 aus und würde einen Würfel von (5⋅106)1 ⁄ 3 oder runden 170 Metern Kantenlänge füllen.

    Um so ein Volumen einzuordnen, erkläre ich nachträglich den Neckar-Abfluss aus dem Flächen-Post, 150 m3 ⁄ s im Jahresmittel, zur Kopfzahl. Dann entspricht der ganze Katastrophenschwefel des Pinatubo dem Wasser, das in 30 Kilosekunden (coole Einheit: gerade in der Röntgenastronomie wird die viel verwendet) oder knapp 10 Stunden durchläuft. Und das alles Schwefel. Whoa. Vielleicht nehmen wir doch lieber den nächstgrößeren Fluss:

    Foto: Rhein bei Köln

    Der Rhein bei Köln; als ich das Foto gemacht habe, wars eher heiß und Sommer, und so mag das sogar etwas weniger als Normalwasserstand sein.

    Im Rhein bei Köln fließen bei Normalwasserstand 2000  m3 ⁄ s (hatte ich nicht im Kopf, will ich mir als ein Dutzend Neckare merken), und da bräuchte der Pinatubo-Schwefel 2500 Sekunden oder eine Dreiviertelstunde. Immer noch beängstigend. Legen wir also nochmal eins drauf und nehmen den Amazonas. Der führt an der Mündung 70-mal mehr Wasser als der Rhein (was ungefähr 1000 Neckare wären). In dem wäre der Pinatubo-Schwefel in so etwa einer halben Minute durch. Puh. Aber auch nicht sehr tröstlich, denn, wie die Wikipedia ausführt, ist der Amazonas

    der mit Abstand wasserreichste Fluss der Erde und führt an der Mündung mehr Wasser als die sechs nächstkleineren Flüsse zusammen und ca. 70-mal mehr als der Rhein.

    Etwas anfassbarer, gerade für Menschen, die dann und wann im URRmEL sind, ist ein Transportcontainer. Die kurzen davon („TEU“) wiegen leer 2300 kg, voll fast 25 Tonnen und fassen[2] 33 m3. Unsere 5 Millionen Kubikmeter Pinatubo-Schwefel entsprichen also rund 150'000 solcher Container – oder rund 1000 ziemlich langen Güterzügen. Aber das Volumen wäre hier nicht mal das Problem: Angesichts des 25-Tonnen-Limits braucht es für die 10 Megatonnen Schwefel mindestens 400'000 Container (die nicht ganz voll sein dürfen).

    Für solche Containerzahlen braucht es Schiffe. Eines wie die Ever Given, die im letzten März im Suezkanal steckenblieb und vorher schon 2019 eine (liegende) Passagierfähre in Blankenese umgenietet hatte, trägt rund 20'000 TEUs. Für den Pinatubo-Schwefel bräuchte es mithin naiv gerechnet 20 Ever Givens[3].

    Beim Schiffgucken bin ich leider in der Wikipedia versunken. Als ich wieder rausgekommen bin, hatte ich albern viel Zeit mit der Liste der größten Schiffe verbracht und mir vorgekommen, mir als Kopfzahlen für große Massen die Titanic (50'000 Tonnen; moderne Kreuzfahrtschiffe oder Flugzeugträger kommen auch nur auf rund 100'000) und richtig große Tanker (500'000 Tonnen) zu merken, von denen entsprechend einer reichen würde für das angemessen verdichtete Schwefeldioxid vom Hunga Tonga Hunga Ha'apai. Und wo ich so weit war, habe ich festgestellt, dass ich die die 3000 Tonnen der großen Rheinschiffe aus meiner Kraftwerks-Abschätzung schon wieder vergessen hatte. Das erkläre ich jetzt auch zu einer Kopfzahl, im Hinblick auf die Sammlung, die ich demnächst anlegen werde.

    Während meiner Wikipedia-Expedition hat mich ein Artikel ganz besonders fasziniert: Fruchtsafttanker. Oh! Ein ganzes Schiff voll Orangensaft! Ein Paradies!

    Es gibt, so sagt die Wikipedia, „weltweit weniger als 20 Schiffe“, die als Fruchtsafttanker betrieben werden. Aber dafür trägt eines davon gleich mal über 10'000 Kubikmeter Saft. Dass es so etwas wirklich gibt, könnte mich glatt zum Kapitalismus bekehren.

    [1]Das heißt nicht, dass Seiteneffekte der Kohleverbrennung nicht doch kühlende Effekte gehabt hätten; vgl. etwa Klimawirkung von Aerosolen. Es gibt ernsthafte Spekulationen (die rauszusuchen ich jetzt zu faul bin), dass die CO₂-bedingte Erderwärmung erst ab den 1970er Jahren so richtig auffällig wurde, weil vorher erstaunliche Mengen Kohlenruß in der Atmosphäre waren Das große Fragezeichen dabei ist, ob dessen kühlende Wirkungen (Nebel- und Wolkenbildung) seine heizenden Wirkungen (etwa, indem er Schneeflächen verdreckt und damit ihre Albedo reduziert oder vielleicht sogar ähnliches mit Wolken anstellt) wirklich überwiegen.
    [2]Das Containervolumen ist über „Zwanzig Fuß mal ungefähr zwei Meter mal ungefähr zwei Meter als 2⋅2⋅20 ⁄ 3 oder rund 25 Kubikmeter so gut abschätzbar, dass ich da keine Kopfzahl draus machen würde.
    [3]In Wahrheit braucht es deutlich mehr als 20 Ever Givens. Als Tragfähigkeit des Schiffs gibt die Wikipedia nämlich 200'000 Tonnen (dabei ist mir wurst ob metrisch oder long), was bei 20'000 Containern bedeutet, dass ein Container im Schnitt nur 10 und nicht 25 Tonnen wiegen darf. Das reime ich mir so zusammen, dass einerseits auf diesen Schiffen vor allem 40-Fuß-Container fahren werden, die aber nur 30 Tonnen wiegen dürfen, also 2/3 der Maximaldichte der 20-Fuß-Container erlauben – und damit, dass in Containern normalerweise eher Stückgut ist, und selbst wenn an dem viel Metall sein sollte – ohnehin unwahrscheinlich in unserer Plastikgesellschaft – wirds normalerweise schwierig sein, das Zeug so eng zu packen, dass es am Schluss auch nur die Dichte von Wasser hat.
  • Werkstattbericht: Kohlendioxid auf dem Balkon

    Im November hatte ich mich gefragt, was wohl die recht deutlichen Spitzen der CO₂-Konzentration auf meinem Balkon verursachen mag, die sich da immer mal wieder zeigen. Um Antworten zu finden, habe ich seit Ende Dezember eine längere Messreihe laufen lassen und derweil vierstündlich Windrichtungen von der Open Weathermap aufgenommen. Das, so hoffte ich, sollte zeigen, woher der Wind weht, wenn die Konzentration auffällige Spitzen hat.

    Leider gibt ein schlichter optischer Vergleich von Konzentration (oben) und Windrichtung (unten; hier als Cosinus, damit das Umschlagen von 0 auf 360 Grad nicht so hässlich aussieht) nicht viel her:

    Zwei unterbrochene Kurven, die jeweils recht munter vor sich hinwackeln

    CO₂-Konzentration auf meinem Balkon und Windrichtung für Heidelberg aus der Open Weathermap zwischen Ende Dezember 2021 und Anfang Februar 2022. Die Lücken ergeben sich aus fehlenden Daten zur Windrichtung.

    Tatsächlich hilft es ein wenig, wenn mensch das anders plottet. Unten bespreche ich kurz das Programm, das Wind- und CO₂-Daten zusammenbringt. Dieses Programm produziert auch folgenden Plot in Polarkoordinaten:

    Scatterplot in Polarkoordinaten: Im Wesentlichen ein oranger Ring

    CO₂-Konzentration auf meinem Balkon gegen meteorologische Windrichtung (also: Herkunft des Windes, hier gezählt ab Nord über Ost, so dass das orientiert ist wie eine Landkarte) und farbkodierte Windgeschwindigkeit (in Meter pro Sekunde). Das ist ein PNG und kein SVG, weil da doch viele Punkte drauf sind und Browser mit so großen SVGs immer noch ins Schlingern kommen.

    Ich hatte mich seit einem Monat auf diesen Plot gefreut, weil ich erwartet habe, darin eine ordentliche „Beule“ zu sehen dort, wo die CO₂-Emission herkommt. Gemessen daran ist wirkliche Ergebnis eher ernüchternd. Dort, wo ich die Abgasfahne des Großkraftwerk Mannheim sehen würde, etwas unterhalb der 270°-Linie, ist allenfalls ein kleines Signälchen und jedenfalls nichts, was ich wirklich ernst nehmen würde.

    Etwas deutlicher zeichnet sich etwas zwischen 280 und 305 Grad ab, also Westnordwest. Das könnte die Ladenburger Chemieindustrie oder die BASF in Ludwigshafen sein; zu letzterer haben die kritischen Aktionäre im letzten Jahr angesagt, sie emittiere als Konzern 20 Megatonnen Kohlendioxid im Jahr. Wenn, was nicht unplausibel ist, die Hälfte davon am Standort Ludwigshafen anfällt, würden sich diese 10 Mt ganz gut vergleichen mit den 8 Mt, die ich neulich fürs Großkraftwerk gefunden hatte – die Abschätzung von dort, so eine Abgasfahne könne durchaus die Konzentrationsspitzen erklären, kommt also auch für die BASF hin. Allerdings wird deren Emission angesichts des riesigen Werksgeländes natürlich auch verteilter sein…

    Also: Überzeugend ist das alles nicht. Ein anderes Feature ist jedoch schlagend, wegen weniger Übermalung – die bei beiden Plots ein echtes Problem ist; nächstes Mal muss ich mit halbtransparenten Punkten arbeiten – noch mehr, wenn ich den Polarplot „ausrolle“, also den Winkel von unten nach oben laufen lasse:

    Scatterplot kartesisch: ein starker dunkler Klops bei 230 Grad

    In dieser Darstellung fällt ins Auge, dass die CO₂-Konzentration bei starken (dunkle Töne) Südwest- (um die 225°) -strömungen recht drastisch fällt. Das passt sehr gut zu meinen Erwartungen: Südwestwind schafft hier in der Rheinebene Luft durch die Burgundische Pforte, hinter der im Mittelmeerraum auch jetzt im Winter eifrig Photosynthese stattfindet. Wer drauf aufpasst, sieht die Entsprechungen auch im Polarplot von oben, in dem dann sogar auffällt, dass reiner Südwind gelegentlich noch besser photosynthetisierte Luft heranführt, auch wenn der Wind nicht ganz so stark bläst.

    Demgegenüber ist mir eigentlich alles, was sich im nordöstlichen Quadranten des Polarplots (und hier zwischen 0 und 90 Grad) abspielt, eher rätselhaft. Der doppelseitige Sporn bei genau 90 Grad ist vermutlich auf Datenmüll der Wetterstation zurückzuführen: Wahrscheinlich hat die einen Bias, der bei wenig Wind diese 90 Grad ausspuckt. Selbst nach meiner Interpolation (vgl. unten) ist das noch zu ahnen, wenn mensch die Verteilung der Geschwindigkeiten insgesamt (in rot) und die der Geschwindigkeiten rund um einen auffälligen Hügel rund um 90° Windrichtung herum (in blau) ansieht:

    Zwei Histogramme über Geschwindigkeiten, bei dem das blaue nur im linken Bereich ist

    Die elegante Schleife, die von (0, 500) über (70, 540) nach (90, 510) führt und die im Polarplot ganz alleine außen vor sich hinläuft, dürfte ziemlich sicher teils physikalisch sein. Dass das da so einen Ring macht, dürfte zwar ein Artefakt meiner gewagten Interpolation sein (vgl. Technics). Der Anstieg als solcher und wohl auch die grobe Verortung dürften aber ganz gut hinkommen. Sieht mensch sich das im zeitlichen Verlauf an, entspricht die Schleife der höchsten Spitze in der ganzen Zeitreihe.

    Nur leider ist im Nordosten von meinem Balkon nicht mehr viel: Ein paar Dutzend Häuser und dann der Odenwald, also für fast 10 km nur Bäume. Na gut, und ein Ausflugsrestaurant.

    Die aus meiner Sicht plausibelste Interpretation für diese Stelle basiert auf der Beobachtung, dass in der fraglichen Zeit (am 10.1.) wenig Wind wehte, die Temperaturen aber ziemlich niedrig lagen. Vielleicht schauen wir hier wirklich auf die Heizungen der Umgebung? Der Schlot unserer lokalen Gemeinschafts-Gasheizung ist in der Tat so in etwa im Nordosten des Balkons – und vielleicht wurde ja sonst nicht so viel geheizt?

    Technics

    Die wesentliche Schwierigkeit in diesem Fall war, dass ich viel engmaschiger CO₂-Konzentrationen (alle paar Minuten) habe als Windrichtungen (bestenfalls alle vier Stunden), und zudem viele Windrichtungen aus welchen Gründen auch immer (offensichtlich wäre etwa: zu wenig Wind) fehlen. Auf der positiven Seite erzeugt mein Open Weathermap-Harvester weathercheck.py eine SQLite-Datenbank, so dass ich, wenn es nicht furchtbar schnell gehen muss, recht bequem interessante Anfragen laufen lassen kann.

    Mein Grundgedanke war, die beiden einem CO₂-Wert nächsten Wind-Werte zu bekommen und dann linear zu interpolieren[1]. Das ist schon deshalb attraktiv, weil die Zeit (als Sekunden seit 1.1.1970) als Primärschlüssel der Tablle deklariert ist und deshalb ohnehin ein Index darauf liegt.

    Dabei sind aber je nach Datenverfügbarkeit ein Haufen Fälle zu unterscheiden, was zu hässlichen if-else-Ketten führt:

    def get_for_time(self, time, col_name, default=None):
      res = list(self.conn.execute(f"SELECT timestamp, {col_name} FROM climate"
        " WHERE TIMESTAMP BETWEEN ? AND ?"
        " ORDER BY ABS(timestamp-?) LIMIT 2",
        (time-40000, time+40000, time)))
    
      if len(res)!=2:
        if default is not None:
          return default
        raise ValueError(f"No data points close to {time}")
    
      elif abs(res[0][0]-time)<200 and res[0][1] is not None:
        return res[0][1]
    
      elif res[0][1] is None or res[1][1] is None:
        if default is not None:
          return default
        raise ValueError("One or more limits missing.  Cannot interpolate.")
    
      else:
        t1, v1 = res[0]
        t2, v2 = res[1]
        return (v1*(t2-time)+v2*(time-t1))/(t2-t1)
    

    Die Fallunterscheidung ist:

    1. Es gibt überhaupt keine Daten innerhalb von einem halben Tag. Dann kann ich nur einen Fehler werfen; zumindest in unseren Breiten sind Windrichtungen eigentlich schon über kürzere Zeiträume hinweg nur lose korreliert.
    2. Innerhalb von 200 Sekunden der gesuchten Zeit gibt es einen tatsächlichen Messwert, und dieser ist nicht NULL. Dann gebe ich den direkt zurück.
    3. Einer der beiden Werte, die um die gesuchte Zeit herum liegen, fehlt (also ist NULL). Dann kann ich nicht interpolieren und muss wieder einen Fehler werfen. Hier wäre es nicht viel unplausibler als die Interpolation, wenn ich einfach einen nicht-NULL-Wert nehmen würde; aber es wäre doch nochmal ein Stückchen spekulativer.
    4. Ansonsten mache ich einfach eine lineare Interpolation.

    NULL-Werte machen die Dinge immer komplex. Aber wenn ihr euch überlegt, wie viel Stress sowas ohne SQL wäre, ist das, finde ich, immer noch ganz elegant. Im echten Code kommt noch etwas Zusatzkomplexität dazu, weil ich Winkel interpolieren will und dabei immer die Frage ist, wie mensch die Identität von 360 und 0 Grad einrührt.

    Eine vorsorgliche Warnung: aus der Art, wie ich den Spaltennamen hier reinfummele, folgt, dass, wer den Parameter kontrolliert, beliebiges SQL ausführen kann. Sprich: wer diesen Code irgendwie Web-zugänglich macht, darf keine unvalidierte Eingabe in col_name reinlassen.

    Eingestandenermaßen ist diese Sorte von datenbankbasierter Interpolation nicht furchtbar effizient, aber für die 100000 Punkte, die ich im Augenblick plotten will, reicht es. Siehe: Den Code.

    [1]Klar: Windrichtungen über Stunden linear zu interpolieren ist in den meisten Wetterlagen eher zweifelhaft. So, wie ich meine Plots mache, ist es aber nicht wesentlich verschieden davon, die Punkte über den Bereich zu verschmieren. Das wiederum wäre konzeptionell gar nicht so arg falsch.
  • Optimierte Inzidenz

    Mortalitätspunkte und eine Fit-Gerade in einem Logplot

    Abbildung 3 aus dem Paper von Levine et al, auf das ich unten ein wenig eingehe: das Risiko, an SARS-2 zu sterben, geht ziemlich genau exponentiell mit dem Alter (die Ordinate ist logarithmisch aufgeteilt). Diese Beobachtung führt ziemlich direkt zu einem Kult-Paper aus den wilden Jahres des Internet. CC-BY doi:10.1007/s10654-020-00698-1.

    Als das WWW noch jung war und das Internet jedenfalls nicht alt, im Dezember 1999 nämlich, haben Chris Gottbrath, Jeremy Bailin, Casey Meakin, Todd Thompson und J.J. Charfman vom Steward Observatory das bemerkenswerte Paper „The Effects of Moore's Law and Slacking on Large Computations“ auf astro-ph, der Astrophyik-Abteilung des Preprint-Servers arXiv, veröffentlicht. Obwohl das damals nach meiner Erinnerung hohe Wellen geschlagen hat (selbst slashdot, damals eine der wichtigsten Seiten im Netz, berichtete), haben sie es bis heute zu keiner Fachzeitschrift eingereicht. Keine Ahnung, warum nicht, denn ihr Punkt ist trotz ihres eher leichtfüßigen Stils[1] völlig korrekt und jedenfalls nicht ganz offensichtlich.

    Gottbrath und Freunde sagen nämlich, dass, wer eine riesige Rechenaufgabe und ein festes Budget hat, durch Warten schneller fertig werden kann. Das liegt daran, dass mensch nach 18 Monaten (das ist die konventionelle Zeitskala für Moore's Law) fürs gleiche Geld einen Rechner mit doppelt so vielen Transistoren kaufen kann und der wird mit etwas Glück doppelt so schnell sein wie der, den mensch heute kaufen würde. Sie berechnen auch, wie groß eine Rechnung sein muss, damit sich das Warten lohnt: mit dem 18-Monate-Gesetz ist die Grenze bei Aufgaben, die 26 Monate rechnen würden.

    Weil das Paper damals in meiner Blase intensiv herumgereicht worden ist, finde ich überraschend, dass es laut ADS nur sechs Mal zitiert (wenn auch von einer illustren Auswahl von Papern) worden ist und bei den üblichen Suchmaschinen bei Anfragen wie „Moore's Law optimal waiting“ nicht in Sicht kommt.

    Transistoren vs. SARS-2

    Gesucht hatte ich es wiederum, weil ich ja schon länger mit Niedriginzidenzsstrategien hadere. Ganz unabhängig davon, ob wir als Gesellschaft hohe Inzidenzen ohne Schrammen überstehen, dürfte inzwischen niemand mehr ernsthaft bestreiten, dass „am Ende“ alle SARS-2 gehabt haben werden – die Frage ist nur, wann („werden wir im Herbst 2022 wieder einen Lockdown brauchen?“) und auch, wie viele Menschen bis dahin wegen SARS-2 schwer krank geworden oder gar gestorben sein werden.

    An diesem Punkt ist mir das 1999er-Paper eingefallen, denn wir haben bei SARS-2 etwas ganz ähnliches wie Moore's Gesetz: Die Sterblichkeit nach einer Erstinfektion steigt exponentiell mit dem Alter. Das haben im September 2020 (also einige Monate, bevor Impfungen gegen SARS-2 epidemiologisch relevant wurden) Andrew Levin und Kollegen in ihrem Artikel „Assessing the age specificity of infection fatality rates for COVID-19: systematic review, meta-analysis, and public policy implications“ (doi:10.1007/s10654-020-00698-1) recht sorgfältig und beeindruckend gezeigt. Die Abbildung am oben im Post ist aus dieser Arbeit.

    Da hier das Risiko und nicht die Leistung zunimmt, ist jetzt allerdings die Frage nicht, ob mensch lieber etwas warten soll. Nein, je älter Leute werden, desto größer ist ihr Risiko, eine SARS-2-Infektion nicht zu überleben, und dieses Risiko wächst ziemlich steil. Der Gedanke, die Gesamtopferzahl könnte sinken, wenn sich Menschen anstecken, solange sie noch jünger sind und sie also die Infektion mit höherer Wahrscheinlichkeit überleben, liegt also nicht fern. Die zur Prüfung des Gedankens notwendige Mathematik läuft im Wesentlichen analog zu den Überlegungen von Gottbrath und Freunden.

    Ethisch ist es natürlich nicht analog, aber ich wollte dennoch wissen, wie viel das eigentlich ausmachen könnte. Deshalb habe ich mir folgendes Modell ausgedacht:

    1. Die Infection Fatality Rate, also die Wahrscheinlichkeit, an einer (erkannten oder unerkannten) SARS-2-Infektion zu sterben, ist inspiriert von der Abbildung oben

      IFR = exp((t − A1) ⁄ λ) ⁄ 100.

      Dabei ist t das Alter der erkrankten Person, A1 das Alter, in dem 1% der Infizierten versterben (das pro-cent ist auch der Grund für die Division durch Hundert), und λ so etwas wie die Steigung; nennt mensch das Alter, in dem die Todesrate auf 10% gestiegen ist, A10, so lässt sich leicht

      λ = (A10 − A1) ⁄ ln(10)

      ausrechnen.

    2. Eine ultrakompetente Regierung (oder Schwarmintelligenz auf Brillianzniveau cosmic) kriegt es hin, die Inzidenz konstant über viele Jahre auf i zu halten. In meiner Simulation bleibe bei der Interpretation als Wocheninzidenz und simuliere die Infektion von Woche zu Woche. Gegenüber den Inzidenzen in der realen Welt gibt es bei mir außerdem keine Dunkelziffer.

    3. Wer nicht an SARS-2 stribt, stirbt nach Gompertz (cf. Mortalität in der Wikpedia), es stirbt also jedes Jahr ein Anteil („General Fatality Rate”)

      GFR = S30⋅exp(G⋅(t − 30  a)).

      der t-jährigen. Dabei ist S30 die Sterberate für 30-jährige, die ich aus dem Wikipedia-Artikel als ungefähr 40/100000 pro Jahr ablese, und G der Gompertz-Sterbekoeffizient – ich bin nicht sicher, ob ich so eine Größe eigentlich nach mir benannt haben wollte -, den die Wikipedia als 0.08 ⁄  a gibt. Etwas jenseits von Gompertz lasse ich jede Woche 1/52 der fürs jeweilige Wochen-Alter berechneten Menschen sterben; das macht vor allem die Kurven von SARS-2-Opfern über der Zeit glatter.

    4. Wer eine SARS-2-Infektion überlebt hat, stirbt nicht mehr an SARS-2. Das ist sicher eine unrealistische Annahme, aber sie macht das Modell auch deutlich klarer.

    Bliebe noch die Schätzung der Parameter aus der Formel für die IFR. Aus der Abbildung am Artikelanfang lese ich per Auge A1 = 65  a und A10 = 83  a ab (wer von den a irritiert ist: das ist die Einheit, nämlich das Jahr).

    Hier liegt die zweite wesentliche Schwäche meines Modells: Nachdem inzwischen in den dabei mitspielenden Altersgruppen wirklich eine überwältigende Mehrheit geimpft ist, werden diese Zahlen heute garantiert anders aussehen als in der ersten Jahreshälfte 2020, als die Studien gemacht wurden, die Levine et al ausgewertet haben. Andererseits legen die immer noch recht erheblichen Sterbefallzahlen nahe, dass sich die Kurve wohl nur ein wenig nach rechts verschoben haben wird; ich komme gleich nochmal darauf zurück.

    Der Berg des Todes

    Habe ich dieses Modell, kann ich einer Gruppe von Menschen folgen, bis sich (fast) niemand mehr infizieren kann, weil alle entweder tot oder in meinem Sinne immun sind. Ohne es probiert zu haben, glaube ich, dass das Modell einfach genug ist, um es in eine geschlossen lösbare Differentialgleichung umschreiben zu können. Aber wer will denken, wenn es doch Computer gibt?

    Und so habe ich die Modellannahmen von oben einfach in ein paar Zeilen Python gepackt und folge dem Schicksal einer Kohorte von 100000 70-jährigen, bis alle tot oder genesen sind. Und das mache ich für einen Satz von Inzidenzen zwischen 20 und 2000. für Das Ergebnis:

    Eine Kurve mit einem deutlichen Maximum um die 100

    Ich gebe zu, dass ich mit dieser Kurvenform nicht gerechnet hatte. Dass ganz niedrige Inzidenzen die Todeszahlen drücken, ist zwar zunächst klar, denn bei, sagen wir, 20/100000/Woche würde es 100000 ⁄ 20 = 5000 Wochen oder fast 100 Jahre dauern, bis alle mal das Virus hätten haben können, und in der Zeit sind 70-jährige natürlich anderweitig gestorben.

    Das hohe und recht steile Maximum um die 100 herum hatte ich so aber nicht erwartet. Zu ihm tragen vor allem Leute bei, die erst nach einigen Jahren – und dann deutlich gebrechlicher – mit SARS-2 in Kontakt kommen. Bei einer 100er-Inzidenz sieht die Wochensterblichkeit über der Zeit (in Wochen) so aus (cf. make_hist_fig im Skript):

    Kurve mit einem Maximum zwischen 1000 und 1700 Wochen

    Diese Kurve wäre ziemlich zackig, wenn ich strikt nach Gompertz-Formel nur ein Mal im Jahr natürliche Tode hätte, statt die diese geeignet auf die Wochen zu verteilen.

    Die Menschen, die am Anfang der Pandemie 70 sind, sterben in diesem Modell also typischerweise nach 1000 Wochen oder fast 20 Jahren, wenn sie ihn ihren 90ern wären. Das mag etwas fantastisch klingen. Jedoch: Das RKI hat früher immer dienstags die Demographie der Verstorbenen veröffentlicht (z.B. Bericht vom 30.3.2021, siehe S. 12), und tatsächlich sind 20% der Coronatoten in der Altersgruppe 90-99.

    Aber klar: Das ist hypothetisch. Niemand kann die Inzidenzen konstant auf 100 halten, und niemand wird das vernünftigerweise wollen. Vor allem aber mag die Impfung die IFR-Kurve durchaus so weit nach rechts verschieben, dass der Sterblichkeitspeak, der hier noch bei 90-jährigen sitzt, jenseits der 100 rutscht, und dann betrifft das, bei heutigen Lebenswerwartungen, praktisch niemanden mehr.

    Zynische Metriken

    Als Gedankenexperiment jedoch finde ich das Ganze schon bemerkenswert: Wenn wir eine 1000er-Inzidenz aushalten können, würden wir nach diesem, eingestandenermaßen idealisierten, Modell 7% der 70-jährigen den Tod durch SARS-2 ersparen.

    Ein so starker Effekt muss eigentlich schon aufgefallen sein. Wenn das kein Fehler auf meiner Seite ist: steht das schon irgendwo in der epidemiologischen Literatur?

    Allerdings ist die, ach ja, Metrik „Wie viele Leute sterben an SARS-2?“ auch ziemlich nichtssagend. Weit üblicher zur Einschätzung der Frage, wie viel Geld (oder Nerven) mensch für Interventionen gegen Krankheiten ausgeben mag, sind die YLL, Years of Life Lost (cf. nochmal DALY in der Wikipedia). Diese Metrik ist zwar – ganz wie meine Rechnung hier – ein wenig zynisch, aber doch nachvollziebar genug, dass ich mir aus meinem Modell auch nochmal die Gesamtlebensjahre habe ausspucken lassen, die meine 100000er-Kohorte in den Läufen mit den verschiedenen Inzidenzen …

  • Wieder falsch vorhergesagt

    Also gut. Ich sehe es ein. Und gebe es auf. Vor neun Tagen hatte ich vorhergesagt, heute müssten so in etwa 4700 Intensivbetten mit SARS-2-PatientInnen belegt sein. In Wahrheit liegt die DIVI-Zahl im RKI-Bericht von heute bei 3987, also gut 15% darunter. Das wäre bei meinen sonstigen Handwerks-Abschätzungen kein Drama. Hier aber sagt es klar: Meine Methode taugt (erstmal) nicht (mehr).

    Hintergrund war mein Artikel von vor 18 Tagen, in dem ich (für Verhältnisse dieses Blogs sorgfältig) die Verzögerung zwischen steigenden Inzidenzen und in der Folge steigender Intensivbelegung abgeschätzt habe. Das Ergebnis für die vierte Welle waren neun Tage. Doch schon die daraus folgende Abschätzung der Intensivbelegung vor neun Tagen lag weit daneben.

    Und nun liege ich eine weitere Verzögerungsperiode später wieder falsch. Das ist also ganz offenbar alles Quatsch. Während ich mich bei der letzten falschen Vorhersage noch mit einer Fehlanwendung des heuristischen Modells herausreden konnte, ist das bei zwei falschen Vorhersagen nicht mehr drin. Nein. Die Prämisse ist falsch. Die Instensivbelegung folgt nicht mehr, wie noch in den zweiten und dritten Wellen, ganz brauchbar der Inzidenz. Die beiden Kurven haben sich inzwischen sehr deutlich entkoppelt:

    Graph: Entkoppelte Entwicklungen

    Meldezahlen des RKI vs. DIVI-Zahlen (Quellen vgl. Halbwegs gute Nachrichten). Auf der Zeitachse Sekunden seit 1.1.2020; 5⋅107 entspricht dabei dem 1.8.2021. Die Intensivbelegung ist um neun Tage nach vorne gezogen, um den wahrscheinlichsten Verzug auszugleichen und die Kurven übereinanderzubringen. Die y-Achse ist wie immer bei solchen Wachstumsplots von mir logarithmisch (also: exponentielles Wachstum ist eine Gerade). Die Skalierung der Intensivbelegung ist frei Auge, aber egal, wie mensch das macht: die Kurven passen nicht übereinander.

    Ganz offensichtlich reagiert die Intensivbelegung „weicher“ als die Inzidenz, und zwar nicht nur, wie aufgrund längerer Liegezeiten zu erwarten, nach unten, sondern auch nach oben. Es ist eben derzeit nicht so, dass aus einer gegebenen Zahl von Infizierten eine leicht vorhersehbare Zahl von IntensivpatientInnen wird. Daher ist vorläufig jede Vorhersage, die von einem konstanten Verhältnis von Intensivbelegung zu Inzidenz ausgeht, eine schlechte und ziemlich sicher falsche Vorhersage.

    Das richtige Vorgehen wäre jetzt, nachzusehen, was eigentlich diese Annahme kaputt macht (wobei: wie ich im September herausgefunden habe, war sie so ganz richtig ohnehin nie). Leider gibt es eine große Zahl möglicher Gründe, allen voran ist das natürlich die Demographie. Solange sie nicht ihre Eltern und Großeltern anstecken, können sich sehr viele Kinder mit SARS-2 infizieren, bevor das irgendwo in Intensivstatistiken sichtbar wird, während umgekehrt ein einziger Ausbruch in einem Pflegeheim mit gebrechlichen Menschen einige dutzend Intensivbetten belegen mag, was auch bundesweit schon eine Veränderung im einstelligen Prozentbereich ausmachen würde.

    Dazu kommen dann regional und nach Altersgruppen recht deutlich schwankende Impfquoten: Rasant steigende Inzidenzen in Bremen mit einer relativ stark durchimpften Bevölkerung geben ziemlich sicher ein deutlich schwächeres Signal auf Intensiv als eine rollende Welle in Sachsen, wo immer noch viele Menschen im mittleren Altersbereich ungeimpft sind und damit weit eher langwierige und kritische Verläufe nehmen werden

    Nachtrag (2021-11-25)

    Zum Thema Sachsen ist in der taz vom 25.11. zu lesen, von den dortigen 14000 PolizistInnen seien derzeit 519 SARS-2-positiv. Das ist eine 100000er-Wocheninzidenz zwischen 1500 und 4000, je nach dem, wie die zählen, und damit selbst für sächsische Verhältnisse (RKI-Inzidenz heute 1075) ziemlich sportlich.

    Mein int/inc-Maß (IntensivpatientInnen pro Inzidenzpunkt) ist aber auch empfindlich für Auswahleffekte. So wird es immer dann stark sinken, wenn systematisch getestet wird: Wenn die Dunkelziffer unerkannt Infizierter runtergeht, geht die Inzidenz im Hellfeld und damit mein Nenner hoch, ohne dass sich an der im Zähler reflektierten Realität etwas ändert. Besonders verzerrend werden sich solche Effekte auswirken, wenn systematische Tests nur demographisch oder impfstatistisch sehr auffällige Teile der Bevölkerung erreichen (sagen wir: SchülerInnen).

    In Summe: Wer derzeit aus der Inzidenzkurve Vorhersagen über die Intensivbelegung machen will, musss Impfquoten und Demographie, und damit auch die geographische Verteilung der Inzidenz, berücksichtigen, wenn das irgendwie hinkommen soll. Und das mutiert zu mehr Arbeit als ich in der Kategorie handwerk tun will.

    Bestimmt macht das irgendwer auch richtig. Aber dann: die Zahlenspielereien ändern nichts daran, dass wir Inzidenzen um 5000 haben müssten, wenn wir im nächsten Frühling durch sein wollen (100000/(5000 pro Woche) entspricht 20 Wochen oder einem knappen halben Jahr, mit Dunkelziffer also vielleicht einem Vierteljahr oder so), und auch nicht daran, dass das mit unseren augenblicklichen Techniken und Politiken ein furchtbares Gemetzel werden würde. Seufz.

  • Kohlendioxid auf dem Balkon

    Nicht offensichtlich korrelierte Kurven von CO_2, Windgeschwindigkeit und Temperatur

    CO2-Konzentrationen auf meinem Straßenbalkon, zusammen mit Windgeschwindigkeiten und Temperaturen. Das ist ein SVG, es lohnt sich also durchaus, in einem separaten Browserfenster in den Plot zu zoomen.

    Ich habe neulich eine längere Zeitreihe mit CO2-Konzentrationen auf meinem „vorderen” Balkon genommen. Zur Einordnung: Das Messgerät steht so etwa 10 Meter über und 15 Meter neben einer halbwegs viel befahrenen Straße. Ob das wohl etwas mit den wilden Schwankungen zu tun hat, die in der Kurve oben vor allem um den 9.11. herum zu sehen sind? Muss ich meine Einschätzung von neulich, einzelne Autos seien selbst im mittleren Nahbereich im CO2 kaum nachzuweisen (nun: an der frischen Luft, natürlich), revidieren?

    Verheizt jemand 100000 Tonnen Kohlenstoff am Tag?

    Wer die Kurven von Windgeschwindigkeit[1] und CO2-Konzentration vergleicht, könnte schon glauben wollen, ohne externe Frischluftzufuhr (also bei niedrigen Windgeschwindigkeiten) gehe das CO2 lokal merklich nach oben. Wirklich überzeugen kann mich aber keine Korrelation zwischen den verschiedenen geplotteten Größen.

    Darum gehe ich die Frage zunächst deduktiv an: woher könnten die enormen Schwankungen der CO2-Konzentration wohl kommen? Wir reden hier von einer Spanne zwischen 260 ppm und über 400 ppm, wobei es vorkommen kann, dass ich innerhalb von wenigen Stunden 100 ppm mehr CO2 sehe. Der langfristig ansteigende Trend macht mir übrigens weniger Sorgen: Wenn die Photosyntheserate Richtung Winter dramatisch sinkt, die Emission aber z.B. wegen Heizung eher zunimmt, ist das angesichts der beschränkten globalen Durchmischung der Atmosphäre auf der Erde zu erwarten[2], auch wenn das vielleicht nicht gerade innerhalb von zwei Wochen vonstatten gehen sollte.

    Mit den Werkzeugen aus dem Artikel zu meiner Heizleistung von neulich kann mensch abschätzen, was so eine Konzentrationsschwankung in einer lokal gut durchmischten Atmosphäre in, sagen wir, verbranntem Kohlenstoff bedeuten würde.

    Dafür muss ich erst überlegen, wie viele CO2-Teilchen ΔNCO2, oder der Bequemlichkeit halber eher welche CO2-Stoffmenge ΔnCO2 = NCO2 ⁄ A („in mol”) es braucht, um die Konzentration (in ppm, also CO2-Molekülen pro Million Teilchen insgesamt) innerhalb eines angenommenen Volumens V um das Δcppm zu erhöhen, das ich aus dem Plot ablese. Gemäß meinen Rezepten von neulich ist das:

    ΔnCO2 = (V)/(Vm)⋅Δcppm⋅106, 

    wobei Vm wieder das Normvolumen ist (22.4 Liter pro mol); das A von oben war die Avogadro-Konstante. Um herauszukriegen, wie viel Kohlenstoff (sagen wir, in Kilogramm) ich verbrennen muss, um diese Änderung quasi durch „frisches“ CO2 hinzukriegen, muss ich das nur noch mit dem Atomgewicht von Kohlenstoff uC multiplizieren.

    Das Atomgewicht ist, weil Kohlenstoffkerne meist 6 Protonoen und 6 Neutronen enthalten, mit 12 g/mol gut abgeschätzt (ganz genau ist das nicht, vor allem weil in der Atmosphäre auch etwas C-13 und sogar ein wenig C-14 herumschwebt). In dieser Kopfzahl steht das Gramm aus historischen Gründen. Das Mol wurde so definiert, dass die Zahl der Nukleonen im Kern so in etwa das Atomgewicht liefert, als in der Wissenschaft das cgs-System (aus Zentimeter, Gramm und Sekunde) seine große Zeit hatte. Würde mensch das Mol in den heutigen SI-Zeiten (na gut: die meisten AstronomInnen bleiben dem cgs verhaftet und reden zum Beispiel über Energien in erg) definieren, wäre die Avogadro-Konstante um einen Faktor 1000 (nämlich den Faktor zur SI-Einheit Kilogramm) größer.

    Wie auch immer: Wenn ich mir mal vorstelle, dass das, was ich da auf meinem Balkon messe, repräsentativ für den Umkreis von 10 km und bis in eine Höhe von 2 km wäre (mensch ahnt schon: Ich eröffne hier eine Reductio ad absurdum), komme ich auf ein Volumen von

    V = 2⋅π⋅(10  km)2⋅(2  km) ≈ 1.3⋅1012  m3

    was mit Vm ≈ 0.02 m3 ⁄  mol, einer Änderung von 100 ppm, die mensch als Sprung am 9. und 10.11. sehen kann, sowie der Formel oben auf

    ΔmC  = uC(V)/(Vm)⋅Δcppm⋅106  ≈ 0.012 kg ⁄ mol(1.3⋅1012  m3)/(0.02 m3 ⁄  mol)⋅100⋅10 − 6  ≈ 8⋅107  kg

    oder achzigtausend Tonnen verbrannten Kohlenstoff führt. Das klingt nach richtig viel und ist es auch. Aber das Volumen, das ich hier betrachte, sind eben auch 1200 Kubikkilometer, und wer sich erinnert, dass ein Kubikmeter eines normalen Gase bei Normalbedingungen um die 1 kg wiegt, kann leicht ausrechnen, dass die Luft in diesem Volumen 1.2⋅1012  kg (oder 1.2 Milliarden Tonnen – Luft in großen Mengen ist überhaupt nicht leicht) wiegen wird. Dieser ganze Kohlenstoff macht also ungefähr 0.07 Promille (oder 70 Milionstel) der Masse der Atmosphäre aus, was ganz gut mit den 100 ppm in Teilchen zusammengeht, die wir in die ganze Rechnung reingesteckt haben.

    Andersrum gerechnet

    Tatsächlich kann mensch die Kohlenstoffmasse, die eine Erhöhung der Teilchenkonzentration in einem Gasvolumen bewirkt, auch so herum abschätzen. Der Umrechnungsfaktor von Teilchen- zu Massenkonzentration ist der Faktor zwischen den Dichten von CO2 und Luft. Das Verhältnis dieser Dichten ist wiederum das der jeweiligen Atommassen, solange jedes Teilchen das gleiche Volumen einnimmt; das schließlich folgt aus der Annahme, dass die Gase ideal sind, was wiederum für unsere Abschätzungen überallhin gut genug ist.

    Für CO2 ist das mit den überwiegend vorkommenden Isotopen von Sauerstoff und Kohlenstoff 16 + 16 + 12 = 44, für Luft, wenn wir nur auf den Stickstoff N2 schauen, 14 + 14 = 28. Demnach macht 1 ppm in der Teilchenzahl von CO2 44 ⁄ 28 ≈ 1.6 ppm in der Masse aus, solange die CO2-Konzentration so gering ist, dass tatsächlich N2 die Dichte dominiert.

    Andererseits macht Kohlenstoff nur 12 ⁄ 44 ≈ 0.3 an der Masse im CO2 aus, die Zunahme an Kohlenstoff ist demnach nur ein Drittel von dem gerade berechneten 1.6, also etwas wie 0.5. Folglich werden aus 100 ppm Änderung in der Teilchenzahl etwas wie 100⋅0.5 = 50  ppm Änderung in der Masse; wer das genauer rechnet, bekommt auf diese Weise natürlich das gleiche Resultat wie oben raus.

    Wie herum mensch das auch rechnet, es ist klar, dass niemand in der kurzen Zeit so viel Kohlenstoff verbrennt. Ein schneller Reality Check: Meine Kohlendioxid-Kopfzahl war, dass die BRD 2/3 Gigatonnen im Jahr emittiert, was mit dem C/CO2-Verhältnis von 0.3 von oben ungefähr 200 Megatonnen Kohlenstoff entspricht, oder irgendwas wie gut 500000 Tonnen am Tag. Damit wäre die Zunahme, die ich hier sehe, rund ein Sechstel des gesamten Kohlenstoffbudgets der BRD, und mehr, wenn der Anstieg schneller als in einem Tag vonstatten geht: Das ist (fast) natürlich Quatsch.

    Aber was ist es dann? Noch immer gefällt mir die These ganz lokaler Schwankungen nicht. Wenn hier wirklich nur das CO2 von Autos und Heizungen nicht mehr weggepustet würde, müsste die Korrelation zwischen CO2 und Wind viel deutlicher sein.

    Ist es eine die Abgasfahne des GKM?

    Nächster Versuch: Rund 12 km westlich von meiner Wohnung läuft das Großkraftwerk Mannheim („GKM“). Wenn das Volllast fährt und meine Wohnung in seine Abgasfahne kommt, könnte das so ein Signal geben?

    Nun, so ein Kraftwerk liefert ungefähr 1 Gigawatt elektrische Leistung (wie mir der Wikipedia-Artikel dazu gerade verrät: darunter 15% des deutschen Bahnstroms), was bei einem Wirkungsgrad von 1/3 (ok, bei modernen Kohlekraftwerken ist das noch ein wenig mehr, aber als Kopfzahl taugt es) auf 3 Gigawatt thermische Leistung führt (tatsächlich nennt die Wikpedia eine Bruttoleistung von 2146 MW für das GKM).

    Aus den 394 kJ/mol, die bei der Verbrennung von Kohlenstoff frei werden (vgl. den Artikel zu meiner thermischen Leistung) könnte mensch jetzt die CO2-Emission aus der Bruttoleistung ableiten, aber ich bin mal faul und sehe beim WWF nach, der für Kraftwerke dieser Größenordnung ansagt, für eine Kilowattstunde Strom (wir sind dann also wieder bei der Nutzleistung) werde rund ein Kilogramm CO2 emittiert.

    Wenn das Kraftwerk also Volldampf (rund ein GW netto) macht, wird es etwa

    109  W⋅0.001 kg ⁄ Wh = 106 kg ⁄ h

    CO2 emittieren, also etwa 1000 Tonnen, was wiederum mit unserem 0.3-Faktor zwischen Kohlenstoff und CO2 zu einem Kohleverbrauch von 300 Tonnen pro Stunde führt.

    Damit leert das Kraftwerk unter Vollast ein Großes Rheinschiff in zehn Stunden – das scheint mir zwar schon sehr schnell zu gehen, ist aber auch nicht gänzlich unplausibel. Gegenrechnung: Das WWF-Dokument von oben nennt 7.7⋅109  kg ⁄ a als CO2-Emission des GKM im Jahr 2006. Mit der Ur-Kopfzahl π ⋅ 1e7 Sekunden pro Jahr übersetzt sich das in eine mittlere Emission von etwa 200 kg pro Sekunde oder gut 1000 Tonnen pro Stunde. Das passt fast zu gut, denn als jemand, der das Kraftwerk von seiner Leseecke aus sehen kann, kann ich zuverlässig sagen, dass das Ding keineswegs durchläuft. Andererseits hatte das Kraftwerk 2006 auch noch einen Block weniger, und überhaupt ist in der Rechnung genug Luft für Stillstandszeiten.

    Nehmen wir …

  • Keine guten Nachrichten

    Und wieder muss ich meinen Hut essen im Zusammenhang mit meinen Corona-Zahlenspielen. Ich hatte nämlich vor neun Tagen zuversichtlich vorhergesagt, so etwa jetzt sollten knapp 3500 Intensivbetten in der BRD mit SARS-2-PatientInnen belegt sein, mit dem Argument, dass sich die entsprechenden Zahlen derzeit neun Tage hinter der Inzidenz herbewegen. Da (und das war, wie unten diskutiert, ein Fehlschluss) die Inzidenz in den neun Tagen vor dem 6.11. um 44% gestiegen war, sah ich die Intensivbelegung heute bei 2332⋅1.44 ≈ 3350. Tatsächlich aber berichtet das RKI heute von nur 3034 SARS-2 IntensivpatientInnen, also um die 10% weniger als meine Vorhersage – oder 30% weniger Anstieg, um die Fehleinschätzung mal deutlicher zu machen.

    Ein Metafehler und einige Nicht-Fehler

    Es war schon ein paar Tage abzusehen, dass ich falsch liegen würde, und ich habe mir bereits letzte Woche ein paar lose Gedanken gemacht, wo wohl mein Fehler liegen könnte. Nicht angreifen konnte ich meine Argumentation aus dem Artikel, nach der die Leute, die in den vergangenen neun Tagen intensivpflichtig geworden sind, damals bereits krank waren und in diesem Sinn nicht mehr viel zu ändern sein würde.

    Ich hatte dann kurz überlegt, ob vielleicht bei der Normalisierung der Ableitungen (das incs /= sum(abs(incs)) irgendwas schief gegangen sein kann. Aber nein, eine Angabe wie „44%“ ist natürlich selbst normalisiert („pro hundert“). Der Verdacht jedoch führte schon mal in die richtige Richtung: Nachdenken über die Ableiterei und was dabei so passiert.

    Bevor ich da weiterknoble, zunächst die eigenliche Selbstbezichtung, denn was ich vor neun Tagen zumindest hätte tun sollen, wäre eine simple Validierung an den bestehenden Daten, nämlich am unmittelbar vorhergehenden 9-Tage-Intervall. Am 27.10. war die Intensivbelegung bei 1707, in den neun Tagen vor dem 6.11. war die Intensivbelegung also um 37% gestiegen. Es wäre ganz leicht gewesen, gleich nachzusehen, ob auch die Meldezahlen des RKI in den neun Tagen davor um etwas wie 37% gestiegen sind. Ich hätte festgestellt, dass sie das nicht sind – am 27.10. lag die RKI-Meldeinzidenz bei 118, am 18.10. bei 74, ein Anstieg also um satte 59% –, und das hätte mir gesagt, dass ich einen Fehler gemacht habe.

    Auch dann hätte ich vermutlich, wie heute auch, den nächsten Verdacht auf die heftige Kontamination der tageweisen Inzidenzschätzungen des RKI durch Wochenenden und Co gelenkt – schon in meinem allerersten Corona-Post hatte ich die bejammert. Vielleicht ist es ja das? Im Programm von neulich glätte ich deshalb vor der Ableitung. Die geglättete Kurve kommt am 18.10. auf 75, am 27.10. auf 120, und für den 6.11. habe ich noch keine geglätteten Daten, weil da noch zu viele Randeffekte dabei sind. Das ist sehr nah an den ungeglätteten Daten. Also, nein: Das macht repariert meine Fehlvorhersage nicht.

    Der wirkliche Fehler

    Das tatsächliche Problem liegt in der Methode, und zwar nicht in dem komplizierten Teil. Die Berechnung des Verzuges mit all dem Glätten und Ableiten ist völlig in Ordnung. Das Problem ist vielmehr, und ein wenig Nachdenken über Schulmathematik hätte mich darauf bringen können, in der Natur der Ableitung. Bei der gehen Konstanten nämlich verloren: (d)/(dx)(f(x) + C) = (d)/(dx)f(x). Ein hoher Sockel von Langzeit-IntensivpatientInnen wird bei meiner Verzögerungsrechnung einfach wegdifferenziert. Das ist ja sogar der Sinn der Differenziererei.

    Nur: Wenn ich am Schluss blind „44% mehr“ rechne, wird der Sockel (das C) mitmultipliziert, und genau da wird es falsch. Die richtige Rechnung wäre gewesen, die Differenz der Inzidenzen über die neun Tage vor dem 27.10. (von 74 auf 118) zu vergleichen mit der Differenz der Intensivbelegung der neun Tage vor dem 6.11 (von 1707 auf 2332) – dabei geht der Verzug ein, irgendwelche konstanzen Sockel spielen aber keine Rolle.

    Dieser Vergleich ergibt einen, sagen wir, 9-Tage-Übersetzungfaktor von 625 ⁄ 44 ≈ 14. In diesem stecken die Demographie der Erkrankten, die Eigenschaften des Virus, das Verhalten der Bevölkerung, und alles andere, was die mittlere Wahrscheinlichkeit bestimmt, mit einer SARS-2-Infektion intensivpflichtig zu werden. Unter der Annahme jedoch, dass der Übersetzungsfaktor über kurze Zeiten in etwa kontant ist, kann mensch jetzt die Entwicklung korrekt vorhersagen. Und zwar übersetzt sich demnach die Inzidenzentwicklung zwischen 27.10. und 6.11. (von 118 auf 164) 14-fach in die Intensivbelegung der jetzt gerade vergangenen neun Tage (das ist letztlich etwas wie ein Momentanwert von meiner int/inc-Metrik aus dem September).

    Ich hätte damit am 6.11. vorhergesagt, die Intensivbelegung würde um 46⋅16 = 644 zunehmen oder eben auf 2332 + 644 = 2976, in guter Übereinstimmung mit dem berichteten Wert von 3034.

    Blöd, dass ich nach meinen Zahlen- und Interpolationsspielen beim Zusammenbau der Vorhersage nicht aufgepasst habe. Aber es zeigt mal wieder, dass Mathe voll ist mit Fallen und ein Moment der Unaufmerksamkeit ziemlich unausweichlich zu zwanghaftem Vertilgen von Hüten führt. Und dabei hätte ich mir durch einfache Versuche, die Zukunft der Verangenheit vorherzusagen – ein sehr probates Mittel, wann immer mensch Zeitreihen analysiert – diese wenig erfreuliche Mahlzeit sparen können. Rülps.

    Aus eine physikalischen Betrachtung heraus ist diese Methode auch nicht so arg befriedigend, denn natürlich gibts bei den Meldezahlen keinen Sockel. Die sind ja selbst schon Ableitungen[1], nämlich die der Gesamtzahl der Infizierten. Die Intensivbelegung ist von der Genese her noch komplexer, da dort Zu- wie Abgänge eingehen. Insofern ist die Sache mit dem Übersetzungsfaktor zutiefst phänomenologisch und kann also aus vielen Gründen brechen.

    Schauen wir also mal, wie es in neun Tagen, am 24.11., aussieht. Meine Vorhersage wäre 3034 + (303 − 184)⋅14 = 4700. Das ist auch von der Dynamik her nicht mehr weit weg von der Höchstbelegung am 3.1.2021 (5762), und ohne ziemlich deutliche „Maßnahmen” werden wir wohl recht bald an der vorbeirauschen.

    [1]Wobei: Solange die Entwicklung exponentiell ist, ist das mit der Ableitung in diesem Kontext quasi wurst, denn die Exponentialfunktion ex ist ihre eigene Ableitung. Reale Wachstumsfunktionen über der Zeit t sehen aus wie N(1 + r)t = Neln(1 + r)⋅t, wobei r die Wachstumsrate ist (mit RKI-Zahlen R-Wert minus 1). Die Ableitung solcher Funktionen sind sie selbst mal einem konstanten Faktor, und der würde bequem in unserem Übersetzungfaktor 14 aufgehen. Wie gesagt: alles erstmal phänomenologisch.
  • Halbwegs gute Nachrichten

    Eine Kurve mit einem breitem Minimum um die 8.5

    Aus dieser Kurve lässt sich ablesen, dass wir in acht Tagen knapp 3500 SARS-2-Fälle auf Intensivstationen haben werden. Wie, verrate ich in diesem Artikel.

    In meinen Corona-Überlegungen gestern habe ich mich mal wieder gefragt, wie lange wohl die „Intensiv-Antwort“ dem Inzidenzsignal nachläuft, wie viele Tage es also dauert, bis sich ein Anstieg in den Inzidenzen in der Intensivbelegung reflektiert. Diese Frage ist, wie ich unten ausführe, derzeit ziemlich relevant im Hinblick auf Überlegungen, wie lange wir eigentlich noch Zeit haben, um massenhafte Triage in (oder vor) unseren Intensivstationen abzuwenden.

    Meine Null-Annahme für diese Verzögerung war seit Mai 2020 – nach einer entsprechenden Ansage eines befreundeten Anästhesisten – „eher so drei Wochen“. Bei nährem Nachdenken ist mir gestern aber aufgefallen, dass er wohl eher „von Infektion bis Intensiv“ gemeint haben wird, und dann ist die Antwort sicher schneller, denn von Infektion bis Meldung vergeht normalerweise wohl mindestens eine Woche. Aber: Ich muss nicht raten. Wir spielen hier mit Kennzahlen, die vielleicht in der Realität nicht immer viel bedeuten, aber zumindest klar definiert sind. Daher lässt sich der Verzug auf der Basis von RKI- und DIVI-Zahlen nachrechnen.

    Ich verrate gleich mal das Ergebnis: ich komme für die zweite Welle auf gut fünf Tage Verzug der Intensiv-Antwort, für die dritte auf etwa sieben Tage, für die vierte Welle auf acht bis neun Tage. Wie ich unten ausführe, sind das relativ gute Nachrichten.

    Zeitreihen

    Wie habe ich das gerechnet? Nun, die Korrelation von Zeitreihen ist ein ganzer Satz von Wissenschaften, bei denen es meist darum geht, ungleiche Abdeckungen, unregelmäßig gesetzte Messpunkte sowie allerlei Rauschen und Schmutz weggefummelt zu kriegen, ohne allzu viele Informationen zu verlieren oder, vielleicht schlimmer, damit Artefakte einzubauen.

    Die so gereinigten Daten lassen sich dann zum Beispiel geeignet skaliert und verschoben übereinanderlegen. Tatsächlich sind die Parameter dieser Transformationen im Regelfall (und gewissermaßen auch hier) viel interessanter als die Zeitreihen selbst[1]. Es gibt daher zahlreiche mathematische Verfahren, die das von einer Augenmaß-Übung in etwas verwandeln, das reproduzierbar und auch quantifizierbar ist. Vorsicht: ich bin da kein Experte und gehe hier nur mit nicht allzu schwer erkranktem Menschenverstand ran, verwende also (zumindest in Summe) gerade kein wirklich wohldurchdachtes Verfahren. Wer sowas wie das hier für Hausaufgaben oder Hausarbeiten verwendet, tut das auf eigene Gefahr.

    Andererseits bin ich recht zuversichtlich, dass der Kram insgesamt schon stimmt.

    Ausgangsdaten sind meine aus RKI-Berichten gescrapten Intensivbelegungen und ein RKI-Sheet (in, ach weh, „Office Open XML“ a.k.a. XSLX – muss das sein?) mit den Inzidenzen. Dabei ist das erste Problem, dass ich aus verschiedenen Gründen nicht für jeden Tag Belegungszahlen habe, und so ist mein erster Schritt, fehlende Punkte zu interpolieren. Das Scipy-Paket macht es leicht, aus einem Satz von Zeit/Wert-Paaren (die Zeit wird in den Lesefunktionen auf Sekunden seit einer Epoche gewandelt) ein handliches Array zu rechnen:

    grid_points = numpy.arange(
      raw_crits[0][0],
      raw_crits[-1][0],
      86400)  # ein Tag in Sekunden
    critnums = interpolate.griddata(
      raw_crits[:,0], raw_crits[:,1], grid_points)
    

    Ich wollte diese Interpolation eigentlich visualisieren, habe aber keine gute Stelle gefunden, an der sie einen sichtbaren Unterschied gemacht hätte, und entscheidend ist eigentlich nur, dass ich ab diesem Schritt blind mit Arrays arbeiten kann; deren Index ist zunächst die Zahl der Tage seit dem ersten Tag mit Daten, hier speziell dem 11.8.2020, denn damals habe ich mit dem Screenscrapen der DIVI-Daten angefangen.

    Übergeplottete Kurven

    Wenn ich diese interpolierten Kurven übereinanderlege, kommt das hier heraus:

    Zwei nicht so arg gut aufeinanderpassende Kurven

    Weil das, wie gesagt, erst im August 2020 anfängt, fehlt die erste Welle.

    Das bloße Auge reicht für die Bestätigung der Erwartung, dass die Intensivbelegung der Inzidenzkurve meist etwas hinterherläuft, wenn auch nicht so, dass mensch hoffen könnte, die beiden durch etwas Schieben global übereinanderzubekommen. Die großen Zacken in den Inzidenzen durch Weihnachten und Ostern finden sich in der Intensivbelegung gar nicht wieder, was ein klares Zeichen ist, dass sie weitgehend Erfassungsartefakte sind. In der Hinsicht wären die „großen“ RKI-Zahlen mit Referenzdaten (vgl. die Film-Geschichte) bestimmt besser, aber ich wollte für dieses Ding nicht die 200 Megabyte durchkämmen, zumal die „kleinen“ RKI-Daten besser auf die Meldedaten aus den Tagesberichten passen, um die es mir hier ja geht.

    Vor allem fällt auf, dass meine Jammerei darüber, dass der Impffortschritt die Intensivantwort nicht wesentlich abgeflacht hat, unzutreffend ist: Mit der Skalierung aus dem Plot liegen Inzidenz und Belegung in der zweiten und dritten Welle ziemlich übereinander, während in der vierten Welle doch ein knapper Faktor zwei dazwischenliegt; da scheint die Impfung doch ein wenig gegenüber Delta zu gewinnen (aber, klar, nirgendwo hinreichend).

    Ich hatte erwartet, dass die abfallenden Flanken der Intensivkurven deutlich flacher sind als die der Inzidenzkurven, weil Leute unter Umständen lang auf Intensiv liegen und es entsprechend lang dauern sollte, bis sich die Stationen wieder leeren. Das sieht im Abfall der zweiten Welle auch ein wenig so aus, nicht jedoch bei dem der dritten Welle. Bei ihr fällt die Intensivbelegung sehr treu mit der Inzidenz. So viele LangzeitpatientInnen gibt es glücklicherweise wohl doch nicht.

    Nach Glätten differenzierbar

    Wie kann ich jetzt den Verzug zu quantifizieren? Mein (wie gesagt eher intuitiv gefasster) Plan ist, über die Ableitung der jeweiligen Kurven zu gehen, und zwar aus der Überlegung heraus, dass mich ja Veränderungen viel mehr als Pegel interessieren. Nun habe ich aber keine differenzierbaren Funktionen, sondern lediglich Arrays, bei denen ich Ableitungen allenfalls durch Subtrahieren benachbarter Elemente simulieren kann. Solche numerischen „Ableitungen“ reagieren ziemlich empfindlich auf das Gewackel („Rauschen“), das es in realen Daten immer gibt („Subtraktion ist in der Regel numerisch schlecht konditioniert“). Deshalb will ich meine rohen Daten glätten, bevor ich die „Ableitung“ ausrechne, sprich: das Rauschen rausnehmen, ohne das Signal wesentlich zu verzerren.

    Glättung heißt eigentlich immer, Kurvenpunkte in einem Zelle für Zelle über die Daten laufenden Fenster zu mitteln, also z.B., indem mensch je fünf Nachbarpunkte rechts und links auf den aktuellen Punkt draufaddiert und ihn dann durch die durch elf geteilte Summe ersetzt. Mit diesem ganz naiven Rezept bekommen relativ weit entfernte Werte aber genauso viel Einfluss auf den aktuellen Punkt wie die unmittelbaren Nachbarn. Das modelliert meist die sachlichen Grundlagen des Rauschens nur schlecht. Es ist auch aus theoretischeren Gründen normalerweise eher ungünstig.

    Der eher theoretische Hintergrund ist grob, dass bei der Glättung letztlich zwei Funktionen gefaltet werden. Das ist äquivalent dazu, die Spektren der beiden Signale (ihre Fouriertransformierten) zu multiplizieren und dann wieder zurückzutransformieren. Bei einem einfachen Fenster des oben skizierten Typs („Rechteckfunktion“) gibts nun sehr scharfe Kanten, die wiederum zu einem sehr breiten Spektrum führen, so dass auch das Spektrum der geglätteten Funktion allerlei unwillkommene Features bekommen kann (manchmal ist das aber auch genau das, was mensch haben will – hier nicht).

    Wie auch immer: scipy macht es einfach, mit einer lärmarmen Funktion – die sieht ein wenig gaußig aus und ist im nächsten Plot im kleinen Inset zu sehen – zu glätten, nämlich etwa so:

    import numpy
    from scipy import signal
    
    smoothing_kernel = numpy.kaiser(20, smoothing_width)
    smoothing_kernel = smoothing_kernel/sum(smoothing_kernel)
    convolved = signal.convolve(arr, smoothing_kernel, mode="same"
      )[smoothing_width:-smoothing_width]
    

    Die Division durch die Summe von smoothing_kernel in der zweiten Zeile sorgt dafür, dass sich an der „Höhe“ der geglätteten Funktion insgesamt nichts ändert: Sozusagen ausgeklammert ist die Faltung eine Multiplikation mit eins. Das Wegschneiden der Ränder in der letzten Zeile wiederum entfernt Punkte, bei denen fehlende Werte am Anfang und Ende der Zeitreihe im Fenster waren. Scipy ersetzt die durch Nullen, so dass die geglätteten Werte am Rand steil abfallen. Was ich hier mache, entspricht technisch dem valid-Mode der convolve-Funktion. Nur weiß ich hier zuverlässig, wie lang das Array am Schluss ist.

    Der Effekt, hier auf Indzidenzdaten der vierten Welle:

    Zwei Kurven, eng beieinander, aber eine viel rauschiger, mit einem glockenähnlichen Inset

    Damit kann ich jetzt meine numerische „Ableitung“ bilden, ohne dass mir das Ergebnis furchtbar rauscht:

    diff = convolved[1:]-convolved[:-1]
    

    Die nächsten beiden Grafiken zeigen diese Pseudo-Ableitungen für Inzidenz und Intensivbelegung. Ich habe jeweils in blau reingemalt, wie es ohne Glättung aussehen würde, um deutlich zu machen, warum diese eine gute Idee ist und was ich mit „furchtbar rauschen“ meine. Weiterverwendet werden natürlich die orangen Verläufe:

    Zwei Kurven, eine schlimm wackelnd, die andere ruhig
    Zwei Kurven, eine schlimm wackelnd, die andere ruhig

    In der Inzidenzkurve fallen wieder Weihnachten und Ostern besonders auf, weil sie selbst in den geglätteten Graphen noch wilde Ausschläge verursachen.

    In der Zeit verschieben

    Schon der optische Eindruck aus dem Rohdaten-Plot legt nahe, die einzelnen Wellen getrennt zu untersuchen, und das ist angesichts von über die Zeit stark veränderlichen Viren, Testverhältnissen, demographischen Gegebenheiten und nichtpharamzeutischen Maßnahmen sicher auch sachlich geboten.

    Deshalb hier zunächst der Verlauf der Ableitungen von Inzidenzen und Intensivbelegung in der aktuellen vierten Welle (das ist eine Kombination der rechten Enden der orangen Graphen der letzten beiden Plots):

    Zwei Kurven, die eine der anderen recht schön folgend

    In dem Graphen steckt noch eine weitere Normalisierung. Und zwar habe ich für beide Arrays etwas wie:

    incs /= sum(abs(incs))
    

    laufen lassen. Damit ist die Fläche zwischen den Kurven …

  • Kohlendioxid und die thermische Leistung von Menschen

    Mit meinem zyTemp-Kohlendioxid-Messgerät – das, für das ich neulich Software gebastelt habe – bin ich natürlich gleich in die Welt gezogen, um mal zu sehen, wo es überall CO2 (und mithin plausiblerweise Corona-Aerosol) geben wird.

    Der Wind und die Seuche

    Nachdem mich ja zunächst sehr überrascht hat, wie deutlich sich die Anwesenheit von Menschen in rasch steigendem CO2-Gehalt der Luft in Innenräumen niederschlägt, war meine zweite große Überraschung, dass sich umgekehrt im Freien nichts tut. Also, richtig gar nichts. Selbst Autos, die mindestens eine Größenordnungen mehr CO2 emittieren als Menschen (vgl. unten), fallen schon aus ein paar Metern Entfernung im Wesentlichen nicht mehr auf. Ich musste mich schon an Kreuzungen neben die Ampeln stellen, um überhaupt ein schwaches Signal zu bekommen. Und das war kaum mehr als ein leichtes Oszillieren um ein paar ppm, während die wartenden Autos vor sich hinstanken und dann losbrausten. So sehr es nach Abgasen stank – CO2 ist im Nahbereich von Autos kein Problem.

    Die gute Nachricht ist also: Wenn CO2 ein guter Indikator ist, wie schlimm es mit Aerosol sein kann – real verschwindet Aerosol im Regelfall aus hinreichend ruhiger Luft durch Niederschlag, was CO2 nicht tut – ist praktisch sicher, dass an der frischen Luft bei nicht völlig irren Wetterlagen SARS-2 allenfalls durch Tröpfchen übertragen wird.

    Umgekehrt war meine Sorge ja immer der öffentliche Verkehr, und so habe ich mit Hingabe in verschiedenen Zügen gemessen. Als Referenz: Frischluft liegt derzeit hier irgendwo zwischen 280 und 350 ppm CO2. In einem halb vollen ICE habe ich zwischen 800 und 1400 ppm gemessen (interessanterweise nicht so ganz korreliert mit den Bahnhofsstopps; die Bahn kennend, vermute ich eine Nicht-so-ganz-wie-gedacht-Funktion der Lüftung in dem Wagen, in dem ich saß). Ein vollbesetzter IC-Zug der SBB war zwischen 800 und 1050 dabei, ein leerer Nahverkehrszug bei etwa 400, ein halb voller eher bei 700.

    Bei solchen Dynamiken ist wohl klar, dass hinreichend viel frisches Aerosol in der Luft sein wird, jedenfalls, solange nicht alle Passagiere mit richtig sitzenden FFP2-Masken dahocken, und sowas habe ich noch nicht mal dort gesehen, wo es wie in Berlin und Bayern gesetzlich gefordert ist oder war. Es muss also im letzten Winter weit mehr Ansteckungen in Zügen gegeben haben als das RKI in seinen Ausbruchshistogrammen (z.B. S. 12 am 9.3.2021) mit den kleinen roten Säulen andeutet. Aber ok, sie haben ja immer dazugesagt, „Clustersituationen in anonymen Menschengruppen (z.B. ÖPNV, Kino, Theater)“ seien fast sicher unterrepräsentiert.

    Atmende Blumen

    Aber ich hatte auch anderweitig viel Spaß mit dem Gerät. So war ich neulich verreist, und in der Wohnung verlief die CO2-Konzentration so:

    Graph mit Periodizitäten

    CO2-Konzentrationen in meinem Wohnzimmer während der Abwesenheit aller BewohnerInnen. Zeiten sind in UTC.

    Wohlgemerkt: Da war niemand. Es könnte sein, dass sich hier einfach Schwankungen in der Außenluft reflektieren; aber ich glaube zunächst mal, dass wir hier einer Birkenfeige beim Stoffwechsel zusehen; 6 Uhr UTC, wenn die Kurve sich nach unten wendet, entspricht 8 Uhr Lokalzeit und damit wohl der Zeit, in der es in dem Zimmer hell genug für Photosynthese werden dürfte; der große Peak rund um 18 Uhr am 28.9. wäre schön konsistent damit, dass die Pflanze sich zur Ruhe setzt und dazu kurz mal ihre Mitochondrien anwirft; der folgende Abfall wäre dann wieder ein Mischungseffekt, denn der Sensor lag (mehr zufällig) praktisch in den Zweigen des Ficus. Warum er, das angenommen, den Peak am 29.9. doch deutlich früher gemacht hat? Nun, vielleicht war ja Mistwetter? Oder vielleicht ist das auch alles ganz anders: das bräuchte definitiv mehr Forschung.

    Rauchmelder diagnostizieren Blasenschwäche

    Graph mit einigen Spitzen

    CO2-Konzentrationen in meiner Diele. Zeiten sind in UTC.

    Wenig überraschend zeigt sich, dass die CO2-Konzentrationen dramatisch personenbezogene Daten sind. Der zweite Graph illustriert das an einem relativ harmlosen Beispiel: Der Sensor steht jetzt in der Diele, vor meiner Zimmertür. Deutlich zu sehen ist, dass ich an dem Tag gegen 23 Uhr geschlafen habe, oder jedenfalls, dass meine Schlafzimmertür dann zu war. Und dann bin ich kurz vor zwei mal wach gewesen, weil ich am Abend etwas viel Tee getrunken hatte. am Morgen aufgestanden bin ich um sieben, kurz vor acht habe ich mal gelüftet, und um halb neun bin ich gegangen.

    Wer da etwas länger auf diese Weise zuschaut, findet viel über die BewohnerInnen von Wohungen heraus – angefangen davon, wann wie viele Menschen wo in der Wohnung sind –, und das im Zweifelsfall auch automatisiert unter vielen Menschen. Ich habe dabei lediglich zwei Messwerte pro Minute genommen. Das ginge, so würde ich schätzen, für eine ganze Weile mit den zumindest hier im Haus recht verbreiteten per Funk auslesbaren Rauchmeldern ganz gut, ohne dass ihre Batterien gleich alle wären – für die Betreiber und, weil die Krypto von den Teilen schon aus Stromspargründen sehr wahrscheinlich lausig ist, vermutlich auch ungefähr für jedeN, der/die sich hinreichend intensiv für das Leben der Anderen interessiert.

    Nachdenken nur für 50W?

    Schließlich bin ich jeden Tag wieder aufs Neue fasziniert, wie schnell ich in meinem Büro schlechte Luft verbreite.

    Graph mit zwei recht gleichmäßigen Anstiegen

    CO2-Konzentrationen in meinem Büro; ich komme von der Mittagspause zurück, arbeite, und lüfte ein Mal. Zeiten sind in UTC.

    An dieser Kurve ist viel zu sehen, unter anderem, dass sich offenbar die Luft in dem Raum doch recht schnell mischt; das würde jedenfalls schön erklären, warum es beim Lüften kurz nach 12 Uhr UTC so eine Delle nach unten gibt: Das ist die Frischluft von außen, die ziemlich direkt an den Sensor weht, sich dann aber innerhalb von fünf Minuten mit meinen im Raum gebliebenen Abgasen mischt.

    Diese schnelle Homogenisierung ist wesentlich für eine Überlegung, die sich für mich da aufdrängt: Wie viel CO2 mache ich eigentlich? Das geht so:

    In den 96 Minuten von 10:30 bis 12:06 habe ich die Konzentration von 808 auf 1245 ppm erhöht, was einer Rate von

    ((1245 − 808)  ppm)/((96⋅60)  s) = 0.077  ppm ⁄ s

    entspricht[1] (ich habe das nicht aus dem PNG, sondern noch im Plotprogramm selbst abgelesen). Ein zweiter Datenpunkt ist nach Lüften und Mischen: Da ging es von 12:17 bis 14:08 von 837 auf 1288 ppm, was auf eine Rate von 0.068 ppm/s führt.

    Aus den beiden Werten würde ich grob schätzen, dass ich die CO2-Konzentration in meinem Büro so etwa mit 0.07 ppm/s erhöhe, wenn ich normal arbeite; ich nenne diese Rate hier kurz δ. Unter der sicher falschen, aber vielleicht noch hinnehmbaren Annahme, dass kein CO2 entweicht und der nach den Beobachtungen plausiblen Annahme voller Durchmischung im Raum kann ich nun abschätzen, was mein Stoffwechsel so tut.

    Was es dazu braucht, ist das Wissen, dass bei einem idealen Gas (was die Luft nicht ist, aber für die Abschätzung reicht es) bei „Normalbedingungen“ (die bei mir im Zimmer glücklicherweise auch nicht ganz perfekt realisiert sind) ein Mol 22.4 Liter Volumen einnimmt[2]. Unter Kopfzahl-Aspekten kann ich nicht genau sagen, warum ich mir da drei Stellen gemerkt habe. In Wirklichkeit sind 20 l/mol natürlich genau genug als Kopfzahl. Ich nenne das unten Vm.

    Das ist eine Aussage über die Zahl der Gasmoleküle in einem Volumen V, denn ein Mol sind ungefähr 6e23 (so schreibe ich wieder kurz für 6⋅1023) Teilchen („Avogadro-Konstante“; außerhalb von Kopfzahlen ist die inzwischen exakt festgelegt und definiert das Mol). Mein Büro ist so in etwa fünf Meter lang, 2.5 Meter breit und drei Meter hoch, hat also V = 40 Kubikmeter Rauminhalt. Das heißt, dass sich darin

    (40  m3)/(0.0224  m3 ⁄  mol) ≈ 1800  mol

    befinden. Das sind gegen 1e27 oder 1000000000000000000000000000[3] Moleküle. Diese Zahl hat einen Namen: das ist eine Quadrillarde. Aber klar: der Name ist selbstverständlich Quatsch. Ich musste ihn selbst nachsehen. Der wissenschaftliche Fachbegriff für solche Zahlen ist Gazillion. Für alle davon. Weshalb wir eben immer zehn hoch siebenundzwanzig sagen, was viel nützlicher ist.

    Und dann brauche ich noch die Energie (oder hier genauer die Enthalpie, normalerweise geschrieben als ΔH) die bei der Bildung eines Moleküls CO2 auch C und O₂ frei wird; konventionell geben die Leute das nicht für ein Molekül, sondern für ein ganzes Mol (ihr erinnert euch: ganz platt 6e23 Moleküle statt nur eins) an, und die Wikipedia verrät, dass das 394 kJ/mol sind.

    Jetzt baue ich das zusammen, nämlich die Erzeugungsrate von CO2 in physikalischen Einheiten (statt in ppm/s), δV ⁄ Vm, auf der einen Seite, und mein ΔH auf der anderen Seite. Es ergibt sich für meine Leistung:

    P = ΔHδV ⁄ Vm

    Wenn mensch da die Einheiten glattzieht und bedenkt, dass ppm/s eigentlich 1e-6/s ist, muss mensch was rechnen wie:

    P = 394⋅103  J ⁄ mol⋅0.07⋅10 − 6 ⁄  s⋅40  m3 ⁄ (0.0224  m3 ⁄  mol)

    (ich schreibe das so ausführlich, weil ich mich beim schnellen Hinschreiben prompt verrechnet habe), was rund 50 J/s (also 50 W) ergibt.

    Ich habe von irgendwoher im Kopf, dass ein …

  • Wahlen und Informationstheorie

    Ich hatte neulich versprochen, ein paar Worte zu Zweifeln am repräsentativen Modell zu sagen, die sich aus der Informationstheorie speisen. Dazu braucht es zunächst einen Begriff von Information, und um den definieren zu können, ein Modell von Nachrichtenübertragung, in diesem Fall etwa: eine Wahl überträgt die Wünsche zur Organisation der Gesellschaft von Wählenden an die Macht.

    Information: Nachrichten in Bits gemessen

    Wie viel Information steckt nun in den Wunschlisten dieses Modells? Nun, Information – gemessen in Bit – lässt sich recht anschaulich definieren als die Zahl der ja/nein-Fragen, die mensch bei optimaler Fragestrategie im schlimmsten Fall stellen muss, um einer Menge verschiedener Nachrichten eine ganz bestimmte Nachricht rauszufiltern.

    Wenn die Wahl heißt „Parkplätze zu Parks?“ und sonst nichts, reicht eine solche Frage, und mithin wird ein Bit Information übertragen. Kommt als zweite Frage hinzu „Lebkuchen subventionieren?“, braucht es zwei Fragen und mithin Bit, um die kompletten Wünsche zu übertragen.

    Wenn mensch das fortführt, ergibt sich: Für ein komplettes Programm mit n binären Entscheidungen braucht es naiv erstmal n bit Information. Diese n bit reichen aus, um 2n Programme zu kodieren, nämlich alle Kombinationen von ja/nein Entscheidungen über die n Fragen hinweg. Wenn es nur die Parkplätze und die Lebkuchen von oben gäbe, wären das beispielsweise:

    • für Parkplätze/für Lebkuchen
    • für Parkplätze/gegen Lebkuchen
    • gegen Parkplätze/für Lebkuchen
    • gegen Parkplätze/gegen Lebkuchen

    Nochmal: Mit n bits kann ich 2n verschiedene Nachrichten (hier also Programme oder Wunschzettel) auseinanderhalten.

    Das kann mensch jetzt rückwärts aufziehen. Um den Informationsgehalt einer Nachricht herauszubekommen, muss mensch sehen, wie viele verschiedene Nachrichten es gibt und diese Zahl dann als 2x darstellen. Das x in diesem Ausdruck ist der Informationsgehalt in Bit. Das x braucht mensch nicht zu raten, denn es ist nichts anderes als der Logarithmus der Zahl der verschiedenen Nachrichten, genauer der Zweierlogarithmus (meist als ld geschrieben). Wenn euer Taschenrechner den nicht kann: ld x = ln x/ln 2 – aber letztlich kommts nicht so drauf an, denn ln 2 ist nicht viel was anderes als eins. Profis schenken sich sowas.

    Pop Quiz: Wie viele Bits braucht ihr, um eine von 1000 Nachrichten rauszufummeln? (Ungefähr 10). Wie viele, um eine von 1'000'000'0000 zu kriegen? (Ungefähr 30; ihr seht, der Logarithmus wächst sehr langsam).

    Nicht gleichverteilt, nicht unabhängig

    In Wahrheit ist das mit der Information etwas komplizierter. Stellt euch vor, zur Parkplatz-Lebkuchen-Programmatik käme jetzt die Frage „Vorrang für FußgängerInnen auf der Straße?“. Wer die Antwort einer Person auf die Parkplatz-Frage kennt, dürfte recht zuverlässig vorhersagen können, wie ihre Antwort auf die Vorrang-Frage aussehen wird.

    Mathematisch gesprochen sind die beiden Entscheidungen nicht unabhängig, und das führt dazu, dass mensch durch geschicktes Fragen im Schnitt deutlich weniger als drei Fragen brauchen wird, um das komplette Programm mit den drei Antworten rauszukriegen, etwa, indem mensch zusammen nach Parkplätzen und Vorrang fragt. Dieser Schnitt liegt irgendwo zwischen 2 und 3 – für die Mathematik (und den Logarithmus) ist es kein Problem, Fragen auch hinter dem Komma zu zählen: 2.3 bit, vielleicht (ich bin immer wieder erstaunt, wie viele Menschen noch gewillt sind, Parkplätze hinzunehmen, während der Vorrang für FußgängerInnen doch hoffentlich unbestrittener Konsens in der zivilisierten Welt ist[1]).

    Ein ähnlicher Effekt ergibt sich, wenn bestimmte Antworten viel wahrscheinlicher sind als andere. Wenn es z.B. zwei Texte A und B gibt, die jeweils 45% der Nachrichten ausmachen, bekomme ich in 90% der Fälle die Nachricht in nur zwei Fragen raus („Eins von A oder B?“, worauf zu 90% schlicht „A?“ reicht, um die gewählte Nachricht rauszukriegen), ganz egal, ob es noch 10 oder 10'000'000'000 andere Nachrichten gibt.

    Die Sache mit „Information in bit rechnest du als den Logarithmus der Zahl der verschiedenen Nachrichten aus“ gibt also eine Obergrenze für den Informationsgehalt. Sie wird erreicht wenn die Nachrichten gleichverteilt sind (und in gewissem Sinn in sich unabhängig; besser verständlich wird der Unabhängigkeits-Teil, wenn mensch nicht eine Nachricht, sondern eine Folge von Nachrichten betrachtet). Wer wissen will, wie das richtig geht, sei auf die Wikipedia verwiesen.

    Das ganz einfache Modell unabhängiger, gleichverteilter Nachrichten von oben gilt in der Regel nicht – in natürlichsprachigen Texten sind z.B. die Buchstabenhhäufigkeiten drastisch verschieden (Scrabble-SpielerInnen kennen das), und es gibt allerlei Regeln, in welchen Reihenfolgen Buchstaben kommen können. Eine erstaunlich effektive Schätzung für den Informationsgehalt von Nachrichten ist übrigens, einfach mal gzip laufen zu lassen: Für diesen Text bis hierher kommt da 2090 Bytes (á 8 bit) raus, während er auf der Platte 4394 Bytes braucht: Was gzip da geschluckt hat, sind die Abweichungen von Gleichverteilung und Unabhängigkeit, die so ein dummes Computerprogramm leicht finden kann.

    Klar: auch die 2090 ⋅ 8 bit sind höchst fragwürdig als Schätzung für den Informationsgehalt bis hier. Wenn die Nachrichtenmenge „alle bisherigen Blogposts hier“ wäre (davon gibt es etwas weniger als 100), wären es nur sechseinhalb Bit, ist sie „Zeug, das Anselm Flügel schreibt“, wäre es zwar mehr, aber immer noch klar weniger als die 16720 Bit, trotz aller Exkurse über Information und Logarithmen[2]. Informationsgehalt ist nur im Kontext aller anderen möglichen Nachrichten gut definiert. Und dem, was bei EmpfängerInnen ankommt, was bei diesem Post für SchurkInnen auch nur ein Bit sein kann: „Alles Mist“.

    Wie viele bit in einem Wahlzettel?

    Euer Wahlzettel bei der Bundestagswahl neulich dürfte so um die zwei Mal sechzehn Möglichkeiten gehabt haben, etwas anzukreuzen. Im besten Fall – unabhängige Parteien mit gleichen Erfolgschancen – könntet ihr also 8 bit übertragen mit euren zwei Kreuzen. In Wahrheit sorgt schon die 5%-Hürde dafür, dass es allenfalls 8 Listen gibt, die in der Logik repräsentativer Regierungsbildung wählbar sind, und dann noch vielleicht eineN von vier DirektkandidatInnen, die auch nur irgendeine Chance haben. Zusammen, schätze ich (immer noch optimistisch), vielleicht drei Bit.

    Vergleicht das mit den Nachrichten, die so eine Regierung aussendet: So redundant und erwartbar da auch viel sein mag, kein gzip dieser Welt wird die Gesetze, Verordnungen und Exekutivakte von Regierung und Parlament in der letzten Legislaturperiode auf irgendwas unter 100 Megabyte bringen können, selbst wenn es, das Kompressionsprogramm, Politik und Jura schon kann. Gesetze wie das zur Bestandsdatenauskunft etwa sind völlig beliebig: sie setzen einfach Wünsche der Polizeien um und kümmern sich weder um Verfassungen noch um Sinn, und sie würden deutlich anders aussehen, wenn bei BKA, Innenministerium und Polizeiverbänden gerade andere Individuen am Werk gewesen wären. Beliebigkeit ist aber nur ein anderes Wort für Unabhängigkeit und Gleichverteilung. Die 100 Megabyte werden also eine harte untere Grenze sein.

    Bei einem Verhältnis von rund drei Bit rein zu mindestens 100 Megabyte raus (in Worten: eins zu zweihunderfünfzig Millionen, weit unter der Gewinnchance beim 6 aus 49-Lotto) ist evident, dass Wahlen gewiss kein „Hochamt der Demokratie“ sind; ihr Einfluss auf konkrete Entscheidungen wäre auch dann minimal, wenn bei realen Wahlen viel entschieden würde.

    Was natürlich nicht der Fall ist. Niemand erwartet ernsthaft, dass eine Wahl irgendetwas ändert an wesentlichen Politikfragen, hierzulande beispielsweise Reduzierung des Freihandels, Zurückrollen von Privatisierungen, Abschaffung des Militärs, Befreiung der Menschen von der Autoplage, weniger autoritäres Management sozialer Spannungen (z.B. durch weniger übergriffige Polizeigesetze), weniger blutige Staatsgrenzen, weniger marktförmige Verteilung von Boden, kein Wachstum bis zum Kollaps und so weiter und so fort; praktisch die gesamte Bevölkerung hat in allen diesen Punkten die bestehende Regierungspolitik bestätigt, obwohl sie manifest ihren Interessen oder zumindest ihrem moralischen Empfinden widerspricht.

    Warum Wahlen wichtig sind

    Entsprechend tut in den gegenwärtigen Koalitionsverhandlungen nicht mal wer so, als ginge es um mehr als um Selbstverständlichkeiten wie Tempolimits auf Autobahnen (stellt euch mal kurz vor, wie unfassbar bizarr das auf in 100 Jahren eventuell noch lebende Menschen wirken muss).

    Was nicht heißt, dass Wahlen nicht wichtig sind. Die ganz zentrale Funktion von Wahlen dieser Art hat neulich im Deutschlandfunk ein gewisser Andrej Kolesnikow am Beispiel Russland erläutert:

    Die Wahl soll vor allem das Staatsmodell legitimieren, das sich in Russland entwickelt hat. Sie ist deshalb für die Staatsmacht wichtiger als für die Bürger. Die Wahl soll den Menschen auch vor Augen führen, dass die Staatsmacht weiterhin über eine Mehrheit verfügt und dass es besser ist, sich dieser Mehrheit anzuschließen, oder, wenn jemand unzufrieden ist, wenigstens ruhig zu bleiben und seine Unzufriedenheit für sich zu behalten.

    Wer aus ein paar Schritt Entfernung auf die hiesigen Verhältnisse blickt, wird diese Beobachtung auch hierzulande im Wesentlichen bestätigt sehen. Versteht mich nicht falsch: Das ist durchaus wichtig. Ein delegitimierter Staat geht schnell in eine kaputte Gesellschaft über, solange wir es nicht hinbekommen, Menschen auch ohne Nationalgeklingele zu rationalem, sprich kooperativem Verhalten zu bekommen (nicht, dass ich glaube, dass das sehr schwer wäre; es würde aber jedenfalls andere Schulen brauchen). Etwas von dieser Delegitimation sehen wir schon hier, verglichen mit den 1980er Jahren jedenfalls, etwas mehr in den USA, und noch viel mehr im, sagen wir, Libanon. Und etwas weniger als hier in Dänemark oder Schweden. Ich mache kein Geheimnis daraus, wo auf diesem Spektrum ich lieber leben will.

    Allerdings: diese Legitimationsfunktion der Wahl funktioniert weitgehend unabhängig von politischer Partizipation. Auch die finstersten autoritären Regimes halten Wahlen ab und wollen diese in aller Regel auch recht ehrlich …

  • Die Viren loben

    „Jetzt ist aber wirklich höchste Zeit, dass Corona endlich mal weggeht“ ist inzwischen ein universelles Sentiment, und auch mich lockt gelegentlich die autoritäre Versuchung, einen „harten Lockdown“ zu wünschen, damit das Ding weggeht (was es natürlich nicht täte). Der Hass auf SARS-2 steigt, und damit womöglich auf Viren allgemein.

    In der Tat scheinen Viren erstmal richtig doof, eklig und widerwärtig. Wie scheiße ist das eigentlich, sich von den Zellen vertrauensvoll aufnehmen zu lassen und dann den Laden zu übernehmen mit dem einzigen Ziel, neues Virus zu machen? Und dann die Ähnlichkeit von z.B. der T2-Bakteriophage mit Invasoren vom Mars...

    Andererseits bin ich überzeugt, dass eine gewisse Anfälligkeit gegen Viren wahrscheinlich ein evolutionärer Vorteil ist. Da gibts bestimmt jede Menge echte Wissenschaft dazu, aber ich denke, eine einfache Intiution geht auch ohne: Praktisch alle Viren nämlich wirken nur auf kurze Distanz in Zeit und Raum (verglichen etwa mit Pflanzenpollen, aber sogar mit vielen Bakterien), werden also im Wesentlichen bei Begegnungen übertragen. Da die Wahrscheinlichkeit von Begegnungen mit dem Quadrat der Bevölkerungsdichte geht, sollten Viren explodierende Populationen „weicher“ begrenzen als leergefressene Ressourcen und so wahrscheinlich katastrophalen Aussterbeereignissen vorbeugen.

    Vorneweg: Ja, das klingt alles erstmal wild nach Thomas Malthus. Dessen Rechtfertigung massenhaften Sterbenlassens ist natürlich unakzeptabel (ebenso allerdings wie das fortgesetzte Weggucken von den Meadows-Prognosen, die in der Regel auch katastrophale Zusammenbrüche erwarten lassen).

    Dies aber nicht, weil falsch wäre, dass in endlichen Systemen der Ressourcengebrauch nicht endlos steigen kann; das ist nahe an einer Tautologie. Nein, Malthus' Fehler ist der der Soziobiologie, nämlich menschliche Gesellschaft und menschliches Verhalten an Funktionsweisen der Natur auszurichten. Wer das will, wird recht notwendig zum Schlächter, während umgekehrt die Geschichte der letzten 100 Jahre überdeutlich zeigt, wie (sagen wir) Wachstumszwänge diverser Art durch mehr Bildung, mehr Gleichheit und vor allem durch reproduktive Selbstbestimmung von Frauen ganz ohne Blutbad und unter deutlicher Hebung der generellen Wohlfahrt zu beseitigen sind.

    Bei Kaninchen ist das aber, da muss ich mich leider etwas als Speziezist outen, anders. Und daher habe ich mir Modellkaninchen für ein weiteres meiner Computerexperimente herausgesucht, ganz analog zu den Schurken und Engeln.

    Die Fragestellung ist: Werden Ausschläge in Populationen wirklich weniger wild, wenn Viren (also irgendwas, das Individuen nach Begegnungen mit einer gewissen Wahrscheinlichkeit umbringt) im Spiel sind?

    Um das zu untersuchen, baue ich mir eine Spielwelt (wer mag, kann auch „modifiziertes Lotka-Volterra-Modell“ dazu sagen) wie folgt:

    • Es gibt 1000 Felder, auf denen Gras wachsen kann oder nicht.
    • In der Welt leben Kaninchen, die pro Periode ein Grasfeld leerfressen müssen, damit sie glücklich sind.
    • Haben Kaninchen mehr Gras als sie brauchen, vermehren sie sich, und zwar um so mehr, je mehr Extrafutter sie haben (so machen das zumindest Rehe).
    • Haben Kaninchen zu wenig Gras, sterben ein paar.
    • In jeder Periode verdoppelt sich die Zahl der Grasfelder (sagen wir: durch Aussaat), bis alle 1000 Felder voll sind.

    In Code sieht die Berechnung der Vermehrungsrate der Kaninchen so aus:

    def get_growth_factor(self):
      grass_per_rabbits = self.grass/self.rabbits
      if grass_per_rabbits<1:
        return grass_per_rabbits**2
      else:
        return 1+math.sqrt(grass_per_rabbits-1)
    

    Wer den Verlauf der Vermehrungsrate mit dem Gras/Kaninchenverhältnis γ auf der Abszisse sehen will:

    Um dieses Modell zu rechnen, habe ich ein kleines Python-Programm geschrieben, lv.py, das, mit anfänglichen Zahlen von Gras und Kaninchen aufgerufen, den Verlauf der jeweiligen Populationen im Modell ausgibt (nachdem es die Anfangsbedingungen etwas rausevolvieren hat lassen).

    Wie bei dieser Sorte von Modell zu erwarten, schwanken die Populationen ziemlich (außer im Fixpunkt Kaninchen=Gras). So sieht das z.B. für python3 lv.py 400 410 (also: anfänglich ziemlich nah am Gleichgewicht) aus:

    Das sieht nicht viel anders aus, wenn ich mit einem Kaninchen-Überschuss anfange (python3 lv.py 400 800):

    oder mit einem Gras-Paradies (python3 lv.py 800 150):

    Aus Modellsicht ist das schon mal fein: Recht unabhängig von den Anfangsbedingungen (solange sie im Rahmen bleiben) kommen zwar verschiedene, aber qualitativ doch recht ähnliche Dinge raus: die Kaninchenpopulationen liegen so zwischen 250 und 600 – im anfänglichen Gras-Paradies auch mal etwas weiter auseinander – und schwanken wild von Schritt zu Schritt.

    Jetzt baue ich einen Virus dazu. Im lv.py geht das durch Erben vom LV-Modell, was auf die LVWithVirus-Klasse führt. Diese hat einen zusätzlichen Parameter, deadliness, der grob sagt, wie wahrscheinlich es ist, dass ein Kaninchen nach einer Begegnung mit einem anderen Kaninchen stirbt. Die Mathematik in der propagate-Methode,

    def propagate(self):
      LV.propagate(self)
      self.rabbits = max(1, self.rabbits-self.rabbits**2*self.deadliness)
    

    würde etwa einem Bau entsprechen, in dem sich alle Kaninchen ein Mal pro Periode sehen. Das ist jetzt sicher kein gutes Modell für irgendwas, aber es würde mich sehr überraschen, wenn die Details der Krankheitsmodellierung viel an den qualitativen Ergebnissen ändern würden. Wichtig dürfte nur sein, dass die Todesrate irgendwie überlinear mit der Population geht.

    lv.py lässt das Modell mit Virus laufen, wenn es ein drittes Argument, also die Tödlichkeit, bekommt. Allzu tödliche Viren löschen die Population aus (python3 lv.py 800 150 0.05):

    Zu harmlose Viren ändern das Verhalten nicht nennenswert (python3 lv.py 800 150 1e-6):

    Interessant wird es dazwischen, zum Beispiel python3 lv.py 800 150 2.1e-4 (also: rund jede fünftausendste Begegnung bringt ein Kaninchen um):

    – wer an die Beschriftung der Ordinate schaut, wird feststellen, dass die Schwankungen tatsächlich (relativ) kleiner geworden sind. Das Virus wirkt offenbar wirklich regularisierend.

    Wir befinden uns aber im Traditionsgebiet der Chaostheorie, und so überrascht nicht, dass es Bereiche der Tödlichkeit gibt, in denen plötzlich eine starke Abhängigkeit von den Anfangsbedingungen entsteht und sich die Verhältnisse weit in die Entwicklung rein nochmal grundsätzlich ändern können („nicht-ergodisch“). So etwa python3 lv.py 802 300 0.0012:

    gegen python3 lv.py 803 300 0.0012:

    Ein Kaninchen weniger am Anfang macht hundert Schritte später plötzlich so ein gedrängeltes, langsames Wachstum.

    Warum ich gerade bei 0.0012 geschaut habe? Nun ich wollte einen Überblick über das Verhalten bei verschiedenen Tödlichkeiten und habe darum stability_by_deadliness.py geschrieben, das einfach ein paar interessante Tödlichkeiten durchprobiert und dann die relative Schwankung (in Wirklichkeit: Standardabweichung durch Mittelwert) und den Mittelwert der Population über der Virustödlichkeit aufträgt:

    – das sieht sehr gut aus für meine These: Mit wachsender Tödlichkeit des Virus nimmt die relative Streuung der Population ab, irgendwann allerdings auch die Population selbst. Ganz links im Graphen gehts durcheinander, weil sich dort chaotisches Systemverhalten mit kleinen Zahlen tifft, und dazwischen scheint es noch ein, zwei Phasenübergänge zu geben.

    Leider ist dieses Bild nicht wirklich robust. Wenn ich z.B. die Anfangsbedingungen auf 600 Gras und 250 Kaninchen ändere, kommt sowas raus:

    – die meisten der Effekte, die mich gefreut haben, sind schwach oder gar ganz weg – wohlgemerkt, ohne Modelländerung, nur, weil ich zwei (letztlich) Zufallszahlen geändert habe.

    Mit etwas Buddeln findet mensch auch das Umgekehrte: wer immer mit 170 Gras und 760 Kaninchen anfängt, bekommt einen Bereich, in dem die Populationen mit Virus größer sind als ohne, während gleichzeitig die relative Schwankung nur noch halb so groß ist wie ohne Virus. Dazwischen liegt ein 1a Phasenübergang:

    Mensch ahnt: da steckt viel Rauschen drin, und auf der anderen Seite höchst stabiles Verhalten, wo mensch es vielleicht nicht erwarten würde (bei den hohen Tödlichkeiten und mithin kleinen Zahlen). Wissenschaft wäre jetzt, das systematisch anzusehen (a.k.a. „Arbeit“). Das aber ist für sehr ähnliche Modelle garantiert schon etliche Male gemacht worden, so dass der wirklich erste Schritt im Jahr 51 nach PDP-11 erstmal Literatur-Recherche wäre.

    Dazu bin ich natürlich zu faul – das hier ist ja nicht mein Job.

    Aber das kleine Spiel hat meine Ahnung – Viren stabilisieren Ökosysteme – weit genug gestützt, dass ich weiter dran glauben kann. Und doch wäre ich ein wenig neugierig, was die Dynamische-Systeme-Leute an harter Wissenschaft zum Thema zu bieten haben. Einsendungen?

  • Schurken und Engel, Teil 2

    Ich bin gestern nochmal der Sache mit den Schurken und Engeln von neulich nachgegangen, denn auch wenn die grundsätzliche Schlussfolgerung – wenn du Chefposten kompetetiv verteilst, kriegst du ziemlich wahrscheinlich Schurken als Chefs – robust ist und ja schon aus der dort gemachten qualitativen Abschätzung folgt, so gibt es natürlich doch jede Menge interessante offene Fragen: Setzen sich Schurken drastischer durch wenn die Engeligkeit steiler verteilt ist? Wie sehr wirkt sich der Vorteil für die Schurken wirklich aus, vor allem, wenn sie auch nur eine endliche Lebensdauer haben? Wie ändern sich die Ergebnisse, wenn Leute zweite und dritte Chancen bekommen, mal wie ein richtiger Schurke Karriere zu machen? Wie verändert sich das Bild, wenn mensch mehr Hierarchiestufen hinzufügt?

    Weil das alte Modell mit der einen Kohorte, die bei jedem Schritt um den Faktor 2 eindampft, für solche Fragen zu schlicht ist, muss ein neues her. Es hat den Nachteil, dass es viel mehr Code braucht als das alte – es hat aber der Vorteil, dass es im Prinzip beliebig lang laufen kann und über einen weiten Bereich von Parametern hinweg stationär werden dürfte, sich also der Zustand nach einer Weile (der „Relaxationszeit“) nicht mehr ändern sollte – natürlich vom Rauschen durch die diskrete Simulation abgesehen. Wem also das alte Modell zu schlicht und langweilig ist: Hier ist sunde2.py.

    Das Neue

    Wie sieht das Modell aus? Nun, wir haben jetzt simultan einen ganzen Haufen N von Hierarchiestufen, die auch immer alle besetzt sind; derzeit habe ich konstant N = 50. Von Stufe zu Stufe ändert sich jetzt die Population nicht mehr je um einen Faktor zwei, sondern so, dass die unterste Stufe 16-mal mehr Aktoren hat als die oberste und die Besetzungszahl dazwischen exponentiell geht. Diese Schicht-Statistik sollte keinen großen Einfluss auf die Ergebnisse haben, hält aber einerseits die Zahl der zu simulierenden Aktoren auch bei tiefen Hierarchien im Rahmen, ohne andererseits auf den oberen Ebenen die ganze Zeit mit allzu kleinen Zahlen kämpfen zu müssen.

    Aktoren haben jetzt auch ein Alter; sie sterben (meist) nach LN Runden; L kann interpretiert werden als die Zahl der Versuche pro Wettbewerb, die ein Aktor im Mittel hat, wenn er ganz nach oben will. Im Code heißt das lifetime_factor (hier: Lebenzeit-Faktor), und ich nehme den meist als 2 („vita brevis“).

    Es gibt eine Ausnahme auf der strikten Lebenszeitbegrenzung: Wenn ein Level sich schon um mehr als die Hälfte geleert hat, überleben die, die noch drin sind, auch wenn sie eigentlich schon sterben müssten. An sich ist diese künstliche Lebensverlängerung nur ein technischer Trick, damit mir der Kram mit ungünstigen Parametern und bei der Relaxation nicht auf interessante Weise um die Ohren fliegt; es kann nämlich durchaus sein, dass die oberen Ebenen „verhungern“, weil Aktoren schneller sterben als befördert werden. Er hat aber den interessanten Nebeneffekt, dass speziell in Modellen mit kleinem L wie in der Realität die Lebenserwartung der höheren Klassen höher ist als die der unteren.

    Um die Gesamtzahl der Aktoren konstant zu halten, werden in jeder Runde so viele Aktoren geboren wie gestorben sind, und zwar alle in die niedrigste Schicht.

    Das enspricht natürlich überhaupt nicht der Realität – schon die Zahlen zur Bildungsbeteiligung gegen Ende des Posts Immerhin gegen Ende zeigen ja, dass viele Menschen mitnichten bei Null anfangen in ihrem gesellschaftlichen Aufstieg. Insofern hätte mensch darüber nachdenken können, bestehende Aktoren irgendwie fortzupflanzen. Das aber hätte eine Theorie zum Erbgang von Schurkigkeit gebraucht (die auch dann nicht einfach ist, wenn mensch wie ich da wenig oder keine biologische Komponenten vermutet) und darüber hinaus den Einbau von Abstiegen in der Hierarchie erfordert.

    Die zusätzliche Komplexität davon wäre jetzt nicht dramatisch gewesen, aber das kontrafaktische „alle fangen bei Null an“ residiert als „Chancengleichheit“ auch im Kern der modernen Wettbewerbsreligion. Für ein Modell – das ohnehin in einer eher lockeren Beziehung zur Wirklichkeit steht – ist sie daher genau richtig. Sollten übrigens in der Realität Kinder von eher schurkigen Menschen auch tendenziell eher schurkig werden, würde das die Anreicherung von Schurkigkeit gegenüber dem chancengleichen Modell nur verstärken.

    Das Alte

    Der Rest ist wie beim einfachen Modell: da es gibt den Schurken-Vorteil, die Wahrscheinlichkeit, dass ein Aktor, der gerade schurkig ist, gegen einen, der gerade engelig ist, gewinnt. Dieser rogue_advantage ist bei mir in der Regel 0.66.

    Der letzte Parameter ist die Verteilung der Schurkigkeit (also der Wahrscheinlichkeit, dass sich ein Aktor in einem Wettbewerb als Schurke verhält). Dazu habe ich wie zuvor eine Gleichverteilung, Exponentialverteilungen der Schurkigkeit mit verschidenen λ (also: gegenüber der Gleichverteilung sind mehr Aktoren Engel, wobei die allerdings alle Schurkeigkeiten über 1 auf 1 beschnitten werden; für kleine λ wird das also schwer zu interpretieren) und Normalverteilungen reingebaut, dieses Mal aber viel expliziter als im einfachen Modell des letzten Posts.

    Ich hatte eigentlich vor, den Kram immer laufen zu lassen, bis er „stationär“ würde, also sagen wir, bis der Schurkigkeits-Gradient in den mittleren Schichten sich von Runde zu Runde nicht mehr wesentlich ändert. Stellt sich aber raus: durch die relativ überschaubaren Aktor-Zahlen und die Dynamik der Gesellschaft, in der ja per Design viel Aufstieg stattfindet, rauschen die Metriken, die ich da probiert habe, zu stark, um guten Gewissens sagen zu können, jetzt sei das Ding relaxiert (im Code: DiffingWatcher).

    Was passiert?

    Stattdessen lasse ich die Modelle jetzt erstmal laufen, bis die (gleichverteilte) Anfangspopulation weitgehend ausgestorben ist (nämlich NL Runden) und ziehe dann nochmal für NL Runden Statistiken, vor allem die mittlere Schurkigkeit in Abhängigkeit von der Hierarchieebene. Die kann ich dann übereinanderplotten, wobei ich die Zeit durch den Grauwert einfließen lasse (spätere, wahrscheinlich etwas relaxiertere, Zustände sind dunkler):

    Dabei ist auf der Abszisse die mittlere Hierarchieebene, auf der Ordinate die mittlere Schurkigkeit auf der entsprechenden Ebene; die Zeit ist, wie gesagt, durch den Grauwert der Punkte angedeutet und sorgt für die Streuung.

    Am auffälligsten ist wohl, dass Schurkigkeit auf den letzten paar Stufen am drastischsten ansteigt. Das hätte ich in dem Ausmaß nicht erwartet und deckt sich jedenfalls nach meiner Erfahrung nicht mit irgendwelchen Realitäten (in denen die Schurkigkeit schon auf nur moderat schwindelerregenden Ebenen rapide wächst). Ich komme gegen Ende nochmal etwas quantitativer auf die Steilheit des Anstiegs zurück.

    Hier, wie auch sonst, sind die Modelle bezeichnet durch einen String – sunde2.py verwendet ihn als Dateinamen –, der aus einer Bezeichnung der Verteilung (hier Exponential mit λ=4), der Zahl der Level N, dem Schurken-Vorteil und dem Lebenszeit-Faktor L besteht.

    Eine andere Art, diese Daten anzusehen, die insbesondere etwas mehr von der Dynamik erahnen lässt, ist eine Heatmap der Schurkigkeit; hier laufen die Hierarchieebenen auf der Ordinate, die Zeit auf der Abszisse; aus Bequemlichkeitsgründen hat hier die höchste Ebene mal die Bezeichnung 0 (so ist das übrigens auch im Programm gemacht, in den anderen Grafiken ist dagegen Ebene 50 das Nüßlein-Territorium):

    In-joke: Regenbogen-Palette. Ich habe gerade frei, ich darf das.

    Hier lässt sich ganz gut erkennen, dass der Kram nach einer maximalen Lebensdauer (da fängt die Grafik an) weitgehend relaxiert ist, und wieder, dass die letzten paar Hierarchieebenen die dramatischsten Schurken-Konzentrationen aufweisen. Die schrägen Strukturen, die überall sichtbar sind, sind zufällige Schurken-Konzentrationen auf der Karriereleiter. Intuitiv wäre wohl zu erwarten, dass sich Engel in Haifischbecken eher noch schwerer tun und so Schurkigkeitszonen selbstverstärkend sein könnten. Insofern ist die relativ geringe Streifigkeit der Grafik – die sagt, dass das wenigstens im Modell nicht so ist – erstmal eher beruhigend.

    Umgekehrt bilde mich mir ein, dass im unteren Bereich der Grafik einige blauere (also: engeligere) Strukturen deutlich flacher als 45 Grad laufen: Das könnten Engel-Konzentrationen sein, die gemeinsam langsamer die Karriereleiter besteigen. Fänd ich putzig (wenns die Karriereleiter denn schon gibt), kann aber auch nur überinterpretiertes Rauschen sein.

    Und noch eine Auswertung von diesem spezifischen Modell: Alter über Hierarchieebene, was angesichts des aktuellen Alte-weiße-Männer-Diskurses vielleicht interessant sein mag:

    Diese Abbildung funktioniert so wie die der mittleren Schurkigkeit, nur ist auf der Ordinate jetzt das Alter statt der Schurkigkeit. In dem Modell leben Aktoren ja zwei Mal die Zahl der Hierarchieebenen Runden, hier also 100 Runden. Die Aktoren ganz unten sind erkennbar deutlich jünger als der Schnitt (der bei 50 liegt), ganz oben sammeln sich alte Aktoren. Klingt speziell in dieser Ausprägung, in der oben wirklich nur Aktoren kurz vom Exitus sind, irgendwie nach später Sowjetunion, und klar ist das Modell viel zu einfach, um etwas wie die City of London zu erklären.

    Note to self: Beim nächsten Mal sollte ich mal sehen, wie sich das mittlere Alter von Schuken und Engeln in den unteren Schichten so verhält.

    Mal systematisch

    Weil Simulationen dieser Art schrecklich viele Parameter haben, ist das eigentlich Interessante, den Einfluss der Parameter auf die Ergebnisse zu untersuchen. Dazu habe ich mir mal ein paar Modelle herausgesucht, die verschiedene Parameter variieren (in der run_many-Funktion von sunde2); Ausgangspunkt sind dabei 50 Ebenen mit einem Lebenszeit-Faktor von zwei und einem Schurkenvorteil von 0.66. Das kombiniere ich mit:

    • einer Gleichverteilung von Schurkigkeiten
    • einer Exponentialverteilung mit λ = 2
    • einer Exponentialverteilung mit λ = 4
    • einer Exponentialverteilung mit λ = 4, aber einem Schurkenvorteil von 0.75
    • einer Exponentialverteilung mit λ = 4, aber einem Lebenszeit-Faktor von 4
    • einer Normalverteilung um 0.75 …
  • Fast alles Schurken

    Die gerade durch die Medien gehende Geschichte von Georg Nüßlein zeichnet, ganz egal, was an Steuerhinterziehung und Bestechung nachher übrig bleibt, jedenfalls das Bild von einem Menschen, der, während rundrum die Kacke am Dampfen ist, erstmal überlegt, wie er da noch den einen oder anderen Euro aus öffentlichen Kassen in seine Taschen wandern lassen kann.

    Die Unverfrorenheit mag verwundern, nicht aber, dass Schurken in die Fraktionsleitung der CSU aufsteigen. Im Gegenteil – seit ich gelegentlich mal mit wichtigen Leuten umgehe, fasziniert mich die Systematik, mit der die mittlere Schurkigkeit von Menschen mit ihrer Stellung in der Hierarchie steil zunimmt: Wo in meiner unmittelbaren Arbeitsumgebung eigentlich die meisten Leute recht nett sind, gibt es unter den Profen schon deutlich weniger Leute mit erkennbarem Herz. Im Rektorat wird es schon richtig eng, und im Wissenschaftsministerium verhalten sich oberhalb der Sekretariate eigentlich alle wie Schurken, egal ob nun früher unter Frankenberg oder jetzt unter Bauer.

    Tatsächlich ist das mehr oder minder zwangsläufig so in Systemen, die nach Wettbewerb befördern. Alles, was es für ein qualitatives Verständnis dieses Umstands braucht, sind zwei Annahmen, die vielleicht etwas holzschnittartig, aber, so würde ich behaupten, schwer zu bestreiten sind.

    1. Es gibt Schurken und Engel
    2. Wenn Schurken gegen Engel kämpfen (na ja, wettbewerben halt), haben die Schurken in der Regel bessere Chancen.

    Die zweite Annahme mag nach dem Konsum hinreichend vieler Hollywood-Filme kontrafaktisch wirken, aber eine gewisse moralische Flexibilität und die Bereitschaft, die Feinde (na ja, Wettbewerber halt) zu tunken und ihnen auch mal ein Bein zu stellen, dürfte unbestreitbar beim Gewinnen helfen.

    Um mal ein Gefühl dafür zu kriegen, was das bedeutet: nehmen wir an, der Vorteil für die Schurken würde sich so auswirken, dass pro Hierarchieebene der Schurkenanteil um 20% steigt, und wir fangen mit 90% Engeln an (das kommt für mein soziales Umfeld schon so in etwa hin, wenn mensch hinreichend großzügig mit dem Engelbegriff umgeht). Als Nerd fange ich beim Zählen mit Null an, das ist also die Ebene 0.

    Auf Ebene 1 sind damit noch 0.9⋅0.8, also 72% der Leute Engel, auf Ebene 2 0.9⋅0.8⋅0.8, als knapp 58% und so fort, in Summe also 0.9⋅0.8n auf Ebene n. Mit diesen Zahlen sind in Hierarchieebene 20 nur noch 1% der Leute Engel, und dieser Befund ist qualitativ robust gegenüber glaubhaften Änderungen in den Anfangszahlen der Engel oder der Vorteile für Schurken.

    Tatsächlich ist das Modell schon mathematisch grob vereinfacht, etwa weil die Chancen für Engel sinken, je mehr Schurken es gibt, ihr Anteil also schneller sinken sollte als hier abgeschätzt. Umgekehrt sind natürlich auch Leute wie Herr Nüßlein nicht immer nur Schurken, sondern haben manchmal (wettbewerbstechnisch) schwache Stunden und verhalten sich wie Engel. Auch Engel ergeben sich dann und wann dem Sachzwang und sind von außen von Schurken nicht zu unterscheiden. Schließlich ist wohl einzuräumen, dass wir alle eher so eine Mischung von Engeln und Schurken sind – wobei das Mischungsverhältnis individuell ganz offensichtlich stark schwankt.

    Eine Simulation

    All das in geschlossene mathematische Ausdrücke zu gießen, ist ein größeres Projekt. Als Computersimulation jedoch sind es nur ein paar Zeilen, und die würde ich hier gerne zur allgemeinen Unterhaltung und Kritik veröffentlichen (und ja, auch die sind unter CC-0).

    Ein Ergebnis vorneweg: in einem aus meiner Sicht recht plausiblen Modell verhält sich die Schurkigkeit (auf der Ordinate; 1 bedeutet, dass alle Leute sich immer wie Schurken verhalten) über der Hierarchiebene (auf der Abszisse, höhere Ebenen rechts) wie folgt (da sind jeweils mehrere Punkte pro Ebene, weil ich das öfter habe laufen lassen):

    Graph: Scatterplot von Schurkigkeit gegen Karriereschritt

    Ergebnis eines Laufs mit einem Schurken-Vorteil von 0.66, mittlere Schurkigkeit über der Hierarchieebene: Im mittleren Management ist demnach zur 75% mit schurkigem Verhalten zu rechnen. Nochmal ein paar Stufen drüber kanns auch mal besser sein. Die große Streuung auf den hohen Hierarchieebenen kommt aus den kleinen Zahlen, die es da noch gibt; in meinen Testläufen fange ich mit 220 (also ungefähr einer Million) Personen an und lasse die 16 Mal Karriere machen; mithin bleiben am Schluss 16 Oberchefs übrig, und da macht ein_e einzige_r Meistens-Engel schon ziemlich was aus.

    Das Programm, das das macht, habe ich Schurken und Engel getauft, sunde.py – und lade zu Experimenten damit ein.

    Zunächst das Grundmodell, in Python formuliert:

    ROGUE_ADVANTAGE = 0.66
    
    _WIN_PROB = {
        (False, False): 0.5,
        (False, True): 1-ROGUE_ADVANTAGE,
        (True, False): ROGUE_ADVANTAGE,
        (True, True): 0.5,}
    
    class Actor:
        def __init__(self, angelicity):
            self.angelicity = angelicity
    
        def is_rogue(self):
            return random.random()>self.angelicity
    
        def wins_against(self, other):
            return _WIN_PROB[self.is_rogue(), other.is_rogue()]>random.random()
    

    Es wird also festgelegt, dass, wenn ein Schurke gegen einen Engel wettbewerbt, der Schurke mit zu 66% gewinnt (und ich sage mal voraus, dass der konkrete Wert hier qualitativ nicht viel ändern wird), während es ansonsten 50/50 ausgeht. Das ist letztlich das, was in _WIN_PROB steht.

    Und dann gibt es das Menschenmodell: Die Person wird, wir befinden uns in gefährlicher Nähe zu Wirtschafts„wissenschaften“, durch einen Parameter bestimmt, nämlich die Engeligkeit (angelicity; das Wort gibts wirklich, meint aber eigentlich nicht wie hier irgendwas wie Unbestechlichkeit). Diese ist die Wahrscheinlichkeit, sich anständig zu verhalten, so, wie das in der is_rogue-Methode gemacht ist: Wenn eine Zufallszahl zwischen 0 und 1 (das Ergebnis von random.random()) großer als die Engeligkeit ist, ist die Person gerade schurkig.

    Das wird dann in der wins_against-Methode verwendet: sie bekommt eine weitere Actor-Instanz, fragt diese, ob sie gerade ein Schurke ist, fragt sich das auch selbst, und schaut dann in _WIN_PROB nach, was das für die Gewinnwahrscheinlichkeit bedeutet. Wieder wird das gegen random.random() verglichen, und das Ergebnis ist, ob self gegen other gewonnen hat.

    Der nächste Schritt ist die Kohorte; die Vorstellung ist mal so ganz in etwa, dass wir einem Abschlussjahrgang bei der Karriere folgen. Für jede Ebene gibt es eine Aufstiegsprüfung, und wer die verliert, fliegt aus dem Spiel. Ja, das ist harscher als die Realität, aber nicht arg viel. Mensch fängt mit vielen Leuten an, und je weiter es in Chef- oder Ministerialetage geht, desto dünner wird die Luft – oder eher, desto kleiner die actor-Menge:

    class Cohort:
        draw = random.random
    
        def __init__(self, init_size):
            self.actors = set(Actor(self.draw())
                for _ in range(init_size))
    
        def run_competition(self):
            new_actors = set()
            for a1, a2 in self.iter_pairs():
                if a1.wins_against(a2):
                    new_actors.add(a1)
                else:
                    new_actors.add(a2)
    
            self.actors = new_actors
    
        def get_meanness(self):
            return 1-sum(a.angelicity
              for a in self.actors)/len(self.actors)
    

    (ich habe eine technische Methode rausgenommen; für den vollen Code vgl. oben).

    Interessant hier ist vor allem das draw-Attribut: Das zieht nämlich Engeligkeiten. In dieser Basisfassung kommen die einfach aus einer Gleichverteilung zwischen 0 und 1, wozu unten noch mehr zu sagen sein wird. run_competition ist der Karriereschritt wie eben beschrieben, und get_meanness gibt die mittlere Schurkigkeit als eins minus der gemittelten Engeligkeit zurück. Diesem Wortspiel konnte ich nicht widerstehen.

    Es gäbe zusätzlich zu meanness noch interessante weitere Metriken, um auszudrücken, wie schlimm das Schurkenproblem jeweils ist, zum Beispiel: Wie groß ist der Anteil der Leute mit Engeligkeit unter 0.5 in der aktuellen Kohorte? Welcher Anteil von Friedrichs (Engeligkeit<0.1) ist übrig, welcher Anteil von Christas (Engeligkeit>0.9)? Aus wie vielen der 10% schurkgisten Personen „wird was“? Aus wie vielen der 10% Engeligsten? Der_die Leser_in ahnt schon, ich wünschte, ich würde noch Programmierkurse für Anfänger_innen geben: das wären lauter nette kleine Hausaufgaben. Andererseits sollte mensch wahrscheinlich gerade in so einem pädagogischen Kontext nicht suggerieren, dieser ganze Metrik-Quatsch sei unbestritten. Hm.

    Nun: Wer sunde.py laufen lässt, bekommt Paare von Zahlen ausgegeben, die jeweils Hierarchiestufe und meanness der Kohorte angeben. Die kann mensch dann in einer Datei sammeln, etwa so:

    $ python3 sunde.py >> results.txt
    $ python3 sunde.py >> results.txt
    

    und so fort. Und das Ganze lässt sich ganz oldschool mit gnuplot darstellen (das hat die Abbildung oben gemacht), z.B. durch:

    plot "results.txt" with dots notitle
    

    auf der gnuplot-Kommandozeile.

    Wenn mir wer ein ipython-Notebook schickt, das etwa durch matplotlib plottet, veröffentliche ich das gerne an dieser Stelle – aber ich persönlich finde shell und vi einfach eine viel angenehmere Umgebung...

    Anfangsverteilungen

    Eine spannende Spielmöglichkeit ist, die Gesellschaft anders zu modellieren, etwa durch eine Gaußverteilung der Engeligkeit, bei der die meisten Leute so zu 50% halb Engel und halb Schurken sind (notabene deckt sich das nicht mit meiner persönlichen Erfahrung, aber probieren kann mensch es ja mal).

    Dazu ersetze ich die draw-Zuweisung in Cohort durch:

    def draw(self):
         return min(1,
             max(0, random.normalvariate(0.5, 0.25)))
    

    Die „zwei Sigma“, also – eine der wichtigeren Faustformeln, die mensch im Kopf haben sollte – 95% der Fälle, liegen hier zwischen 0 und 1. Was drüber und drunter rausguckt, wird auf „immer Engel“ oder „immer Schurke“ abgeschnitten. Es gibt in diesem Modell also immerhin 2.5% Vollzeitschurken. Überraschenderweise sammeln sich die in den ersten 16 Wettbewerben nicht sehr drastisch in den hohen Chargen, eher im Gegenteil:

    Graph: Scatterplot wie oben, nur für gaussverteilte Aktoren

    Deutlich plausibler als die Normalverteilung finde ich in diesem Fall ja eine …

Seite 1 / 1

Letzte Ergänzungen