Complete VIDEO-001 through VIDEO-004 software video studies
This commit is contained in:
81
protocol/punctured_fec.py
Normal file
81
protocol/punctured_fec.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""Программные варианты R=2/3 и 3/4 на базе штатного кода R=1/2.
|
||||
|
||||
Прокалывание удаляет известные позиции кодового слова. При декодировании
|
||||
эти позиции имеют нулевую мягкую метрику (стирание), после чего работает
|
||||
штатный терминированный декодер Витерби.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import lru_cache
|
||||
import numpy as np
|
||||
|
||||
from protocol import convolutional_fec
|
||||
|
||||
|
||||
PUNCTURE_PATTERNS: dict[str, tuple[int, ...]] = {
|
||||
"1/2": (1, 1),
|
||||
"2/3": (1, 1, 1, 0),
|
||||
"3/4": (1, 1, 1, 0, 0, 1),
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=32)
|
||||
def _mask(mother_bit_count: int, rate: str) -> np.ndarray:
|
||||
if rate not in PUNCTURE_PATTERNS:
|
||||
raise ValueError("неизвестная скорость кода")
|
||||
if mother_bit_count < 0:
|
||||
raise ValueError("отрицательная длина кодового слова")
|
||||
pattern = np.asarray(PUNCTURE_PATTERNS[rate], dtype=bool)
|
||||
mask = np.resize(pattern, mother_bit_count)
|
||||
mask.flags.writeable = False
|
||||
return mask
|
||||
|
||||
|
||||
def coded_bit_count(information_bit_count: int, rate: str) -> int:
|
||||
"""Точное число передаваемых битов, включая шесть хвостовых битов кода."""
|
||||
mother_count = convolutional_fec.encoded_bit_count(information_bit_count)
|
||||
if rate not in PUNCTURE_PATTERNS:
|
||||
raise ValueError("неизвестная скорость кода")
|
||||
pattern = PUNCTURE_PATTERNS[rate]
|
||||
periods, remaining = divmod(mother_count, len(pattern))
|
||||
return periods * sum(pattern) + sum(pattern[:remaining])
|
||||
|
||||
|
||||
def effective_rate(information_bit_count: int, rate: str) -> float:
|
||||
"""Отношение полезных битов к реально передаваемым кодовым битам."""
|
||||
if information_bit_count <= 0:
|
||||
raise ValueError("число полезных битов должно быть положительным")
|
||||
return information_bit_count / coded_bit_count(information_bit_count, rate)
|
||||
|
||||
|
||||
def encode(information_bits: np.ndarray, rate: str) -> np.ndarray:
|
||||
"""Сначала применить штатный код, затем удалить позиции по маске."""
|
||||
mother_bits = convolutional_fec.encode(information_bits)
|
||||
return mother_bits[_mask(len(mother_bits), rate)]
|
||||
|
||||
|
||||
def depuncture_soft(
|
||||
soft_values: np.ndarray, information_bit_count: int, rate: str
|
||||
) -> np.ndarray:
|
||||
"""Вернуть стёртые позиции с нулевой мягкой метрикой."""
|
||||
values = np.asarray(soft_values, dtype=np.float64)
|
||||
if values.ndim != 1 or not np.all(np.isfinite(values)):
|
||||
raise ValueError("мягкие значения должны быть конечным одномерным массивом")
|
||||
mother_count = convolutional_fec.encoded_bit_count(information_bit_count)
|
||||
mask = _mask(mother_count, rate)
|
||||
if len(values) != int(np.count_nonzero(mask)):
|
||||
raise ValueError("неверная длина проколотого кодового слова")
|
||||
restored = np.zeros(mother_count, dtype=np.float64)
|
||||
restored[mask] = values
|
||||
return restored
|
||||
|
||||
|
||||
def decode_soft(
|
||||
soft_values: np.ndarray, information_bit_count: int, rate: str
|
||||
) -> np.ndarray:
|
||||
"""Декодировать через существующий 64-состояний декодер Витерби."""
|
||||
return convolutional_fec.viterbi_decode_soft(
|
||||
depuncture_soft(soft_values, information_bit_count, rate),
|
||||
information_bit_count,
|
||||
)
|
||||
Reference in New Issue
Block a user