Files
SDR-Rover/experiments/lab005_virtual_channel.py
LittleSam129 c486039053 Split experiments from tests
The tests/ directory held 50 laboratory programs and no tests. They model
channels, run hundreds of repetitions and write CSV, PNG and reports;
calling that a test suite blocked introducing a real one, because any
pytest run would have collected the labs and re-executed every
experiment.

- move all 50 lab programs to experiments/ with git mv, preserving history
- rewrite the 38 cross-imports between labs from tests.labNNN to
  experiments.labNNN
- leave tests/ empty for actual fast checks of protocol/
- point quick_gate and the hook at the new layout and add experiments/ to
  the syntax sweep
- update the paths quoted in the Lab042 specification and the verifier
  agent definition

This also defuses the import-time work finding without touching 41 files:
the labs still create directories and write files on import, but nothing
imports them now except the gate, which does so deliberately.

Gate passes: syntax clean, protocol imports, 15 lab modules import, 2
functional suites run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 14:34:58 +03:00

254 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Lab005. Передача пакетов через виртуальный радиоканал.
Эксперимент:
1. Формируем 100 цифровых пакетов.
2. Передаём их через виртуальный канал.
3. Канал может:
- полностью потерять пакет;
- изменить отдельные биты.
4. Приёмник проверяет структуру пакета и CRC-32.
5. Выводится статистика доставки.
"""
import random
from protocol.packet import (
CRCError,
MESSAGE_TYPE_TEXT,
PacketError,
build_packet,
parse_packet,
)
from tools.virtual_channel import transmit
# ============================================================
# Настройки эксперимента
# ============================================================
# Количество передаваемых пакетов.
PACKET_COUNT = 100
# Вероятность полной потери одного пакета.
#
# 0.10 означает 10 %.
DROP_PROBABILITY = 0.10
# Вероятность повреждения каждого отдельного бита.
#
# 0.002 означает:
# 0,2 % вероятности ошибки для каждого бита.
BIT_ERROR_PROBABILITY = 0.002
# Генератор случайных чисел.
#
# Число 2026 позволяет получать одинаковый результат
# при каждом запуске программы.
random_generator = random.Random(2026)
# ============================================================
# Счётчики результатов
# ============================================================
sent_packets = 0
# Пакеты, полностью исчезнувшие в канале.
dropped_packets = 0
# Доставленные, но повреждённые пакеты.
rejected_packets = 0
# Пакеты, правильно принятые и разобранные.
received_ok = 0
# Общее количество изменённых битов.
total_flipped_bits = 0
# ============================================================
# Передача серии пакетов
# ============================================================
for sequence_number in range(PACKET_COUNT):
# Создаём уникальное сообщение для каждого пакета.
message = f"ПАКЕТ {sequence_number}"
# Текст превращается в байты UTF-8.
payload = message.encode("utf-8")
# Формируем полный пакет с заголовком и CRC-32.
packet = build_packet(
payload=payload,
message_type=MESSAGE_TYPE_TEXT,
sequence_number=sequence_number,
)
sent_packets += 1
# Передаём пакет через виртуальный канал.
received_packet, flipped_bits = transmit(
packet=packet,
drop_probability=DROP_PROBABILITY,
bit_error_probability=BIT_ERROR_PROBABILITY,
random_generator=random_generator,
)
total_flipped_bits += flipped_bits
# None означает, что пакет полностью потерян.
if received_packet is None:
dropped_packets += 1
continue
# Пытаемся разобрать принятый пакет.
try:
parsed_packet = parse_packet(received_packet)
except (CRCError, PacketError):
# CRCError:
# контрольная сумма не совпала.
#
# PacketError:
# повреждены SYNC, версия, длина
# или другая часть структуры.
rejected_packets += 1
continue
# Восстанавливаем текст из полезной нагрузки.
restored_message = parsed_packet.payload.decode("utf-8")
# Проверяем, что получен именно тот пакет,
# который был передан.
assert parsed_packet.sequence_number == sequence_number
assert restored_message == message
received_ok += 1
# ============================================================
# Вывод настроек
# ============================================================
print("=== Lab005. Виртуальный канал ===")
print("\nНастройки эксперимента:")
print(
"Количество пакетов:",
PACKET_COUNT,
)
print(
"Вероятность полной потери пакета:",
DROP_PROBABILITY,
)
print(
"Вероятность ошибки отдельного бита:",
BIT_ERROR_PROBABILITY,
)
# ============================================================
# Вывод результатов
# ============================================================
print("\nРезультаты:")
print(
"Передано пакетов:",
sent_packets,
)
print(
"Потеряно полностью:",
dropped_packets,
)
print(
"Отклонено из-за повреждений:",
rejected_packets,
)
print(
"Принято правильно:",
received_ok,
)
print(
"Всего изменено битов:",
total_flipped_bits,
)
# ============================================================
# Расчёт процентов
# ============================================================
delivery_rate = (
received_ok
/ sent_packets
* 100
)
drop_rate = (
dropped_packets
/ sent_packets
* 100
)
rejection_rate = (
rejected_packets
/ sent_packets
* 100
)
packet_failure_rate = (
dropped_packets
+ rejected_packets
) / sent_packets * 100
print("\nСтатистика:")
print(
f"Успешно доставлено: "
f"{delivery_rate:.1f} %"
)
print(
f"Потеряно полностью: "
f"{drop_rate:.1f} %"
)
print(
f"Отклонено приёмником: "
f"{rejection_rate:.1f} %"
)
print(
f"Общая доля недоставленных пакетов: "
f"{packet_failure_rate:.1f} %"
)
# ============================================================
# Контроль правильности
# ============================================================
accounted_packets = (
received_ok
+ dropped_packets
+ rejected_packets
)
assert accounted_packets == sent_packets
print(
"\nПроверка пройдена: "
"все переданные пакеты учтены."
)