Modulation · Digital
Amplitude Shift Keying (ASK)
Digitale Information über Amplitudenstufen eines Trägersignals — einfach zu implementieren, aber störanfällig.
Amplitude Shift Keying ist eine Modulationsmethode, bei der die Amplitude eines Trägersignals verändert wird, um digitale Informationen zu übertragen. Sie ist einfach zu implementieren, aber anfällig für Rauschen und Störungen — geeignet für Anwendungen über kurze Distanzen mit geringem Rauschpegel.
Typische Anwendungen
- Fernbedienungen
- Nahfeldkommunikation (NFC)
- RFID (Radio Frequency Identification)
- Übertragung von Messdaten
- Hausautomation
Wichtige Konzepte
On-Off-Keying (OOK) — eine Sonderform, bei der die Amplitude für den Low-Pegel auf 0 gesetzt wird, wie z.B. bei der Morsetelegrafie.
Mehrstufiges ASK — es können mehrere Amplitudenstufen genutzt werden. ASK-4 überträgt 2 Bit pro Symbol mittels vier unterschiedlicher Amplitudenwerte.
Samples per Symbol (SPS) — Anzahl der Samples pro Symbol bei der Signalerzeugung; im Beispiel werden 100 Samples pro Symbol verwendet.
Symbolrate — gibt an, wie viele Symbole pro Sekunde übertragen werden. Bei 3 MHz Abtastrate und SPS = 100 ergeben sich ca. 30.000 Symbole pro Sekunde.

Beispiel in Python
Die folgenden Funktionen erzeugen ein 4-stufiges ASK-Signal aus einer Symbolfolge und demodulieren es anschließend wieder — einmal per Korrelation, einmal per Schwellwertentscheidung.
import numpy as np
# Parameter
sampling_rate = 3_000_000 # 3 MHz
sps = 100 # Samples pro Symbol
carrier_frequency = 300_000 # Hz
levels = np.array([0.0, 1/3, 2/3, 1.0]) # 4 Amplitudenstufen für 2 Bit/Symbol
def generate_ask_signal(symbols, levels, carrier_frequency, sampling_rate, sps):
"""Erzeugt ein mehrstufiges ASK-Signal aus einer Symbolfolge."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
return np.concatenate([levels[symbol] * carrier for symbol in symbols])
import numpy as np
# Parameter
sampling_rate = 3_000_000 # 3 MHz
sps = 100 # Samples pro Symbol
carrier_frequency = 300_000 # Hz
levels = np.array([0.0, 1/3, 2/3, 1.0]) # 4 Amplitudenstufen für 2 Bit/Symbol
def generate_ask_signal(symbols, levels, carrier_frequency, sampling_rate, sps):
"""Erzeugt ein mehrstufiges ASK-Signal aus einer Symbolfolge."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
return np.concatenate([levels[symbol] * carrier for symbol in symbols])

Demodulationsverfahren
Es gibt zwei grundlegende Ansätze:
1. Korrelationsverfahren
Das Empfangssegment wird mit dem bekannten Trägersignal korreliert (Skalarprodukt) und auf die Energie des Trägers normiert. Das Ergebnis entspricht direkt der gesendeten Amplitude; die nächstgelegene bekannte Stufe liefert das demodulierte Symbol.
def demodulate_ask_correlation(signal, levels, carrier_frequency, sampling_rate, sps):
"""Demoduliert ein ASK-Signal per Korrelation mit dem Träger."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
carrier_energy = np.dot(carrier, carrier)
symbols = []
for i in range(0, len(signal) - sps + 1, sps):
segment = signal[i:i + sps]
amplitude = np.dot(segment, carrier) / carrier_energy
symbol = np.argmin(np.abs(levels - amplitude))
symbols.append(symbol)
return np.array(symbols)
def demodulate_ask_correlation(signal, levels, carrier_frequency, sampling_rate, sps):
"""Demoduliert ein ASK-Signal per Korrelation mit dem Träger."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
carrier_energy = np.dot(carrier, carrier)
symbols = []
for i in range(0, len(signal) - sps + 1, sps):
segment = signal[i:i + sps]
amplitude = np.dot(segment, carrier) / carrier_energy
symbol = np.argmin(np.abs(levels - amplitude))
symbols.append(symbol)
return np.array(symbols)
2. Schwellwertverfahren
Statt der Korrelation wird hier nur die Energie des Empfangssegments relativ zur Energie des Trägers betrachtet. Aus dem Energieverhältnis lässt sich die Amplitude zurückrechnen; feste Schwellen zwischen den bekannten Stufen entscheiden dann über das Symbol.
def demodulate_ask_threshold(signal, levels, carrier_frequency, sampling_rate, sps):
"""Demoduliert ein ASK-Signal über die Energie je Symbolabschnitt und feste Schwellen."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
carrier_energy = np.dot(carrier, carrier)
thresholds = (levels[:-1] + levels[1:]) / 2 # Mitte zwischen benachbarten Stufen
symbols = []
for i in range(0, len(signal) - sps + 1, sps):
segment = signal[i:i + sps]
amplitude_estimate = np.sqrt(np.dot(segment, segment) / carrier_energy)
symbol = np.searchsorted(thresholds, amplitude_estimate)
symbols.append(symbol)
return np.array(symbols)
def demodulate_ask_threshold(signal, levels, carrier_frequency, sampling_rate, sps):
"""Demoduliert ein ASK-Signal über die Energie je Symbolabschnitt und feste Schwellen."""
t_symbol = np.arange(sps) / sampling_rate
carrier = np.cos(2 * np.pi * carrier_frequency * t_symbol)
carrier_energy = np.dot(carrier, carrier)
thresholds = (levels[:-1] + levels[1:]) / 2 # Mitte zwischen benachbarten Stufen
symbols = []
for i in range(0, len(signal) - sps + 1, sps):
segment = signal[i:i + sps]
amplitude_estimate = np.sqrt(np.dot(segment, segment) / carrier_energy)
symbol = np.searchsorted(thresholds, amplitude_estimate)
symbols.append(symbol)
return np.array(symbols)

Zum Test lässt sich Rauschen künstlich hinzufügen und beide Verfahren vergleichen:
symbols_to_send = [0, 1, 2, 3, 2, 1, 0, 3]
tx_signal = generate_ask_signal(symbols_to_send, levels, carrier_frequency, sampling_rate, sps)
# Rauschen hinzufügen
noise = np.random.normal(0, 0.05, size=tx_signal.shape)
rx_signal = tx_signal + noise
decoded_correlation = demodulate_ask_correlation(rx_signal, levels, carrier_frequency, sampling_rate, sps)
decoded_threshold = demodulate_ask_threshold(rx_signal, levels, carrier_frequency, sampling_rate, sps)
symbols_to_send = [0, 1, 2, 3, 2, 1, 0, 3]
tx_signal = generate_ask_signal(symbols_to_send, levels, carrier_frequency, sampling_rate, sps)
# Rauschen hinzufügen
noise = np.random.normal(0, 0.05, size=tx_signal.shape)
rx_signal = tx_signal + noise
decoded_correlation = demodulate_ask_correlation(rx_signal, levels, carrier_frequency, sampling_rate, sps)
decoded_threshold = demodulate_ask_threshold(rx_signal, levels, carrier_frequency, sampling_rate, sps)
