import numpy as np
import pytest
import orion_sdr as sdr
from .conftest import FS, real_tone, snr_db, tail
N = 32_768
def test_roundtrip_cw_envelope():
n = 24_000
pitch_hz = 700.0
key_f = 5.0
key_env = np.array(
[(1.0 if (k * key_f / FS) % 1.0 < 0.5 else 0.0) for k in range(n)],
dtype=np.float32,
)
iq = sdr.CwKeyedMod(FS, pitch_hz, 3.0, 3.0).process(key_env)
audio = sdr.CwEnvelopeDemod(FS, pitch_hz, 300.0).process(iq)
skip = int(0.100 * FS)
a = audio[skip:]
k = key_env[skip:]
on_rms = float(np.sqrt(np.mean(a[k > 0.5] ** 2)))
off_rms = float(np.sqrt(np.mean(a[k < 0.5] ** 2))) + 1e-12
contrast_db = 20.0 * np.log10(on_rms / off_rms)
assert contrast_db > 14.0, f"CW ON/OFF contrast {contrast_db:.1f} dB < 14 dB"
def test_roundtrip_am_envelope():
f_mod = 1_000.0
audio_in = real_tone(FS, f_mod, N, 0.5)
iq = sdr.AmDsbMod(FS, 0.0, 0.8, 0.5).process(audio_in)
audio_out = sdr.AmEnvelopeDemod(FS, 5_000.0).process(iq)
snr = snr_db(tail(audio_out), FS, f_mod)
assert snr > 24.0, f"AM roundtrip SNR {snr:.1f} dB < 24 dB"
def test_roundtrip_am_envelope_abs_approx():
f_mod = 1_000.0
audio_in = real_tone(FS, f_mod, N, 0.5)
iq = sdr.AmDsbMod(FS, 0.0, 0.8, 0.5).process(audio_in)
audio_out = sdr.AmEnvelopeDemod(FS, 5_000.0, abs_approx=True).process(iq)
snr = snr_db(tail(audio_out), FS, f_mod)
assert snr > 20.0, f"AM AbsApprox roundtrip SNR {snr:.1f} dB < 20 dB"
def test_roundtrip_ssb_usb():
f_audio = 1_200.0
audio_bw_hz = 2_800.0
audio_if_hz = 1_500.0
audio_in = real_tone(FS, f_audio, N, 0.4)
iq = sdr.SsbPhasingMod(FS, audio_bw_hz, audio_if_hz, 0.0, True).process(audio_in)
audio_out = sdr.SsbProductDemod(FS, audio_if_hz, audio_bw_hz).process(iq)
skip = int(0.120 * FS)
snr = snr_db(audio_out[skip:], FS, f_audio)
assert snr > 18.0, f"SSB USB roundtrip SNR {snr:.1f} dB < 18 dB"
def test_roundtrip_fm_quadrature():
f_mod = 1_000.0
audio_in = real_tone(FS, f_mod, N, 0.5)
iq = sdr.FmPhaseAccumMod(FS, 2_500.0, 0.0).process(audio_in)
audio_out = sdr.FmQuadratureDemod(FS, 2_500.0, 5_000.0).process(iq)
snr = snr_db(tail(audio_out), FS, f_mod)
assert snr > 20.0, f"FM roundtrip SNR {snr:.1f} dB < 20 dB"
def test_roundtrip_pm_quadrature():
f_mod = 900.0
audio_in = real_tone(FS, f_mod, N, 0.5)
iq = sdr.PmDirectPhaseMod(FS, 0.9, 0.0).process(audio_in)
audio_out = sdr.PmQuadratureDemod(FS, 0.9, 5_000.0).process(iq)
snr = snr_db(tail(audio_out), FS, f_mod)
assert snr > 18.0, f"PM roundtrip SNR {snr:.1f} dB < 18 dB"