<div dir="ltr"><div>The ideal is to robust in the case of any (unpredictable) parameter update.</div><div><br></div><div>Current design seems to assume voice. </div><div><br></div><div>Relying on RTP to paper over the missing data works for voice. </div><div><br></div><div>It dos not work for other classes of signals.</div><div><br></div><div>Being able to vary block size on the fly allows us to tune for latency. </div><div><br></div><div>We have an opportunity to craft some very useful code that takes full advantage of modern SDRs and current DSP techniques. There are a lot of other parameters besides filter stuff.</div><div><br></div><div>The challenge to you, and everyone else here, is to craft a general, not a specific, solution. </div><div><br></div><div>Please give this some thought.<br><br>Let's see what we can all do about it, together. </div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr">-Michelle W5NYV<br><br><div dir="ltr"><br></div></div></div></div></div></div></div></div></div>
<br><div class="gmail_quote">On Mon, Apr 23, 2018 at 11:26 PM, Phil Karn <span dir="ltr"><<a href="mailto:karn@ka9q.net" target="_blank">karn@ka9q.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 4/23/18 17:41, Michelle Thompson wrote:<br>
> The parameter update issue is a general-case design issue. It is<br>
> important. Please think about it some more.<br>
<br>
</span>I think there's been some misunderstanding. **EVERY** filter parameter<br>
can **ALREADY** be updated as frequently as once per FFT block, which is<br>
typically 20 ms. That includes the frequency response and window shape<br>
factor.<br>
<br>
The only thing that can't (yet) is the length of the FFT block itself.<br>
That requires so much reinitialization, and I had so little need for the<br>
feature, that I just restart the program when I have to do it. Which is<br>
about never.<br>
<br>
Frequency mixing is in the time domain, so it can change on a per-sample<br>
basis. Which it does when Doppler steering is in effect.<br>
<br>
Remember, it's all just RTP streams. If the program restarts fast<br>
enough, you may not even notice the interruption (though the RTP stream<br>
ID will change unless you make it the same). One easy way to implement<br>
this is to simply have the program exec() a new copy of itself with the<br>
new parameters. I'll probably hook this onto a command to load a state<br>
file (which normally happens only at startup).<br>
<br>
I'm writing this package mainly as a proof-of-concept for RTP and<br>
multicast in distributed SDR implementations. If my actual code is<br>
useful to somebody, so much the better.<br>
<br>
It was the same with my TCP/IP software in the mid-late 1980s; I wrote<br>
it as a proof-of-concept for those protocols over ham packet radio, and<br>
it turned out that the software had other uses. Until it was replaced by<br>
Linux, which is what should have happened.<br>
<span class=""><br>
> RTP/multicast and Opus features are things I want to fold in to our GNU<br>
> Radio implementation. <br>
<br>
</span>Since this invokes interoperability issues, this is where we need to<br>
nail things down.<br>
<br>
The RTP AVP (Audio-Video Profile) already defines static payload types<br>
for 48 kHz 16-bit PCM, one for mono and one for stereo. The samples are<br>
sent in big-endian order (like all IETF standards) despite big-endian<br>
CPUs being nearly extinct. I flip the bytes on both ends just to be sure<br>
I'm compatible.<br>
<br>
Opus is a more of a problem. After assigning a whole bunch of static<br>
payload types to now-obsolete codecs, the powers-that-be decided to stop<br>
assigning payload types altogether and require that they be dynamically<br>
established with the Session Description Protocol (SDP). (As the saying<br>
goes, every problem in computer science can be solved with yet another<br>
layer of indirection).<br>
<br>
Unfortunately, this happened before Opus was standardized, so even<br>
though the IETF wants to promote Opus as *the* standard audio codec,<br>
they've made it harder to use than the old fashioned codecs it's<br>
supposed to replace.<br>
<br>
So to force VLC on my iPad to play it, I have to write a short SDP text<br>
file, serve it up on some local web server, and point VLC at it. Then<br>
it will join the multicast stream and decode Opus. All that extra work<br>
and points of failure just to set one number that shouldn't need to be set.<br>
<br>
My 'monitor' program doesn't need SDP because I use the fixed value of<br>
111 on both ends. It *seems* be some sort of unofficial convention, so I<br>
chose it.<br>
<br>
Lastly, there's I/Q data. I know about VITA-42 (?) but I took one look<br>
and the horrible CCITT/ISO/OSI flashbacks to the 1980s began. (Bob knows<br>
of what I speak.)<br>
<br>
This is totally nonstandard so obviously there won't be a static payload<br>
type for it. But that's actually less of a problem because we're not<br>
trying to interoperate with anybody; we control both ends and consenting<br>
Internet hosts can do whatever they want. My RTP format looks like this:<br>
<br>
RTP Header (standard), PT = 97 (arbitrary, in dynamic space)<br>
custom SDR status header<br>
16-bit I sample<br>
16-bit Q sample<br>
16-bit I sample<br>
.......<br>
<br>
The samples are in little endian format because, again, they don't have<br>
to be big-endian. The custom SDR header looks like this:<br>
<br>
struct status {<br>
long long timestamp;<br>
double frequency;<br>
uint32_t samprate;<br>
uint8_t lna_gain;<br>
uint8_t mixer_gain;<br>
uint8_t if_gain;<br>
uint8_t pad;<br>
};<br>
<br>
Essentially the same format is used in unicast UDP packets back to the<br>
I/Q sender to control the device (though some fields can't be changed.)<br>
<br>
The timestamp is a little-endian integer count of nanoseconds since the<br>
GPS epoch of January 6, 1980 at 00:00:00 UTC. This will wrap in 584<br>
years from 1980. This timestamp comes from the original source, so you<br>
can play back an I/Q recording and see the original time in the 'radio'<br>
display. That's its main use; internal SDR timekeeping is all done by<br>
counting samples, so it is only as accurate as the FCD A/D clock.<br>
<br>
I feel *very* strongly that UTC should not be used for internal<br>
timestamps. Nor can UTC be correctly represented as a single number, as<br>
UNIX traditionally tries to do. That's fundamentally broken.<br>
<br>
After I did this, I discovered that NTP has its own internal time format<br>
consisting of two 32-bit integers counting full and fractional seconds<br>
since Jan 1, 1900 UTC, which is almost 60 years before UTC even existed,<br>
and long before atomic clocks that could nail down such an early epoch.<br>
It will roll over in 2036. And NTP follows UTC, so it jumps every time<br>
there's a leap second. In other words, I think Dave Mills made a major<br>
mistake here, and I even told him at the time. But he actually enjoyed<br>
watching the transient response of hundreds of NTP hosts to an abrupt<br>
jump in time.<br>
<br>
Because my timestamps are in GPS time, you can get it from a local GPS<br>
receiver, which indicates the UTC-GPS offset, or from UNIX system time<br>
(via NTP) and a leap second table -- which I've already done. I prefer<br>
the first approach. GPS receivers are now cheap commodity devices.<br>
<br>
The frequency is a double precision float giving the center frequency of<br>
the I/Q stream, i.e., the local oscillator frequency in a zero-IF<br>
receiver front end.<br>
<br>
The sample rate is the *nominal* A/D sample rate, uncorrected for any<br>
oscillator error (which the sender doesn't know anyway; that's corrected<br>
by the I/Q consumer, e.g, 'radio').<br>
<br>
lna_gain, mixer_gain and if_gain are specific to the FCD, though I<br>
believe a bunch of zero-IF SDR front ends are using the same tuner chip.<br>
The first two take the values '1' or '0' to indicate whether the<br>
corresponding amplifier is on or off.<br>
<br>
if_gain is an integer between 0 and 59 giving the gain of the baseband<br>
amplifiers in dB between the quadrature mixers and the A/D converters.<br>
The FCD already has so much front end gain that I always leave this at<br>
zero, as recommended.<br>
<br>
These values can change at any time, which is why they're included in<br>
every packet. In fact, 'radio' won't even start up until it gets the<br>
first I/Q RTP packet because it doesn't yet know the A/D sample rate,<br>
and virtually every initialization needs that.<br>
<br>
The FCD has a wide dynamic range so 'radio' doesn't even have a way to<br>
set them right now, though the protocol allows for it. The 'funcube'<br>
program that talks directly to the FCD will change the LNA and IF gain<br>
settings as a strictly defensive measure when an overload is detected.<br>
This happens in two steps: first IF gain is reduced, then if more<br>
reduction is still needed, LNA is turned off. If either is off when the<br>
level falls below a lower threshold, they're turned back on in reverse<br>
order. I only see this happen on local TV and radio stations.<br>
<br>
I strongly resisted putting hardware-specific fields in here. I really<br>
wanted the header to convey the actual conversion gain in dB (i.e., the<br>
output level in dBFS for an input level in dBm) but that turned out to<br>
be impossible. I measured the gain of the FCD and it varies enormously<br>
over its coverage range. The mixer amplifier is always 19 dB, and the IF<br>
gain steps do seem accurate, but the LNA can range from hardly more than<br>
1 dB up to over 20, and the big bank of switchable preselectors didn't<br>
help matters.<br>
<span class="HOEnZb"><font color="#888888"><br>
Phil<br>
</font></span></blockquote></div><br></div></div>