[linrad] Re: Network standards for SDR

2007-01-06 Thread Leif Asbrink
On Sat, 6 Jan 2007 05:59:55 +0100
"J.D. Bakker" <[EMAIL PROTECTED]> wrote:

> typedef struct {
>short header_len;  // This field is always present, and always first
>short data_len;// This field is always present, and always second
>[ header contents, including header version, type, etc. goes here ]
>char data[NET_MULTICAST_PAYLOAD];
> } NET_RX_STRUCT;
> 
> NET_RX_STRUCT msg;
> rxin_char=(void*)(&timf1_char[timf1p_pa]);
> timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;
> for(j=0; j{
>recvfrom(netfd.rec_rx,&msg,sizeof(NET_RX_STRUCT),0,
>   (struct sockaddr *) &rx_addr,&addrlen);
>memcpy(&rxin_char[j], ((void *)&msg) + msg.header_len, 
> NET_MULTICAST_PAYLOAD);
>}
OK, now you just added an extra copy operation and the ReadData
does not return a pointer. This was exactly what I referred to
from the start.

> For the time being I kept the data size constant, to not mix the 
> issues (variable data size adds 5-6 lines). And yes, there is a 
> memcpy. But read below...
> 
> By the way, there appears to be an inconsistency in your program. Here:
> 
>timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;
> 
> you make sure that the address pointer for the circular buffer wraps 
> around, but I see no such protection in the for() loop. Or am I 
> missing something ?
Yes. ad_read_bytes is a power of two so it always goes even in the buffer.

> An extra memcpy makes little difference in this loop. Note that the 
> recvfrom() needs to do the equivalent of a memcpy() anyway. I wrote a 
> little test program (see the bottom of this mail) to test the speed 
> difference between 1 and 2 copy instructions if the destination 
> buffer is larger than the cache.
> 
> On a Pentium MMX 166MHz, a Thinkpad laptop with X running, I get:
> 
> Single copy: 1000 loops in 129.44 seconds, or 79.11 MiBps.
> Double copy: 1000 loops in 147.21 seconds, or 69.56 MiBps.
Hmmm, actually changing the Linrad code to do the double copy as
you suggest increases the CPU load from 47.5% to 48.5% when
16 bit raw data is received on a 200 MHz Pentium MMX. This makes
me believe that receiving fft1 transforms which will be necessary
for this computer to do meaningful work will lead to an extra
load of 4 percent units and that is not insignificant at all.
(32 bit floats, interleaved transforms)

The fft1 mode does not yet work so I can not test right now, but
I hav reasons to believe that the MMX routines will allow this
computer to work well as a slave with two channels at 96 kHz
bandwidth.

> Is there any way at all that you can avoid that, and process the data 
> as it comes in ? My first big multi-threaded program was a real-time 
> streaming video encoder for a quad Pentium Pro machine, and switching 
> processing from a frame at a time to a macroblock (16x16pixels) at a 
> time sped the encoder up tremendously, even though the required 
> number of operations almost doubled.
I do not know, but it is going to be difficult if possible at all.

> >The most demanding task is the full bandwidth, full dynamic
> >range FFT. It would be identical in all computers and it does
> >not make any sense to do it in more than one computer.
> 
> Why ? Because this one computer would be much faster than the others ?
Yes. Amateurs typically have one modern computer
(running Windows) plus a couple of scrap computers that 
would be perfectly adequate as slaves.

> So would it be correct to say that:
> 
> (a) if all computers were equally fast, there is little advantage in 
> cooked mode over raw mode (other than energy conservation), and
Right now yes, but with future add-ons this might change because
the master might do only front-end processing because it is not
fast enough to do everything. Actually I think it will be possible
to use two Pentium MMX with one doing fft1 and nothing more
while the other is doing fft2 and down conversion. It will be
near the limits for what these computers can do - one of them
is just a little to slow.

At the moment CPU time is no problem at all because we do not
yet have the wideband hardware that modern computers could
serve.
 
> (b) cooked mode allows slow slaves that would normally not be able to 
> keep up with the FFTs to still display the data.
There are many FFTs in Linrad. fft1(forward full bw) -> fft1(backward 2 * full 
bw) ->
fft2(forward full bw) -> fft2(backward narrow bw) -> fft3(forward narrow bw) ->
fft3(backward narrow bw)

There is dsp processing alternating between the frequency domain and the
time domain. Only the very first fft needs full dynamic range and uses
float. The remaining wideband processing uses MMX. This was necessary
when a modern computer was Pentium 3. Today floats can be used, but
not if one wants to monitor several microwave bands on the same computer.

Because of the much higher speed of 16 bit MMX routines the first
fft takes as much time as all the other tasks together. Since the
processing of all the other transfo

[linrad] Re: Network standards for SDR

2007-01-05 Thread J.D. Bakker

 >As for the
 > ReceiveData() function, that line can be directly replaced with your

 recvfrom() call (I just was too lazy too look up recvfrom() when I
 wrote that example).

Well, if you care to write the full code you will find that
this statement is not quite what it looks like.


It's not much different. This is what a modified version of your 
program looks like:


typedef struct {
  short header_len;  // This field is always present, and always first
  short data_len;// This field is always present, and always second
  [ header contents, including header version, type, etc. goes here ]
  char data[NET_MULTICAST_PAYLOAD];
} NET_RX_STRUCT;

NET_RX_STRUCT msg;
rxin_char=(void*)(&timf1_char[timf1p_pa]);
timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;
for(j=0; j  memcpy(&rxin_char[j], ((void *)&msg) + msg.header_len, 
NET_MULTICAST_PAYLOAD);

  }


For the time being I kept the data size constant, to not mix the 
issues (variable data size adds 5-6 lines). And yes, there is a 
memcpy. But read below...


By the way, there appears to be an inconsistency in your program. Here:

  timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;

you make sure that the address pointer for the circular buffer wraps 
around, but I see no such protection in the for() loop. Or am I 
missing something ?



 > even if it

 did, it matters very little on modern CPUs (packets this size will
 remain entirely within the CPU cache).

Linrad is intended to run on elderly computers and it is also
intended to run at much higher bandwidths on modern ones.
You suggest that the data is put into a buffer to which a
pointer is returned by ReceiveData. The next step would be to
store the payload into a circular buffer. This will cause the data
to become written into memory twice.


An extra memcpy makes little difference in this loop. Note that the 
recvfrom() needs to do the equivalent of a memcpy() anyway. I wrote a 
little test program (see the bottom of this mail) to test the speed 
difference between 1 and 2 copy instructions if the destination 
buffer is larger than the cache.


On a Pentium MMX 166MHz, a Thinkpad laptop with X running, I get:

Single copy: 1000 loops in 129.44 seconds, or 79.11 MiBps.
Double copy: 1000 loops in 147.21 seconds, or 69.56 MiBps.

The first copy takes about two cycles per byte, adding a second copy 
adds less than 0.3 cycles per byte.


On a Pentium II 350MHz (rescued from the garbage a month ago):

Single copy: 1000 loops in 55.76 seconds, or 183.64 MiBps.
Double copy: 1000 loops in 66.36 seconds, or 154.30 MiBps.

The ratio is similar: first copy just under 2 cycles/byte, second 
copy adds 0.36 cycles/byte.


Your scenario will likely be even closer, since the kernel will need 
to read the UDP datagrams from main memory, too.



 Processing of the data is
in another thread that require hundreds of packages in the circular
buffer. It will fetch its input from memory because other
threads have been using the cash in the meantime.


Is there any way at all that you can avoid that, and process the data 
as it comes in ? My first big multi-threaded program was a real-time 
streaming video encoder for a quad Pentium Pro machine, and switching 
processing from a frame at a time to a macroblock (16x16pixels) at a 
time sped the encoder up tremendously, even though the required 
number of operations almost doubled.



 > Zero-copy architectures make

 sense for hi-speed packet switching on slow computers; as soon as you
 add any processing on the data, that single extra copy gets lost in
 the noise. Cache line/block alignment is much more important for
 performance.

Actually this is not in agreement with my observations. It does depend
on how efficcien "processing" is done.


In some cases, yes. I've re-written a fixed-point FFT for ARM so that 
reading the first word would trigger the loading of a full cache 
line, so that the FFT would never have to wait for its data. But even 
that would get lost in the noise once you actually started processing 
the data.



The most demanding task is the full bandwidth, full dynamic
range FFT. It would be identical in all computers and it does
not make any sense to do it in more than one computer.


Why ? Because this one computer would be much faster than the others ?


 > Do you want to have an exact, synchronized display on

 multiple machines ?

This would be the case also if raw data were used.


[snip]


The "innocent" slave does not have to know that a data stream is
"cooked". It can be processed as if it were raw data, but a clever
slave can make use of complex information that it might want to
as for. If you want to compute the noise floor power density
you want to know what percentage of samples that were blanked
out because of noise pulses for example. Normally one would not care
at all.


So would it be correct to say that:

(a) if all comp

[linrad] Re: Network standards for SDR

2007-01-05 Thread Leif Asbrink
Hi JDB and all,

> I've never written a single line of C++ in my life. As for the 
> ReceiveData() function, that line can be directly replaced with your 
> recvfrom() call (I just was too lazy too look up recvfrom() when I 
> wrote that example).
Well, if you care to write the full code you will find that 
this statement is not quite what it looks like.
ReceiveData returns a pointer. recvfrom fills data into a buffer that
the user passes to the function. It does make a difference.

> I don't see that having a header in front of the 
> package needs more copy calls than one after the package;
Just compare the code I supplied with the code you will have to write 
to make ReceiveData operational.

> even if it 
> did, it matters very little on modern CPUs (packets this size will 
> remain entirely within the CPU cache). 
Linrad is intended to run on elderly computers and it is also
intended to run at much higher bandwidths on modern ones.
You suggest that the data is put into a buffer to which a
pointer is returned by ReceiveData. The next step would be to 
store the payload into a circular buffer. This will cause the data
to become written into memory twice. Processing of the data is
in another thread that require hundreds of packages in the circular
buffer. It will fetch its input from memory because other
threads have been using the cash in the meantime.

> Zero-copy architectures make 
> sense for hi-speed packet switching on slow computers; as soon as you 
> add any processing on the data, that single extra copy gets lost in 
> the noise. Cache line/block alignment is much more important for 
> performance.
Actually this is not in agreement with my observations. It does depend
on how efficcien "processing" is done.

> I was assuming that the multicast connection would be used for 
> distributing raw data only. Re-reading your earlier posts it looks 
> like you want to be able to send both raw *and* cooked (processed) 
> data. Why ? Do you expect the slaves to be much slower than the 
> master ? 
Yes.

The most demanding task is the full bandwidth, full dynamic 
range FFT. It would be identical in all computers and it does
not make any sense to do it in more than one computer.

> Do you want to have an exact, synchronized display on 
> multiple machines ?
This would be the case also if raw data were used.

> Looking at other network protocols (especially streaming), it has 
> historically been a bad idea to combine multiple modes into one 
> protocol, for reasons of maintainability, performance and clarity. 
> Linrad is your code, and it's completely up to you, but might I 
> suggest you consider either splitting the transmission modes in raw 
> and cooked, or (better) multicasting only raw, unprocessed data and 
> sending all filter parameters over a separate channel ?
???

There are two classes of multicasted data that Linrad will send.
1) Time domain data.
2) Frequency domain data.

Raw data is a special and pretty un-interesting case. I am providing
it because it might be useful for experimentation that others may
want to do. The normal operating mode will be "cooked data". It might
be in the time domain or it might be in the frequency domain.

The "innocent" slave does not have to know that a data stream is
"cooked". It can be processed as if it were raw data, but a clever
slave can make use of complex information that it might want to 
as for. If you want to compute the noise floor power density
you want to know what percentage of samples that were blanked
out because of noise pulses for example. Normally one would not care
at all.

> >  > [about an ADC-to-Ethernet]
> >Probably it would be better to connect it to a socket on a
> >dedicated ethernet port on one computer, the one which has
> >the controls for the radio hardware connected to this soundcard.
> >The master wants 100% reliable data because I assume you do not
> >want to put the master system clock on the audio-to-Ethernet
> >converter.
> 
> Why not ? It has a GPS-controlled OCXO to synchronize all sampling 
> clocks and to keep time, isn't that sufficient ?
Oooh! Then it would be a suitable master clock - you would just
have to make it count 24 hours and provide a way to set it correctly.


> Pretty much what I described above: header with header length, data 
> length, number of channels, sample size, sample rate, timestamp and a 
> few descriptive fields (with a version field, so that -- if truly 
> necessary -- upgrades are possible). Nothing that isn't strictly 
> required: less is more.
> 
> It's what everybody else does. I know that that's not much of an 
> argument ('50 million Elvis fans can't be wrong'), but in 15 years of 
> working on network protocols, this is pretty much the only way that 
> I've seen working reliably for successful sampled AV or radio 
> projects (I've seen a similar system used on an antenna array for 
> MIMO trials). Conversely, I have never ever seen a combined 
> raw/cooked protocol that worked,

[linrad] Re: Network standards for SDR

2007-01-05 Thread J.D. Bakker

 > This is still easy to parse, since all a user needs to do is something like


struct NET_RX_STRUCT *rx_packet;
char *my_data;
short i, my_data_len;

rx_packet = ReceiveData();
my_data = ((char *) rx_packet) + rx_packet->header_len;
for(i = 0; i < rx_packet->data_len; i++)
  DoSomethingWithMyData(my_data[i]);

Yes, but but these modern ways of writing scares off all my
friends who can use old-fashioned C but not C++.

First of all ReceiveData() has to be written, separate
buffers of size NET_RX_STRUCT have to be allocated and
managed etc. I do not currently have such code and I suspect
it involves needless copy operations. I am looking
for bandwidths of 2 MHz and above (for VHF noise blanking
to remove static rain) so needless copy - probably
up and down to main memory is something I want to avoid.


I've never written a single line of C++ in my life. As for the 
ReceiveData() function, that line can be directly replaced with your 
recvfrom() call (I just was too lazy too look up recvfrom() when I 
wrote that example). I don't see that having a header in front of the 
package needs more copy calls than one after the package; even if it 
did, it matters very little on modern CPUs (packets this size will 
remain entirely within the CPU cache). Zero-copy architectures make 
sense for hi-speed packet switching on slow computers; as soon as you 
add any processing on the data, that single extra copy gets lost in 
the noise. Cache line/block alignment is much more important for 
performance.



 > This is enough for basic decoding of any stream, no ? Even the center

 frequency can be seen as superfluous (since it's only for display and
 not strictly needed for decoding).

The primary usage of the Linrad network was for the second operator
in a contest station. It is an obvious advantage that the display
is always correct - particularly if several bands are monitored
simultaneously.


 I cannot imagine what systems would evolve over the coming five years
 that couldn't fit in this framework.

Linrad can also send data in the frequency domain and there is
quite a lot of info that a slave will need. Admittedly those
formats are likely to be used by Linrad only but they carry
many more complications.


OK, I see.

I was assuming that the multicast connection would be used for 
distributing raw data only. Re-reading your earlier posts it looks 
like you want to be able to send both raw *and* cooked (processed) 
data. Why ? Do you expect the slaves to be much slower than the 
master ? Do you want to have an exact, synchronized display on 
multiple machines ?


Looking at other network protocols (especially streaming), it has 
historically been a bad idea to combine multiple modes into one 
protocol, for reasons of maintainability, performance and clarity. 
Linrad is your code, and it's completely up to you, but might I 
suggest you consider either splitting the transmission modes in raw 
and cooked, or (better) multicasting only raw, unprocessed data and 
sending all filter parameters over a separate channel ?



 > [about an ADC-to-Ethernet]
Probably it would be better to connect it to a socket on a
dedicated ethernet port on one computer, the one which has
the controls for the radio hardware connected to this soundcard.
The master wants 100% reliable data because I assume you do not
want to put the master system clock on the audio-to-Ethernet
converter.


Why not ? It has a GPS-controlled OCXO to synchronize all sampling 
clocks and to keep time, isn't that sufficient ?



Are you aware of any standard format for streaming unprocessed
audio data?


At my previous job we had a few, but they were paper-only. There is 
MADI (digital audio) and SMPTE-259M (digital video) over ATM, but 
that doesn't quite apply here. I believe the AES have some, but those 
are for-pay documents, and I'm not an AES member anymore.



What data format were you contemplating before this discussion
started?


Pretty much what I described above: header with header length, data 
length, number of channels, sample size, sample rate, timestamp and a 
few descriptive fields (with a version field, so that -- if truly 
necessary -- upgrades are possible). Nothing that isn't strictly 
required: less is more.


It's what everybody else does. I know that that's not much of an 
argument ('50 million Elvis fans can't be wrong'), but in 15 years of 
working on network protocols, this is pretty much the only way that 
I've seen working reliably for successful sampled AV or radio 
projects (I've seen a similar system used on an antenna array for 
MIMO trials). Conversely, I have never ever seen a combined 
raw/cooked protocol that worked, or better: that remained working. Or 
it evolved into something like WAV: a historical accident that 
everyone loves to hate.


JDB.
--
In protocol design, perfection has been reached not when there is 
nothing left to add, but when there is nothing left to take away.

   --

[linrad] Re: Network standards for SDR

2007-01-04 Thread Leif Asbrink
Hi again,

> WAV is an example of a file format where *everyone* added their own 
> custom headers/chunks, without any planning. As a result, no program 
> can read all existing WAV files; WAV is considered an example how 
> *not* to do a file format.
And still we have to use it.

> Would you consider a very simple, easy to parse header like this:
> 
> typedef struct {
>short header_len;  // This field is always present, and always first
>short data_len;// This field is always present, and always second
>[ header contents, including header version, type, etc. goes here ]
>char data[];
> } NET_RX_STRUCT;
Perhaps. At the moment I do not see any advantage. You want to
add the flexibility of a variable data_len. The cost is that there
are bytes ahead of the data so it is less straightforward to
read directly into the final buffer. One could copy the few bytes
back, but there is an increaced time delay of one buffer. This
is not a big deal.

> This is still easy to parse, since all a user needs to do is something like
> 
>struct NET_RX_STRUCT *rx_packet;
>char *my_data;
>short i, my_data_len;
> 
>rx_packet = ReceiveData();
>my_data = ((char *) rx_packet) + rx_packet->header_len;
>for(i = 0; i < rx_packet->data_len; i++)
>  DoSomethingWithMyData(my_data[i]);
Yes, but but these modern ways of writing scares off all my
friends who can use old-fashioned C but not C++. 

First of all ReceiveData() has to be written, separate
buffers of size NET_RX_STRUCT have to be allocated and
managed etc. I do not currently have such code and I suspect
it involves needless copy operations. I am looking
for bandwidths of 2 MHz and above (for VHF noise blanking
to remove static rain) so needless copy - probably 
up and down to main memory is something I want to avoid. 

In Linrad It is like this now:
NET_RX_STRUCT *msg;
rxin_char=(void*)(&timf1_char[timf1p_pa]);
timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;
for(j=0; j 0
{
if(FD_ISSET(netfd.rec_rx,&testfds))
  {
  recvfrom(netfd.rec_rx,msg,sizeof(NET_RX_STRUCT),0,
  (struct sockaddr *) 
&rx_addr,&addrlen);
// รถ fill zeroes and move data if block_no not correct here. 
}
  }
}
  else
{
lir_sleep(10);
goto seltest16;
} 
  }
This might look like more code, but there is nothing hidden here.
timf1_char is the circular buffer which the fft routines use as input.
Data is transferred directly into this buffer which has a size of
2 to power N. Some extra space is reserved for the header so 
writes do not become illegal when the pointer is at its last position.

If it were not for the requirement that the thread has to
exit nicely even if the network is broken the same code
would look like this:
NET_RX_STRUCT *msg;
rxin_char=(void*)(&timf1_char[timf1p_pa]);
timf1p_pa=(timf1p_pa+ad_read_bytes)&timf1_bytemask;
for(j=0; j >  > That, too, makes it harder for dedicated hardware receivers; ideally
> >>  these would not need _any_ communication from the slave to the
> >>  master. As I see it, encoding this information in the header of each
> >>  package is a low-overhead way to reduce ambiguity, too.
> >The problem is that there are so many possibillities. I do not
> >want to invent a complicated scheme for describing the myriad
> >of things I can imagine now only to discover in a few years that
> >something entirely different has evolved.
> 
> I would suggest keeping it extremely simple. There is not very much 
> information that varies between sampled systems:
> 
> - sample size
> - sample rate
> - number of channels (could even be fixed to 'always I/Q')
Ooooh! We talk about the wideband output from an SDR. It is far
more complicated. Are noise pulses subtracted? Are some points
blanked out (how many percent ?) Are some carriers (spurs) removed
Is ALC splatter from some SSB transmission processed etc. etc.

There are really many possible wideband processes that serve
the purpose of removing interference of various kinds. Removing
the second harmonic at 1836 kHz of an AM transmitter at 918 kHz
is one recent example. One would like to do it while processing
over 1 MHz bandwidth in order to have access to the fundamental
but already in 90 kHz bandwidth one should be able to do a lot
by use of the knowledge that the modulation sidebands (splatter)
belong to a second harmonic. 

> and, for radio systems,
> 
> - center frequency
AND phase. Is Q before or after I? (direction of the
frequency scale)

> This is enough for basic decoding of any stream, no ? Even the center 
> frequency can be seen as superfluous (since it's only for display and 
> not strictly needed for decoding).
The primary usage of the Linrad network was for the second operator
in a contest station. It is an obvious advantage that the display
is always correct - particularly if several bands are monitored
simultaneously.

> I cannot imagine what systems would evolve over the coming 

[linrad] Re: Network standards for SDR

2007-01-04 Thread J.D. Bakker

Leif and all,


Would you agree on milliseconds since midnight? From JDB I
learned that a double with seconds since Unix epoch would be a bad 
idea since conversion may be difficult on non-PC platforms. (It is 
the internal time format within

Linrad however)


Yes, milliseconds since  UTC would be OK.  Maybe you should send 
BOTH this quantity AND a double with seconds since Unix epoch (which 
I would actually prefer).  I don't see the conversion issue as a big 
deal; little-endian to big-endian copnversion is trivial, and 
doesn't nearly everybody use IEEE floating point these days?


Pretty hard to fit in a 256-cell CPLD.

JDB.
--
LART. 250 MIPS under one Watt. Free hardware design files.
http://www.lartmaker.nl/

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-04 Thread Joe Taylor

Leif and all,


Would you agree on milliseconds since midnight? From JDB I
learned that a double with seconds since Unix epoch 
would be a bad idea since conversion may be difficult on 
non-PC platforms. (It is the internal time format within
Linrad however) 


Yes, milliseconds since  UTC would be OK.  Maybe you 
should send BOTH this quantity AND a double with seconds 
since Unix epoch (which I would actually prefer).  I don't 
see the conversion issue as a big deal; little-endian to 
big-endian copnversion is trivial, and doesn't nearly 
everybody use IEEE floating point these days?


-- Joe

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-04 Thread J.D. Bakker

The newcomer who wants to write his own software does not have
to know anything about the header, he can just use the 1024
bytes of data and ignore whatever has been appended. Having a
header which has to be properly decoded in order to extract
the data builds a threshold that makes it more difficult to
get started. (Processing simple .wav files has a pretty high
threshold in decoding the header. Common practice between
amateurs has been to just dicard the header and read the actual
data using the information supplied with the file. Those
who worked with the UNKN422 challenge were adviced to do
so for example.)


WAV is an example of a file format where *everyone* added their own 
custom headers/chunks, without any planning. As a result, no program 
can read all existing WAV files; WAV is considered an example how 
*not* to do a file format.


Would you consider a very simple, easy to parse header like this:

typedef struct {
  short header_len;  // This field is always present, and always first
  short data_len;// This field is always present, and always second
  [ header contents, including header version, type, etc. goes here ]
  char data[];
} NET_RX_STRUCT;

This is still easy to parse, since all a user needs to do is something like

  struct NET_RX_STRUCT *rx_packet;
  char *my_data;
  short i, my_data_len;

  rx_packet = ReceiveData();
  my_data = ((char *) rx_packet) + rx_packet->header_len;
  for(i = 0; i < rx_packet->data_len; i++)
DoSomethingWithMyData(my_data[i]);



 > That, too, makes it harder for dedicated hardware receivers; ideally

 these would not need _any_ communication from the slave to the
 master. As I see it, encoding this information in the header of each
 package is a low-overhead way to reduce ambiguity, too.

The problem is that there are so many possibillities. I do not
want to invent a complicated scheme for describing the myriad
of things I can imagine now only to discover in a few years that
something entirely different has evolved.


I would suggest keeping it extremely simple. There is not very much 
information that varies between sampled systems:


- sample size
- sample rate
- number of channels (could even be fixed to 'always I/Q')

and, for radio systems,

- center frequency

This is enough for basic decoding of any stream, no ? Even the center 
frequency can be seen as superfluous (since it's only for display and 
not strictly needed for decoding).


I cannot imagine what systems would evolve over the coming five years 
that couldn't fit in this framework.


At 17:47 +0100 04-01-2007, Leif Asbrink wrote (in another mail):

Would you agree on milliseconds since midnight? From JDB I
learned that a double with seconds since Unix epoch
would be a bad idea since conversion may be difficult on
non-PC platforms. (It is the internal time format within
Linrad however)


I would use the same interface that gettimeofday() uses: a long with 
seconds since the Epoch (Jan 1 1970), and a long with microseconds.



The formats I intend to use within Linrad will use IA32 little endian
(as well as IA32 float) I have no intention to make Linrad portable
to other platforms and I am pretty sure I will not change my mind
on this point for the next 5 years or more. Probably never.


OK, that's fine, so please document this somewhere so those of us on 
non-IA32 can deal with it.


As an example: I'm currently soldering the prototype of an 
audio-to-Ethernet converter as part of a portable hard disk recorder. 
This design uses the CS5381 ADC, one of the best professional audio 
converters on the market with a dynamic range approaching 120dB. This 
is an open-hardware system[1], and with a few modifications I could 
see it being usable for Linrad. A lot of the limitations (time jitter 
on the system clock etc) that are present on a PC platform simply do 
not appear for such a dedicated device. How would you like me to 
interface such a system to Linrad ? Should it be able to act as a 
Linrad master ?


JDB
[1] Converter schematics are here:
http://www.lartmaker.nl/recbox-adc-cs5381-main.png
http://www.lartmaker.nl/recbox-adc-cs5381-power.png
http://www.lartmaker.nl/recbox-adc-cs5381.pdf
--
LART. 250 MIPS under one Watt. Free hardware design files.
http://www.lartmaker.nl/

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-04 Thread Leif Asbrink
Hi Joe and all,

> I agree that a timestamp will be useful.  For what I am 
> thinking about, very high precision and high accuracy are 
> not required.  JT65 wants to know the UTC of a data block to 
> within a second or so.  (Relative timing among successive 
> blocks is of course maintained by the fixed and nominally 
> known sample rate.)  Of course the slave computer could use 
> its own time, but that will add another level of jitter.
> 
> As a minimum, I suggest that each packet include as a 32-bit 
> integer the number of seconds since the Unix epoch, 
> according to the master computer's system clock.  So much 
> the better if you include a number of milliseconds as a 
> second number, or combine both into a double.
> 
> Never mind about jitter; the receiving program would need to 
> know that jitter in the time values will exist, and behave 
> accordingly.
> 
> Together with the block number, these approaches will 
> suffice very nicely for JT65, anyway.  They will work better 
> and more reliably than having the slave computer use its own 
> system clock.
OK. This is what it looks like under Windows:

int lir_get_epoch_seconds(void)
{
// Here we have to add a calendar to add the number
// of seconds from todays (year, month, day) to Jan 1 1970.
// The epoch time is needed for moon position computations.
SYSTEMTIME tim;
GetLocalTime(&tim);
return 3600.*tim.wHour+60.*tim.wMinute+tim.wSecond;
}

I can put the number of seconds since the Unix epoch if 
someone supplies the code needed in Windows. (It is needed 
anyway to make moon computations correct under Windows)

Would it not be more convenient to supply an integer with
the number of milliseconds since midnight? The accuracy
(jitter) might be a few ms and that should allow averaging 
to find the sync tone provided that each station has 
adequate stability and a correction for his own part of 
the doppler shift.

> Please let me know when a broadcast-enabled Linrad version 
> is available for testing with MAP65.  And if you have some 
> example code for use by the receiving program -- or, say, a 
> stand-alone "dummy" receiving program that can receive 
> broadcast packets, I would be happy to see the code!
Pretty soon, but I will await further comments on the way 
it will be implemented. You already talked me into adding
a time stamp. I can see that it should have less time jitter 
than the time stamp you can add from the system clock in 
MAP65. 

The time stamp will not necessarily be the time at which the 
samples arrive for each block however. The SDR-14 for example 
sends 8192 bytes and all 8 network packages from one read will
then have the same time stamp. (Of course this can be corrected
at a later stage.)

Would you agree on milliseconds since midnight? From JDB I
learned that a double with seconds since Unix epoch 
would be a bad idea since conversion may be difficult on 
non-PC platforms. (It is the internal time format within
Linrad however) 
 

 73

Leif

#
This message is sent to you because you are subscribed to
  the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-04 Thread Leif Asbrink
Hi JDB and all,

> A general point: in virtually all communications protocols the 
> (descriptive) header comes before the data block, since the receiver 
> usually needs to decode the header to be sure what to do with the 
> data. This also makes it possible to vary the length of the data 
> block, if desired (for instance, to tune to FFT block sizes or 
> sampling hardware word length).

My primary goal is radio and experimenting with radio receivers.
Today we can do many things inside computers and I want to
make it easy for newcomers to enter radio experimenting from 
the digital side. That is why I have placed the fixed size data 
block in front of the header. 

The newcomer who wants to write his own software does not have 
to know anything about the header, he can just use the 1024 
bytes of data and ignore whatever has been appended. Having a 
header which has to be properly decoded in order to extract
the data builds a threshold that makes it more difficult to 
get started. (Processing simple .wav files has a pretty high
threshold in decoding the header. Common practice between
amateurs has been to just dicard the header and read the actual
data using the information supplied with the file. Those 
who worked with the UNKN422 challenge were adviced to do
so for example.)  

> >  > - I would want a timestamp in there somewhere. It might be derived
> >>  from  block_no, but why not make it explicit ?
> >I do not see what it would be good for. Why do you want the clock
> >from the master while there is another one in the slave?
> 
> Array processing. It would be very useful for a situation where you 
> have multiple masters on one network (either during a contest, or -in 
> my case- with a few servers each connected to an antenna+receiver). 
> Time sync is not hard over either GPS/TAC or ntp.
Do you mean that the time stamp should be used to combine
the signals from separate hardwares so one could build
an adaptive antenna by combining them properly? That would
mean that local oscillators and sampling clocks have to
be phase locked to a common reference and that there is a way
for Linrad to find out how many samples reside in the various
buffers in the soundcard and the device drivers.
This is all impossible with todays hardware.

The solution as I see it is a box with a fast ADC and a decimation
chip. Something like the SDR14, but with provision to synchronize 
any number of boxes. It would be natural to add a network interface
into each box and make them broadcast their data and the obvious
synchronization would be the block number, a counter that is kept
synchronous exactly as the counters in the decimation chip.

> Even in one-master situations it could be useful: with timestamps, it 
> is very easy to make something similar to the Time Machine.
Please explain what you mean by this. The only Time Machine
I know of is a direct conversion receiver with analog output.

> >  > - how is the sampling rate communicated ?
> >The slave(client) asks the server for the meaning of the data.
> >Number of channels, nominal sampling rate, whether the format is
> >real or complex etc.
> 
> That, too, makes it harder for dedicated hardware receivers; ideally 
> these would not need _any_ communication from the slave to the 
> master. As I see it, encoding this information in the header of each 
> package is a low-overhead way to reduce ambiguity, too.
The problem is that there are so many possibillities. I do not
want to invent a complicated scheme for describing the myriad
of things I can imagine now only to discover in a few years that
something entirely different has evolved.
Certainly it will be possible to append a couple of bytes to the
header to allow each package to define its contents. The beauty of
the structure I have suggested is that a user (newcomer) can read 
1024 bits of data from each package without knowing the size and
meaning of whatever header that comes later in the package. As I
see it, the primary usage is just to send the time domain signal
in a known standard format just as if it were read from some
hardware on the client computer.


> >  > - if you are not doing so already, please please _please_ use the
> >>  functions htons() / ntohs() and friends to convert between host byte
> >>  order and network byte order (or forever determine that linrad
> >>  communicates with either little endian (IA32) or big endian (Alpha,
> >>  PowerPC etc) byte order. I would want to be able to use a PC as the
> >>  server and my PowerBook as the client, for instance.
> >I do not see how it matters. Linrad does not put port numbers or
> >addresses in the packages, that is done by the operating system
> >and the inner workings of Linrad is not visible from the network.
> 
> Byte ordering is not restricted to port numbers or addresses. Every 
> time you put an integer which is larger than one byte into a packet, 
> the transmitter and receiver need to agree on the byte order. See
> 
> http://en.wikipedia.org/

[linrad] Re: Network standards for SDR

2007-01-04 Thread Joe Taylor

Hi Leif and all,

- I would want a timestamp in there somewhere. It might be derived 
from  block_no, but why not make it explicit ?


I do not see what it would be good for. Why do you want the clock
from the master while there is another one in the slave? 


Surely I could add this, but there is a cost to it.
The packages are sent out at maybe 1 kHz. The corresponding
time resolution is 1 ms. There is an appreciable time jitter 
however and it is not obvious what time to put into

a specific package. Presumably it should be the time
when the first sample within the package was taken from 
the hardware. What would it be good for? It is not trivial

to evaluate.


I agree that a timestamp will be useful.  For what I am 
thinking about, very high precision and high accuracy are 
not required.  JT65 wants to know the UTC of a data block to 
within a second or so.  (Relative timing among successive 
blocks is of course maintained by the fixed and nominally 
known sample rate.)  Of course the slave computer could use 
its own time, but that will add another level of jitter.


As a minimum, I suggest that each packet include as a 32-bit 
integer the number of seconds since the Unix epoch, 
according to the master computer's system clock.  So much 
the better if you include a number of milliseconds as a 
second number, or combine both into a double.


Never mind about jitter; the receiving program would need to 
know that jitter in the time values will exist, and behave 
accordingly.


Together with the block number, these approaches will 
suffice very nicely for JT65, anyway.  They will work better 
and more reliably than having the slave computer use its own 
system clock.


Please let me know when a broadcast-enabled Linrad version 
is available for testing with MAP65.  And if you have some 
example code for use by the receiving program -- or, say, a 
stand-alone "dummy" receiving program that can receive 
broadcast packets, I would be happy to see the code!


-- Joe, K1JT

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-03 Thread J.D. Bakker
A general point: in virtually all communications protocols the 
(descriptive) header comes before the data block, since the receiver 
usually needs to decode the header to be sure what to do with the 
data. This also makes it possible to vary the length of the data 
block, if desired (for instance, to tune to FFT block sizes or 
sampling hardware word length).



 > - I would want a timestamp in there somewhere. It might be derived

 from  block_no, but why not make it explicit ?

I do not see what it would be good for. Why do you want the clock
from the master while there is another one in the slave?


Array processing. It would be very useful for a situation where you 
have multiple masters on one network (either during a contest, or -in 
my case- with a few servers each connected to an antenna+receiver). 
Time sync is not hard over either GPS/TAC or ntp.


Even in one-master situations it could be useful: with timestamps, it 
is very easy to make something similar to the Time Machine.



 > - how is the sampling rate communicated ?
The slave(client) asks the server for the meaning of the data.
Number of channels, nominal sampling rate, whether the format is
real or complex etc.


That, too, makes it harder for dedicated hardware receivers; ideally 
these would not need _any_ communication from the slave to the 
master. As I see it, encoding this information in the header of each 
package is a low-overhead way to reduce ambiguity, too.



 > - if you are not doing so already, please please _please_ use the

 functions htons() / ntohs() and friends to convert between host byte
 order and network byte order (or forever determine that linrad
 communicates with either little endian (IA32) or big endian (Alpha,
 PowerPC etc) byte order. I would want to be able to use a PC as the
 server and my PowerBook as the client, for instance.

I do not see how it matters. Linrad does not put port numbers or
addresses in the packages, that is done by the operating system
and the inner workings of Linrad is not visible from the network.


Byte ordering is not restricted to port numbers or addresses. Every 
time you put an integer which is larger than one byte into a packet, 
the transmitter and receiver need to agree on the byte order. See


http://en.wikipedia.org/wiki/Endianness

for details. Taking my example, if the master runs on an Intel 
machine and the slave on my PowerBook, if the master transmits a 
block_no of 0x01020304, my PowerBook will see that as 0x04030201. Not 
good.


JDB.
--
Years from now, if you are doing something quick and dirty,
you imagine that I am looking over your shoulder and say to
yourself, "Dijkstra would not like this," well that would be
immortality for me.  -- Edsger Dijkstra, 1930 - 2002

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-03 Thread Leif Asbrink
On Thu, 4 Jan 2007 04:02:10 +0100
"J.D. Bakker" <[EMAIL PROTECTED]> wrote:

> >// Structure for multicasting receive data on the network.
> >#define NET_MULTICAST_PAYLOAD 1024
> >typedef struct {
> >char buf[NET_MULTICAST_PAYLOAD];
> >double passband_center;
> >float userx_freq;
> >unsigned int block_no;
> >unsigned char userx_no;
> >char passband_direction;
> >} NET_RX_STRUCT;
> 
> Very interesting ! A couple of observations:
> 
> - I would want a timestamp in there somewhere. It might be derived 
> from  block_no, but why not make it explicit ?
I do not see what it would be good for. Why do you want the clock
from the master while there is another one in the slave? 

Surely I could add this, but there is a cost to it.
The packages are sent out at maybe 1 kHz. The corresponding
time resolution is 1 ms. There is an appreciable time jitter 
however and it is not obvious what time to put into
a specific package. Presumably it should be the time
when the first sample within the package was taken from 
the hardware. What would it be good for? It is not trivial
to evaluate.

> - how is the sampling rate communicated ?
The slave(client) asks the server for the meaning of the data. 
Number of channels, nominal sampling rate, whether the format is
real or complex etc.

The user might know the format of the data and just
set up the slave manually as you would do when reading 
data from a soundcard.

> - using float/double makes it much harder for dedicated hardware 
> receivers to act as server.
OK. The internal formats of Linrad are floats or 16 bit integers.
I will make provisions to add 32 bit integers if there would
be a need in the future.

> - if you are not doing so already, please please _please_ use the 
> functions htons() / ntohs() and friends to convert between host byte 
> order and network byte order (or forever determine that linrad 
> communicates with either little endian (IA32) or big endian (Alpha, 
> PowerPC etc) byte order. I would want to be able to use a PC as the 
> server and my PowerBook as the client, for instance.
I do not see how it matters. Linrad does not put port numbers or
addresses in the packages, that is done by the operating system
and the inner workings of Linrad is not visible from the network.

  73

  Leif


#
This message is sent to you because you are subscribed to
  the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-03 Thread J.D. Bakker

// Structure for multicasting receive data on the network.
#define NET_MULTICAST_PAYLOAD 1024
typedef struct {
char buf[NET_MULTICAST_PAYLOAD];
double passband_center;
float userx_freq;
unsigned int block_no;
unsigned char userx_no;
char passband_direction;
} NET_RX_STRUCT;


Very interesting ! A couple of observations:

- I would want a timestamp in there somewhere. It might be derived 
from  block_no, but why not make it explicit ?

- how is the sampling rate communicated ?
- using float/double makes it much harder for dedicated hardware 
receivers to act as server.
- if you are not doing so already, please please _please_ use the 
functions htons() / ntohs() and friends to convert between host byte 
order and network byte order (or forever determine that linrad 
communicates with either little endian (IA32) or big endian (Alpha, 
PowerPC etc) byte order. I would want to be able to use a PC as the 
server and my PowerBook as the client, for instance.


JDB.
--
LART. 250 MIPS under one Watt. Free hardware design files.
http://www.lartmaker.nl/

#
This message is sent to you because you are subscribed to
 the mailing list .
To unsubscribe, E-mail to: <[EMAIL PROTECTED]>
To switch to the DIGEST mode, E-mail to <[EMAIL PROTECTED]>
To switch to the INDEX mode, E-mail to <[EMAIL PROTECTED]>
Send administrative queries to  <[EMAIL PROTECTED]>



[linrad] Re: Network standards for SDR

2007-01-03 Thread Leif Asbrink
Hi All,

Alberto wrote on the Winrad mailing list:
> The network model is very general, and could allow 
> even to have Winrad and MAP65 on different PCs, 
> maybe one with Linux and the other with Windows. 
> But this could be a long range target. 

Thanks to the assistance from ON4IY Linrad now
has a network that can send data in seven different
formats and number of bits:
raw 16
raw 18
raw 24
fft1 32
timf2 16 or 32
fft2 16 or 32

The first four formats can be used for input to Linrad. 
timf2, the input to fft2 and fft2 will be sent as 16 bit 
integers if the user selected the MMX implmentations of the 
FFT algorithms, otherwise they are 32 bit floating point. 
Besides broadcasting one or more of these formats the computer 
that owns the hardware, the master, has a simple server to 
which slaves can connect and request calibration data as well 
as post what frequency the operator is focussing on for all 
other computers on the network to know.

Right now, only the raw data broadcasts and the client server 
communication with calibration data works. I see no problems 
in adding the remaining things however.

On a "modern" computer, a 2.6GHz Pentium 4, the master can run 
under X11 and put out all raw data formats simultaneously. 
4*96000*(16+18+24)bit/s =22 megabit/s of useful data. To that 
adds several percent of overhead because the payload in each 
packet is fixed to 1024 bit.

On a not so modern computer, a 200MHz Pentium MMX, and presumably 
more importantly running Mandrake 8.0 with a very old Linux kernel 
(2.4.3) the 16 bit data 4*96000*16=6 megabit/s uses up 50% of 
the available CPU time allowing very little time for the actual 
signal processing within Linrad. The time reported by linrad goes 
up from 47% to 98%. Receiving data at the same speed does not load 
the CPU much. (A Pentium 1 at 133 MHz can put out 2*48000*16=1.5 
megabytes/s with 5% cpu load using a modern kernel like 2.6.18)

I post this to the Winrad mailing list because it seems to me
that the network of modern computers is capable of doing what 
we need with a broad margin. It would be fine if Linrad, Winrad,
MAP65 and other softwares to come would use the same standards
for sending data over the network. It means we would have to
agree on a protocol and that is why I would like to see a 
discussion on the mailing lists. 

Currently the broadcasting is like this in Linrad:
// Structure for multicasting receive data on the network.
#define NET_MULTICAST_PAYLOAD 1024
typedef struct {
char buf[NET_MULTICAST_PAYLOAD];
double passband_center;
float userx_freq;
unsigned int block_no;
unsigned char userx_no;
char passband_direction;
} NET_RX_STRUCT;

The contents of the payload is determined by the port address
last digit. Linrad uses the 5 first ones and allows the user to
select a port between 5 and 65000 in steps of 10.
Multicasting groups are 239.255.0.0 to 239.255.0.16.
I will be happy to change to accomodate to suggestions that
make it easier for Linrad and future SDR softwares to communicate.

Slaves connect to the master and the protocol is extremely simple
at the moment. 
// Structure for messages from slaves.
typedef struct {
int type;
double frequency;
} SLAVE_MESSAGE;

Here type is a 32 bit integer telling the master what the slave
wants (calibration functions etc.) Frequency is the frequency that
the slave currently has in focus. Messages are sent infrequently
so there is no problem adding many more things but presumably the
need for communication between different computers does not need
standardization at this point. In the future the wideband unit
might be a commercial transceiver and not a computer running
Linrad and the two-way communication protocol would probably 
be similar to what is used today over the serial port. 

I have tested to run one instance of Linrad as the master 
sending all three raw formats to the network with three more 
instances of of Linrad receiving each one of them on the 
same computer. The cpu load is about 50%:

  PID USER  PR  NI  VIRT  RES  SHR S %CPU %MEMTIME+  COMMAND
 9629 root  17   0  244m 154m 1348 S  9.3  7.6   0:23.93 xlinrad
 9663 root  17   0  138m  15m 1388 S  7.3  0.8   0:07.75 xlinrad
 9487 root  14  -1 99.4m  12m 6664 S  6.3  0.6   0:18.32 Xorg
 9652 root  17   0  109m  27m 1340 S  5.0  1.3   0:09.33 xlinrad
 9641 root  19   0  109m  27m 1340 S  4.0  1.3   0:08.74 xlinrad
 9682 root  15   0 22728  12m 8932 S  2.0  0.6   0:01.93 gnome-system-mo
 9561 root  15   0 33280  14m 9340 R  1.7  0.7   0:02.93 gnome-terminal
 2428 root  18   0  1812  620  536 S  0.3  0.0   0:38.18 hald-addon-stor

This experiment was with the second fft disabled, but it shows 
that the network is pretty good within the same computer. 
(The purpose of the test was to show the significance of using 18 
bits but that 24 bits does not improve over 18.)

I have tested six computers simultaneously on the network, two
different masters and the others an one or more