Für die Gammaspektroskopie (https://stoppi-homemade-physics.de/gammaspektroskopie/) wird ein sogenannter Multi-channel-analyzer (kurz MCA oder zu deutsch Vielkanalzähler) benötigt. Was macht ein MCA?
Nun, wie wir bei meiner Gammaspektroskopie gesehen haben, ist die Höhe des Photomultiplier-Ausgabepulses proportional zur Lichtintensität, welche von dem Elektron im Szintillator erzeugt wurde. Und die Energie des Elektrons ist wiederum proportional zur Energie des Gammaquants. Also ist die Höhe der Photomultiplier-Ausgabepulse proportional zur Energie der Gammastrahlung h·f. Um ein Gammaenergiespektrum aufnehmen zu können, muss ich daher die Höhe der Ausgabepulse bestimmen und dann der Höhe nach zählen bzw. ordnen. Genau dies macht ein Multi-channel-analyzer. Er bestimmt die Höhe der Spannungspulse (z.B. 2.3 V) und erhöht dann den Zähler für eben diese Spannung um +1. Am Ende stellt er die Anzahl der gezählten Pulse in Abhängigkeit von ihrer Größe graphisch dar. Dies ergibt das sog. Gammaspektrum.

Es gibt mehrere kostenlose MCA-Softwarelösungen wie etwa Theremino (http://www.theremino.com/wp-content/uploads/files/Theremino_MCA_V7.2.zip), BecMoni oder PRA (https://www.gammaspectacular.com/blue/pra-spectrometry-software).
Ich habe nun aber auch versucht, mittels Arduino einen MCA zu realisieren. Die Aufgabe der Elektronik ist es, bei einem ankommenden Spannungspuls mittels Monoflop den Arduino darüber zu informieren. Die Höhe des ankommenden Pulses wird sodann kurz gespeichert. Dies macht ein sog. Spitzenwertdetektor bzw. peak-detector. Nun liest der Arduino über einen seiner analogen Eingänge den gespeicherten Spitzenwert ein und erhöht den entsprechenden Zähler. Danach leert er den Spitzenwertspeicher und wartet auf den nächsten Puls.

Der unten abgebildete Schaltungsteil ist genau dieser peak-detector. Der 4.7 nF Kondensator dient dazu, den Spitzenwert so lange zu speichern, bis dieser vom Arduino ausgelesen wird. Die Diode 1N4148 sorgt dafür, dass immer nur höhere Spannungen als bisher gespeichert zum Kondensator gelangen und der Transistor BC327 soll die an der Diode abfallende Spannung (ca. 0.5 V) kompensieren:


Der komplette Schaltplan sieht wiefolgt aus:

Angezeigt wird das Gammaspektrum schlussendlich mit einem 128 x 64 pixel display:








Im letzten Spektrum ist der Photopeak von Cäsium-137 bei 662 keV sehr schön zu sehen. Auch tritt die sog. Comptonkante sehr gut hervor.

Zum Schluss das Youtube-Video:
Arduino-Code:
#include <U8glib.h>
U8GLIB_ST7920_128X64 u8g(13, 11, 12, U8G_PIN_NONE);
// Einstellungs-Tabelle für die Erhöhung der Taktfrequenz
// ======================================================
// ADPS2 ADPS1 ADPS0 Division factor
// 0 0 0 2
// 0 0 1 2
// 0 1 0 4
// 0 1 1 8
// 1 0 0 16
// 1 0 1 32
// 1 1 0 64
// 1 1 1 128 (Standard)
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// Variablendeklaration
// ====================
const int analogInPin = A0; // Analog input pin für die Pulshöhe
const int pin_verzoegerung = A1; // Analog input pin für die über ein Poti einstellbare variable Verzögerung
const int pin_entleeren = 3; // Digital output pin für das Entleeren des Speicherkondensators
const int pin_treffer = 4; // Digital input pin für vom Monoflop kommenden treffer
const int pin_switch = 5; // Digital output pin für switch
const int pin_test = 7; // Digital output pin um zu überprüfen, in welcher Phase der Entladekurve von C die Spannungsmessung erfolgt
const int pin_reset = 8; // Digital input pin für das Leeren des Pulshöhenarrays um eine neue Messung zu starten
int U_puls = 0; // aktuelle gemessene Pulshöhe
float Spannung; // aktuelle gemessene Pulsspannung
int Index = 0; // Index der gemessenen Pulshöhe im Intervall [0,127]
float Faktor = 1; // Vergrößerungs- bzw. Verkleinerungsfaktor
int Pulshoehen[128]; // array mit der Anzahl der jeweils 128 verschiedenen Pulshöhen
int reset_time; // Zeitdauer in ms der U-Max-Speicherentleerung
int j; // Zählvariable als Maß für die Schnelligkeit der Pulsabfrage
int time_alt, time_neu; // Variablen zur Ermittlung der Schleifendauer
int Verzoegerung; // Verzögerungszeit in µs
// ===========================
// ========== SETUP ==========
// ===========================
void setup(void)
{
Serial.begin(9600);
pinMode(pin_entleeren, OUTPUT); // U-Speicher-Entleer-pin als output deklariert
pinMode(pin_switch, OUTPUT); // switch-pin als output deklariert
pinMode(pin_test, OUTPUT); // test-pin als output deklariert
pinMode(pin_treffer, INPUT); // treffer-pin als input deklariert
pinMode(pin_reset, INPUT); // reset-pin für die Anzeige als input deklariert
digitalWrite(pin_entleeren, HIGH); // U_max-Speicher entleeren
digitalWrite(pin_switch, LOW); // Schalter für U-Zuleitung offen
digitalWrite(pin_test, LOW); // Test-pin auf 0 setzen
for (int i = 0; i < 128; i++)
{
Pulshoehen[i] = 0; // alle Pulshöhentreffer auf 0 setzen
}
Faktor = 1; // Startvergrößerung für die graphische Darstellung
reset_time = 5; // Zeitdauer in ms der U-Max-Speicherentleerung
#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ; // ADPS2 auf 1 gesetzt
cbi(ADCSRA,ADPS1) ; // ADPS1 auf 0 gesetzt
cbi(ADCSRA,ADPS0) ; // ADPS0 auf 0 gesetzt
// cbi = 0; sbi = 1
#endif
// Zeichnen der Achsen
// ===================
u8g.firstPage();
do
{
u8g.drawLine(0, 63, 127, 63);
u8g.drawLine(0, 0, 0, 63);
}
while( u8g.nextPage() );
}
// ===================================
// ========== HAUPTSCHLEIFE ==========
// ===================================
void loop(void)
{
/*
Verzoegerung = analogRead(pin_verzoegerung);
Verzoegerung = Verzoegerung * 10; // Verzögerungsintervall 0 bis 1023 * 10 µs
Serial.print("Verzoegerung im µs = ");
Serial.println(Verzoegerung);
*/
digitalWrite(pin_entleeren, HIGH); // U_max-Speicher gelöscht
delay(reset_time); // reset_time ms Wartezeit zum ausreichenden Löschen des U_max-Speichers
digitalWrite(pin_entleeren, LOW); // U_max-Speicher bereit
digitalWrite(pin_switch, HIGH); // Schalter für U-Zuleitung geschlossen; Messung startet... eigentlich unnötig, da ja eh der Kondensator gelöscht wird und auf den ersten Puls gewartet wird
// Warte bis ein vom Monoflop verlängerter Puls über DIGITAL-IN registriert wird!
// ==============================================================================
while(digitalRead(pin_treffer) == LOW)
{
}
//delayMicroseconds(Verzoegerung); // übers Poti variable Verzögerung, damit der Zuleitungsschalter nicht schon schließt obwohl der Spannungspuls noch nicht sein Maximum erreicht hat!
delayMicroseconds(5); // fixe Verzögerung, damit der Zuleitungsschalter nicht zu früh schließt und der Spannungspuls auch zu seinem Maximum anwachsen kann!
digitalWrite(pin_switch, LOW); // Puls wurde registriert --> Schalter für U-Zuleitung offen; Messung gestoppt
// Pulshöhe wird eingelesen
// ========================
U_puls = analogRead(analogInPin); // Einlesen der Pulshöhe 0-5V
// digitale Ausgabe über den Test-Pin unmittelbar nach Einlesen der Spannung um festzustellen, "wo" in der Entladekurve die Spannung gemessen wird. Soll ja genau im Maximum erfolgen!
// -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
digitalWrite(pin_test, HIGH); // Test-pin auf 1 setzen
delay(5); // Verzögerung
digitalWrite(pin_test, LOW); // Test-pin auf 0 setzen
*/
// graphische und Speicher-Verarbeitung der registrierten Pulshöhe
// ---------------------------------------------------------------
if(U_puls > 130) // Vermeidung von der Anzeige dominierender peaks mit geringer Amplitude
{
Index = map(U_puls, 0, 1023, 0, 127); // Index der aktuell gemessenen Pulshöhe im Intervall [0,127]
Pulshoehen[Index] = Pulshoehen[Index] + 1; // aktuelle Pulshöhe erhält einen Treffer
//Spannung = U_puls * 5.0 / 1023;
//Serial.print("Pulshoehe = "); // serielle Ausgabe der aktuellen Pulshöhe 0-5V
//Serial.println(Spannung,2);
}
// ==============================================
// ============ graphische Ausgabe ==============
// ==============================================
if (int(Faktor * Pulshoehen[Index]) > 62) // Zuviele Treffer für die ausreichende y-Darstellung ---> Stauchung um Faktor 2
{
u8g.firstPage();
do
{
u8g.drawLine(0, 63, 127, 63);
u8g.drawLine(0, 0, 0, 63);
for (int i = 0; i < 128; i++)
{
u8g.drawLine(0+i, 63, 0+i, 63 - int(Faktor * Pulshoehen[i])); // zeichnen aller Treffer
}
}
while( u8g.nextPage() );
Faktor = Faktor / 2;
}
// Abfrage, ob der Reset-Knopf betätigt wurde
// ------------------------------------------
if (digitalRead(pin_reset) == HIGH)
{
// Spektrum an den Computer senden
// ===============================
for (int i = 0; i < 128; i++)
{
Serial.println(Pulshoehen[i]);
}
// Spektrum löschen
// ================
for (int i = 0; i < 128; i++)
{
Pulshoehen[i] = 0; // alle Pulshöhentreffer auf 0 setzen
}
Faktor = 1; // Startvergrößerung für die graphische Darstellung
u8g.firstPage();
do
{
u8g.drawLine(0, 63, 127, 63);
u8g.drawLine(0, 0, 0, 63);
}
while( u8g.nextPage() );
}
//delay(2); // optionale Zeitverzögerung
}
