/* -*- c++ -*- */ /* * Copyright 2004,2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include <gnuradio/trellis/calc_metric.h> #include <gnuradio/trellis/core_algorithms.h> #include <cstring> #include <iostream> #include <stdexcept> namespace gr { namespace trellis { static const float INF = 1.0e9; float min(float a, float b) { return a <= b ? a : b; } float min_star(float a, float b) { return (a <= b ? a : b) - log(1 + exp(a <= b ? a - b : b - a)); } template <class T> void viterbi_algorithm(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, const float* in, T* out) //, // std::vector<int> &trace) { std::vector<int> trace(S * K); std::vector<float> alpha(S * 2); int alphai; float norm, mm, minm; int minmi; int st; if (S0 < 0) { // initial state not specified for (int i = 0; i < S; i++) alpha[0 * S + i] = 0; } else { for (int i = 0; i < S; i++) alpha[0 * S + i] = INF; alpha[0 * S + S0] = 0.0; } alphai = 0; for (int k = 0; k < K; k++) { norm = INF; for (int j = 0; j < S; j++) { // for each next state do ACS minm = INF; minmi = 0; for (unsigned int i = 0; i < PS[j].size(); i++) { // int i0 = j*I+i; if ((mm = alpha[alphai * S + PS[j][i]] + in[k * O + OS[PS[j][i] * I + PI[j][i]]]) < minm) minm = mm, minmi = i; } trace[k * S + j] = minmi; alpha[((alphai + 1) % 2) * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) alpha[((alphai + 1) % 2) * S + j] -= norm; // normalize total metrics so they do not explode alphai = (alphai + 1) % 2; } if (SK < 0) { // final state not specified minm = INF; minmi = 0; for (int i = 0; i < S; i++) if ((mm = alpha[alphai * S + i]) < minm) minm = mm, minmi = i; st = minmi; } else { st = SK; } for (int k = K - 1; k >= 0; k--) { // traceback int i0 = trace[k * S + st]; out[k] = (T)PI[st][i0]; st = PS[st][i0]; } } template void viterbi_algorithm<unsigned char>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, const float* in, unsigned char* out); template void viterbi_algorithm<short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, const float* in, short* out); template void viterbi_algorithm<int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, const float* in, int* out); //============================================== template <class Ti, class To> void viterbi_algorithm_combined(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<Ti>& TABLE, digital::trellis_metric_type_t TYPE, const Ti* in, To* out) { std::vector<int> trace(S * K); std::vector<float> alpha(S * 2); std::vector<float> metric(O); int alphai; float norm, mm, minm; int minmi; int st; if (S0 < 0) { // initial state not specified for (int i = 0; i < S; i++) alpha[0 * S + i] = 0; } else { for (int i = 0; i < S; i++) alpha[0 * S + i] = INF; alpha[0 * S + S0] = 0.0; } alphai = 0; for (int k = 0; k < K; k++) { calc_metric(O, D, TABLE, &(in[k * D]), metric.data(), TYPE); // calc metrics norm = INF; for (int j = 0; j < S; j++) { // for each next state do ACS minm = INF; minmi = 0; for (unsigned int i = 0; i < PS[j].size(); i++) { // int i0 = j*I+i; if ((mm = alpha[alphai * S + PS[j][i]] + metric[OS[PS[j][i] * I + PI[j][i]]]) < minm) minm = mm, minmi = i; } trace[k * S + j] = minmi; alpha[((alphai + 1) % 2) * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) alpha[((alphai + 1) % 2) * S + j] -= norm; // normalize total metrics so they do not explode alphai = (alphai + 1) % 2; } if (SK < 0) { // final state not specified minm = INF; minmi = 0; for (int i = 0; i < S; i++) if ((mm = alpha[alphai * S + i]) < minm) minm = mm, minmi = i; st = minmi; } else { st = SK; } for (int k = K - 1; k >= 0; k--) { // traceback int i0 = trace[k * S + st]; out[k] = (To)PI[st][i0]; st = PS[st][i0]; } } // Ti = s i f c // To = b s i //--------------- template void viterbi_algorithm_combined<char, unsigned char>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<char>& TABLE, digital::trellis_metric_type_t TYPE, const char* in, unsigned char* out); template void viterbi_algorithm_combined<short, unsigned char>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<short>& TABLE, digital::trellis_metric_type_t TYPE, const short* in, unsigned char* out); template void viterbi_algorithm_combined<int, unsigned char>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<int>& TABLE, digital::trellis_metric_type_t TYPE, const int* in, unsigned char* out); template void viterbi_algorithm_combined<float, unsigned char>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t TYPE, const float* in, unsigned char* out); template void viterbi_algorithm_combined<gr_complex, unsigned char>( int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t TYPE, const gr_complex* in, unsigned char* out); //--------------- template void viterbi_algorithm_combined<char, short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<char>& TABLE, digital::trellis_metric_type_t TYPE, const char* in, short* out); template void viterbi_algorithm_combined<short, short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<short>& TABLE, digital::trellis_metric_type_t TYPE, const short* in, short* out); template void viterbi_algorithm_combined<int, short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<int>& TABLE, digital::trellis_metric_type_t TYPE, const int* in, short* out); template void viterbi_algorithm_combined<float, short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t TYPE, const float* in, short* out); template void viterbi_algorithm_combined<gr_complex, short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t TYPE, const gr_complex* in, short* out); //-------------- template void viterbi_algorithm_combined<char, int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<char>& TABLE, digital::trellis_metric_type_t TYPE, const char* in, int* out); template void viterbi_algorithm_combined<short, int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<short>& TABLE, digital::trellis_metric_type_t TYPE, const short* in, int* out); template void viterbi_algorithm_combined<int, int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<int>& TABLE, digital::trellis_metric_type_t TYPE, const int* in, int* out); template void viterbi_algorithm_combined<float, int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t TYPE, const float* in, int* out); template void viterbi_algorithm_combined<gr_complex, int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t TYPE, const gr_complex* in, int* out); //=============================================== void siso_algorithm(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), const float* priori, const float* prioro, float* post //, // std::vector<float> &alpha, // std::vector<float> &beta ) { float norm, mm, minm; std::vector<float> alpha(S * (K + 1)); std::vector<float> beta(S * (K + 1)); if (S0 < 0) { // initial state not specified for (int i = 0; i < S; i++) alpha[0 * S + i] = 0; } else { for (int i = 0; i < S; i++) alpha[0 * S + i] = INF; alpha[0 * S + S0] = 0.0; } for (int k = 0; k < K; k++) { // forward recursion norm = INF; for (int j = 0; j < S; j++) { minm = INF; for (unsigned int i = 0; i < PS[j].size(); i++) { // int i0 = j*I+i; mm = alpha[k * S + PS[j][i]] + priori[k * I + PI[j][i]] + prioro[k * O + OS[PS[j][i] * I + PI[j][i]]]; minm = (*p2mymin)(minm, mm); } alpha[(k + 1) * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) alpha[(k + 1) * S + j] -= norm; // normalize total metrics so they do not explode } if (SK < 0) { // final state not specified for (int i = 0; i < S; i++) beta[K * S + i] = 0; } else { for (int i = 0; i < S; i++) beta[K * S + i] = INF; beta[K * S + SK] = 0.0; } for (int k = K - 1; k >= 0; k--) { // backward recursion norm = INF; for (int j = 0; j < S; j++) { minm = INF; for (int i = 0; i < I; i++) { int i0 = j * I + i; mm = beta[(k + 1) * S + NS[i0]] + priori[k * I + i] + prioro[k * O + OS[i0]]; minm = (*p2mymin)(minm, mm); } beta[k * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) beta[k * S + j] -= norm; // normalize total metrics so they do not explode } if (POSTI && POSTO) { for (int k = 0; k < K; k++) { // input combining norm = INF; for (int i = 0; i < I; i++) { minm = INF; for (int j = 0; j < S; j++) { mm = alpha[k * S + j] + prioro[k * O + OS[j * I + i]] + beta[(k + 1) * S + NS[j * I + i]]; minm = (*p2mymin)(minm, mm); } post[k * (I + O) + i] = minm; if (minm < norm) norm = minm; } for (int i = 0; i < I; i++) post[k * (I + O) + i] -= norm; // normalize metrics } for (int k = 0; k < K; k++) { // output combining norm = INF; for (int n = 0; n < O; n++) { minm = INF; for (int j = 0; j < S; j++) { for (int i = 0; i < I; i++) { mm = (n == OS[j * I + i] ? alpha[k * S + j] + priori[k * I + i] + beta[(k + 1) * S + NS[j * I + i]] : INF); minm = (*p2mymin)(minm, mm); } } post[k * (I + O) + I + n] = minm; if (minm < norm) norm = minm; } for (int n = 0; n < O; n++) post[k * (I + O) + I + n] -= norm; // normalize metrics } } else if (POSTI) { for (int k = 0; k < K; k++) { // input combining norm = INF; for (int i = 0; i < I; i++) { minm = INF; for (int j = 0; j < S; j++) { mm = alpha[k * S + j] + prioro[k * O + OS[j * I + i]] + beta[(k + 1) * S + NS[j * I + i]]; minm = (*p2mymin)(minm, mm); } post[k * I + i] = minm; if (minm < norm) norm = minm; } for (int i = 0; i < I; i++) post[k * I + i] -= norm; // normalize metrics } } else if (POSTO) { for (int k = 0; k < K; k++) { // output combining norm = INF; for (int n = 0; n < O; n++) { minm = INF; for (int j = 0; j < S; j++) { for (int i = 0; i < I; i++) { mm = (n == OS[j * I + i] ? alpha[k * S + j] + priori[k * I + i] + beta[(k + 1) * S + NS[j * I + i]] : INF); minm = (*p2mymin)(minm, mm); } } post[k * O + n] = minm; if (minm < norm) norm = minm; } for (int n = 0; n < O; n++) post[k * O + n] -= norm; // normalize metrics } } else throw std::runtime_error("Not both POSTI and POSTO can be false."); } //=========================================================== template <class T> void siso_algorithm_combined(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), int D, const std::vector<T>& TABLE, digital::trellis_metric_type_t TYPE, const float* priori, const T* observations, float* post) { float norm, mm, minm; std::vector<float> alpha(S * (K + 1)); std::vector<float> beta(S * (K + 1)); std::vector<float> prioro(O * K); if (S0 < 0) { // initial state not specified for (int i = 0; i < S; i++) alpha[0 * S + i] = 0; } else { for (int i = 0; i < S; i++) alpha[0 * S + i] = INF; alpha[0 * S + S0] = 0.0; } for (int k = 0; k < K; k++) { // forward recursion calc_metric( O, D, TABLE, &(observations[k * D]), &(prioro[k * O]), TYPE); // calc metrics norm = INF; for (int j = 0; j < S; j++) { minm = INF; for (unsigned int i = 0; i < PS[j].size(); i++) { // int i0 = j*I+i; mm = alpha[k * S + PS[j][i]] + priori[k * I + PI[j][i]] + prioro[k * O + OS[PS[j][i] * I + PI[j][i]]]; minm = (*p2mymin)(minm, mm); } alpha[(k + 1) * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) alpha[(k + 1) * S + j] -= norm; // normalize total metrics so they do not explode } if (SK < 0) { // final state not specified for (int i = 0; i < S; i++) beta[K * S + i] = 0; } else { for (int i = 0; i < S; i++) beta[K * S + i] = INF; beta[K * S + SK] = 0.0; } for (int k = K - 1; k >= 0; k--) { // backward recursion norm = INF; for (int j = 0; j < S; j++) { minm = INF; for (int i = 0; i < I; i++) { int i0 = j * I + i; mm = beta[(k + 1) * S + NS[i0]] + priori[k * I + i] + prioro[k * O + OS[i0]]; minm = (*p2mymin)(minm, mm); } beta[k * S + j] = minm; if (minm < norm) norm = minm; } for (int j = 0; j < S; j++) beta[k * S + j] -= norm; // normalize total metrics so they do not explode } if (POSTI && POSTO) { for (int k = 0; k < K; k++) { // input combining norm = INF; for (int i = 0; i < I; i++) { minm = INF; for (int j = 0; j < S; j++) { mm = alpha[k * S + j] + prioro[k * O + OS[j * I + i]] + beta[(k + 1) * S + NS[j * I + i]]; minm = (*p2mymin)(minm, mm); } post[k * (I + O) + i] = minm; if (minm < norm) norm = minm; } for (int i = 0; i < I; i++) post[k * (I + O) + i] -= norm; // normalize metrics } for (int k = 0; k < K; k++) { // output combining norm = INF; for (int n = 0; n < O; n++) { minm = INF; for (int j = 0; j < S; j++) { for (int i = 0; i < I; i++) { mm = (n == OS[j * I + i] ? alpha[k * S + j] + priori[k * I + i] + beta[(k + 1) * S + NS[j * I + i]] : INF); minm = (*p2mymin)(minm, mm); } } post[k * (I + O) + I + n] = minm; if (minm < norm) norm = minm; } for (int n = 0; n < O; n++) post[k * (I + O) + I + n] -= norm; // normalize metrics } } else if (POSTI) { for (int k = 0; k < K; k++) { // input combining norm = INF; for (int i = 0; i < I; i++) { minm = INF; for (int j = 0; j < S; j++) { mm = alpha[k * S + j] + prioro[k * O + OS[j * I + i]] + beta[(k + 1) * S + NS[j * I + i]]; minm = (*p2mymin)(minm, mm); } post[k * I + i] = minm; if (minm < norm) norm = minm; } for (int i = 0; i < I; i++) post[k * I + i] -= norm; // normalize metrics } } else if (POSTO) { for (int k = 0; k < K; k++) { // output combining norm = INF; for (int n = 0; n < O; n++) { minm = INF; for (int j = 0; j < S; j++) { for (int i = 0; i < I; i++) { mm = (n == OS[j * I + i] ? alpha[k * S + j] + priori[k * I + i] + beta[(k + 1) * S + NS[j * I + i]] : INF); minm = (*p2mymin)(minm, mm); } } post[k * O + n] = minm; if (minm < norm) norm = minm; } for (int n = 0; n < O; n++) post[k * O + n] -= norm; // normalize metrics } } else throw std::runtime_error("Not both POSTI and POSTO can be false."); } //--------- template void siso_algorithm_combined<short>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), int D, const std::vector<short>& TABLE, digital::trellis_metric_type_t TYPE, const float* priori, const short* observations, float* post); template void siso_algorithm_combined<int>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), int D, const std::vector<int>& TABLE, digital::trellis_metric_type_t TYPE, const float* priori, const int* observations, float* post); template void siso_algorithm_combined<float>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t TYPE, const float* priori, const float* observations, float* post); template void siso_algorithm_combined<gr_complex>(int I, int S, int O, const std::vector<int>& NS, const std::vector<int>& OS, const std::vector<std::vector<int>>& PS, const std::vector<std::vector<int>>& PI, int K, int S0, int SK, bool POSTI, bool POSTO, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t TYPE, const float* priori, const gr_complex* observations, float* post); //========================================================= template <class Ti, class To> void sccc_decoder_combined(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<Ti>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const Ti* observations, To* data) { // allocate space for priori, prioro and posti of inner FSM std::vector<float> ipriori(blocklength * FSMi.I(), 0.0); std::vector<float> iprioro(blocklength * FSMi.O()); std::vector<float> iposti(blocklength * FSMi.I()); // allocate space for priori, prioro and posto of outer FSM std::vector<float> opriori(blocklength * FSMo.I(), 0.0); std::vector<float> oprioro(blocklength * FSMo.O()); std::vector<float> oposti(blocklength * FSMo.I()); std::vector<float> oposto(blocklength * FSMo.O()); // turn observations to neg-log-priors for (int k = 0; k < blocklength; k++) { calc_metric(FSMi.O(), D, TABLE, &(observations[k * D]), &(iprioro[k * FSMi.O()]), METRIC_TYPE); iprioro[k * FSMi.O()] *= scaling; } for (int rep = 0; rep < iterations; rep++) { // run inner SISO siso_algorithm(FSMi.I(), FSMi.S(), FSMi.O(), FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(), blocklength, STi0, STiK, true, false, p2mymin, &(ipriori[0]), &(iprioro[0]), &(iposti[0])); // interleave soft info inner -> outer for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.DEINTER()[k]; // for(int i=0;i<FSMi.I();i++) { // oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; //} memcpy(&(oprioro[k * FSMi.I()]), &(iposti[ki * FSMi.I()]), FSMi.I() * sizeof(float)); } // run outer SISO if (rep < iterations - 1) { // do not produce posti siso_algorithm(FSMo.I(), FSMo.S(), FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0, SToK, false, true, p2mymin, &(opriori[0]), &(oprioro[0]), &(oposto[0])); // interleave soft info outer --> inner for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.DEINTER()[k]; // for(int i=0;i<FSMi.I();i++) { // ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; //} memcpy(&(ipriori[ki * FSMi.I()]), &(oposto[k * FSMi.I()]), FSMi.I() * sizeof(float)); } } else // produce posti but not posto siso_algorithm(FSMo.I(), FSMo.S(), FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0, SToK, true, false, p2mymin, &(opriori[0]), &(oprioro[0]), &(oposti[0])); /* viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0,SToK, &(oprioro[0]), data ); */ } // generate hard decisions for (int k = 0; k < blocklength; k++) { float min = INF; int mini = 0; for (int i = 0; i < FSMo.I(); i++) { if (oposti[k * FSMo.I() + i] < min) { min = oposti[k * FSMo.I() + i]; mini = i; } } data[k] = (To)mini; } } //------- template void sccc_decoder_combined<float, unsigned char>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, unsigned char* data); template void sccc_decoder_combined<float, short>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, short* data); template void sccc_decoder_combined<float, int>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, int* data); template void sccc_decoder_combined<gr_complex, unsigned char>( const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, unsigned char* data); template void sccc_decoder_combined<gr_complex, short>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, short* data); template void sccc_decoder_combined<gr_complex, int>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, int* data); //========================================================= template <class T> void sccc_decoder(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* iprioro, T* data) { // allocate space for priori, and posti of inner FSM std::vector<float> ipriori(blocklength * FSMi.I(), 0.0); std::vector<float> iposti(blocklength * FSMi.I()); // allocate space for priori, prioro and posto of outer FSM std::vector<float> opriori(blocklength * FSMo.I(), 0.0); std::vector<float> oprioro(blocklength * FSMo.O()); std::vector<float> oposti(blocklength * FSMo.I()); std::vector<float> oposto(blocklength * FSMo.O()); for (int rep = 0; rep < iterations; rep++) { // run inner SISO siso_algorithm(FSMi.I(), FSMi.S(), FSMi.O(), FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(), blocklength, STi0, STiK, true, false, p2mymin, &(ipriori[0]), &(iprioro[0]), &(iposti[0])); // interleave soft info inner -> outer for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.DEINTER()[k]; // for(int i=0;i<FSMi.I();i++) { // oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; //} memcpy(&(oprioro[k * FSMi.I()]), &(iposti[ki * FSMi.I()]), FSMi.I() * sizeof(float)); } // run outer SISO if (rep < iterations - 1) { // do not produce posti siso_algorithm(FSMo.I(), FSMo.S(), FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0, SToK, false, true, p2mymin, &(opriori[0]), &(oprioro[0]), &(oposto[0])); // interleave soft info outer --> inner for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.DEINTER()[k]; // for(int i=0;i<FSMi.I();i++) { // ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; //} memcpy(&(ipriori[ki * FSMi.I()]), &(oposto[k * FSMi.I()]), FSMi.I() * sizeof(float)); } } else { // produce posti but not posto siso_algorithm(FSMo.I(), FSMo.S(), FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0, SToK, true, false, p2mymin, &(opriori[0]), &(oprioro[0]), &(oposti[0])); /* viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(), FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(), blocklength, STo0,SToK, &(oprioro[0]), data); */ } } // end iterations // generate hard decisions for (int k = 0; k < blocklength; k++) { float min = INF; int mini = 0; for (int i = 0; i < FSMo.I(); i++) { if (oposti[k * FSMo.I() + i] < min) { min = oposti[k * FSMo.I() + i]; mini = i; } } data[k] = (T)mini; } } //------- template void sccc_decoder<unsigned char>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* iprioro, unsigned char* data); template void sccc_decoder<short>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* iprioro, short* data); template void sccc_decoder<int>(const fsm& FSMo, int STo0, int SToK, const fsm& FSMi, int STi0, int STiK, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* iprioro, int* data); //==================================================== template <class T> void pccc_decoder(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* cprioro, T* data) { // allocate space for priori, prioro and posti of FSM1 std::vector<float> priori1(blocklength * FSM1.I(), 0.0); std::vector<float> prioro1(blocklength * FSM1.O()); std::vector<float> posti1(blocklength * FSM1.I()); // allocate space for priori, prioro and posti of FSM2 std::vector<float> priori2(blocklength * FSM2.I(), 0.0); std::vector<float> prioro2(blocklength * FSM2.O()); std::vector<float> posti2(blocklength * FSM2.I()); // generate prioro1,2 (metrics are not updated per iteration: this is not the best you // can do...) for (int k = 0; k < blocklength; k++) { // std::cout << k << std::endl; for (int i = 0; i < FSM1.O(); i++) { float x = cprioro[k * FSM1.O() * FSM2.O() + i * FSM1.O() + 0]; for (int j = 1; j < FSM2.O(); j++) x = (*p2mymin)(x, cprioro[k * FSM1.O() * FSM2.O() + i * FSM1.O() + j]); prioro1[k * FSM1.O() + i] = x; // std::cout << prioro1[k*FSM1.O()+i] << ", "; } // std::cout << std::endl; for (int i = 0; i < FSM2.O(); i++) { float x = cprioro[k * FSM1.O() * FSM2.O() + 0 * FSM1.O() + i]; for (int j = 1; j < FSM1.O(); j++) x = (*p2mymin)(x, cprioro[k * FSM1.O() * FSM2.O() + j * FSM1.O() + i]); prioro2[k * FSM2.O() + i] = x; } } for (int rep = 0; rep < iterations; rep++) { // run SISO 1 siso_algorithm(FSM1.I(), FSM1.S(), FSM1.O(), FSM1.NS(), FSM1.OS(), FSM1.PS(), FSM1.PI(), blocklength, ST10, ST1K, true, false, p2mymin, &(priori1[0]), &(prioro1[0]), &(posti1[0])); // for(int k=0;k<blocklength;k++){ // for(int i=0;i<FSM1.I();i++) // std::cout << posti1[k*FSM1.I()+i] << ", "; // std::cout << std::endl; //} // interleave soft info 1 -> 2 for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.INTER()[k]; // for(int i=0;i<FSMi.I();i++) { // oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; //} memcpy(&(priori2[k * FSM2.I()]), &(posti1[ki * FSM1.I()]), FSM1.I() * sizeof(float)); } // run SISO 2 siso_algorithm(FSM2.I(), FSM2.S(), FSM2.O(), FSM2.NS(), FSM2.OS(), FSM2.PS(), FSM2.PI(), blocklength, ST20, ST2K, true, false, p2mymin, &(priori2[0]), &(prioro2[0]), &(posti2[0])); // interleave soft info 2 --> 1 for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.INTER()[k]; // for(int i=0;i<FSMi.I();i++) { // ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; //} memcpy(&(priori1[ki * FSM1.I()]), &(posti2[k * FSM2.I()]), FSM1.I() * sizeof(float)); } } // end iterations // generate hard decisions for (int k = 0; k < blocklength; k++) { for (int i = 0; i < FSM1.I(); i++) posti1[k * FSM1.I() + i] = (*p2mymin)(priori1[k * FSM1.I() + i], posti1[k * FSM1.I() + i]); float min = INF; int mini = 0; for (int i = 0; i < FSM1.I(); i++) { if (posti1[k * FSM1.I() + i] < min) { min = posti1[k * FSM1.I() + i]; mini = i; } } data[k] = (T)mini; // std::cout << data[k] << ", "<< std::endl; } // std::cout << std::endl; } //---------------- template void pccc_decoder<unsigned char>(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* cprioro, unsigned char* data); template void pccc_decoder<short>(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* cprioro, short* data); template void pccc_decoder<int>(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), const float* cprioro, int* data); //---------------- template <class Ti, class To> void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<Ti>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const Ti* observations, To* data) { // allocate space for cprioro std::vector<float> cprioro(blocklength * FSM1.O() * FSM2.O(), 0.0); // allocate space for priori, prioro and posti of FSM1 std::vector<float> priori1(blocklength * FSM1.I(), 0.0); std::vector<float> prioro1(blocklength * FSM1.O()); std::vector<float> posti1(blocklength * FSM1.I()); // allocate space for priori, prioro and posti of FSM2 std::vector<float> priori2(blocklength * FSM2.I(), 0.0); std::vector<float> prioro2(blocklength * FSM2.O()); std::vector<float> posti2(blocklength * FSM2.I()); // turn observations to neg-log-priors for cprioiro int O = FSM1.O() * FSM2.O(); for (int k = 0; k < blocklength; k++) { calc_metric(O, D, TABLE, &(observations[k * D]), &(cprioro[k * O]), METRIC_TYPE); cprioro[k * O] *= scaling; } // generate prioro1,2 (metrics are not updated per iteration: this is not the best you // can do...) for (int k = 0; k < blocklength; k++) { // std::cout << k << std::endl; for (int i = 0; i < FSM1.O(); i++) { float x = cprioro[k * O + i * FSM2.O() + 0]; for (int j = 1; j < FSM2.O(); j++) x = (*p2mymin)(x, cprioro[k * O + i * FSM2.O() + j]); prioro1[k * FSM1.O() + i] = x; // std::cout << prioro1[k*FSM1.O()+i] << ", "; } // std::cout << std::endl; for (int i = 0; i < FSM2.O(); i++) { float x = cprioro[k * O + 0 * FSM2.O() + i]; for (int j = 1; j < FSM1.O(); j++) x = (*p2mymin)(x, cprioro[k * O + j * FSM2.O() + i]); prioro2[k * FSM2.O() + i] = x; } } for (int rep = 0; rep < iterations; rep++) { // run SISO 1 siso_algorithm(FSM1.I(), FSM1.S(), FSM1.O(), FSM1.NS(), FSM1.OS(), FSM1.PS(), FSM1.PI(), blocklength, ST10, ST1K, true, false, p2mymin, &(priori1[0]), &(prioro1[0]), &(posti1[0])); // for(int k=0;k<blocklength;k++){ // for(int i=0;i<FSM1.I();i++) // std::cout << posti1[k*FSM1.I()+i] << ", "; // std::cout << std::endl; //} // interleave soft info 1 -> 2 for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.INTER()[k]; // for(int i=0;i<FSMi.I();i++) { // oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i]; //} memcpy(&(priori2[k * FSM2.I()]), &(posti1[ki * FSM1.I()]), FSM1.I() * sizeof(float)); } // run SISO 2 siso_algorithm(FSM2.I(), FSM2.S(), FSM2.O(), FSM2.NS(), FSM2.OS(), FSM2.PS(), FSM2.PI(), blocklength, ST20, ST2K, true, false, p2mymin, &(priori2[0]), &(prioro2[0]), &(posti2[0])); // interleave soft info 2 --> 1 for (int k = 0; k < blocklength; k++) { int ki = INTERLEAVER.INTER()[k]; // for(int i=0;i<FSMi.I();i++) { // ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i]; //} memcpy(&(priori1[ki * FSM1.I()]), &(posti2[k * FSM2.I()]), FSM1.I() * sizeof(float)); } } // end iterations // generate hard decisions for (int k = 0; k < blocklength; k++) { for (int i = 0; i < FSM1.I(); i++) posti1[k * FSM1.I() + i] = (*p2mymin)(priori1[k * FSM1.I() + i], posti1[k * FSM1.I() + i]); float min = INF; int mini = 0; for (int i = 0; i < FSM1.I(); i++) { if (posti1[k * FSM1.I() + i] < min) { min = posti1[k * FSM1.I() + i]; mini = i; } } data[k] = (To)mini; // std::cout << data[k] << ", "<< std::endl; } // std::cout << std::endl; } template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, unsigned char* data); template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, short* data); template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<float>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const float* observations, int* data); template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, unsigned char* data); template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, short* data); template void pccc_decoder_combined(const fsm& FSM1, int ST10, int ST1K, const fsm& FSM2, int ST20, int ST2K, const interleaver& INTERLEAVER, int blocklength, int iterations, float (*p2mymin)(float, float), int D, const std::vector<gr_complex>& TABLE, digital::trellis_metric_type_t METRIC_TYPE, float scaling, const gr_complex* observations, int* data); } /* namespace trellis */ } /* namespace gr */