more info here (login account required): http://wsprnet.org/drupal/node/2043
Thursday, March 12, 2009
Wednesday, March 11, 2009
Saturday, February 14, 2009
1st WSPR spot @18MHz
The Si570 10mW WSPR beacon has reached now OH3QN, 1634km away at 17m band. Interesting to see that it received at -7dB below noise in 2.4kHz SSB bandwidth. As the WSPR threshold is -27dB below noise, this means in theory the beacon could still be seen with a power below 100µW, wow!
Also DL2NQ did receive the beacon at 80m. It is special as the antenna is just an inerted V for 40m.
Wednesday, February 11, 2009
10mW WSPR beacon at 40m is born and alive
Just to inform you about the results of the beacon experiments. After some hacking the ATTINY45 firmware of my SoftrockV9 / USB Synthesizer board, I finally succeeded to integrate the WSPR generation code. As an experiment it broadcasts on three different frequencies in the 40m band my call, grid location and TX power.
This morning, just for fun and as a joke I connected my dipole directly to the output of the si570. A small 3 pole lowpass filter was placed in between to attenuate harmonics, the output must be about 10mW.
In the picture you see the reception reports. Amazing that this is working. The first three lines below were reception reports by using the Softrock RXTX (1 Watt); the upper lines where the SI570 transmissions; interesting to see that HB9OAB sees a signal strength difference of 20dB.
Friday, January 30, 2009
Simplified WSPR code
Simplified C snippet for generating WSPR sequences:
#include <stdio.h>
void main(){
#ifndef TEXTMSG
// pack call in n1
static char c[6]=" K1JT "; //call
// all must be in uppercase
// char at position 3 must be last digit of call prefix
// left and right idented with space characters
unsigned long n1;
n1=(c[0]>='0'&&c[0]<='9'?c[0]-'0':c[0]==' '?36:c[0]-'A'+10);
n1=36*n1+(c[1]>='0'&&c[1]<='9'?c[1]-'0':c[1]==' '?36:c[1]-'A'+10);
n1=10*n1+c[2]-'0';
n1=27*n1+(c[3]==' '?26:c[3]-'A');
n1=27*n1+(c[4]==' '?26:c[4]-'A');
n1=27*n1+(c[5]==' '?26:c[5]-'A');
// pack grid, dbm in n2
static int lon = 5; //degrees longitude east -74 5
static int lat = 51; //degrees latitude north 40 51
int ng = 90*(180-lon+(lon<0?1:0) ) + lat;
static int dbm = 33; //EIRP dBm (0<=dbm<=60)
// must be in set {0,3,7,10,13,17,20,23,27,30,33,37,40,43,47,50,53,57,60}
unsigned long n2=(ng<<7)|(dbm+64);
#else
unsigned char msg[8] = "HI W0RLD";
// pack text
unsigned long long dn=0;
int y;
for(y=0;y!=8;y++){
unsigned char c = msg[y];
dn = 41*dn + (c>='0'&&c<='9'?c-'0': c>='A'&&c<='Z'?c-'A'+10:
c=='+'?37: c=='.'?38: c=='/'?39: c=='?'?40: 36);
}
unsigned int ng=dn&0x7fff;
unsigned long n1=dn>>15;
int ntype=-57; //plain text
unsigned long n2=ng<<7|(ntype+64);
#endif
// pack n1,n2 into 50 bits
char packed[11] = {n1>>20, n1>>12, n1>>4, (n1&0x0f)<<4|(n2>>18)&0x0f,
n2>>10, n2>>2, (n2&0x03)<<6, 0, 0, 0, 0};
// Convolutional encoder for a K=32, r=1/2 code.
// Layland-Lushbaugh polynomials for a K=32, r=1/2 convolutional code
int k = 0;
int i,j,p;
int nstate = 0;
unsigned char symbol[176];
for(j=0;j!=sizeof(packed);j++){
for(i=7;i>=0;i--){
unsigned long poly[2] = { 0xf2d05351L, 0xe4613c47L };
nstate = (nstate<<1) | ((packed[j]>>i)&1);
for(p=0;p!=2;p++){ //convolve
unsigned long n = nstate & poly[p];
// even := parity(n)
int even = 0;
while(n){
even = 1 - even;
n = n & (n - 1);
}
symbol[k] = even;
k++;
}
}
}
// Interleave symbols
unsigned char symbol2[162];
for(i=0;i!=162;i++){
// j0 := bit reversed_values_smaller_than_161[i]
unsigned char j0;
p=-1;
for(k=0;p!=i;k++){
for(j=0;j!=8;j++) // j0:=bit_reverse(k)
j0 = ((k>>j)&1) | (j0<<1);
if(j0<162)
p++;
}
symbol2[j0]=symbol[i]; //interleave
}
// Sync vector 162 bits
const unsigned char npr3[162] = {
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,
0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,
0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,
0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1,
0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,
0,0 };
for(i=0;i!=162;i++){
printf("symbol[%u]=%u\n", i, symbol2[i]);
symbol2[i] = npr3[i] | symbol2[i]<<1;
}
// Modulate
FILE* pf = fopen("a.au", "wb");
fputc(0x2e,pf); //.au magic number
fputc(0x73,pf);
fputc(0x6e,pf);
fputc(0x64,pf);
fputc(0x00,pf); //offset
fputc(0x00,pf);
fputc(0x00,pf);
fputc(24,pf);
fputc(0xff,pf); //size
fputc(0xff,pf);
fputc(0xff,pf);
fputc(0xff,pf);
fputc(0x00,pf); //encoding
fputc(0x00,pf);
fputc(0x00,pf);
fputc(0x03,pf);
fputc(0x00,pf); //samplerate
fputc(0x00,pf);
fputc(0x2e,pf);
fputc(0xe0,pf);
fputc(0x00,pf); //channels
fputc(0x00,pf);
fputc(0x00,pf);
fputc(0x01,pf);
const int nmax=120*12000;
double tsymbol=8192.0/12000.0;
double dt=1.0/12000.0;
double f0=1500;
double dfgen=12000.0/8192.0;
double t=0;
double dphi;
double phi=0;
double dj0=0;
for(i=0; i!=nmax; i++){
t=t+dt;
j=(int)(t/tsymbol)+1;
if(j!=dj0){
double f=f0+dfgen*(symbol2[j]-1.5);
dj0=j;
dphi=2*3.14*dt*f;
}
phi=phi+dphi;
int wave=32767.0*sin(phi);
fputc((wave>>8)&0xff,pf);
fputc(wave&0xff,pf);
}
fclose(pf);
}
Monday, January 19, 2009
C snippet for WSPR broadcasts
This is a short update about my WSPR beacon experiments. I am trying to set up a small standalone micro controller based WSPR beacon. As there are no details available about the WSPR protocol, I have analysed the original Fortran code of the original WSPR application written by K1JT.
#include <stdio.h>
void main(){
// pack call in n1
static char c[6]=" K1JT "; //call
// all must be in uppercase
// char at position 3 must be last digit of call prefix
// left and right idented with space characters
unsigned int n1;
n1=(c[0]>='0'&&c[0]<='9'?c[0]-'0':c[0]==' '?36:c[0]-'A'+10);
n1=36*n1+(c[1]>='0'&&c[1]<='9'?c[1]-'0':c[1]==' '?36:c[1]-'A'+10);
n1=10*n1+c[2]-'0';
n1=27*n1+(c[3]==' '?26:c[3]-'A');
n1=27*n1+(c[4]==' '?26:c[4]-'A');
n1=27*n1+(c[5]==' '?26:c[5]-'A');
// pack grid, dbm in n2
static int lat = 40; //degrees latitude north
static int lon = -74; //degrees longitude east
int ng =(-lon+180+1)*90 + lat;
static int dbm = 33; //EIRP dBm
// must be in set {0,3,7,10,13,17,20,23,27,30,33,37,40,43,47,50,53,57,60}
int n2=ng<<7|0x40|dbm;
// pack n1,n2 into 50 bits
char packed[11] = {n1>>20, n1>>12, n1>>4, (n1&0x0f)<<4|(n2>>18)&0x0f, n2>>10, n2>>2, (n2&0x03)<<6, 0, 0, 0, 0};
// printf("packed=%d %d %d %d %d %d %d %d %d %d %d\n",packed[0],packed[1],packed[2],packed[3],packed[4],packed[5],packed[6],packed[7],packed[8],packed[9],packed[10]);
// Convolutional encoder for a K=32, r=1/2 code.
// Layland-Lushbaugh polynomials for a K=32, r=1/2 convolutional code,
// and 8-bit parity lookup table.
const unsigned char partab[256] = {
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 };
unsigned char symbol[176];
int nstate = 0;
int k = 0;
int i,j;
for(j=0;j!=sizeof(packed);j++){
for(i=7;i>=0;i--){
int i4 = packed[j];
if(i4 < 0) i4 = i4 + 0x100;
nstate = (nstate<<1) | ((i4>>i) & 0x01);
int n = nstate & 0xf2d05351;
n=n^(n>>16);
symbol[k] = partab[(n^(n>>8)) & 0xff];
k++;
n=nstate & 0xe4613c47;
n=n^(n>>16);
symbol[k] = partab[(n^(n>>8)) & 0xff];
k++;
}
}
// Interleave symbols
// j0 is iteration of bit swapped bytes 0 to 255 with value < 162
const unsigned char j0[162] = {
0x00,0x80,0x40,0x20,0xa0,0x60,0x10,0x90,
0x50,0x30,0x70,0x08,0x88,0x48,0x28,0x68,
0x18,0x98,0x58,0x38,0x78,0x04,0x84,0x44,
0x24,0x64,0x14,0x94,0x54,0x34,0x74,0x0c,
0x8c,0x4c,0x2c,0x6c,0x1c,0x9c,0x5c,0x3c,
0x7c,0x02,0x82,0x42,0x22,0x62,0x12,0x92,
0x52,0x32,0x72,0x0a,0x8a,0x4a,0x2a,0x6a,
0x1a,0x9a,0x5a,0x3a,0x7a,0x06,0x86,0x46,
0x26,0x66,0x16,0x96,0x56,0x36,0x76,0x0e,
0x8e,0x4e,0x2e,0x6e,0x1e,0x9e,0x5e,0x3e,
0x7e,0x01,0x81,0x41,0x21,0xa1,0x61,0x11,
0x91,0x51,0x31,0x71,0x09,0x89,0x49,0x29,
0x69,0x19,0x99,0x59,0x39,0x79,0x05,0x85,
0x45,0x25,0x65,0x15,0x95,0x55,0x35,0x75,
0x0d,0x8d,0x4d,0x2d,0x6d,0x1d,0x9d,0x5d,
0x3d,0x7d,0x03,0x83,0x43,0x23,0x63,0x13,
0x93,0x53,0x33,0x73,0x0b,0x8b,0x4b,0x2b,
0x6b,0x1b,0x9b,0x5b,0x3b,0x7b,0x07,0x87,
0x47,0x27,0x67,0x17,0x97,0x57,0x37,0x77,
0x0f,0x8f,0x4f,0x2f,0x6f,0x1f,0x9f,0x5f,
0x3f,0x7f };
unsigned char symbol2[162];
for(i=0;i!=162;i++)
symbol2[j0[i]]=symbol[i]; //interleave
// Sync vector 162 bits
const unsigned char npr3[162] = {
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,
0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,
0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,
1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,
0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,
0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,
0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,
1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1,
0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,
0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,
0,0 };
for(i=0;i!=162;i++){
symbol2[i] = npr3[i] | symbol2[i]<<1;
}
for(i=0;i!=162;i++){
// printf("%u", symbol2[i]&0x02);
// printf("symbol[%u]=%u\n", i, symbol[i]);
}
// Modulate
FILE* pf = fopen("a.au", "wb");
fputc(0x2e,pf); //.au magic number
fputc(0x73,pf);
fputc(0x6e,pf);
fputc(0x64,pf);
fputc(0x00,pf); //offset
fputc(0x00,pf);
fputc(0x00,pf);
fputc(24,pf);
fputc(0xff,pf); //size
fputc(0xff,pf);
fputc(0xff,pf);
fputc(0xff,pf);
fputc(0x00,pf); //encoding
fputc(0x00,pf);
fputc(0x00,pf);
fputc(0x03,pf);
fputc(0x00,pf); //samplerate
fputc(0x00,pf);
fputc(0x2e,pf);
fputc(0xe0,pf);
fputc(0x00,pf); //channels
fputc(0x00,pf);
fputc(0x00,pf);
fputc(0x01,pf);
const int nmax=120*12000;
double tsymbol=8192.0/12000.0;
double dt=1.0/12000.0;
double f0=1500;
double dfgen=12000.0/8192.0;
double t=0;
double dphi;
double phi=0;
double dj0=0;
for(i=0; i!=nmax; i++){
t=t+dt;
j=(int)(t/tsymbol)+1;
if(j!=dj0){
double f=f0+dfgen*(symbol2[j]-1.5);
dj0=j;
dphi=2*3.14*dt*f;
}
phi=phi+dphi;
int wave=32767.0*sin(phi);
fputc((wave>>8)&0xff,pf);
fputc(wave&0xff,pf);
}
fclose(pf);
}
Subscribe to:
Posts (Atom)