<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Hi All,<br>
<br>
This email is about a software/DSP enhancement that those of you
writing software for the HPSDR (or other hardware) may want to
consider.<br>
<br>
The explosion in popularity of the WSJT modes since the first of the
year has presented me (and probably many of you as well) with a new
problem, due to the now frequent occurrence of very strong local
stations on the VHF digital frequencies where I am trying to work
very weak, distant stations. This was not previously an issue for
me, as there were not other locals active on these frequencies. But
these frequencies are now like Grand Central Station in NYC. <br>
<br>
I do NOT get RF overload from these strong local stations, that is
well taken care of due to appropriate station design. But the
computer final audio stages cannot tolerate the wide range of signal
levels present without some sort of AGC. <br>
<br>
And as everyone on this list knows, one does NOT want to run AGC for
weak signal work digital or otherwise, because the action of the AGC
on a strong station within the AGC passband will mask the weak
stations.<br>
<br>
This problem was particularly vexsome on Monday of this week when a
very strong local station seemed to be omnipresent. I had 2 states
of operation [1] AGC off and [2] AGC on. With [1], the strong
station would overload the audio when the audio levels were adjusted
for proper copy of the weak DX stations. With [2], when the strong
station came on the weak stations' signal levels were pushed way
down so that they were no longer copiable/visible.<br>
<br>
The problem with the usual AGC is that it is done in the time
domain, and it is not frequency specific. And to solve this
interference problem we need frequency-specific AGC.<br>
<br>
But in the SDR receive chain we are in the frequency domain for
audio filtering anyway, and so there is little computing penalty for
adding some simple code that applies frequency-specific AGC to each
individual FFT bin.<br>
<br>
It was a simple matter to write a few lines of code to add the
frequency-specific AGC code to run immediately after the filter
code, and the results thus far have been outstanding here with both
JT65 and FT8 weak signal work in the presence of strong stations. It
is only Thursday and I started playing with this only Tuesday, so
more real world testing is to be done.<br>
<br>
But the results of this have been so outstanding for me that I
wanted to share them with the rest of the group so that they can add
this function to their software too. My code is idiosyncratic to my
software here, but the basic principles are general. Here, the
frequency-specific AGC code working in the frequency domain by
limiting the signal strengths individually for each FFT bin is
placed just after the filter deconvolution is done, and before the
"usual" time-domain AGC, which I have disabled. <br>
<br>
The approach I am using is to allow the user (me) to select a "knee"
amplitude and a "limit" amplitude. Signals below the knee amplitude
are passed without change. Signals above the knee amplitude are
modified using these equations:<br>
<br>
++++++++++++++++<br>
thisMagnitude[i] = (float)Math.Sqrt(w3sz_tmp_cpx[i].real *
w3sz_tmp_cpx[i].real + w3sz_tmp_cpx[i].imaginary *
w3sz_tmp_cpx[i].imaginary)<br>
--------------------------<br>
float w =( -(float)Math.Log(1 - (1 / this.fagclimit))) /
this.fagcknee; <br>
<br>
for (int i = 0; i < size; i++)<br>
{<br>
if (this.fagctype == "OFF") //turns of time-domain
AGC<br>
{<br>
if (thisMagnitude[i] > this.fagcknee) //
frequency domain formula for amplitude > knee amplitude<br>
{<br>
d.tmp_cpx_2[i].real = 0.0001f *
this.fagclimit * (1.0f - (float)Math.Exp(-w * thisMagnitude[i])) *
w3sz_tmp_cpx[i].real;<br>
d.tmp_cpx_2[i].imaginary =
(d.tmp_cpx_2[i].real / w3sz_tmp_cpx[i].real) *
w3sz_tmp_cpx[i].imaginary;<br>
}<br>
else // frequency domain formula for amplitude
<= knee amplitude<br>
{<br>
d.tmp_cpx_2[i].real = 0.0001f *
w3sz_tmp_cpx[i].real;<br>
d.tmp_cpx_2[i].imaginary = 0.0001f *
w3sz_tmp_cpx[i].imaginary;<br>
}<br>
}<br>
else //if time domain AGC is to be used instead
(separate code block), there is some level setting done here<br>
{<br>
d.tmp_cpx_2[i].real = 0.01f *
w3sz_tmp_cpx[i].real;<br>
d.tmp_cpx_2[i].imaginary = 0.01f *
w3sz_tmp_cpx[i].imaginary;<br>
}<br>
}<br>
+++++++++++++++<br>
where:<br>
w3sz_tmp_cpx is input<br>
d.tmp.cpx_2 is output<br>
<br>
w sets the level of the signal at the knee calculated by the the
formulas above to be equal to the input signal, so that there is no
discontinuity at the knee. <br>
this.fagclimit is the limit amplitude<br>
this.fagcknee is the knee amplitude<br>
<br>
The most useful range for user selectable signal limits here thus
far is 1-20 and useful range for knees is 0.0001 to 0.02.<br>
<br>
the initial factors of 0.0001 and 0.01 in the above formulas are
just to set baseline signal level as appropriate for my setup here.<br>
<br>
This approach should be easy for anyone to adapt to their software,
and I've been very pleased with the results here.<br>
And of course NONE of this would have happened without the work of
Phil VK6PH and Kiss Konsole.<br>
<br>
If you want more details on my software or want to download my
entire codebase, you can go to <br>
<a class="moz-txt-link-freetext" href="http://www.nitehawk.com/w3sz/CSharpsdrclientANDserverVersion2pt0.html">http://www.nitehawk.com/w3sz/CSharpsdrclientANDserverVersion2pt0.html</a><br>
<br>
73,<br>
<br>
Roger Rehr<br>
W3SZ<br>
<br>
</body>
</html>