mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-03-21 11:38:34 -04:00
Building sfrx[.exe] in the wsjtx repository is now basically operational.
This commit is contained in:
parent
073e644f12
commit
d845bd0466
@ -353,6 +353,10 @@ set (wsjt_FSRCS
|
||||
lib/wavhdr.f90
|
||||
lib/qra/q65/q65_encoding_modules.f90
|
||||
lib/ft8/ft8_a7.f90
|
||||
lib/superfox/sfox_mod.f90
|
||||
lib/superfox/julian.f90
|
||||
lib/superfox/popen_module.f90
|
||||
lib/superfox/qpc/qpc_mod.f90
|
||||
|
||||
# remaining non-module sources
|
||||
lib/addit.f90
|
||||
@ -597,8 +601,18 @@ set (wsjt_FSRCS
|
||||
lib/fst4/get_crc24.f90
|
||||
lib/fst4/fst4_baseline.f90
|
||||
lib/77bit/hash22calc.f90
|
||||
|
||||
lib/superfox/qpc_decode2.f90
|
||||
lib/superfox/qpc_likelihoods2.f90
|
||||
lib/superfox/qpc_snr.f90
|
||||
lib/superfox/qpc_sync.f90
|
||||
lib/superfox/sfox_ana.f90
|
||||
lib/superfox/sfox_demod.f90
|
||||
lib/superfox/sfox_remove_ft8.f90
|
||||
lib/superfox/sfox_unpack.f90
|
||||
lib/superfox/sfox_wave.f90
|
||||
lib/superfox/sfox_wave_gfsk.f90
|
||||
lib/superfox/twkfreq2.f90
|
||||
)
|
||||
|
||||
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
|
||||
@ -641,6 +655,15 @@ set (wsjt_CSRCS
|
||||
lib/wrapkarn.c
|
||||
${ldpc_CSRCS}
|
||||
${qra_CSRCS}
|
||||
|
||||
lib/superfox/qpc/dbgprintf.c
|
||||
lib/superfox/qpc/nhash2.c
|
||||
lib/superfox/qpc/np_qpc.c
|
||||
lib/superfox/qpc/np_rnd.c
|
||||
lib/superfox/qpc/qpc_fwht.c
|
||||
lib/superfox/qpc/qpc_n127k50q128.c
|
||||
lib/superfox/qpc/qpc_subs.c
|
||||
|
||||
)
|
||||
|
||||
set (wsjt_qt_UISRCS
|
||||
@ -1226,6 +1249,9 @@ target_link_libraries (echosim wsjt_fort wsjt_cxx)
|
||||
add_executable (ft8sim lib/ft8/ft8sim.f90)
|
||||
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (sfrx lib/superfox/sfrx.f90)
|
||||
target_link_libraries (sfrx wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (msk144sim lib/msk144sim.f90)
|
||||
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
|
||||
|
||||
@ -1613,7 +1639,7 @@ install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
|
||||
install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
install (TARGETS jt9 wsprd fmtave fcal fmeasure sfrx
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@ -1686,7 +1712,7 @@ if (WIN32)
|
||||
endif ()
|
||||
|
||||
install (FILES
|
||||
${sfox_dir}/sfrx.exe
|
||||
# ${sfox_dir}/sfrx.exe
|
||||
${sfox_dir}/sftx.exe
|
||||
${sfox_dir}/foxchk.exe
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@ -1696,7 +1722,7 @@ endif (WIN32)
|
||||
|
||||
if (UNIX)
|
||||
install (FILES
|
||||
lib/superfox/linux/sfrx
|
||||
# lib/superfox/linux/sfrx
|
||||
lib/superfox/linux/sftx
|
||||
lib/superfox/linux/foxchk
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@ -1709,7 +1735,7 @@ endif (UNIX)
|
||||
|
||||
if (APPLE)
|
||||
install (FILES
|
||||
lib/superfox/mac/sfrx
|
||||
# lib/superfox/mac/sfrx
|
||||
lib/superfox/mac/sftx
|
||||
lib/superfox/mac/foxchk
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@ -1729,7 +1755,7 @@ execute_process(COMMAND
|
||||
|
||||
if(${CMAKE_DEB_HOST_ARCH} MATCHES "arm64")
|
||||
install (FILES
|
||||
lib/superfox/arm/sfrx
|
||||
# lib/superfox/arm/sfrx
|
||||
lib/superfox/arm/sftx
|
||||
lib/superfox/arm/foxchk
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@ -1742,7 +1768,7 @@ endif()
|
||||
|
||||
if(${CMAKE_DEB_HOST_ARCH} MATCHES "armhf")
|
||||
install (FILES
|
||||
lib/superfox/arm32/sfrx
|
||||
# lib/superfox/arm32/sfrx
|
||||
lib/superfox/arm32/sftx
|
||||
lib/superfox/arm32/foxchk
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
|
@ -8,10 +8,10 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
||||
logical newdat,first
|
||||
complex c1(0:NFFT2-1)
|
||||
complex cx(0:NFFT1/2)
|
||||
real dd(NMAX),x(NFFT1),taper(0:100)
|
||||
equivalence (x,cx)
|
||||
real dd(NMAX),x(NFFT1+2),taper(0:100)
|
||||
data first/.true./
|
||||
save cx,first,taper
|
||||
save x,cx,first,taper
|
||||
equivalence (x,cx)
|
||||
|
||||
if(first) then
|
||||
pi=4.0*atan(1.0)
|
||||
@ -23,11 +23,10 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
||||
if(newdat) then
|
||||
! Data in dd have changed, recompute the long FFT
|
||||
x(1:NMAX)=dd
|
||||
x(NMAX+1:NFFT1)=0. !Zero-pad the x array
|
||||
x(NMAX+1:NFFT1+2)=0. !Zero-pad the x array
|
||||
call four2a(cx,NFFT1,1,-1,0) !r2c FFT to freq domain
|
||||
newdat=.false.
|
||||
endif
|
||||
|
||||
df=12000.0/NFFT1
|
||||
baud=12000.0/NSPS
|
||||
i0=nint(f0/df)
|
||||
|
12
lib/superfox/ft8_params.f90
Normal file
12
lib/superfox/ft8_params.f90
Normal file
@ -0,0 +1,12 @@
|
||||
! LDPC (174,91) code
|
||||
parameter (KK=91) !Information bits (77 + CRC14)
|
||||
parameter (ND=58) !Data symbols
|
||||
parameter (NS=21) !Sync symbols (3 @ Costas 7x7)
|
||||
parameter (NN=NS+ND) !Total channel symbols (79)
|
||||
parameter (NSPS=1920) !Samples per symbol at 12000 S/s
|
||||
parameter (NZ=NSPS*NN) !Samples in full 15 s waveform (151,680)
|
||||
parameter (NMAX=15*12000) !Samples in iwave (180,000)
|
||||
parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
|
||||
parameter (NSTEP=NSPS/4) !Rough time-sync step size
|
||||
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
|
||||
parameter (NDOWN=60) !Downsample factor
|
3
lib/superfox/gtag.f90
Normal file
3
lib/superfox/gtag.f90
Normal file
@ -0,0 +1,3 @@
|
||||
integer ntag
|
||||
data ntag/z"1234567"/
|
||||
!-----------------------------------------------------------------------
|
39
lib/superfox/julian.f90
Normal file
39
lib/superfox/julian.f90
Normal file
@ -0,0 +1,39 @@
|
||||
module julian
|
||||
|
||||
contains
|
||||
|
||||
integer*8 function itime8()
|
||||
|
||||
implicit integer (a-z)
|
||||
! 1 2 3 4 5 6 7
|
||||
integer it(8) !y m d nmin h m s
|
||||
integer*8 secday
|
||||
data secday/86400/
|
||||
|
||||
call date_and_time(values=it)
|
||||
iyr=it(1)
|
||||
imo=it(2)
|
||||
iday=it(3)
|
||||
days=JD(iyr,imo,iday) - 2440588 !Days since epoch Jan 1, 1970
|
||||
ih=it(5)
|
||||
im=it(6)-it(4) !it(4) corrects for time zone
|
||||
is=it(7)
|
||||
nsec=3600*ih + 60*im + is
|
||||
itime8=days*secday + nsec
|
||||
|
||||
return
|
||||
end function itime8
|
||||
|
||||
integer function JD(I,J,K)
|
||||
|
||||
! Return Julian Date for I=year, J=month, K=day
|
||||
! Reference: Fliegel and Van Flandern, Comm. ACM 11, 10, 1968
|
||||
|
||||
JD = K - 32075 + 1461*(I + 4800 + (J - 14)/12)/4 &
|
||||
+ 367*(J - 2 - (J - 14)/12*12)/12 - 3 &
|
||||
*((I + 4900 + (J - 14)/12)/100)/4
|
||||
|
||||
return
|
||||
end function JD
|
||||
|
||||
end module julian
|
103
lib/superfox/popen_module.f90
Normal file
103
lib/superfox/popen_module.f90
Normal file
@ -0,0 +1,103 @@
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! A simple module for `popen`.
|
||||
|
||||
module popen_module
|
||||
|
||||
use,intrinsic :: iso_c_binding
|
||||
|
||||
implicit none
|
||||
|
||||
private
|
||||
|
||||
! interfaces to C functions
|
||||
interface
|
||||
|
||||
function popen(command, mode) bind(C,name='popen')
|
||||
!! initiate pipe streams to or from a process
|
||||
import :: c_char, c_ptr
|
||||
implicit none
|
||||
character(kind=c_char),dimension(*) :: command
|
||||
character(kind=c_char),dimension(*) :: mode
|
||||
type(c_ptr) :: popen
|
||||
end function popen
|
||||
|
||||
function fgets(s, siz, stream) bind(C,name='fgets')
|
||||
!! get a string from a stream
|
||||
import :: c_char, c_ptr, c_int
|
||||
implicit none
|
||||
type (c_ptr) :: fgets
|
||||
character(kind=c_char),dimension(*) :: s
|
||||
integer(kind=c_int),value :: siz
|
||||
type(c_ptr),value :: stream
|
||||
end function fgets
|
||||
|
||||
function pclose(stream) bind(C,name='pclose')
|
||||
!! close a pipe stream to or from a process
|
||||
import :: c_ptr, c_int
|
||||
implicit none
|
||||
integer(c_int) :: pclose
|
||||
type(c_ptr),value :: stream
|
||||
end function pclose
|
||||
|
||||
end interface
|
||||
|
||||
public :: c2f_string, get_command_as_string
|
||||
|
||||
contains
|
||||
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! Convert a C string to a Fortran string.
|
||||
|
||||
function c2f_string(c) result(f)
|
||||
|
||||
character(len=*),intent(in) :: c !! C string
|
||||
character(len=:),allocatable :: f !! Fortran string
|
||||
|
||||
integer :: i
|
||||
|
||||
i = index(c,c_null_char)
|
||||
|
||||
if (i<=0) then
|
||||
f = c
|
||||
else if (i==1) then
|
||||
f = ''
|
||||
else if (i>1) then
|
||||
f = c(1:i-1)
|
||||
end if
|
||||
|
||||
end function c2f_string
|
||||
|
||||
!*******************************************************************************
|
||||
!>
|
||||
! Return the result of the command as a string.
|
||||
|
||||
function get_command_as_string(command) result(str)
|
||||
|
||||
character(len=*),intent(in) :: command !! the command to run
|
||||
character(len=:),allocatable :: str !! the result of that command
|
||||
|
||||
integer,parameter :: buffer_length = 1000 !! read stream in chunks of this size
|
||||
|
||||
type(c_ptr) :: h !! for `popen`
|
||||
integer(c_int) :: istat !! `pclose` status
|
||||
character(kind=c_char,len=buffer_length) :: line !! buffer to read from `fgets`
|
||||
|
||||
str = ''
|
||||
h = c_null_ptr
|
||||
h = popen(command//c_null_char,'r'//c_null_char)
|
||||
|
||||
if (c_associated(h)) then
|
||||
do while (c_associated(fgets(line,buffer_length,h)))
|
||||
str = str//c2f_string(line)
|
||||
end do
|
||||
istat = pclose(h)
|
||||
end if
|
||||
|
||||
end function get_command_as_string
|
||||
|
||||
!*******************************************************************************
|
||||
end module popen_module
|
||||
!*******************************************************************************
|
||||
|
67
lib/superfox/qpc/dbgprintf.c
Normal file
67
lib/superfox/qpc/dbgprintf.c
Normal file
@ -0,0 +1,67 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// dbgprintf.c
|
||||
// Functions for printing debug information
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include "dbgprintf.h"
|
||||
|
||||
// print functions for debug purposes
|
||||
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize)
|
||||
{
|
||||
int k;
|
||||
|
||||
printf("%s=", name);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x0F) == 0)
|
||||
printf("\n");
|
||||
printf("%02X ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dbgprintf_vector_float(const char* name, const float* v, int vsize)
|
||||
{
|
||||
int k;
|
||||
|
||||
printf("%s=", name);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x07) == 0)
|
||||
printf("\n");
|
||||
printf("%10.3f ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows)
|
||||
{
|
||||
int k;
|
||||
int j;
|
||||
|
||||
printf("%s=\n", name);
|
||||
for (j = 0; j < nrows; j++) {
|
||||
printf("r%d:", j);
|
||||
for (k = 0; k < vsize; k++) {
|
||||
if ((k & 0x07) == 0)
|
||||
printf("\n");
|
||||
printf("%7.3f ", v[k]);
|
||||
}
|
||||
printf("\n");
|
||||
v += vsize;
|
||||
}
|
||||
}
|
64
lib/superfox/qpc/dbgprintf.h
Normal file
64
lib/superfox/qpc/dbgprintf.h
Normal file
@ -0,0 +1,64 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// dbgprintf.h
|
||||
// Functions for printing debug information
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _dbgprintf_h_
|
||||
#define _dbgprintf_h_
|
||||
|
||||
// Define DBGPRINTF_ANYWAY
|
||||
// in order to print debug information also
|
||||
// when _DEBUG is not defined
|
||||
|
||||
#define DBGPRINTF_ANYWAY
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DBG_PRINTF
|
||||
#else
|
||||
#ifdef DBGPRINTF_ANYWAY
|
||||
#define DBG_PRINTF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// print functions for debug purposes
|
||||
#ifdef DBG_PRINTF
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize);
|
||||
void dbgprintf_vector_float(const char* name, const float* v, int vsize);
|
||||
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define dbgprintf_vector_uchar(a,b)
|
||||
#define dbgprintf_vector_float(a,b)
|
||||
#define dbgprintf_rows_float(a, b, c, d)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _dbgprintf_h_
|
383
lib/superfox/qpc/nhash2.c
Normal file
383
lib/superfox/qpc/nhash2.c
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
|
||||
File name: nhash2.c
|
||||
|
||||
*------------------------------------------------------------------------------
|
||||
*
|
||||
* This file is part of the WSPR application, Weak Signal Propogation Reporter
|
||||
*
|
||||
* File Name: nhash.c
|
||||
* Description: Functions to produce 32-bit hashes for hash table lookup
|
||||
*
|
||||
* Copyright (C) 2008-2014 Joseph Taylor, K1JT
|
||||
* License: GNU GPL v3+
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc., 51 Franklin
|
||||
* Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Files: lookup3.c
|
||||
* Copyright: Copyright (C) 2006 Bob Jenkins <bob_jenkins@burtleburtle.net>
|
||||
* License: public-domain
|
||||
* You may use this code any way you wish, private, educational, or commercial.
|
||||
* It's free.
|
||||
*
|
||||
*-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
These are functions for producing 32-bit hashes for hash table lookup.
|
||||
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
are externally useful functions. Routines to test the hash are included
|
||||
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||
the public domain. It has no warranty.
|
||||
|
||||
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||
little-endian machines. Intel and AMD are little-endian machines.
|
||||
On second thought, you probably want hashlittle2(), which is identical to
|
||||
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||
|
||||
If you want to find a hash of, say, exactly 7 integers, do
|
||||
a = i1; b = i2; c = i3;
|
||||
mix(a,b,c);
|
||||
a += i4; b += i5; c += i6;
|
||||
mix(a,b,c);
|
||||
a += i7;
|
||||
final(a,b,c);
|
||||
then use c as the hash value. If you have a variable length array of
|
||||
4-byte integers to hash, use hashword(). If you have a byte array (like
|
||||
a character string), use hashlittle(). If you have several byte arrays, or
|
||||
a mix of things, see the comments above hashlittle().
|
||||
|
||||
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||
then mix those integers. This is fast (you can do a lot more thorough
|
||||
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||
*/
|
||||
|
||||
#define SELF_TEST 1
|
||||
|
||||
#include <stdio.h> /* defines printf for tests */
|
||||
#include <time.h> /* defines time_t for timings in the test */
|
||||
#include "nhash2.h"
|
||||
//#include <sys/param.h> /* attempt to define endianness */
|
||||
//#ifdef linux
|
||||
//# include <endian.h> /* attempt to define endianness */
|
||||
//#endif
|
||||
|
||||
#define HASH_LITTLE_ENDIAN 1
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
|
||||
This is reversible, so any information in (a,b,c) before mix() is
|
||||
still in (a,b,c) after mix().
|
||||
|
||||
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||
mix() in reverse, there are at least 32 bits of the output that
|
||||
are sometimes the same for one pair and different for another pair.
|
||||
This was tested for:
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||
satisfy this are
|
||||
4 6 8 16 19 4
|
||||
9 15 3 18 27 15
|
||||
14 9 3 7 17 3
|
||||
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||
the operations, constants, and arrangements of the variables.
|
||||
|
||||
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||
avalanche in c.
|
||||
|
||||
This allows some parallelism. Read-after-writes are good at doubling
|
||||
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||
direction as the goal of parallelism. I did what I could. Rotates
|
||||
seem to cost as much as shifts on every machine I could lay my hands
|
||||
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||
rotates.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= c; a ^= rot(c, 4); c += b; \
|
||||
b -= a; b ^= rot(a, 6); a += c; \
|
||||
c -= b; c ^= rot(b, 8); b += a; \
|
||||
a -= c; a ^= rot(c,16); c += b; \
|
||||
b -= a; b ^= rot(a,19); a += c; \
|
||||
c -= b; c ^= rot(b, 4); b += a; \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||
|
||||
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||
produce values of c that look totally different. This was tested for
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
These constants passed:
|
||||
14 11 25 16 4 14 24
|
||||
12 14 25 16 4 14 24
|
||||
and these came close:
|
||||
4 8 15 26 3 22 24
|
||||
10 8 15 26 3 22 24
|
||||
11 8 15 26 3 22 24
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define final(a,b,c) \
|
||||
{ \
|
||||
c ^= b; c -= rot(b,14); \
|
||||
a ^= c; a -= rot(c,11); \
|
||||
b ^= a; b -= rot(a,25); \
|
||||
c ^= b; c -= rot(b,16); \
|
||||
a ^= c; a -= rot(c,4); \
|
||||
b ^= a; b -= rot(a,14); \
|
||||
c ^= b; c -= rot(b,24); \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
hashlittle() -- hash a variable-length key into a 32-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
length : the length of the key, counting by bytes
|
||||
initval : can be any 4-byte value
|
||||
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||
the return value. Two keys differing by one or two bits will have
|
||||
totally different hash values.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (uint8_t **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
|
||||
code any way you wish, private, educational, or commercial. It's free.
|
||||
|
||||
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||
acceptable. Do NOT use for cryptographic purposes.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t nhash2( const void *key, uint64_t length, uint32_t initval)
|
||||
//int nhash( const char *key, int length, int initval)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
// printf("AAA %x %d %x %d\n",c,c,c&32767,c&32767);
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
/*
|
||||
* "k[2]&0xffffff" actually reads beyond the end of the string, but
|
||||
* then masks off the part it's not allowed to read. Because the
|
||||
* string is aligned, the masked-off tail is in the same word as the
|
||||
* rest of the string. Every machine with memory protection I've seen
|
||||
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||
* still catch it and complain. The masking trick does make the hash
|
||||
* noticably faster for short strings (like English words).
|
||||
*/
|
||||
#ifndef VALGRIND
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
|
||||
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
|
||||
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
|
||||
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
|
||||
case 5 : b+=k[1]&0xff; a+=k[0]; break;
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=k[0]&0xffffff; break;
|
||||
case 2 : a+=k[0]&0xffff; break;
|
||||
case 1 : a+=k[0]&0xff; break;
|
||||
case 0 : return c; /* zero length strings require no mixing */
|
||||
}
|
||||
|
||||
#else /* make valgrind happy */
|
||||
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return c;
|
||||
}
|
||||
|
||||
#endif /* !valgrind */
|
||||
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return c; /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24;
|
||||
/* fall through */
|
||||
case 11: c+=((uint32_t)k[10])<<16;
|
||||
/* fall through */
|
||||
case 10: c+=((uint32_t)k[9])<<8;
|
||||
/* fall through */
|
||||
case 9 : c+=k[8];
|
||||
/* fall through */
|
||||
case 8 : b+=((uint32_t)k[7])<<24;
|
||||
/* fall through */
|
||||
case 7 : b+=((uint32_t)k[6])<<16;
|
||||
/* fall through */
|
||||
case 6 : b+=((uint32_t)k[5])<<8;
|
||||
/* fall through */
|
||||
case 5 : b+=k[4];
|
||||
/* fall through */
|
||||
case 4 : a+=((uint32_t)k[3])<<24;
|
||||
/* fall through */
|
||||
case 3 : a+=((uint32_t)k[2])<<16;
|
||||
/* fall through */
|
||||
case 2 : a+=((uint32_t)k[1])<<8;
|
||||
/* fall through */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return c;
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return c;
|
||||
}
|
22
lib/superfox/qpc/nhash2.h
Normal file
22
lib/superfox/qpc/nhash2.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NHASH_H_
|
||||
#define NHASH_H_
|
||||
|
||||
#ifdef Win32
|
||||
#include "win_stdint.h" /* defines uint32_t etc */
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* defines uint32_t etc */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t nhash( const void * key, uint64_t length, uint32_t initval);
|
||||
//int nhash(const char *key, int length, int initval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
329
lib/superfox/qpc/np_qpc.c
Normal file
329
lib/superfox/qpc/np_qpc.c
Normal file
@ -0,0 +1,329 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_qpc.h
|
||||
// Q-Ary Polar Codes encoding/decoding functions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
// static constant / functions
|
||||
|
||||
static const float knorm = 1.0f / QPC_Q;
|
||||
|
||||
static float* pdf_conv(float *dst, float* pdf1, float* pdf2)
|
||||
{
|
||||
// convolution between two pdf
|
||||
|
||||
float fwht_pdf1[QPC_Q];
|
||||
float fwht_pdf2[QPC_Q];
|
||||
int k;
|
||||
|
||||
qpc_fwht(fwht_pdf1, pdf1);
|
||||
qpc_fwht(fwht_pdf2, pdf2);
|
||||
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
fwht_pdf1[k] *= fwht_pdf2[k];
|
||||
|
||||
qpc_fwht(dst, fwht_pdf1);
|
||||
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
dst[k] *= knorm;
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_conv(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// convolutions between rows of pdfs
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_conv(dstarray, pdf1array, pdf2array);
|
||||
dstarray += QPC_Q;
|
||||
pdf1array += QPC_Q;
|
||||
pdf2array += QPC_Q;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static float _pdfuniform[QPC_Q];
|
||||
static const float* _pdf_uniform1();
|
||||
static const float* _pdf_uniform0();
|
||||
typedef const float*(*ptr_pdfuniform)(void);
|
||||
|
||||
static ptr_pdfuniform _ptr_pdf_uniform = _pdf_uniform0;
|
||||
|
||||
static const float* _pdf_uniform1()
|
||||
{
|
||||
return _pdfuniform;
|
||||
};
|
||||
static const float* _pdf_uniform0()
|
||||
{
|
||||
// compute uniform pdf once for all
|
||||
int k;
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
_pdfuniform[k] = knorm;
|
||||
|
||||
// next call to _qpc_pdfuniform
|
||||
// will be handled directly by _pqc_pdfuniform1
|
||||
_ptr_pdf_uniform = _pdf_uniform1;
|
||||
|
||||
return _pdfuniform;
|
||||
};
|
||||
static const float* pdf_uniform()
|
||||
{
|
||||
return _ptr_pdf_uniform();
|
||||
}
|
||||
|
||||
static float * pdf_mul(float *dst, float* pdf1, float* pdf2)
|
||||
{
|
||||
int k;
|
||||
float v;
|
||||
float norm = 0;
|
||||
for (k = 0; k < QPC_Q; k++) {
|
||||
v = pdf1[k] * pdf2[k];
|
||||
dst[k] = v;
|
||||
norm += v;
|
||||
}
|
||||
// if norm of the result is not positive
|
||||
// return in dst a uniform distribution
|
||||
if (norm <= 0)
|
||||
memcpy(dst, pdf_uniform(), QPC_Q * sizeof(float));
|
||||
else {
|
||||
norm = 1.0f / norm;
|
||||
for (k = 0; k < QPC_Q; k++)
|
||||
dst[k] = dst[k] * norm;
|
||||
}
|
||||
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_mul(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// products between rows of pdfs
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_mul(dstarray, pdf1array, pdf2array);
|
||||
dstarray += QPC_Q;
|
||||
pdf1array += QPC_Q;
|
||||
pdf2array += QPC_Q;
|
||||
}
|
||||
}
|
||||
|
||||
static float* pdf_convhard(float* dst, const float* pdf, unsigned char hd)
|
||||
{
|
||||
// convolution between a pdf and a hard-decision feedback
|
||||
|
||||
int k;
|
||||
for (k=0;k<QPC_Q;k++)
|
||||
dst[k] = pdf[k^hd];
|
||||
|
||||
return dst;
|
||||
}
|
||||
static void pdfarray_convhard(float* dstarray, const float* pdfarray, const unsigned char *hdarray, int numrows)
|
||||
{
|
||||
int k;
|
||||
|
||||
// hard convolutions between rows
|
||||
|
||||
for (k = 0; k < numrows; k++) {
|
||||
pdf_convhard(dstarray, pdfarray, hdarray[k]);
|
||||
dstarray += QPC_Q;
|
||||
pdfarray += QPC_Q;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char pdf_max(const float* pdf)
|
||||
{
|
||||
int k;
|
||||
|
||||
unsigned char imax = 0;
|
||||
float pdfmax = pdf[0];
|
||||
|
||||
for (k=1;k<QPC_Q;k++)
|
||||
if (pdf[k] > pdfmax) {
|
||||
pdfmax = pdf[k];
|
||||
imax = k;
|
||||
}
|
||||
|
||||
return imax;
|
||||
}
|
||||
|
||||
// local stack functions ---------------------------------------
|
||||
static float _qpc_stack[QPC_N * QPC_Q * 2];
|
||||
static float* _qpc_stack_base = _qpc_stack;
|
||||
|
||||
static float* _qpc_stack_push(int numfloats)
|
||||
{
|
||||
float* addr = _qpc_stack_base;
|
||||
_qpc_stack_base += numfloats;
|
||||
return addr;
|
||||
}
|
||||
static void _qpc_stack_pop(int numfloats)
|
||||
{
|
||||
_qpc_stack_base -= numfloats;
|
||||
}
|
||||
|
||||
// qpc encoder function (internal use) ----------------------------------------------------------
|
||||
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x)
|
||||
{
|
||||
// Non recursive polar encoder
|
||||
// Same architecture of a fast fourier transform
|
||||
// in which the fft butteflies are replaced by the polar transform
|
||||
// butterflies
|
||||
|
||||
int k, j, m;
|
||||
int groups;
|
||||
int bfypergroup;
|
||||
int stepbfy;
|
||||
int stepgroup;
|
||||
int basegroup;
|
||||
int basebfy;
|
||||
|
||||
memcpy(y, x, QPC_N);
|
||||
|
||||
for (k = 0; k < QPC_LOG2N; k++) {
|
||||
groups = 1 << (QPC_LOG2N - 1 - k);
|
||||
stepbfy = bfypergroup = 1 << k;
|
||||
stepgroup = stepbfy << 1;
|
||||
basegroup = 0;
|
||||
for (j = 0; j < groups; j++) {
|
||||
basebfy = basegroup;
|
||||
for (m = 0; m < bfypergroup; m++) {
|
||||
// polar transform
|
||||
y[basebfy + stepbfy] = y[basebfy + stepbfy] ^ y[basebfy];
|
||||
basebfy = basebfy + 1;
|
||||
}
|
||||
basegroup = basegroup + stepgroup;
|
||||
}
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
// qpc polar decoder (internal use )--------------------------------------------------
|
||||
void _qpc_decode(unsigned char* xdec, unsigned char* ydec, const float* py, const unsigned char* f, const unsigned char* fsize, const int numrows)
|
||||
{
|
||||
|
||||
if (numrows == 1) {
|
||||
if (fsize[0] == 0) {
|
||||
// dbgprintf_vector_float("py", py, QPC_Q);
|
||||
|
||||
// frozen symbol
|
||||
xdec[0] = pdf_max(py);
|
||||
ydec[0] = f[0];
|
||||
}
|
||||
else {
|
||||
// fsize = 1 => information symbol
|
||||
xdec[0] = pdf_max(py);
|
||||
ydec[0] = xdec[0];
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
int k;
|
||||
int nextrows = numrows >> 1;
|
||||
int size = nextrows << QPC_LOG2Q;
|
||||
|
||||
// upper block variables
|
||||
unsigned char* xdech = xdec + nextrows;
|
||||
unsigned char* ydech = ydec + nextrows;
|
||||
const unsigned char* fh = f + nextrows;
|
||||
const unsigned char* fsizeh = fsize + nextrows;
|
||||
|
||||
// Step 1.
|
||||
// stack and init variables used in the recursion
|
||||
|
||||
float* pyl = _qpc_stack_push(size);
|
||||
memcpy(pyl, py, size * sizeof(float));
|
||||
|
||||
float* pyh = _qpc_stack_push(size);
|
||||
memcpy(pyh, py + size, size * sizeof(float));
|
||||
|
||||
// Step 2. Recursion on upper block
|
||||
// Forward pdf convolutions for the upper block
|
||||
// (place in the lower part of py the convolution of lower and higher blocks)
|
||||
|
||||
// float* pyh = py + size;
|
||||
// pdfarray_conv(py, pyl, pyh, nextrows); // convolution overwriting the lower block of py which is not needed
|
||||
|
||||
pdfarray_conv(pyh, pyl, pyh, nextrows);
|
||||
_qpc_decode(xdech, ydech, pyh, fh, fsizeh, nextrows);
|
||||
|
||||
// Step 3. compute pdfs in the lower block
|
||||
pdfarray_convhard(pyh, py+size, ydech,nextrows); // dst ptr must be different form src ptr
|
||||
pdfarray_mul(pyl, pyl, pyh, nextrows);
|
||||
// we don't need pyh anymore
|
||||
_qpc_stack_pop(size);
|
||||
|
||||
// Step 4. Recursion on the lower block
|
||||
_qpc_decode(xdec, ydec, pyl, f, fsize, nextrows);
|
||||
// we don't need pyl anymore
|
||||
_qpc_stack_pop(size);
|
||||
|
||||
// Step 5. Update backward results
|
||||
// xdec is already ok, we need just to update ydech
|
||||
for (k = 0; k < nextrows; k++)
|
||||
ydech[k] = ydech[k] ^ ydec[k];
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Public encoding/decoding functions ------------------------------------------------
|
||||
void qpc_encode(unsigned char* y, const unsigned char* x)
|
||||
{
|
||||
|
||||
// map information symbols
|
||||
int kk, pos;
|
||||
for (kk = 0; kk < QPC_K; kk++) {
|
||||
pos = qpccode.xpos[kk];
|
||||
qpccode.f[pos] = x[kk];
|
||||
}
|
||||
// do polar encoding
|
||||
_qpc_encode(y, qpccode.f);
|
||||
}
|
||||
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py)
|
||||
{
|
||||
int k;
|
||||
unsigned char x[QPC_N];
|
||||
|
||||
// set the first py row with know frozen (punctured) symbol
|
||||
if (qpccode.np < qpccode.n) {
|
||||
// assume that we punctured only the first output symbol
|
||||
memset(py, 0, QPC_Q * sizeof(float));
|
||||
py[qpccode.f[0]] = 1.0f;
|
||||
}
|
||||
|
||||
// decode
|
||||
_qpc_decode(x, ydec, py, qpccode.f, qpccode.fsize, QPC_N);
|
||||
|
||||
// demap information symbols
|
||||
for (k = 0; k < QPC_K; k++)
|
||||
xdec[k] = x[qpccode.xpos[k]];
|
||||
|
||||
}
|
62
lib/superfox/qpc/np_qpc.h
Normal file
62
lib/superfox/qpc/np_qpc.h
Normal file
@ -0,0 +1,62 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_qpc.h
|
||||
// Q-Ary Polar Codes encoding/decoding functions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#ifndef _np_qpc_h_
|
||||
#define _np_qpc_h_
|
||||
|
||||
#define QPC_LOG2N 7 // log2(codeword length) (not punctured)
|
||||
#define QPC_N (1<<QPC_LOG2N) // codeword length (not punctured)
|
||||
#define QPC_LOG2Q 7 // bits per symbol
|
||||
#define QPC_Q (1<<QPC_LOG2Q) // alphabet size
|
||||
#define QPC_K 50 // number of information symbols
|
||||
|
||||
|
||||
typedef struct {
|
||||
int n; // codeword length (unpunctured)
|
||||
int np; // codeword length (punctured)
|
||||
int k; // number of information symbols
|
||||
int q; // alphabet size
|
||||
int xpos[QPC_N]; // info symbols mapping/demapping tables
|
||||
unsigned char f[QPC_N]; // frozen symbols values
|
||||
unsigned char fsize[QPC_N]; // frozen symbol flag (fsize==0 => frozen)
|
||||
} qpccode_ds;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void qpc_encode(unsigned char* y, const unsigned char* x);
|
||||
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py);
|
||||
|
||||
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x);
|
||||
void _qpc_decode(unsigned char* xdec, unsigned char* ydec,
|
||||
const float* py, const unsigned char* f, const unsigned char* fsize,
|
||||
const int numrows);
|
||||
|
||||
extern qpccode_ds qpccode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _np_qpc_h_
|
135
lib/superfox/qpc/np_rnd.c
Normal file
135
lib/superfox/qpc/np_rnd.c
Normal file
@ -0,0 +1,135 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_rnd.c
|
||||
// Functions to generate random numbers with uniform/gaussian probability distributions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "np_rnd.h"
|
||||
|
||||
#if _WIN32 // note the underscore: without it, it's not msdn official!
|
||||
// Windows (x64 and x86)
|
||||
#include <windows.h> // required only for GetTickCount(...)
|
||||
#define K_RAND_MAX UINT_MAX
|
||||
#elif _SVID_SOURCE || _XOPEN_SOURCE || __unix__ || (defined (__APPLE__) && defined(__MACH__)) /* POSIX or Unix or Apple */
|
||||
#include <stdlib.h>
|
||||
#define rand_s(x) (*x)=(unsigned int)lrand48() // returns unsigned integers in the range 0..0x7FFFFFFF
|
||||
#define K_RAND_MAX 0x7FFFFFFF // that's the max number
|
||||
// generated by lrand48
|
||||
#else
|
||||
#error "No good quality PRNG found"
|
||||
#endif
|
||||
|
||||
|
||||
void np_normrnd_real(float *dst, int nitems, float mean, float stdev)
|
||||
{
|
||||
// for odd or even nitems
|
||||
|
||||
unsigned int r;
|
||||
float phi=0, u=0;
|
||||
int set = 0;
|
||||
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
|
||||
while (nitems--)
|
||||
if (set==1) {
|
||||
// generate a second normally distributed number
|
||||
*dst++ = sinf(phi)*u*stdev+mean;
|
||||
set = 0;
|
||||
}
|
||||
else {
|
||||
// generate a uniform distributed phase phi in the range [0,2*PI)
|
||||
rand_s((unsigned int*)&r); phi = scalephi * r;
|
||||
|
||||
// generate a uniform distributed random number u in the range (0,1]
|
||||
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
|
||||
|
||||
// generate normally distributed number
|
||||
u = (float)sqrt(-2.0f * log(u));
|
||||
*dst++ = cosf(phi) * u * stdev + mean;
|
||||
|
||||
set=1;
|
||||
}
|
||||
}
|
||||
|
||||
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev)
|
||||
{
|
||||
// as qpc_normrnd_real, but generates always nitems complex numbers (2*nitems reals)
|
||||
|
||||
unsigned int r;
|
||||
float phi = 0, u = 0;
|
||||
// JHT int set = 0;
|
||||
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
// generate a uniform distributed phase phi in the range [0,2*PI)
|
||||
rand_s((unsigned int*)&r); phi = scalephi * r;
|
||||
|
||||
// generate a uniform distributed random number u in the range (0,1]
|
||||
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
|
||||
|
||||
// generate normally distributed real and imaginary parts
|
||||
u = (float)sqrt(-2.0f * log(u));
|
||||
*dst++ = cosf(phi) * u * stdev + mean;
|
||||
*dst++ = sinf(phi) * u * stdev + mean;
|
||||
}
|
||||
}
|
||||
|
||||
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize)
|
||||
{
|
||||
// generate uniform unsigned int random numbers in the range [0..nsetsize)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
|
||||
*dst++ = (unsigned int)floorf(u);
|
||||
}
|
||||
|
||||
}
|
||||
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize)
|
||||
{
|
||||
// generate uniform unsigned char random numbers in the range [0..nsetsize)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
|
||||
*dst++ = (unsigned char)floorf(u);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void np_unifrnd(float* dst, int nitems, float fmax)
|
||||
{
|
||||
// generate uniform float random numbers in the range [0..fmax)
|
||||
|
||||
unsigned int r;
|
||||
float u;
|
||||
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
|
||||
|
||||
while (nitems--) {
|
||||
rand_s((unsigned int*)&r); u = scaleu * fmax * r;
|
||||
*dst++ = u;
|
||||
}
|
||||
|
||||
}
|
59
lib/superfox/qpc/np_rnd.h
Normal file
59
lib/superfox/qpc/np_rnd.h
Normal file
@ -0,0 +1,59 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// np_rnd.h
|
||||
// Functions to generate random numbers with uniform/gaussian probability distributions
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef _np_rnd_h_
|
||||
#define _np_rnd_h_
|
||||
|
||||
#define _CRT_RAND_S
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#define M_2PI (2.0f*(float)M_PI)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// generate a random array of real numbers with a gaussian distribution of given mean and stdev
|
||||
void np_normrnd_real(float *dst, int nitems, float mean, float stdev);
|
||||
|
||||
// generate a random array of nitems complex numbers with a gaussian distribution of given mean and stdev
|
||||
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev);
|
||||
|
||||
// generate a random array of nitems unsigned int numbers with uniform distribution
|
||||
// in the range [0 .. nsetsize)
|
||||
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize);
|
||||
|
||||
// generate a random array of nitems unsigned chars numbers with uniform distribution
|
||||
// in the range [0 .. nsetsize)
|
||||
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize);
|
||||
|
||||
// generate a random array of nitems float numbers with uniform distribution
|
||||
// in the range [0 .. fmax)
|
||||
void np_unifrnd(float* dst, int nitems, float fmax);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _np_rnd_h_
|
||||
|
233
lib/superfox/qpc/qpc_fwht.c
Normal file
233
lib/superfox/qpc/qpc_fwht.c
Normal file
@ -0,0 +1,233 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_fwht.c
|
||||
// Fast Walsh-Hadamard Transforms for q-ary polar codes
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "qpc_fwht.h"
|
||||
|
||||
static void _qpc_sumdiff8_16(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[16];
|
||||
y[16] = t[0] - t[16];
|
||||
|
||||
y[1] = t[1] + t[17];
|
||||
y[17] = t[1] - t[17];
|
||||
|
||||
y[2] = t[2] + t[18];
|
||||
y[18] = t[2] - t[18];
|
||||
|
||||
y[3] = t[3] + t[19];
|
||||
y[19] = t[3] - t[19];
|
||||
|
||||
y[4] = t[4] + t[20];
|
||||
y[20] = t[4] - t[20];
|
||||
|
||||
y[5] = t[5] + t[21];
|
||||
y[21] = t[5] - t[21];
|
||||
|
||||
y[6] = t[6] + t[22];
|
||||
y[22] = t[6] - t[22];
|
||||
|
||||
y[7] = t[7] + t[23];
|
||||
y[23] = t[7] - t[23];
|
||||
|
||||
}
|
||||
static void _qpc_sumdiff8_32(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[32];
|
||||
y[32] = t[0] - t[32];
|
||||
|
||||
y[1] = t[1] + t[33];
|
||||
y[33] = t[1] - t[33];
|
||||
|
||||
y[2] = t[2] + t[34];
|
||||
y[34] = t[2] - t[34];
|
||||
|
||||
y[3] = t[3] + t[35];
|
||||
y[35] = t[3] - t[35];
|
||||
|
||||
y[4] = t[4] + t[36];
|
||||
y[36] = t[4] - t[36];
|
||||
|
||||
y[5] = t[5] + t[37];
|
||||
y[37] = t[5] - t[37];
|
||||
|
||||
y[6] = t[6] + t[38];
|
||||
y[38] = t[6] - t[38];
|
||||
|
||||
y[7] = t[7] + t[39];
|
||||
y[39] = t[7] - t[39];
|
||||
|
||||
}
|
||||
static void _qpc_sumdiff8_64(float* y, float* t)
|
||||
{
|
||||
y[0] = t[0] + t[64];
|
||||
y[64] = t[0] - t[64];
|
||||
|
||||
y[1] = t[1] + t[65];
|
||||
y[65] = t[1] - t[65];
|
||||
|
||||
y[2] = t[2] + t[66];
|
||||
y[66] = t[2] - t[66];
|
||||
|
||||
y[3] = t[3] + t[67];
|
||||
y[67] = t[3] - t[67];
|
||||
|
||||
y[4] = t[4] + t[68];
|
||||
y[68] = t[4] - t[68];
|
||||
|
||||
y[5] = t[5] + t[69];
|
||||
y[69] = t[5] - t[69];
|
||||
|
||||
y[6] = t[6] + t[70];
|
||||
y[70] = t[6] - t[70];
|
||||
|
||||
y[7] = t[7] + t[71];
|
||||
y[71] = t[7] - t[71];
|
||||
|
||||
}
|
||||
|
||||
float* qpc_fwht8(float* y, float* x)
|
||||
{
|
||||
float t[8];
|
||||
|
||||
// first stage
|
||||
y[0] = x[0] + x[1];
|
||||
y[1] = x[0] - x[1];
|
||||
|
||||
y[2] = x[2] + x[3];
|
||||
y[3] = x[2] - x[3];
|
||||
|
||||
y[4] = x[4] + x[5];
|
||||
y[5] = x[4] - x[5];
|
||||
|
||||
y[6] = x[6] + x[7];
|
||||
y[7] = x[6] - x[7];
|
||||
|
||||
// second stage
|
||||
t[0] = y[0] + y[2];
|
||||
t[2] = y[0] - y[2];
|
||||
|
||||
t[1] = y[1] + y[3];
|
||||
t[3] = y[1] - y[3];
|
||||
|
||||
t[4] = y[4] + y[6];
|
||||
t[6] = y[4] - y[6];
|
||||
|
||||
t[5] = y[5] + y[7];
|
||||
t[7] = y[5] - y[7];
|
||||
|
||||
// third stage
|
||||
y[0] = t[0] + t[4];
|
||||
y[4] = t[0] - t[4];
|
||||
|
||||
y[1] = t[1] + t[5];
|
||||
y[5] = t[1] - t[5];
|
||||
|
||||
y[2] = t[2] + t[6];
|
||||
y[6] = t[2] - t[6];
|
||||
|
||||
y[3] = t[3] + t[7];
|
||||
y[7] = t[3] - t[7];
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht16(float* y, float* x)
|
||||
{
|
||||
float t[16];
|
||||
|
||||
qpc_fwht8(t, x);
|
||||
qpc_fwht8(t + 8, x + 8);
|
||||
|
||||
y[0] = t[0] + t[8];
|
||||
y[8] = t[0] - t[8];
|
||||
|
||||
y[1] = t[1] + t[9];
|
||||
y[9] = t[1] - t[9];
|
||||
|
||||
y[2] = t[2] + t[10];
|
||||
y[10] = t[2] - t[10];
|
||||
|
||||
y[3] = t[3] + t[11];
|
||||
y[11] = t[3] - t[11];
|
||||
|
||||
y[4] = t[4] + t[12];
|
||||
y[12] = t[4] - t[12];
|
||||
|
||||
y[5] = t[5] + t[13];
|
||||
y[13] = t[5] - t[13];
|
||||
|
||||
y[6] = t[6] + t[14];
|
||||
y[14] = t[6] - t[14];
|
||||
|
||||
y[7] = t[7] + t[15];
|
||||
y[15] = t[7] - t[15];
|
||||
|
||||
return y;
|
||||
|
||||
}
|
||||
float* qpc_fwht32(float* y, float* x)
|
||||
{
|
||||
float t[32];
|
||||
|
||||
qpc_fwht16(t, x);
|
||||
qpc_fwht16(t + 16, x + 16);
|
||||
|
||||
_qpc_sumdiff8_16(y, t);
|
||||
_qpc_sumdiff8_16(y + 8, t + 8);
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht64(float* y, float* x)
|
||||
{
|
||||
float t[64];
|
||||
|
||||
qpc_fwht32(t, x);
|
||||
qpc_fwht32(t + 32, x + 32);
|
||||
|
||||
_qpc_sumdiff8_32(y, t);
|
||||
_qpc_sumdiff8_32(y + 8, t + 8);
|
||||
_qpc_sumdiff8_32(y + 16, t + 16);
|
||||
_qpc_sumdiff8_32(y + 24, t + 24);
|
||||
|
||||
return y;
|
||||
}
|
||||
float* qpc_fwht128(float* y, float* x)
|
||||
{
|
||||
float t[128];
|
||||
|
||||
qpc_fwht64(t, x);
|
||||
qpc_fwht64(t + 64, x + 64);
|
||||
|
||||
_qpc_sumdiff8_64(y, t);
|
||||
_qpc_sumdiff8_64(y + 8, t + 8);
|
||||
_qpc_sumdiff8_64(y + 16, t + 16);
|
||||
_qpc_sumdiff8_64(y + 24, t + 24);
|
||||
_qpc_sumdiff8_64(y + 32, t + 32);
|
||||
_qpc_sumdiff8_64(y + 40, t + 40);
|
||||
_qpc_sumdiff8_64(y + 48, t + 48);
|
||||
_qpc_sumdiff8_64(y + 56, t + 56);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
// functions over pdfs used by the decoder -----------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
57
lib/superfox/qpc/qpc_fwht.h
Normal file
57
lib/superfox/qpc/qpc_fwht.h
Normal file
@ -0,0 +1,57 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_fwht.h
|
||||
// Fast Walsh-Hadamard Transforms for q-ary polar codes
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// This source 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 file 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 source distribution.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef _qpc_fwht_h_
|
||||
#define _qpc_fwht_h_
|
||||
|
||||
#include "np_qpc.h"
|
||||
|
||||
#if QPC_LOG2Q==7
|
||||
#define qpc_fwht(a,b) qpc_fwht128(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==6
|
||||
#define qpc_fwht(a,b) qpc_fwht64(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==5
|
||||
#define qpc_fwht(a,b) qpc_fwht32(a,b)
|
||||
#endif
|
||||
#if QPC_LOG2Q==4
|
||||
#define qpc_fwht(a,b) qpc_fwht16(a,b)
|
||||
#endif
|
||||
// Note that it makes no sense to use fast convolutions
|
||||
// for transforms that are less than 16 symbols in size.
|
||||
// For such cases direct convolutions are faster.
|
||||
#if QPC_LOG2Q==3
|
||||
#define qpc_fwht(a,b) qpc_fwht8(a,b)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
float* qpc_fwht8(float* y, float* x);
|
||||
float* qpc_fwht16(float* y, float* x);
|
||||
float* qpc_fwht32(float* y, float* x);
|
||||
float* qpc_fwht64(float* y, float* x);
|
||||
float* qpc_fwht128(float* y, float* x);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _qpc_fwht_h_
|
198
lib/superfox/qpc/qpc_main.cpp
Normal file
198
lib/superfox/qpc/qpc_main.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_main.cpp
|
||||
//
|
||||
// Test the WER performance of the QPC (127,50) Q=128 code
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
// for random numbers generation and NCFSK Rayleigh channel simulation
|
||||
#include "np_rnd.h"
|
||||
void qpc_channel(float* yout, unsigned char* y, float EsNo)
|
||||
{
|
||||
// compute channel outputs amplitudes
|
||||
|
||||
int k;
|
||||
|
||||
// generate noise samples -----------------------------------------
|
||||
float sigman = 1.0f / sqrtf(2.0f);
|
||||
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
|
||||
|
||||
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
|
||||
|
||||
// generate rayleigh distributed signal amplitudes -----------------
|
||||
float symamps[QPC_N * 2];
|
||||
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
|
||||
|
||||
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
|
||||
|
||||
// normalize signal amps to unity ----------------------------------
|
||||
float pwr = 0.0f;
|
||||
float* psymamps = symamps;
|
||||
// compute sig power
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
|
||||
psymamps += 2;
|
||||
}
|
||||
pwr = pwr / QPC_N;
|
||||
|
||||
// normalize to avg EsNo
|
||||
float norm = sqrtf(EsNo/pwr);
|
||||
psymamps = symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
psymamps[0] *= norm;
|
||||
psymamps[1] *= norm;
|
||||
psymamps += 2;
|
||||
}
|
||||
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
|
||||
|
||||
// add signal amplitudes to noise -----------------------------------
|
||||
float *pyout = yout;
|
||||
psymamps= symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pyout[y[k]<<1] += psymamps[0];
|
||||
pyout[(y[k]<<1)+1] += psymamps[1];
|
||||
pyout += (QPC_Q*2);
|
||||
psymamps += 2;
|
||||
}
|
||||
|
||||
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
|
||||
|
||||
return;
|
||||
}
|
||||
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
|
||||
{
|
||||
// compute symbols likelihoods
|
||||
// (rayleigh channel)
|
||||
|
||||
int k, j;
|
||||
|
||||
float norm = EsNo / (EsNo + 1) / No;
|
||||
|
||||
// compute likelihoods from energies ----------------------------
|
||||
float* pybase;
|
||||
float* ppyout = yout;
|
||||
float normpwr;
|
||||
float normpwrmax;
|
||||
float pynorm;
|
||||
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
|
||||
// compute loglikelihoods and largest one from energies
|
||||
pybase = py + k * QPC_Q;
|
||||
normpwrmax = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
|
||||
pybase[j] = normpwr;
|
||||
if (normpwr > normpwrmax)
|
||||
normpwrmax = normpwr;
|
||||
ppyout += 2;
|
||||
}
|
||||
// subtract largest exponent
|
||||
pynorm = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
pybase[j] = expf(pybase[j] - normpwrmax);
|
||||
pynorm += pybase[j];
|
||||
}
|
||||
// normalize to probabilities
|
||||
pynorm = 1.0f / pynorm;
|
||||
for (j = 0; j < QPC_Q; j++)
|
||||
pybase[j] = pybase[j] * pynorm;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int k;
|
||||
|
||||
int NT = 20000; // number of transmissions to simultate
|
||||
float EbNodB = 3.7f; // Eb/No to simulate
|
||||
|
||||
|
||||
int kc = qpccode.k;
|
||||
int np = qpccode.np;
|
||||
float Rc = 1.0f * kc / np;
|
||||
float Tm = 10.0f; // message duration
|
||||
float Rb = 1.0f / Tm * (QPC_K - 2) * QPC_LOG2Q; // Bit rate assuming two symbols for CRC
|
||||
|
||||
float EsNodB = EbNodB + 10.0f * log10f(Rc * QPC_LOG2Q);
|
||||
|
||||
static unsigned char xin[QPC_K]; // input information symbols
|
||||
static unsigned char xdec[QPC_K]; // decoded information symbols
|
||||
static unsigned char y[QPC_N]; // encoded codeword
|
||||
static unsigned char ydec[QPC_N]; // decoded codeword
|
||||
|
||||
static float yout[QPC_N * QPC_Q * 2]; // channel complex amplitutes output
|
||||
static float py[QPC_N * QPC_Q]; // channel output probabilities
|
||||
|
||||
float EsNo = powf(10.0f, EsNodB / 10.0f);
|
||||
float No = 1.0f;
|
||||
|
||||
//JHT static float we;
|
||||
static float wer;
|
||||
|
||||
int kk;
|
||||
|
||||
printf("QPC Word Error Rate Test\n");
|
||||
printf("Polar Code (%d,%d) Q=%d for the Rayleigh channel\n", qpccode.np, qpccode.k, qpccode.q);
|
||||
printf("Eb/No = %.1f dB\n", EbNodB);
|
||||
printf("Es/No = %.1f dB\n", EsNodB);
|
||||
printf("Tmsg = %.1f s\n", Tm);
|
||||
printf("Bit Rate = %.1f bit/s\n", Rb);
|
||||
printf("SNR(2500) = %.1f dB\n\n", EbNodB + 10.0f * log10f(Rb/ 2500));
|
||||
|
||||
|
||||
for (k = 0; k < NT; k++) {
|
||||
|
||||
np_unidrnd_uc(xin, QPC_K, QPC_Q); // generate random information symbols
|
||||
|
||||
qpc_encode(y, xin); // encode
|
||||
|
||||
// compute channel outputs and probabilities
|
||||
|
||||
// Note that if the code is punctured (i.e. N=127)
|
||||
// the first codeword symbol must not be transmitted over the channel
|
||||
// Here, in order to avoid useless copies,
|
||||
// the vector of likelihoods py continues to be a QPC_N*QPC_Q vector of floats.
|
||||
// The first received symbol likelihoods should start always at offset QPC_Q.
|
||||
// The first QPC_Q positions of py will be ignored (and set) by the decoder.
|
||||
qpc_channel(yout, y, EsNo);
|
||||
|
||||
// The decoder can't estimate the EsNo easily
|
||||
// so we assume that in any case it is 5 dB
|
||||
float EsNoDec = 3.16;
|
||||
qpc_likelihoods(py, yout, EsNoDec, No);
|
||||
|
||||
qpc_decode(xdec, ydec, py); // decode
|
||||
|
||||
// count words in errors
|
||||
for (kk = 0; kk < QPC_K; kk++)
|
||||
if (xin[kk] ^ xdec[kk]) {
|
||||
wer += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// show the decoder performance every 200 codewords transmissions
|
||||
if ((k % 200) == 0 && k>0) {
|
||||
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
}
|
||||
// show the final result
|
||||
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
|
||||
printf("\nAll done.\n");
|
||||
return 0;
|
||||
}
|
38
lib/superfox/qpc/qpc_mod.f90
Normal file
38
lib/superfox/qpc/qpc_mod.f90
Normal file
@ -0,0 +1,38 @@
|
||||
module qpc_mod
|
||||
interface
|
||||
integer(c_int32_t) function nhash2 (xin, length, initval) bind(C, &
|
||||
name="nhash2")
|
||||
use iso_c_binding, only: c_signed_char, c_int64_t, c_int32_t
|
||||
integer(c_int64_t), intent(in), value :: length
|
||||
integer(c_signed_char), intent(in) :: xin(length)
|
||||
integer(c_int32_t), intent(in), value :: initval
|
||||
end function nhash2
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_encode(y, xin) bind(C,name="qpc_encode")
|
||||
use iso_c_binding, only: c_ptr, c_signed_char
|
||||
integer(c_signed_char), intent(out) :: y(127)
|
||||
integer(c_signed_char), intent(in) :: xin(50)
|
||||
end subroutine qpc_encode
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_channel(yout, y, EsNo) bind(C,name="qpc_channel")
|
||||
use iso_c_binding, only: c_float_complex, c_float, c_signed_char
|
||||
complex(c_float_complex), intent(out) :: yout(128,128)
|
||||
integer(c_signed_char), intent(out) :: y(127)
|
||||
real(c_float), intent(in), value :: EsNo
|
||||
end subroutine qpc_channel
|
||||
end interface
|
||||
|
||||
interface
|
||||
subroutine qpc_decode(xdec, ydec, py) bind(C,name="qpc_decode")
|
||||
use iso_c_binding, only: c_float, c_signed_char
|
||||
real(c_float), intent(in) :: py(128,128)
|
||||
integer(c_signed_char), intent(out) :: ydec(127)
|
||||
integer(c_signed_char), intent(out) :: xdec(50)
|
||||
end subroutine qpc_decode
|
||||
end interface
|
||||
|
||||
end module qpc_mod
|
60
lib/superfox/qpc/qpc_n127k50q128.c
Normal file
60
lib/superfox/qpc/qpc_n127k50q128.c
Normal file
@ -0,0 +1,60 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_n127k50q128.c
|
||||
//
|
||||
// Defines the parameters of the q-ary polar code (127,50) Q=128
|
||||
// for WSJT-X
|
||||
// ------------------------------------------------------------------------------
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
//
|
||||
// WARNING:
|
||||
// This source is NOT free software and it is licensed only for use with WSJT-X.
|
||||
// No derived work is authorized to use this code without the written
|
||||
// permission of his author (Nico Palermo / IV3NWV) who owns all the rights
|
||||
// of this IP (intellectual property).
|
||||
//
|
||||
// This file is distributed ONLY for the purpose of documenting and making of
|
||||
// public domain the encoding scheme used in WSJT-X so that the transmitted
|
||||
// messages can be decoded by anybody.
|
||||
// Anyway this does not imply that one could use the following tables in a
|
||||
// derived work without an explicit and written authorization from his author.
|
||||
// Any unauthorized use, as for any intellectual property, is simply
|
||||
// illegal.
|
||||
// -------------------------------------------------------------------------------
|
||||
#include "np_qpc.h"
|
||||
qpccode_ds qpccode = {
|
||||
128, //n
|
||||
127, //np
|
||||
50, //k
|
||||
128, //q
|
||||
{
|
||||
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 32, 17, 18, 64, 20,
|
||||
33, 34, 24, 7, 11, 36, 13, 19, 14, 65, 40, 21, 66, 22, 35, 68,
|
||||
25, 48, 37, 26, 72, 15, 38, 28, 41, 67, 23, 80, 42, 69, 49, 96,
|
||||
44, 27, 70, 50, 73, 39, 29, 52, 74, 30, 56, 81, 76, 43, 82, 84,
|
||||
97, 45, 71, 88, 98, 46, 100, 51, 104, 53, 75, 112, 54, 57, 99, 119,
|
||||
92, 77, 58, 117, 59, 83, 106, 31, 85, 108, 115, 116, 122, 125, 124, 91,
|
||||
61, 90, 89, 111, 78, 93, 94, 126, 86, 107, 110, 118, 121, 62, 120, 87,
|
||||
105, 55, 114, 60, 127, 63, 103, 101, 123, 95, 102, 47, 109, 79, 113, 0
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 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, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
}
|
||||
};
|
115
lib/superfox/qpc/qpc_subs.c
Normal file
115
lib/superfox/qpc/qpc_subs.c
Normal file
@ -0,0 +1,115 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// qpc_test.cpp
|
||||
//
|
||||
// Test the WER performance of the QPC (127,50) Q=128 code
|
||||
//
|
||||
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "dbgprintf.h"
|
||||
#include "qpc_fwht.h"
|
||||
#include "np_qpc.h"
|
||||
|
||||
#include "nhash2.h"
|
||||
|
||||
// for random numbers generation and NCFSK Rayleigh channel simulation
|
||||
#include "np_rnd.h"
|
||||
void qpc_channel(float* yout, unsigned char* y, float EsNo)
|
||||
{
|
||||
// compute channel outputs amplitudes
|
||||
|
||||
int k;
|
||||
|
||||
// generate noise samples -----------------------------------------
|
||||
float sigman = 1.0f / sqrtf(2.0f);
|
||||
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
|
||||
|
||||
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
|
||||
|
||||
// generate rayleigh distributed signal amplitudes -----------------
|
||||
float symamps[QPC_N * 2];
|
||||
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
|
||||
|
||||
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
|
||||
|
||||
// normalize signal amps to unity ----------------------------------
|
||||
float pwr = 0.0f;
|
||||
float* psymamps = symamps;
|
||||
// compute sig power
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
|
||||
psymamps += 2;
|
||||
}
|
||||
pwr = pwr / QPC_N;
|
||||
|
||||
// normalize to avg EsNo
|
||||
float norm = sqrtf(EsNo/pwr);
|
||||
psymamps = symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
psymamps[0] *= norm;
|
||||
psymamps[1] *= norm;
|
||||
psymamps += 2;
|
||||
}
|
||||
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
|
||||
|
||||
// add signal amplitudes to noise -----------------------------------
|
||||
float *pyout = yout;
|
||||
psymamps= symamps;
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
pyout[y[k]<<1] += psymamps[0];
|
||||
pyout[(y[k]<<1)+1] += psymamps[1];
|
||||
pyout += (QPC_Q*2);
|
||||
psymamps += 2;
|
||||
}
|
||||
|
||||
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
|
||||
|
||||
return;
|
||||
}
|
||||
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
|
||||
{
|
||||
// compute symbols likelihoods
|
||||
// (rayleigh channel)
|
||||
|
||||
int k, j;
|
||||
|
||||
float norm = EsNo / (EsNo + 1) / No;
|
||||
|
||||
// compute likelihoods from energies ----------------------------
|
||||
float* pybase;
|
||||
float* ppyout = yout;
|
||||
float normpwr;
|
||||
float normpwrmax;
|
||||
float pynorm;
|
||||
|
||||
for (k = 0; k < QPC_N; k++) {
|
||||
|
||||
// compute loglikelihoods and largest one from energies
|
||||
pybase = py + k * QPC_Q;
|
||||
normpwrmax = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
|
||||
pybase[j] = normpwr;
|
||||
if (normpwr > normpwrmax)
|
||||
normpwrmax = normpwr;
|
||||
ppyout += 2;
|
||||
}
|
||||
// subtract largest exponent
|
||||
pynorm = 0.0f;
|
||||
for (j = 0; j < QPC_Q; j++) {
|
||||
pybase[j] = expf(pybase[j] - normpwrmax);
|
||||
pynorm += pybase[j];
|
||||
}
|
||||
// normalize to probabilities
|
||||
pynorm = 1.0f / pynorm;
|
||||
for (j = 0; j < QPC_Q; j++)
|
||||
pybase[j] = pybase[j] * pynorm;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
218
lib/superfox/qpc_decode2.f90
Normal file
218
lib/superfox/qpc_decode2.f90
Normal file
@ -0,0 +1,218 @@
|
||||
subroutine qpc_decode2(c0,fsync,ftol,xdec,ndepth,dth,damp,crc_ok, &
|
||||
snrsync,fbest,tbest,snr)
|
||||
|
||||
use qpc_mod
|
||||
|
||||
parameter(NMAX=15*12000,NFT=365,NZ=100)
|
||||
complex c0(NMAX) !Signal as received
|
||||
complex c(NMAX) !Signal as received
|
||||
real py(0:127,0:127) !Probabilities for received synbol values
|
||||
real py0(0:127,0:127) !Probabilities for strong signal
|
||||
real pyd(0:127,0:127) !Dithered values for py
|
||||
real s2(0:127,0:151) !Symbol spectra, including sync
|
||||
real s3(0:127,0:127) !Synchronized symbol spectra
|
||||
real No
|
||||
integer crc_chk,crc_sent
|
||||
integer*8 n47
|
||||
integer idf(NZ),idt(NZ)
|
||||
integer nseed(33)
|
||||
integer*1 xdec(0:49) !Decoded message
|
||||
integer*1 ydec(0:127) !Decoded symbols
|
||||
logical crc_ok
|
||||
integer maxdither(8)
|
||||
integer isync(24) !Symbol numbers for sync tones
|
||||
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80,83, &
|
||||
84,86,89/
|
||||
data n47/47/,maxdither/20,50,100,200,500,1000,2000,5000/
|
||||
data nseed/ &
|
||||
321278106, -658879006, 1239150429, -941466001, -698554454, &
|
||||
1136210962, 1633585627, 1261915021, -1134191465, -487888229, &
|
||||
2131958895, -1429290834, -1802468092, 1801346659, 1966248904, &
|
||||
402671397, -1961400750, -1567227835, 1895670987, -286583128, &
|
||||
-595933665, -1699285543, 1518291336, 1338407128, 838354404, &
|
||||
-2081343776, -1449416716, 1236537391, -133197638, 337355509, &
|
||||
-460640480, 1592689606, 0/
|
||||
|
||||
data idf/0, 0, -1, 0, -1, 1, 0, -1, 1, -2, 0, -1, 1, -2, 2, &
|
||||
0, -1, 1, -2, 2, -3, 0, -1, 1, -2, 2, -3, 3, 0, -1, &
|
||||
1, -2, 2, -3, 3, -4, 0, -1, 1, -2, 2, -3, 3, -4, 4, &
|
||||
0, -1, 1, -2, 2, -3, 3, -4, 4, -5, -1, 1, -2, 2, -3, &
|
||||
3, -4, 4, -5, 1, -2, 2, -3, 3, -4, 4, -5, -2, 2, -3, &
|
||||
3, -4, 4, -5, 2, -3, 3, -4, 4, -5, -3, 3, -4, 4, -5, &
|
||||
3, -4, 4, -5, -4, 4, -5, 4, -5, -5/
|
||||
data idt/0 , -1, 0, 1, -1, 0, -2, 1, -1, 0, 2, -2, 1, -1, 0, &
|
||||
-3, 2, -2, 1, -1, 0, 3, -3, 2, -2, 1, -1, 0, -4, 3, &
|
||||
-3, 2, -2, 1, -1, 0, 4, -4, 3, -3, 2, -2, 1, -1, 0, &
|
||||
-5, 4, -4, 3, -3, 2, -2, 1, -1, 0, -5, 4, -4, 3, -3, &
|
||||
2, -2, 1, -1, -5, 4, -4, 3, -3, 2, -2, 1, -5, 4, -4, &
|
||||
3, -3, 2, -2, -5, 4, -4, 3, -3, 2, -5, 4, -4, 3, -3, &
|
||||
-5, 4, -4, 3, -5, 4, -4, -5, 4, -5/
|
||||
|
||||
|
||||
fsample=12000.0
|
||||
baud=12000.0/1024.0
|
||||
nstype=1
|
||||
n47=47
|
||||
mask21=2**21 - 1
|
||||
crc_ok=.false.
|
||||
|
||||
call qpc_sync(c0,fsample,isync,fsync,ftol,f2,t2,snrsync)
|
||||
f00=1500.0 + f2
|
||||
t00=t2
|
||||
fbest=f00
|
||||
tbest=t00
|
||||
maxd=1
|
||||
if(ndepth.gt.0) maxd=maxdither(ndepth)
|
||||
maxft=NZ
|
||||
if(snrsync.lt.4.0 .or. ndepth.le.0) maxft=1
|
||||
do idith=1,maxft
|
||||
if(idith.ge.2) maxd=1
|
||||
deltaf=idf(idith)*0.5
|
||||
deltat=idt(idith)*8.0/1024.0
|
||||
f=f00+deltaf
|
||||
t=t00+deltat
|
||||
fshift=1500.0 - (f+baud) !Shift frequencies down by f + 1 bin
|
||||
call twkfreq2(c0,c,NMAX,fsample,fshift)
|
||||
a=1.0
|
||||
b=0.0
|
||||
do kk=1,4
|
||||
if(kk.eq.2) b=0.4
|
||||
if(kk.eq.3) b=0.5
|
||||
if(kk.eq.4) b=0.6
|
||||
call sfox_demod(c,1500.0,t,isync,s2,s3) !Compute s2 and s3
|
||||
|
||||
if(b.gt.0.0) then
|
||||
do j=0,127
|
||||
call smo121a(s3(:,j),128,a,b)
|
||||
enddo
|
||||
endif
|
||||
call pctile(s3,128*128,50,base3)
|
||||
s3=s3/base3
|
||||
|
||||
EsNoDec=3.16
|
||||
No=1.
|
||||
py0=s3
|
||||
call qpc_likelihoods2(py,s3,EsNoDec,No) !For weak signals
|
||||
|
||||
call random_seed(put=nseed)
|
||||
do kkk=1,maxd
|
||||
if(kkk.eq.1) then
|
||||
pyd=py0
|
||||
else
|
||||
pyd=0.
|
||||
if(kkk.gt.2) then
|
||||
call random_number(pyd)
|
||||
pyd=2.0*(pyd-0.5)
|
||||
endif
|
||||
where(py.gt.dth) pyd=0. !Don't perturb large likelihoods
|
||||
pyd=py*(1.0 + damp*pyd) !Compute dithered likelihood
|
||||
endif
|
||||
do j=0,127
|
||||
ss=sum(pyd(:,j))
|
||||
if(ss.gt.0.0) then
|
||||
pyd(:,j)=pyd(:,j)/ss
|
||||
else
|
||||
pyd(:,j)=0.0
|
||||
endif
|
||||
enddo
|
||||
|
||||
call qpc_decode(xdec,ydec,pyd)
|
||||
xdec=xdec(49:0:-1)
|
||||
crc_chk=iand(nhash2(xdec,n47,571),mask21) !Compute crc_chk
|
||||
crc_sent=128*128*xdec(47) + 128*xdec(48) + xdec(49)
|
||||
crc_ok=crc_chk.eq.crc_sent
|
||||
|
||||
if(crc_ok) then
|
||||
call qpc_snr(s3,ydec,snr)
|
||||
if(snr.lt.-16.5) crc_ok=.false.
|
||||
! write(61,3061) idith,kk,kkk,idf(idith),idt(idith),a,b
|
||||
!3061 format(5i5,2f8.3)
|
||||
return
|
||||
endif
|
||||
enddo !kk: dither of smoothing weights
|
||||
enddo !kkk: dither of probabilities
|
||||
enddo !idith: dither of frequency and time
|
||||
return
|
||||
end subroutine qpc_decode2
|
||||
|
||||
subroutine smo121a(x,nz,a,b)
|
||||
|
||||
real x(nz)
|
||||
fac=1.0/(a+2*b)
|
||||
x0=x(1)
|
||||
do i=2,nz-1
|
||||
x1=x(i)
|
||||
x(i)=fac*(a*x(i) + b*(x0+x(i+1)))
|
||||
x0=x1
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine smo121a
|
||||
|
||||
subroutine remove_tone(c0,npts)
|
||||
|
||||
parameter (NFILT=8000)
|
||||
complex c0(npts)
|
||||
complex cwindow(15*12000)
|
||||
complex cref(npts)
|
||||
complex cfilt(npts)
|
||||
real window(-NFILT/2:NFILT/2)
|
||||
! real endcorrection(NFILT/2+1)
|
||||
real s(npts/4)
|
||||
integer ipk(1)
|
||||
logical first
|
||||
data first/.true./
|
||||
save cwindow,first,pi
|
||||
|
||||
if(first) then
|
||||
pi=4.0*atan(1.0)
|
||||
fac=1.0/float(npts)
|
||||
sumw=0.0
|
||||
do j=-NFILT/2,NFILT/2
|
||||
window(j)=cos(pi*j/NFILT)**2
|
||||
sumw=sumw+window(j)
|
||||
enddo
|
||||
cwindow=0.
|
||||
cwindow(1:NFILT+1)=window/sumw
|
||||
cwindow=cshift(cwindow,NFILT/2+1)
|
||||
call four2a(cwindow,npts,1,-1,1)
|
||||
cwindow=cwindow*fac ! frequency domain smoothing filter
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
fsample=12000.0
|
||||
df=fsample/npts
|
||||
fac=1.0/npts
|
||||
cfilt=fac*c0
|
||||
call four2a(cfilt,npts,1,-1,1) ! fourier transform of input data
|
||||
iz=npts/4
|
||||
do i=1,iz
|
||||
s(i)=real(cfilt(i))**2 + aimag(cfilt(i))**2
|
||||
enddo
|
||||
|
||||
ia=nint(700.0/df)
|
||||
ib=nint(800.0/df)
|
||||
ipk=maxloc(s(ia:ib))
|
||||
i0=ipk(1) + ia - 1
|
||||
f2=df*i0
|
||||
write(*,*) 'remove_tone - frequency: ',f2
|
||||
|
||||
dt=1.0/fsample
|
||||
do i=1, npts
|
||||
arg=2*pi*f2*i*dt
|
||||
cref(i)=cmplx(cos(arg),sin(arg))
|
||||
enddo
|
||||
cfilt=c0*conjg(cref) ! baseband to be filtered
|
||||
call four2a(cfilt,npts,1,-1,1)
|
||||
cfilt=cfilt*cwindow
|
||||
call four2a(cfilt,npts,1,1,1)
|
||||
|
||||
nframe=50*3456
|
||||
do i=1,nframe
|
||||
cref(i)=cfilt(i)*cref(i)
|
||||
c0(i)=c0(i)-cref(i)
|
||||
enddo
|
||||
|
||||
return
|
||||
|
||||
end subroutine remove_tone
|
28
lib/superfox/qpc_likelihoods2.f90
Normal file
28
lib/superfox/qpc_likelihoods2.f90
Normal file
@ -0,0 +1,28 @@
|
||||
subroutine qpc_likelihoods2(py,s3,EsNo,No)
|
||||
|
||||
integer QQ,QN
|
||||
parameter(QQ=128,QN=128)
|
||||
real py(0:QQ-1,0:QN-1)
|
||||
real s3(0:QQ-1,0:QN-1)
|
||||
real No,norm,normpwr,normpwrmax
|
||||
|
||||
norm=(EsNo/(EsNo+1.0))/No
|
||||
|
||||
! Compute likelihoods for symbol values, from the symbol power spectra
|
||||
do k=0,QN-1
|
||||
normpwrmax=0.
|
||||
do j=0,QQ-1
|
||||
normpwr=norm*s3(j,k)
|
||||
py(j,k)=normpwr
|
||||
normpwrmax=max(normpwr,normpwrmax)
|
||||
enddo
|
||||
pynorm=0.
|
||||
do j=0,QQ-1
|
||||
py(j,k)=exp(py(j,k)-normpwrmax)
|
||||
pynorm=pynorm + py(j,k)
|
||||
enddo
|
||||
py(0:QQ-1,k)=py(0:QQ-1,k)/pynorm !Normalize to probabilities
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine qpc_likelihoods2
|
17
lib/superfox/qpc_snr.f90
Normal file
17
lib/superfox/qpc_snr.f90
Normal file
@ -0,0 +1,17 @@
|
||||
subroutine qpc_snr(s3,y,snr)
|
||||
|
||||
use qpc_mod
|
||||
! real s2(0:NQ-1,0:151) !Symbol spectra, including sync
|
||||
real s3(0:127,0:127) !Synchronized symbol spectra
|
||||
integer*1 y(0:127) !Encoded symbols
|
||||
! integer isync(24)
|
||||
|
||||
p=0.
|
||||
do j=1,127
|
||||
i=y(j)
|
||||
p=p + s3(i,j)
|
||||
enddo
|
||||
snr=db(p/127.0) - db(127.0) - 4.0
|
||||
|
||||
return
|
||||
end subroutine qpc_snr
|
101
lib/superfox/qpc_sync.f90
Normal file
101
lib/superfox/qpc_sync.f90
Normal file
@ -0,0 +1,101 @@
|
||||
subroutine qpc_sync(crcvd0,fsample,isync,fsync,ftol,f2,t2,snrsync)
|
||||
|
||||
parameter(N9SEC=9*12000,NMAX=15*12000,NDOWN=16,NZ=N9SEC/NDOWN)
|
||||
complex crcvd0(NMAX) !Signal as received
|
||||
complex c0(0:N9SEC-1) !For long FFT
|
||||
complex c1(0:NZ-1)
|
||||
complex c1sum(0:NZ-1)
|
||||
complex z
|
||||
real s(N9SEC/4)
|
||||
real p(-1125:1125)
|
||||
integer ipk(1)
|
||||
integer isync(24)
|
||||
|
||||
baud=12000.0/1024.0
|
||||
df2=fsample/N9SEC
|
||||
fac=1.0/N9SEC
|
||||
c0=fac*crcvd0(1:N9SEC)
|
||||
call four2a(c0,N9SEC,1,-1,1) !Forward c2c FFT
|
||||
iz=N9SEC/4
|
||||
do i=1,iz
|
||||
s(i)=real(c0(i))**2 + aimag(c0(i))**2
|
||||
enddo
|
||||
|
||||
do i=1,4 !Smooth the spectrum a bit
|
||||
call smo121(s,iz)
|
||||
enddo
|
||||
|
||||
ia=nint((fsync-ftol)/df2)
|
||||
ib=nint((fsync+ftol)/df2)
|
||||
ipk=maxloc(s(ia:ib))
|
||||
i0=ipk(1) + ia - 1
|
||||
f2=df2*i0-750.0 ! f2 is the offset from nominal 750 Hz.
|
||||
ia=nint(i0-baud/df2)
|
||||
ib=nint(i0+baud/df2)
|
||||
s1=0.0
|
||||
s0=0.0
|
||||
do i=ia,ib
|
||||
s0=s0+s(i)
|
||||
s1=s1+(i-i0)*s(i)
|
||||
enddo
|
||||
delta=s1/s0
|
||||
i0=nint(i0+delta)
|
||||
f2=i0*df2-750.0
|
||||
|
||||
c1=0.
|
||||
ia=nint(i0-baud/df2)
|
||||
ib=nint(i0+baud/df2)
|
||||
do i=ia,ib
|
||||
j=i-i0
|
||||
if(j.ge.0) c1(j)=c0(i)
|
||||
if(j.lt.0) c1(j+NZ)=c0(i)
|
||||
enddo
|
||||
call four2a(c1,NZ,1,1,1) !Reverse c2c FFT: back to time domain
|
||||
|
||||
c1sum(0)=c1(0)
|
||||
do i=1,NZ-1
|
||||
c1sum(i)=c1sum(i-1) + c1(i)
|
||||
enddo
|
||||
|
||||
nspsd=1024/NDOWN
|
||||
dt=NDOWN/12000.0
|
||||
lagmax=1.5/dt
|
||||
i0=nint(0.5*fsample/NDOWN) !Nominal start time is 0.5 s
|
||||
pmax=0.
|
||||
lagpk=0
|
||||
do lag=-lagmax,lagmax
|
||||
sp=0.
|
||||
do j=1,24
|
||||
i1=i0 + (isync(j)-1)*nspsd + lag
|
||||
i2=i1 + nspsd
|
||||
if(i1.lt.0 .or. i1.gt.NZ-1) cycle
|
||||
if(i2.lt.0 .or. i2.gt.NZ-1) cycle
|
||||
z=c1sum(i2)-c1sum(i1)
|
||||
sp=sp + real(z)**2 + aimag(z)**2
|
||||
enddo
|
||||
if(sp.gt.pmax) then
|
||||
pmax=sp
|
||||
lagpk=lag
|
||||
endif
|
||||
p(lag)=sp
|
||||
enddo
|
||||
|
||||
t2=lagpk*dt
|
||||
snrsync=0.
|
||||
sp=0.
|
||||
sq=0.
|
||||
nsum=0
|
||||
tsym=1024/12000.0
|
||||
do lag=-lagmax,lagmax
|
||||
t=(lag-lagpk)*dt
|
||||
if(abs(t).lt.tsym) cycle
|
||||
nsum=nsum+1
|
||||
sp=sp + p(lag)
|
||||
sq=sq + p(lag)*p(lag)
|
||||
enddo
|
||||
ave=sp/nsum
|
||||
rms=sqrt(sq/nsum-ave*ave)
|
||||
snrsync=(pmax-ave)/rms
|
||||
|
||||
return
|
||||
end subroutine qpc_sync
|
17
lib/superfox/sfox_ana.f90
Normal file
17
lib/superfox/sfox_ana.f90
Normal file
@ -0,0 +1,17 @@
|
||||
subroutine sfox_ana(dd,npts,c0,npts2)
|
||||
|
||||
real dd(npts) !Raw data at 12000 Hz
|
||||
complex c0(0:npts2-1) !Complex data at 12000 Hz
|
||||
save
|
||||
|
||||
nfft1=npts
|
||||
nfft2=nfft1
|
||||
fac=2.0/(32767.0*nfft1)
|
||||
c0(0:npts-1)=fac*dd(1:npts)
|
||||
call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT
|
||||
c0(nfft2/2+1:nfft2-1)=0. !Remove negative frequencies
|
||||
c0(0)=0.5*c0(0) !Scale the DC term to 1/2
|
||||
call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT; c0 is analytic sig
|
||||
|
||||
return
|
||||
end subroutine sfox_ana
|
79
lib/superfox/sfox_demod.f90
Normal file
79
lib/superfox/sfox_demod.f90
Normal file
@ -0,0 +1,79 @@
|
||||
subroutine sfox_demod(crcvd,f,t,isync,s2,s3)
|
||||
|
||||
use sfox_mod
|
||||
complex crcvd(NMAX) !Signal as received
|
||||
complex c(0:NSPS-1) !Work array, one symbol long
|
||||
real s2(0:NQ-1,0:151) !Symbol spectra, including sync
|
||||
real s3(0:NQ-1,0:NN) !Synchronized symbol spectra
|
||||
integer isync(24)
|
||||
integer ipk(1)
|
||||
integer hist1(0:NQ-1),hist2(0:NQ-1)
|
||||
|
||||
j0=nint(12000.0*(t+0.5))
|
||||
df=12000.0/NSPS
|
||||
i0=nint(f/df)-NQ/2
|
||||
k2=0
|
||||
s2(:,0)=0. !The punctured symbol
|
||||
s3(:,0)=0. !The punctured symbol
|
||||
|
||||
do n=1,NDS !Loop over all symbols
|
||||
jb=n*NSPS + j0
|
||||
ja=jb-NSPS+1
|
||||
k2=k2+1
|
||||
if(ja.lt.1 .or. jb.gt.NMAX) cycle
|
||||
c=crcvd(ja:jb)
|
||||
call four2a(c,NSPS,1,-1,1) !Compute symbol spectrum
|
||||
do i=0,NQ-1
|
||||
s2(i,k2)=real(c(i0+i))**2 + aimag(c(i0+i))**2
|
||||
enddo
|
||||
enddo
|
||||
|
||||
|
||||
call pctile(s2,NQ*151,50,base2)
|
||||
s2=s2/base2
|
||||
|
||||
hist1=0
|
||||
hist2=0
|
||||
do j=0,151
|
||||
ipk=maxloc(s2(1:NQ-1,j)) !Find the spectral peak
|
||||
i=ipk(1)-1
|
||||
hist1(i)=hist1(i)+1
|
||||
enddo
|
||||
|
||||
hist1(0)=0 !Don't treat sync tone as a birdie
|
||||
do i=0,123
|
||||
hist2(i)=sum(hist1(i:i+3))
|
||||
enddo
|
||||
|
||||
ipk=maxloc(hist1)
|
||||
i1=ipk(1)-1
|
||||
m1=maxval(hist1)
|
||||
ipk=maxloc(hist2)
|
||||
i2=ipk(1)-1
|
||||
m2=maxval(hist2)
|
||||
if(m1.gt.12) then
|
||||
do i=0,127
|
||||
if(hist1(i).gt.12) then
|
||||
s2(i,:)=1.0
|
||||
endif
|
||||
enddo
|
||||
endif
|
||||
|
||||
if(m2.gt.20) then
|
||||
if(i2.ge.1) i2=i2-1
|
||||
if(i2.gt.120) i2=120
|
||||
s2(i2:i2+7,:)=1.0
|
||||
endif
|
||||
|
||||
k3=0
|
||||
do n=1,NDS !Copy symbol spectra from s2 into s3
|
||||
if(any(isync(1:NS).eq.n)) cycle !Skip the sync symbols
|
||||
k3=k3+1
|
||||
s3(:,k3)=s2(:,n)
|
||||
enddo
|
||||
|
||||
call pctile(s3,NQ*NN,50,base3)
|
||||
s3=s3/base3
|
||||
|
||||
return
|
||||
end subroutine sfox_demod
|
73
lib/superfox/sfox_mod.f90
Normal file
73
lib/superfox/sfox_mod.f90
Normal file
@ -0,0 +1,73 @@
|
||||
module sfox_mod
|
||||
|
||||
parameter (NMAX=15*12000) !Samples in iwave (180,000)
|
||||
integer MM,NQ,NN,KK,NS,NDS,NFZ,NSPS,NSYNC,NZ,NFFT1
|
||||
real baud,tsym,bw
|
||||
|
||||
contains
|
||||
subroutine sfox_init(mm0,nn0,kk0,itu,fspread,delay,fsample,ns0)
|
||||
|
||||
character*2 itu
|
||||
integer isps(54)
|
||||
integer iloc(1)
|
||||
data isps/ 896, 960, 972, 980,1000,1008,1024,1029,1050,1080, &
|
||||
1120,1125,1134,1152,1176,1200,1215,1225,1250,1260, &
|
||||
1280,1296,1323,1344,1350,1372,1400,1440,1458,1470, &
|
||||
1500,1512,1536,1568,1575,1600,1620,1680,1701,1715, &
|
||||
1728,1750,1764,1792,1800,1875,1890,1920,1944,1960, &
|
||||
2000,2016,2025,2048/
|
||||
|
||||
MM=mm0 !Bits per symbol
|
||||
NQ=2**MM !Q, number of MFSK tones
|
||||
NN=nn0 !Codeword length
|
||||
KK=kk0 !Number of information symbols
|
||||
NS=ns0 !Number of sync symbols
|
||||
NDS=NN+NS !Total number of channel symbols
|
||||
NFZ=3 !First zero
|
||||
|
||||
jsps=nint(12.8*fsample/NDS)
|
||||
iloc=minloc(abs(isps-jsps))
|
||||
NSPS=isps(iloc(1)) !Samples per symbol
|
||||
NSYNC=NS*NSPS !Samples in sync waveform
|
||||
NZ=NSPS*NDS !Samples in full Tx waveform
|
||||
NFFT1=2*NSPS !Length of FFTs for symbol spectra
|
||||
|
||||
baud=fsample/NSPS
|
||||
tsym=1.0/baud
|
||||
bw=NQ*baud
|
||||
|
||||
fspread=0.0
|
||||
delay=0.0
|
||||
if(itu.eq.'LQ') then
|
||||
fspread=0.5
|
||||
delay=0.5
|
||||
else if(itu.eq.'LM') then
|
||||
fspread=1.5
|
||||
delay=2.0
|
||||
else if(itu.eq.'LD') then
|
||||
fspread=10.0
|
||||
delay=6.0
|
||||
else if(itu.eq.'MQ') then
|
||||
fspread=0.1
|
||||
delay=0.5
|
||||
else if(itu.eq.'MM') then
|
||||
fspread=0.5
|
||||
delay=1.0
|
||||
else if(itu.eq.'MD') then
|
||||
fspread=1.0
|
||||
delay=2.0
|
||||
else if(itu.eq.'HQ') then
|
||||
fspread=0.5
|
||||
delay=1.0
|
||||
else if(itu.eq.'HM') then
|
||||
fspread=10.0
|
||||
delay=3.0
|
||||
else if(itu.eq.'HD') then
|
||||
fspread=30.0
|
||||
delay=7.0
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine sfox_init
|
||||
|
||||
end module sfox_mod
|
55
lib/superfox/sfox_prob.f90
Normal file
55
lib/superfox/sfox_prob.f90
Normal file
@ -0,0 +1,55 @@
|
||||
subroutine sfox_prob(s3,rxdat,rxprob,rxdat2,rxprob2)
|
||||
|
||||
! Demodulate the 64-bin spectra for each of 63 symbols in a frame.
|
||||
|
||||
! Parameters
|
||||
! rxdat most reliable symbol value
|
||||
! rxdat2 second most likely symbol value
|
||||
! rxprob probability that rxdat was the transmitted value
|
||||
! rxprob2 probability that rxdat2 was the transmitted value
|
||||
|
||||
use sfox_mod
|
||||
implicit real*8 (a-h,o-z)
|
||||
real*4 s3(0:NQ-1,0:NN-1)
|
||||
integer rxdat(0:NN-1),rxprob(0:NN-1),rxdat2(0:NN-1),rxprob2(0:NN-1)
|
||||
|
||||
afac=1.1
|
||||
! scale=255.999
|
||||
scale=2047.999
|
||||
|
||||
! Compute average spectral value
|
||||
ave=sum(s3)/(NQ*ND)
|
||||
i1=1 !Silence warning
|
||||
i2=1
|
||||
|
||||
! Compute probabilities for most reliable symbol values
|
||||
do j=0,NN-1 !Loop over all symbols
|
||||
s1=-1.e30
|
||||
psum=0.
|
||||
do i=0,NQ-1 !Loop over frequency bins
|
||||
x=min(afac*s3(i,j)/ave,50.d0)
|
||||
psum=psum+s3(i,j)
|
||||
if(s3(i,j).gt.s1) then
|
||||
s1=s3(i,j) !Find max signal+noise power
|
||||
i1=i !Find most reliable symbol value
|
||||
endif
|
||||
enddo
|
||||
if(psum.eq.0.0) psum=1.e-6 !Guard against zero signal+noise
|
||||
|
||||
s2=-1.e30
|
||||
do i=0,NQ-1
|
||||
if(i.ne.i1 .and. s3(i,j).gt.s2) then
|
||||
s2=s3(i,j) !Second largest signal+noise power
|
||||
i2=i !Bin number for second largest power
|
||||
endif
|
||||
enddo
|
||||
p1=s1/psum !p1, p2 are symbol metrics for ftrsd
|
||||
p2=s2/psum
|
||||
rxdat(j)=i1
|
||||
rxdat2(j)=i2
|
||||
rxprob(j)=scale*p1 !Scaled probabilities, 0 - 255
|
||||
rxprob2(j)=scale*p2
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine sfox_prob
|
229
lib/superfox/sfox_remove_ft8.f90
Normal file
229
lib/superfox/sfox_remove_ft8.f90
Normal file
@ -0,0 +1,229 @@
|
||||
subroutine sfox_remove_ft8(dd,npts)
|
||||
use packjt77
|
||||
include 'ft8_params.f90'
|
||||
parameter (MAXCAND=100)
|
||||
parameter (NP2=2812)
|
||||
integer itone(NN)
|
||||
integer iloc(1), ip(1)
|
||||
integer icos7(0:6)
|
||||
integer graymap(0:7)
|
||||
integer*1 cw(174),apmask(174)
|
||||
integer*1 message91(91)
|
||||
integer*1 message77(77)
|
||||
|
||||
character*77 c77
|
||||
character*37 msg37
|
||||
|
||||
real s8(0:7,NN)
|
||||
real s2(0:7)
|
||||
real ss(9)
|
||||
real candidate(3,MAXCAND)
|
||||
real sbase(NH1)
|
||||
real dd(npts)
|
||||
real bmeta(174),bmetd(174)
|
||||
real llra(174),llrd(174)
|
||||
complex cd0(0:3199)
|
||||
complex csymb(32)
|
||||
complex ctwk(32)
|
||||
complex cs(0:7,NN)
|
||||
data icos7/3,1,4,0,6,5,2/
|
||||
logical first,newdat
|
||||
logical one(0:7,0:2)
|
||||
logical unpk77_success
|
||||
data first/.true./
|
||||
data graymap/0,1,3,2,5,6,4,7/
|
||||
save one,first,twopi
|
||||
|
||||
if(first) then
|
||||
one=.false.
|
||||
do i=0,7
|
||||
do j=0,2
|
||||
if(iand(i,2**j).ne.0) one(i,j)=.true.
|
||||
enddo
|
||||
enddo
|
||||
first=.false.
|
||||
twopi=8.0*atan(1.0)
|
||||
endif
|
||||
|
||||
fs2=12000.0/NDOWN
|
||||
dt2=1.0/fs2
|
||||
nfa=500
|
||||
nfb=2500
|
||||
syncmin=1.5
|
||||
nfqso=750
|
||||
call sync8(dd,npts,nfa,nfb,syncmin,nfqso,MAXCAND,candidate,ncand,sbase)
|
||||
newdat=.true.
|
||||
do icand=1,ncand
|
||||
f1=candidate(1,icand)
|
||||
xdt=candidate(2,icand)
|
||||
xbase=10.0**(0.1*(sbase(nint(f1/3.125))-40.0))
|
||||
call ft8_downsample(dd,newdat,f1,cd0)
|
||||
newdat=.false.
|
||||
i0=nint((xdt+0.5)*fs2)
|
||||
smax=0.0
|
||||
do idt=i0-10,i0+10
|
||||
call sync8d(cd0,idt,ctwk,0,sync)
|
||||
if(sync.gt.smax) then
|
||||
smax=sync
|
||||
ibest=idt
|
||||
endif
|
||||
enddo
|
||||
|
||||
smax=0.0
|
||||
delfbest=0.0
|
||||
do ifr=-5,5 !Search over +/- 2.5 Hz
|
||||
delf=ifr*0.5
|
||||
dphi=twopi*delf*dt2
|
||||
phi=0.0
|
||||
do i=1,32
|
||||
ctwk(i)=cmplx(cos(phi),sin(phi))
|
||||
phi=mod(phi+dphi,twopi)
|
||||
enddo
|
||||
call sync8d(cd0,ibest,ctwk,1,sync)
|
||||
if( sync .gt. smax ) then
|
||||
smax=sync
|
||||
delfbest=delf
|
||||
endif
|
||||
enddo
|
||||
|
||||
f1=f1+delfbest !Improved estimate of DF
|
||||
|
||||
call ft8_downsample(dd,newdat,f1,cd0) !Mix f1 to baseband and downsample
|
||||
|
||||
smax=0.0
|
||||
do idt=-4,4 !Search over +/- one quarter symbol
|
||||
call sync8d(cd0,ibest+idt,ctwk,0,sync)
|
||||
ss(idt+5)=sync
|
||||
enddo
|
||||
smax=maxval(ss)
|
||||
iloc=maxloc(ss)
|
||||
ibest=iloc(1)-5+ibest
|
||||
xdt=(ibest-1)*dt2
|
||||
sync=smax
|
||||
|
||||
do k=1,NN
|
||||
i1=ibest+(k-1)*32
|
||||
csymb=cmplx(0.0,0.0)
|
||||
if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31)
|
||||
call four2a(csymb,32,1,-1,1)
|
||||
cs(0:7,k)=csymb(1:8)/1e3
|
||||
s8(0:7,k)=abs(csymb(1:8))
|
||||
enddo
|
||||
|
||||
! sync quality check
|
||||
is1=0
|
||||
is2=0
|
||||
is3=0
|
||||
do k=1,7
|
||||
ip=maxloc(s8(:,k))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
|
||||
ip=maxloc(s8(:,k+36))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1
|
||||
ip=maxloc(s8(:,k+72))
|
||||
if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1
|
||||
enddo
|
||||
! hard sync sum - max is 21
|
||||
nsync=is1+is2+is3
|
||||
if(nsync .le. 6) then ! bail out
|
||||
nbadcrc=1
|
||||
cycle
|
||||
endif
|
||||
|
||||
nsym=1
|
||||
nt=2**(3*nsym)
|
||||
do ihalf=1,2
|
||||
do k=1,29,nsym
|
||||
if(ihalf.eq.1) ks=k+7
|
||||
if(ihalf.eq.2) ks=k+43
|
||||
amax=-1.0
|
||||
do i=0,nt-1
|
||||
i3=iand(i,7)
|
||||
s2(i)=abs(cs(graymap(i3),ks))
|
||||
enddo
|
||||
i32=1+(k-1)*3+(ihalf-1)*87
|
||||
ibmax=2
|
||||
do ib=0,ibmax
|
||||
bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - &
|
||||
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))
|
||||
if(i32+ib .gt.174) cycle
|
||||
bmeta(i32+ib)=bm
|
||||
den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), &
|
||||
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)))
|
||||
if(den.gt.0.0) then
|
||||
cm=bm/den
|
||||
else ! erase it
|
||||
cm=0.0
|
||||
endif
|
||||
bmetd(i32+ib)=cm
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
|
||||
call normalizebmet(bmeta,174)
|
||||
call normalizebmet(bmetd,174)
|
||||
|
||||
scalefac=2.83
|
||||
llra=scalefac*bmeta
|
||||
llrd=scalefac*bmetd
|
||||
|
||||
cw=0
|
||||
dmin=0
|
||||
norder=2
|
||||
maxosd=-1
|
||||
Keff=91
|
||||
apmask=0
|
||||
message91=0
|
||||
cw=0
|
||||
call decode174_91(llra,Keff,maxosd,norder,apmask,message91,cw, &
|
||||
ntype,nharderrors,dmin)
|
||||
|
||||
if(nharderrors.ge.0) then
|
||||
message77=message91(1:77)
|
||||
else
|
||||
cycle
|
||||
endif
|
||||
|
||||
if(count(cw.eq.0).eq.174) cycle
|
||||
|
||||
write(c77,'(77i1)') message77
|
||||
read(c77(72:74),'(b3)') n3
|
||||
read(c77(75:77),'(b3)') i3
|
||||
if(i3.gt.5 .or. (i3.eq.0.and.n3.gt.6)) cycle
|
||||
if(i3.eq.0 .and. n3.eq.2) cycle
|
||||
|
||||
call unpack77(c77,1,msg37,unpk77_success)
|
||||
! write(77,*) 'FT8 interference: ',msg37
|
||||
if(.not.unpk77_success) cycle
|
||||
! Message structure: S7 D29 S7 D29 S7
|
||||
itone(1:7)=icos7
|
||||
itone(36+1:36+7)=icos7
|
||||
itone(NN-6:NN)=icos7
|
||||
k=7
|
||||
do j=1,ND
|
||||
i=3*j -2
|
||||
k=k+1
|
||||
if(j.eq.30) k=k+7
|
||||
indx=cw(i)*4 + cw(i+1)*2 + cw(i+2)
|
||||
itone(k)=graymap(indx)
|
||||
enddo
|
||||
call subtractft8(dd,itone,f1,xdt,.true.)
|
||||
! return
|
||||
enddo
|
||||
return
|
||||
end subroutine sfox_remove_ft8
|
||||
|
||||
|
||||
subroutine normalizebmet(bmet,n)
|
||||
real bmet(n)
|
||||
|
||||
bmetav=sum(bmet)/real(n)
|
||||
bmet2av=sum(bmet*bmet)/real(n)
|
||||
var=bmet2av-bmetav*bmetav
|
||||
if( var .gt. 0.0 ) then
|
||||
bmetsig=sqrt(var)
|
||||
else
|
||||
bmetsig=sqrt(bmet2av)
|
||||
endif
|
||||
bmet=bmet/bmetsig
|
||||
return
|
||||
end subroutine normalizebmet
|
125
lib/superfox/sfox_unpack.f90
Normal file
125
lib/superfox/sfox_unpack.f90
Normal file
@ -0,0 +1,125 @@
|
||||
subroutine sfox_unpack(nutc,x,nsnr,f0,dt0,foxcall,nsignature)
|
||||
|
||||
use packjt77
|
||||
integer*1 x(0:49)
|
||||
integer*8 n58
|
||||
logical success
|
||||
character*336 msgbits
|
||||
character*22 msg(10) !### only msg(1) is used ??? ###
|
||||
character*13 foxcall,c13
|
||||
character*10 ssignature
|
||||
character*4 crpt(5),grid4
|
||||
character*26 freeTextMsg
|
||||
character*38 c
|
||||
logical use_otp
|
||||
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
|
||||
|
||||
ncq=0
|
||||
if (nsignature.eq.0) then
|
||||
use_otp = .FALSE.
|
||||
else
|
||||
use_otp = .TRUE.
|
||||
endif
|
||||
write(msgbits,1000) x(0:46)
|
||||
1000 format(47b7.7)
|
||||
read(msgbits(327:329),'(b6)') i3 !Message type
|
||||
read(msgbits(1:28),'(b28)') n28 !Standard Fox call
|
||||
call unpack28(n28,foxcall,success)
|
||||
! print*,'aa',i3,foxcall
|
||||
|
||||
if(i3.eq.1) then !Compound Fox callsign
|
||||
! read(msgbits(87:101),'(b15)') n15
|
||||
! call unpackgrid(n15,grid4)
|
||||
! msg(1)='CQ '//trim(foxcall)//' '//grid4
|
||||
! write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
|
||||
! go to 100
|
||||
else if(i3.eq.2) then !Up to 4 Hound calls and free text
|
||||
call unpacktext77(msgbits(161:231),freeTextMsg(1:13))
|
||||
call unpacktext77(msgbits(232:302),freeTextMsg(14:26))
|
||||
do i=26,1,-1
|
||||
if(freeTextMsg(i:i).ne.'.') exit
|
||||
freeTextMsg(i:i)=' '
|
||||
enddo
|
||||
! print*,'aa1 ',freeTextMsg
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),freeTextMsg
|
||||
1100 format(i6.6,i4,f5.1,i5,1x,"~",2x,a)
|
||||
else if(i3.eq.3) then !CQ FoxCall Grid
|
||||
read(msgbits(1:58),'(b58)') n58 !FoxCall
|
||||
do i=11,1,-1
|
||||
j=mod(n58,38)+1
|
||||
foxcall(i:i)=c(j:j)
|
||||
n58=n58/38
|
||||
enddo
|
||||
foxcall(12:13)=' '
|
||||
read(msgbits(59:73),'(b15)') n15
|
||||
call unpackgrid(n15,grid4)
|
||||
msg(1)='CQ '//trim(foxcall)//' '//grid4
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
|
||||
call unpacktext77(msgbits(74:144),freeTextMsg(1:13))
|
||||
call unpacktext77(msgbits(145:215),freeTextMsg(14:26))
|
||||
do i=26,1,-1
|
||||
if(freeTextMsg(i:i).ne.'.') exit
|
||||
freeTextMsg(i:i)=' '
|
||||
enddo
|
||||
if(len(trim(freeTextMsg)).gt.0) write(*,1100) nutc,nsnr,dt0,&
|
||||
nint(f0),freeTextMsg
|
||||
go to 100
|
||||
endif
|
||||
|
||||
j=281
|
||||
iz=4 !Max number of reports
|
||||
if(i3.eq.2) j=141
|
||||
! print*,'aa2',j,iz
|
||||
do i=1,iz !Extract the reports
|
||||
read(msgbits(j:j+4),'(b5)') n
|
||||
if(n.eq.31) then
|
||||
crpt(i)='RR73'
|
||||
else
|
||||
write(crpt(i),1006) n-18
|
||||
1006 format(i3.2)
|
||||
if(crpt(i)(1:1).eq.' ') crpt(i)(1:1)='+'
|
||||
endif
|
||||
! print*,'aa3',i,n,crpt(i)
|
||||
j=j+5
|
||||
enddo
|
||||
|
||||
! Unpack Hound callsigns and format user-level messages:
|
||||
iz=9 !Max number of hound calls
|
||||
if(i3.eq.2 .or. i3.eq.3) iz=4
|
||||
! print*,'bb',i3,iz
|
||||
! print*,msgbits
|
||||
do i=1,iz
|
||||
j=28*i + 1
|
||||
read(msgbits(j:j+27),'(b28)') n28
|
||||
call unpack28(n28,c13,success)
|
||||
! print*,'cc',i,j,n28
|
||||
if(n28.eq.0) cycle
|
||||
msg(i)=trim(c13)//' '//trim(foxcall)
|
||||
if(msg(i)(1:3).eq.'CQ ') then
|
||||
ncq=ncq+1
|
||||
else
|
||||
if(i3.eq.2) then
|
||||
! print*,'dd',i,crpt(i)
|
||||
msg(i)=trim(msg(i))//' '//crpt(i)
|
||||
else
|
||||
if(i.le.5) msg(i)=trim(msg(i))//' RR73'
|
||||
if(i.gt.5) msg(i)=trim(msg(i))//' '//crpt(i-5)
|
||||
endif
|
||||
endif
|
||||
if(ncq.le.1 .or. msg(i)(1:3).ne.'CQ ') then
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(i))
|
||||
endif
|
||||
enddo
|
||||
|
||||
if(msgbits(306:306).eq.'1' .and. ncq.lt.1) then
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),'CQ '//foxcall
|
||||
endif
|
||||
|
||||
100 read(msgbits(307:326),'(b20)') nsignature
|
||||
! print*,'i3:',i3
|
||||
if (use_otp) then
|
||||
write(ssignature,'(I0)') nsignature
|
||||
write(*,1100) nutc,nsnr,dt0,nint(f0),'$VERIFY$ '//trim(foxcall)//' '//trim(ssignature)
|
||||
endif
|
||||
return
|
||||
end subroutine sfox_unpack
|
137
lib/superfox/sfrx.f90
Normal file
137
lib/superfox/sfrx.f90
Normal file
@ -0,0 +1,137 @@
|
||||
program sfrx
|
||||
|
||||
use sfox_mod
|
||||
use julian
|
||||
use popen_module, only: get_command_as_string
|
||||
|
||||
integer*2 iwave(NMAX)
|
||||
integer ihdr(11)
|
||||
integer*8 secday,ntime8,ntime8_chk
|
||||
integer*1 xdec(0:49)
|
||||
character*120 fname,cmnd,cresult
|
||||
character*13 foxcall,foxcall_chk
|
||||
character*256 ppath
|
||||
complex c0(NMAX) !Complex form of signal as received
|
||||
real dd(NMAX)
|
||||
logical crc_ok
|
||||
logical use_otp
|
||||
data secday/86400/
|
||||
include 'gtag.f90'
|
||||
|
||||
use_otp = .FALSE.
|
||||
fsync=750.0
|
||||
ftol=100.0
|
||||
narg=iargc()
|
||||
|
||||
if(narg.lt.1) then
|
||||
! print*,'Usage: sfrx [fsync [ftol]] infile [...]'
|
||||
! print*,'Examples: sfrx 230305_011230.wav'
|
||||
! print*,' sfrx 775 10 240811_102400.wav'
|
||||
! print*,'Reads one or more .wav files and calls SuperFox decoder on each.'
|
||||
! print*,'Defaults: fsync=750, ftol=100'
|
||||
print '(" Git tag: ",z9)',ntag
|
||||
go to 999
|
||||
endif
|
||||
|
||||
ifile1=1
|
||||
call getarg(1,fname)
|
||||
read(fname,*,err=1) fsync
|
||||
ifile1=2
|
||||
call getarg(2,fname)
|
||||
read(fname,*,err=1) ftol
|
||||
ifile1=3
|
||||
|
||||
1 nf=0
|
||||
nd=0
|
||||
nv=0
|
||||
|
||||
fsample=12000.0
|
||||
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
|
||||
|
||||
npts=15*12000
|
||||
|
||||
do ifile=ifile1,narg
|
||||
call getarg(ifile,fname)
|
||||
if(fname.eq.'OTP') then
|
||||
use_otp = .TRUE.
|
||||
cycle
|
||||
endif
|
||||
open(10,file=trim(fname),status='old',access='stream',err=4)
|
||||
|
||||
go to 5
|
||||
4 print*,'Cannot open file ',trim(fname)
|
||||
go to 999
|
||||
5 read(10) ihdr,iwave
|
||||
close(10)
|
||||
|
||||
nz=len(trim(fname))
|
||||
nyymmdd=ihdr(1)
|
||||
nutc=ihdr(2)
|
||||
if(fname(nz-3:nz).eq.'.wav') then
|
||||
read(fname(nz-16:nz-11),*) nyymmdd
|
||||
read(fname(nz-9:nz-4),*) nutc
|
||||
endif
|
||||
if(nyymmdd.eq.-1) then
|
||||
ntime8=itime8()/30
|
||||
ntime8=30*ntime8
|
||||
else
|
||||
iyr=2000+nyymmdd/10000
|
||||
imo=mod(nyymmdd/100,100)
|
||||
iday=mod(nyymmdd,100)
|
||||
ih=nutc/10000
|
||||
im=mod(nutc/100,100)
|
||||
is=mod(nutc,100)
|
||||
ntime8=secday*(JD(iyr,imo,iday)-2440588) + 3600*ih + 60*im + is
|
||||
endif
|
||||
|
||||
dd=iwave
|
||||
call sfox_remove_ft8(dd,npts)
|
||||
|
||||
call sfox_ana(dd,npts,c0,npts)
|
||||
|
||||
ndepth=3
|
||||
dth=0.5
|
||||
damp=1.0
|
||||
|
||||
call qpc_decode2(c0,fsync,ftol, xdec,ndepth,dth,damp,crc_ok, &
|
||||
snrsync,fbest,tbest,snr)
|
||||
if(crc_ok) then
|
||||
nsnr=nint(snr)
|
||||
if (use_otp) then
|
||||
nsignature = 1
|
||||
else
|
||||
nsignature = 0
|
||||
endif
|
||||
|
||||
call sfox_unpack(nutc,xdec,nsnr,fbest-750.0,tbest,foxcall,nsignature)
|
||||
! Execute 'foxchk <foxcall> <ntime8>' to get the correct signature value.
|
||||
write(cmnd,1102) trim(foxcall),ntime8
|
||||
1102 format('foxchk ',a,i12)
|
||||
call getarg(0,ppath)
|
||||
lindex=index(ppath,'sfrx')-1
|
||||
if (.not.use_otp) then
|
||||
cmnd=ppath(1:lindex)//cmnd
|
||||
cresult=get_command_as_string(trim(cmnd))
|
||||
read(cresult,1104) foxcall_chk,ntime8_chk,nsignature_chk
|
||||
1104 format(a11,i13,i10.7)
|
||||
if(nsignature.eq.nsignature_chk) write(*,1110) trim(foxcall)
|
||||
1110 format(a,' verified')
|
||||
if(nsignature.eq.nsignature_chk) nv=nv+1
|
||||
endif
|
||||
nd=nd+1
|
||||
! else
|
||||
! i0=index(fname,'.wav')
|
||||
! write(60,3060) trim(fname)
|
||||
!3060 format('cp ',a,' nodecode')
|
||||
endif
|
||||
nf=nf+1
|
||||
enddo
|
||||
ncarg=narg
|
||||
if (use_otp) then
|
||||
ncarg=ncarg-1
|
||||
endif
|
||||
|
||||
if(ncarg.gt.ifile1) write(*,1999) nf,nd,nv
|
||||
1999 format('nfiles:',i5,' ndecodes:',i5,' nverified:',i5)
|
||||
|
||||
999 end program sfrx
|
19
lib/superfox/twkfreq2.f90
Normal file
19
lib/superfox/twkfreq2.f90
Normal file
@ -0,0 +1,19 @@
|
||||
subroutine twkfreq2(c3,c4,npts,fsample,fshift)
|
||||
|
||||
! Adjust frequency of complex waveform
|
||||
|
||||
complex c3(npts)
|
||||
complex c4(npts)
|
||||
complex w,wstep
|
||||
data twopi/6.283185307/
|
||||
|
||||
w=1.0
|
||||
dphi=fshift*twopi/fsample
|
||||
wstep=cmplx(cos(dphi),sin(dphi))
|
||||
do i=1,npts
|
||||
w=w*wstep
|
||||
c4(i)=w*c3(i)
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine twkfreq2
|
Loading…
Reference in New Issue
Block a user