/******************************************************************************* * sdrtrunk * Copyright (C) 2014-2017 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * ******************************************************************************/ package edac.trellis; import bits.BinaryMessage; import bits.CorrectedBinaryMessage; import java.util.List; public class ViterbiDecoder_3_4_DMR extends ViterbiDecoder { /** * Viterbi decoder for Digital Mobile Radio (DMR) 3/4 rate Trellis Coded Modulation (TCM) encoded messages. */ public ViterbiDecoder_3_4_DMR() { super(3,4); } /** * Decodes a 3/4 rate trellis coded modulation (TCM) encoded DMR binary message containing 196 bits that have * already been deinterleaved. * * @param encodedMessage to decode that has already been deinterleaved. * @return decoded message */ public BinaryMessage decode(BinaryMessage encodedMessage) { int[] symbols = getSymbols(encodedMessage); Path mostLikelyPath = decode(symbols); return getMessage(mostLikelyPath); } /** * Extracts the decoded/corrected message from the surviving path argument. * * @param path to extract a message from * @return corrected binary message. */ private static CorrectedBinaryMessage getMessage(Path path) { List mNodes = path.getNodes(); //Each node contains an input value excluding the starting(0) and final flushing(0) nodes. CorrectedBinaryMessage message = new CorrectedBinaryMessage((mNodes.size() - 2) * 3); if(mNodes.size() > 2) { for(int x = 1; x < mNodes.size() - 1; x++) { int inputValue = mNodes.get(x).getInputValue(); int messageOffset = 3 * (x - 1); if((inputValue & 4) == 4) { message.set(messageOffset); } if((inputValue & 2) == 2) { message.set(messageOffset + 1); } if((inputValue & 1) == 1) { message.set(messageOffset + 2); } } } //Transfer the corrected error count to the message message.setCorrectedBitCount(path.getError()); return message; } /** * Extracts (49) four-bit symbols (196 bits / 4) from the deinterleaved DMR binary message * * @param encodedMessage that deinterleaved and contains 196-bits of 3/4 TCM encoding * @return symbols */ public int[] getSymbols(BinaryMessage encodedMessage) { //Ensure we have an integral number of transmitted symbols (nibbles) in the message if(encodedMessage.size() % getOutputBitLength() != 0) { throw new IllegalArgumentException("Encoded message must contain an integral number of 4-bit symbols -" + " message size: " + encodedMessage.size()); } int[] symbols = new int[encodedMessage.size() / getOutputBitLength()]; int index = 0; int pointer = 0; while(index < encodedMessage.size()) { int symbol = encodedMessage.getInt(index, index + (getOutputBitLength() - 1)); symbols[pointer++] = symbol; index += getOutputBitLength(); } return symbols; } /** * Creates a DMR node * @param inputValue for the specific trellis node * @param transmittedOutputValue the actual transmitted output value * @return created node */ @Override protected Node createNode(int inputValue, int transmittedOutputValue) { return new DMRNode(inputValue, transmittedOutputValue); } /** * Creates a DMR flushing node. DMR uses an input value of zero to flush the final output value out of the * encoder. * * @param transmittedOutputValue the actual transmitted output value * @return */ @Override protected Node createFlushingNode(int transmittedOutputValue) { return new DMRNode(0, transmittedOutputValue); } /** * Creates a DMR starting node. DMR uses a starting input value of zero for the initial node. */ @Override protected Node createStartingNode() { return new DMRNode(0,0); } }