mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2024-12-19 21:58:12 +00:00
Add C models for FFT/IFFT and Viterbi decoder
This commit is contained in:
parent
cbcc2c1951
commit
ea221d0b3f
7
fpga/ip/nuand/fft/model/Makefile
Normal file
7
fpga/ip/nuand/fft/model/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
all: dft idft
|
||||
|
||||
dft: dft.c
|
||||
gcc -o dft dft.c -g3 -lm
|
||||
|
||||
idft: idft.c
|
||||
gcc -o idft idft.c -g3 -lm
|
173
fpga/ip/nuand/fft/model/dft.c
Normal file
173
fpga/ip/nuand/fft/model/dft.c
Normal file
@ -0,0 +1,173 @@
|
||||
// This file is part of bladeRF-wiphy.
|
||||
//
|
||||
// Copyright (C) 2021 Nuand, LLC.
|
||||
//
|
||||
// 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int flip_bits(unsigned in, int bits) {
|
||||
unsigned ret = 0;
|
||||
int i;
|
||||
for (i = 0; i < bits; i++) {
|
||||
ret |= ( !!(in & (1 << i)) ) << (bits - i - 1);
|
||||
}
|
||||
printf("IN %d, OUT %d\n", in, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned rotate_left(unsigned in, int width, int num) {
|
||||
unsigned ret = 0;
|
||||
unsigned bottom = 0;
|
||||
unsigned mask = 0;
|
||||
bottom = in;
|
||||
//printf("#1 = %d\n", bottom);
|
||||
bottom >>= (width - num);
|
||||
//printf("#2 = %d\n", bottom);
|
||||
mask = ((1 << (num+1)) - 1);
|
||||
//printf("mask = %d\n", mask);
|
||||
bottom &= mask;
|
||||
//printf("BOTTOM = %d\n", bottom);
|
||||
|
||||
ret = in;
|
||||
ret <<= num;
|
||||
ret = ret & ((1 << width) - 1);
|
||||
//printf("TOP = %d\n", ret);
|
||||
|
||||
ret |= bottom;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
struct c_sample {
|
||||
float i, q;
|
||||
};
|
||||
|
||||
#define N 64
|
||||
#define N_POW 6
|
||||
#define FMT "%f"
|
||||
|
||||
struct c_sample rfs_i[] = {
|
||||
{ 402, 750}, { -439, 700}, { 909, -96}, {-7, -496}, {76, -711}, {764, 601}, {-192, 315}, {411, -633},
|
||||
{-540, -139}, {-360, -640}, {821, -172}, {160, 291}, {9, -678}, {-679, -241}, {69, -293}, {565, -172},
|
||||
{-356, 999}, {515, -19}, {438, -498}, {78, 693}, {-276, 209}, {-865, 131}, {465, 487}, {454, 35},
|
||||
{-480, 437}, {-324, -45}, {-86, -991}, {-471, 2}, {-805, -38}, {543, -621}, {170, 397}, {-797, 606},
|
||||
{546, 369}, {150, 591}, {-1095, -17}, {109, -684}, {760, -450}, {-573, -478}, {-66, -409}, {682, 484},
|
||||
{-862, 201}, {-695, -192}, {16, 819}, {-403, 172}, {-342, -660}, {443, 14}, {544, -389}, {-734, -339},
|
||||
{-366, -141}, {381, -626}, {280, 382}, {624, 235}, {-218, 980}, {333, 54}, {333, 506}, {-944, 114},
|
||||
{46, 566}, {305, -48}, {457, -20}, {-56, 740}, {-919, 197}, {522, 295}, {-2, 20}, {438, -712}
|
||||
};
|
||||
|
||||
void gen_sample(int n, struct c_sample *ptr) {
|
||||
int r, idx;
|
||||
for (r = 0; r < n; r++) {
|
||||
idx = flip_bits(r, N_POW);
|
||||
ptr[idx] = rfs_i[r];
|
||||
printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q);
|
||||
}
|
||||
}
|
||||
|
||||
void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW)
|
||||
{
|
||||
struct c_sample mix, t_A, t_B;
|
||||
// A = a_i + j * a_q
|
||||
// B = b_i + j * b_q
|
||||
|
||||
// C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q)
|
||||
// C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i )
|
||||
// C_i = a_i * b_i - a_q * b_q
|
||||
// C_q = a_i * b_q + a_q * b_i
|
||||
|
||||
|
||||
mix.i = (B->i * TW->i - B->q * TW->q) /(32768);//>> 15;
|
||||
mix.q = (B->i * TW->q + B->q * TW->i) /(32768);//>> 15;
|
||||
|
||||
//A->i *= 1;
|
||||
//A->q *= 1;
|
||||
//B->i *= 1;
|
||||
//B->q *= 1;
|
||||
|
||||
t_A.i = A->i + mix.i;
|
||||
t_A.q = A->q + mix.q;
|
||||
|
||||
t_B.i = A->i - mix.i;
|
||||
t_B.q = A->q - mix.q;
|
||||
|
||||
printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT " TW: " FMT " + j* " FMT "\n", A->i, A->q, B->i, B->q, TW->i, TW->q);
|
||||
printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q);
|
||||
|
||||
*A = t_A;
|
||||
*B = t_B;
|
||||
printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q);
|
||||
}
|
||||
|
||||
|
||||
int W_i[N/2];
|
||||
int W_q[N/2];
|
||||
int main() {
|
||||
float ti, tq;
|
||||
int i, j;
|
||||
struct c_sample s_a[N], s_b[N], s_tw[N];
|
||||
gen_sample(N, s_a);
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < (N);i++) {
|
||||
printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
for (i = 0; i < (N/2);i++) {
|
||||
printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N));
|
||||
}
|
||||
*/
|
||||
|
||||
for (i = 0; i < (N/2); i++) {
|
||||
ti = cosf((2.0 * M_PI * (float)i) / (float)N);
|
||||
s_tw[i].i = W_i[i] = ti * ((1<<15)-1);
|
||||
tq = sinf((2.0 * M_PI * (float)i) / (float)N);
|
||||
s_tw[i].q = W_q[i] = tq * ((1<<15)-1);
|
||||
|
||||
|
||||
printf("[%.2d] I= %.15f = 0x%.8x Q= %.15f = 0x%.8x\t\t" FMT ", " FMT "\n", i, ti, W_i[i], tq, W_q[i], s_tw[i].i, s_tw[i].q);
|
||||
}
|
||||
|
||||
for (i = 0; i < N_POW; i++) {
|
||||
for (j = 0; j < (N/2); j++) {
|
||||
int a, b, tw;
|
||||
a = rotate_left(j * 2, N_POW, i);
|
||||
b = rotate_left(j * 2 + 1, N_POW, i);
|
||||
//tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF
|
||||
tw = (j ) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1);
|
||||
|
||||
printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw);
|
||||
if ( i == 0) {
|
||||
printf("\t%d,%d => A is timeidx = %d, B is timeidx = %d\n", a,b, flip_bits(a, N_POW), flip_bits(b, N_POW));
|
||||
}
|
||||
butter_fly(s_a + a, s_a + b, s_tw + tw );
|
||||
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i, s_a[i].q);
|
||||
}
|
||||
printf("\n\n");
|
||||
for (i = 0; i < N; i++) {
|
||||
printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q));
|
||||
}
|
||||
return 0;
|
||||
}
|
166
fpga/ip/nuand/fft/model/idft.c
Normal file
166
fpga/ip/nuand/fft/model/idft.c
Normal file
@ -0,0 +1,166 @@
|
||||
// This file is part of bladeRF-wiphy.
|
||||
//
|
||||
// Copyright (C) 2021 Nuand, LLC.
|
||||
//
|
||||
// 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int flip_bits(unsigned in, int bits) {
|
||||
unsigned ret = 0;
|
||||
int i;
|
||||
for (i = 0; i < bits; i++) {
|
||||
ret |= ( !!(in & (1 << i)) ) << (bits - i - 1);
|
||||
}
|
||||
printf("IN %d, OUT %d\n", in, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int f_s[]= {
|
||||
0, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1 };
|
||||
|
||||
unsigned rotate_left(unsigned in, int width, int num) {
|
||||
unsigned ret = 0;
|
||||
unsigned bottom = 0;
|
||||
unsigned mask = 0;
|
||||
bottom = in;
|
||||
//printf("#1 = %d\n", bottom);
|
||||
bottom >>= (width - num);
|
||||
//printf("#2 = %d\n", bottom);
|
||||
mask = ((1 << (num+1)) - 1);
|
||||
//printf("mask = %d\n", mask);
|
||||
bottom &= mask;
|
||||
//printf("BOTTOM = %d\n", bottom);
|
||||
|
||||
ret = in;
|
||||
ret <<= num;
|
||||
ret = ret & ((1 << width) - 1);
|
||||
//printf("TOP = %d\n", ret);
|
||||
|
||||
ret |= bottom;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
struct c_sample {
|
||||
long long int i, q;
|
||||
};
|
||||
|
||||
#define N 64
|
||||
#define N_POW 6
|
||||
#define FMT "%lld"
|
||||
|
||||
void gen_sample(int n, struct c_sample *ptr) {
|
||||
int r, idx;
|
||||
for (r = 0; r < n; r++) {
|
||||
idx = flip_bits(r, N_POW);
|
||||
ptr[idx].i = f_s[r] * 4096;
|
||||
ptr[idx].q = 0;
|
||||
printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q);
|
||||
}
|
||||
}
|
||||
|
||||
void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW)
|
||||
{
|
||||
struct c_sample mix, t_A, t_B;
|
||||
// A = a_i + j * a_q
|
||||
// B = b_i + j * b_q
|
||||
|
||||
// C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q)
|
||||
// C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i )
|
||||
// C_i = a_i * b_i - a_q * b_q
|
||||
// C_q = a_i * b_q + a_q * b_i
|
||||
|
||||
|
||||
mix.i = (B->i * TW->i - B->q * TW->q) >> 15;
|
||||
mix.q = (B->i * TW->q + B->q * TW->i) >> 15;
|
||||
|
||||
//A->i *= 1;
|
||||
//A->q *= 1;
|
||||
//B->i *= 1;
|
||||
//B->q *= 1;
|
||||
|
||||
t_A.i = A->i + mix.i;
|
||||
t_A.q = A->q + mix.q;
|
||||
|
||||
t_B.i = A->i - mix.i;
|
||||
t_B.q = A->q - mix.q;
|
||||
|
||||
printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT " TW: " FMT " + j* " FMT "\n", A->i, A->q, B->i, B->q, TW->i, TW->q);
|
||||
printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q);
|
||||
|
||||
*A = t_A;
|
||||
*B = t_B;
|
||||
printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q);
|
||||
}
|
||||
|
||||
|
||||
int W_i[N/2];
|
||||
int W_q[N/2];
|
||||
int main() {
|
||||
float ti, tq;
|
||||
int i, j;
|
||||
struct c_sample s_a[N], s_b[N], s_tw[N];
|
||||
gen_sample(N, s_a);
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < (N);i++) {
|
||||
printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
for (i = 0; i < (N/2);i++) {
|
||||
printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N));
|
||||
}
|
||||
*/
|
||||
|
||||
for (i = 0; i < (N/2); i++) {
|
||||
ti = cosf((2.0 * M_PI * (float)i) / (float)N);
|
||||
s_tw[i].i = W_i[i] = ti * ((1<<15)-1);
|
||||
tq = sinf((2.0 * M_PI * (float)i) / (float)N);
|
||||
s_tw[i].q = W_q[i] = tq * ((1<<15)-1);
|
||||
|
||||
|
||||
printf("[%.2d] I= %.15f = 0x%.8x Q= %.15f = 0x%.8x\t\t" FMT ", " FMT "\n", i, ti, W_i[i], tq, W_q[i], s_tw[i].i, s_tw[i].q);
|
||||
}
|
||||
|
||||
for (i = 0; i < N_POW; i++) {
|
||||
for (j = 0; j < (N/2); j++) {
|
||||
int a, b, tw;
|
||||
a = rotate_left(j * 2, N_POW, i);
|
||||
b = rotate_left(j * 2 + 1, N_POW, i);
|
||||
//tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF
|
||||
tw = (j) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1);
|
||||
|
||||
printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw);
|
||||
if (i == 0) {
|
||||
printf("\t%d,%d => A is timeidx = %d, B is timeidx = %d\n", a,b, flip_bits(a, N_POW), flip_bits(b, N_POW));
|
||||
}
|
||||
butter_fly(s_a + a, s_a + b, s_tw + tw );
|
||||
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i/64, s_a[i].q/64);
|
||||
}
|
||||
printf("\n\n");
|
||||
for (i = 0; i < N; i++) {
|
||||
printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q));
|
||||
}
|
||||
return 0;
|
||||
}
|
336
fpga/ip/nuand/viterbi_decoder/model/encoder.c
Normal file
336
fpga/ip/nuand/viterbi_decoder/model/encoder.c
Normal file
@ -0,0 +1,336 @@
|
||||
// This file is part of bladeRF-wiphy.
|
||||
//
|
||||
// Copyright (C) 2021 Nuand, LLC.
|
||||
//
|
||||
// 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define K 7
|
||||
#define C_A 91
|
||||
#define C_B 121
|
||||
|
||||
#define NUM_BT 1000
|
||||
#define BIT(y) ( (state >> y) & 1)
|
||||
|
||||
#define T_BIT(y) ( (t_state >> y) & 1)
|
||||
|
||||
uint32_t state;
|
||||
unsigned int byte_a, byte_b ;
|
||||
|
||||
struct path {
|
||||
int32_t cost;
|
||||
uint32_t from_state[NUM_BT];
|
||||
uint32_t bits[NUM_BT];
|
||||
uint32_t bm[NUM_BT];
|
||||
uint32_t set[NUM_BT];
|
||||
uint32_t to_state[NUM_BT];
|
||||
uint32_t win[NUM_BT];
|
||||
};
|
||||
|
||||
uint32_t win_history[100][64];
|
||||
|
||||
struct path_metric {
|
||||
int idx;
|
||||
struct path paths[ 0x40 ];
|
||||
};
|
||||
|
||||
void branch_metric_loop(struct path_metric *in_path, uint8_t r_a, int erasure_a, uint8_t r_b, int erasure_b) {
|
||||
// the T_ prefix just means test
|
||||
unsigned t_state;
|
||||
uint8_t t_bit_a, t_bit_b;
|
||||
uint32_t bm;
|
||||
uint32_t next_state;
|
||||
|
||||
uint32_t bm_tbl_cost[0x40]; // idx: the end state
|
||||
uint32_t bm_tbl_bit[0x40]; // idx: the end state
|
||||
memset(bm_tbl_cost, 0xff, sizeof(bm_tbl_cost));
|
||||
memset(bm_tbl_bit, 0xff, sizeof(bm_tbl_bit));
|
||||
|
||||
struct path_metric out_path;
|
||||
|
||||
memcpy(&out_path, in_path, sizeof(out_path));
|
||||
out_path.idx = in_path->idx++;
|
||||
|
||||
for (t_state = 0; t_state <= 0x3f; t_state++) {
|
||||
// calculate the branch metric by:
|
||||
// assuming the trellis at t_state and is about to head to next_state
|
||||
// the uncoded data bit determines to which one of two states the trellis goes from t_state
|
||||
// as it goes to next_state from t_state, two coded bits t_bit_a and t_bit_b are output
|
||||
// the branch metric is the sum of error between the expected value t_bit_a/t_bit_b and the received value r_a/r_b
|
||||
//
|
||||
// each "destination state"'s path metric is calculated by adding the current corresponding branch metric to the two possible "source state"'s path metric,
|
||||
// and selecting the path with the lowest total path cost
|
||||
//
|
||||
// each state can only be entered from 2 previous states, so the hardware only has to calculate the branch metric (and total path metric) from 2 previous "source states".
|
||||
|
||||
// bit is 0?
|
||||
t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 0;
|
||||
t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 0;
|
||||
|
||||
//bm = (t_bit_a - r_a) + (t_bit_b - r_b);
|
||||
bm = in_path->paths[t_state].cost;
|
||||
if (!erasure_a) {
|
||||
if (t_bit_a > r_a) {
|
||||
bm += t_bit_a - r_a;
|
||||
} else {
|
||||
bm += r_a - t_bit_a;
|
||||
}
|
||||
}
|
||||
|
||||
if (!erasure_b) {
|
||||
if (t_bit_b > r_b) {
|
||||
bm += t_bit_b - r_b;
|
||||
} else {
|
||||
bm += r_b - t_bit_b;
|
||||
}
|
||||
}
|
||||
|
||||
next_state = (t_state << 1) & 0x3f;
|
||||
|
||||
if (bm < bm_tbl_cost[next_state]) {
|
||||
bm_tbl_cost[next_state] = bm;
|
||||
bm_tbl_bit[next_state] = 0;
|
||||
|
||||
out_path.paths[next_state] = in_path->paths[t_state];
|
||||
out_path.paths[next_state].cost = bm;
|
||||
out_path.paths[next_state].from_state[out_path.idx] = t_state;
|
||||
out_path.paths[next_state].bits[out_path.idx] = 0;
|
||||
out_path.paths[next_state].to_state[out_path.idx] = next_state;
|
||||
out_path.paths[next_state].bm[out_path.idx] = bm;
|
||||
out_path.paths[next_state].set[out_path.idx] = 1;
|
||||
win_history[out_path.idx][next_state] = !!(t_state & (1 << 5));
|
||||
}
|
||||
//printf("B=0 COMPUTE S=%.2d TO D=%.2d del=%d\n", t_state, next_state, t_state-next_state);
|
||||
|
||||
|
||||
bm = in_path->paths[t_state].cost;
|
||||
// bit is 1?
|
||||
t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 1;
|
||||
t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 1;
|
||||
|
||||
if (!erasure_a) {
|
||||
if (t_bit_a > r_a) {
|
||||
bm += t_bit_a - r_a;
|
||||
} else {
|
||||
bm += r_a - t_bit_a;
|
||||
}
|
||||
}
|
||||
|
||||
if (!erasure_b) {
|
||||
if (t_bit_b > r_b) {
|
||||
bm += t_bit_b - r_b;
|
||||
} else {
|
||||
bm += r_b - t_bit_b;
|
||||
}
|
||||
}
|
||||
next_state = ((t_state << 1) & 0x3f) | 1;
|
||||
|
||||
if (bm < bm_tbl_cost[next_state]) {
|
||||
bm_tbl_cost[next_state] = bm;
|
||||
bm_tbl_bit[next_state] = 0;
|
||||
|
||||
out_path.paths[next_state] = in_path->paths[t_state];
|
||||
out_path.paths[next_state].cost = bm;
|
||||
out_path.paths[next_state].from_state[out_path.idx] = t_state;
|
||||
out_path.paths[next_state].bits[out_path.idx] = 1;
|
||||
out_path.paths[next_state].to_state[out_path.idx] = next_state;
|
||||
out_path.paths[next_state].bm[out_path.idx] = bm;
|
||||
out_path.paths[next_state].set[out_path.idx] = 1;
|
||||
win_history[out_path.idx][next_state] = !!(t_state & (1 << 5));
|
||||
}
|
||||
//printf("B=1 COMPUTE S=%.2d TO D=%.2d del=%d\n", t_state, next_state, t_state-next_state);
|
||||
|
||||
}
|
||||
|
||||
out_path.idx++;
|
||||
memcpy(in_path, &out_path, sizeof(out_path));
|
||||
|
||||
}
|
||||
|
||||
uint16_t encode_bit(unsigned char bit, int shift, uint8_t *out_a, uint8_t *out_b) {
|
||||
uint8_t bit_a, bit_b;
|
||||
|
||||
//printf("State before = %x\n", (state & 0x3f));
|
||||
|
||||
bit_a = BIT(5) ^ BIT(4) ^ BIT(2) ^ BIT(1) ^ bit;
|
||||
bit_b = BIT(5) ^ BIT(2) ^ BIT(1) ^ BIT(0) ^ bit;
|
||||
|
||||
byte_a |= (bit_a << 7);
|
||||
byte_b |= (bit_b << 7);
|
||||
|
||||
state <<= 1;
|
||||
state |= bit;
|
||||
state &= 0x3f;
|
||||
//printf("State after = %x\n", (state & 0x3f));
|
||||
|
||||
if (shift) {
|
||||
byte_a >>= 1;
|
||||
byte_b >>= 1;
|
||||
}
|
||||
|
||||
if (out_a)
|
||||
*out_a = bit_a;
|
||||
|
||||
if (out_b)
|
||||
*out_b = bit_b;
|
||||
|
||||
return ((bit_a << 8) + bit_b);
|
||||
}
|
||||
|
||||
void dump_path_metric(struct path_metric *pm_in) {
|
||||
int j, z;
|
||||
unsigned min_cost = 0xffff;
|
||||
unsigned idx = 0;
|
||||
unsigned c_state;
|
||||
for (j = 0; j <0x40; j++) {
|
||||
if (pm_in->paths[j].cost < min_cost) {
|
||||
min_cost = pm_in->paths[j].cost;
|
||||
idx = j;
|
||||
}
|
||||
printf("[%.2d] = %d\n", j, pm_in->paths[j].cost);
|
||||
//if (!pm_in->paths[j].cost) {
|
||||
// printf("%d", pm_in->paths[j].bits[0]);
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
printf("%d[%d] idx=%d\n", pm_in->paths[idx].bits[0], min_cost, idx);
|
||||
for (j = 0; j < pm_in->idx; j++) {
|
||||
for (z = 0; z < 0x40; z++) {
|
||||
printf("%d", win_history[j][z]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#if 1
|
||||
for (z = 0; z < pm_in->idx; z++) {
|
||||
printf("%.3d] SET=%d [%.2d]--> bit=%d/w=%d/bm=%d --> [%.2d]", z,
|
||||
pm_in->paths[idx].set[z],
|
||||
pm_in->paths[idx].from_state[z],
|
||||
pm_in->paths[idx].bits[z],
|
||||
win_history[z][pm_in->paths[idx].to_state[z]],
|
||||
pm_in->paths[idx].bm[z],
|
||||
pm_in->paths[idx].to_state[z]
|
||||
);
|
||||
printf(" ");
|
||||
c_state = pm_in->paths[idx].to_state[z];
|
||||
for (j = 5; j >= 0; j--)
|
||||
printf("%d", !!(c_state & (1 << j)));
|
||||
|
||||
if (win_history[z][c_state]) {
|
||||
c_state >>= 1;
|
||||
c_state |= (1<<5);
|
||||
} else {
|
||||
c_state >>= 1;
|
||||
}
|
||||
printf(" prev_state_hat: ");
|
||||
for (j = 5; j >= 0; j--)
|
||||
printf("%d", !!(c_state & (1 << j)));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
state = 0;
|
||||
|
||||
uint8_t bit_a, bit_b;
|
||||
|
||||
struct path_metric *pm_in, *pm_out;
|
||||
|
||||
unsigned int tx_bits[] = {1, 1, 1, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 1, 1, 1,
|
||||
0, 1, 1, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
};
|
||||
unsigned int tx_len = sizeof(tx_bits)/sizeof(tx_bits[0]);
|
||||
|
||||
pm_in = (struct path_metric *)malloc(sizeof(struct path_metric));
|
||||
pm_out = (struct path_metric *)malloc(sizeof(struct path_metric));
|
||||
|
||||
int i, j, z;
|
||||
|
||||
uint8_t *rx_bits = (uint8_t *)malloc(2 * tx_len * sizeof(uint8_t));
|
||||
|
||||
for (i = 0; i < tx_len; i++) {
|
||||
byte_a = byte_b = 0;
|
||||
|
||||
printf("t[%d] = from S[%d] to ", i, state);
|
||||
encode_bit(tx_bits[i], 1, &bit_a, &bit_b); // 0 -- 1
|
||||
printf("= D[%d]\n", state);
|
||||
rx_bits[i*2 + 0] = bit_a;
|
||||
rx_bits[i*2 + 1] = bit_b;
|
||||
//if ((i)==4)
|
||||
// rx_bits[i*2] ^= 1;
|
||||
}
|
||||
memset(pm_in, 0, sizeof(pm_in));
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
pm_in->paths[i].cost = (i == 0) ? 0 : 0xffffff;
|
||||
for (z = 0; z < 12; z++) {
|
||||
pm_in->paths[i].set[z] = 0;
|
||||
pm_in->paths[i].from_state[z] = 0;
|
||||
pm_in->paths[i].bits[z] = 0;
|
||||
pm_in->paths[i].bm[z] = 0;
|
||||
pm_in->paths[i].to_state[z] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int bit;
|
||||
for (bit = 0; bit < (sizeof(tx_bits)/sizeof(tx_bits[0]))/2 ; bit++) {
|
||||
bit_a = rx_bits[bit * 2];
|
||||
bit_b = rx_bits[bit * 2 + 1];
|
||||
branch_metric_loop(pm_in, bit_a, 0, bit_b, 0);
|
||||
}
|
||||
printf("LAST = %d\n", bit);
|
||||
for (j = 0; j <0x40; j++) {
|
||||
printf("[%d] ", pm_in->paths[j].from_state[0]);
|
||||
for (i = bit - 20; i < bit; i++) {
|
||||
printf(" -> [%d]",
|
||||
pm_in->paths[j].to_state[i]
|
||||
);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
dump_path_metric(pm_in);
|
||||
printf("\n");
|
||||
free(pm_in);
|
||||
free(pm_out);
|
||||
|
||||
return 0;
|
||||
}
|
51
fpga/ip/nuand/viterbi_decoder/model/out.c
Normal file
51
fpga/ip/nuand/viterbi_decoder/model/out.c
Normal file
@ -0,0 +1,51 @@
|
||||
// This file is part of bladeRF-wiphy.
|
||||
//
|
||||
// Copyright (C) 2021 Nuand, LLC.
|
||||
//
|
||||
// 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define K 7
|
||||
#define C_A 91
|
||||
#define C_B 121
|
||||
|
||||
#define BIT(y) ( (state >> y) & 1)
|
||||
|
||||
#define T_BIT(y) ( (t_state >> y) & 1)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned t_state;
|
||||
unsigned next_state;
|
||||
uint8_t t_bit_a, t_bit_b;
|
||||
for (t_state = 0; t_state <= 0x3f; t_state++) {
|
||||
// bit is 0?
|
||||
t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 0;
|
||||
t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 0;
|
||||
next_state = (t_state << 1) & 0x3f;
|
||||
printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 0, t_bit_a, t_bit_b, next_state);
|
||||
|
||||
// bit is 1?
|
||||
t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 1;
|
||||
t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 1;
|
||||
next_state = ((t_state << 1) & 0x3f) | 1;
|
||||
printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 1, t_bit_a, t_bit_b, next_state);
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user