In my last post, I mentioned that, even though I'm not wild about computers, they do sometimes make for decent tools, so I try to know enough about using them to be dangerous.
Now that I'm "officially" finished with the SR-16 project, I'm working on ideas for the next one, which will be an even more ambitious attempt at a "contest grade" multi-band HF transceiver.
In building the 30m rig, I initially made a bad choice of IF frequency - 13.51 Mhz - which placed the 2nd harmonic of the VFO smack in the middle of the band. The easy fix was to move the IF to 13.56 so that the harmonic of the VFO fell outside of the band, but that also required additional bandpass filtering to manage the now out-of-band spur. Moving forward, I'm determined to avoid that by analyzing my choice of frequencies and avoiding those that interact unpleasantly.
This requires repeated calculations, something I hate doing but also something computers are pretty good at. So, knowing enough to be dangerous, I wrote a little C++ program to crunch the numbers:
#include <iostream>
using namespace std;
int main ()
{
float lo;
float lowend;
float highend;
float step;
float rf;
int harmonic= 1;
float spur;
float range;
int harmonicNumber;
cout << "Please enter the LOWEST receive/transmit frequency in MHz: ";
cin >> lowend;
cout << "Please enter the HIGHEST receive/transmit frequency in MHz: ";
cin >> highend;
cout << "Please enter the STEP in MHz ";
cin >> step;
cout << "Please enter the IF frequency in MHz: ";
cin >> rf;
cout << "Please enter the number of harmonics to extend to ";
cin >> harmonicNumber;
cout << "The tuning range you entered is " << lowend <<" to"<<" MHz.\n";
cout << "The IF you entered is " << rf <<".\n";
cout << "Analyzing to the " <<harmonicNumber << "th Harmonics... \n";
for(range = lowend; range <= highend; range = range + step)
{
//lo = rf - range; // low side injection
lo = rf + range; //high side injection
for(harmonic=1;harmonic <=harmonicNumber;harmonic ++)
{
spur = lo * harmonic;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the LO ("<<lo<<") is: " << spur << ".\n";
}
spur = rf * harmonic;
if ((harmonic > 1) && (spur > (lowend * .9)) && (spur < (highend * 1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the IF ("<<rf<<") is: " << spur << ".\n";
}
spur=lo*harmonic+rf;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the LO ("<<lo<<") + the IF ("<<rf<<") is: " << spur << ".\n";
}
spur = lo*harmonic - rf;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
if (spur>0)
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the LO ("<<lo<<")- the IF ("<<rf<<") is: "<<spur<<".\n";
}
}
spur=rf*harmonic+lo;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the IF ("<<rf<<") + the LO ("<<lo<<") is: "<<spur<<".\n";
}
spur=rf*harmonic-lo;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
if (spur>0)
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the IF ("<<rf<<") - the LO ("<<lo<<") is: "<<spur<<".\n";
}
}
}
}
main();
return 0;
}
If this looks like gibberish, here's something that I hope will be encouraging: I'm not a programmer, not terribly bright, and figured out how to do this in a couple of hours. If I can do it, anyone can!
Anyway, this program runs in the Linux terminal and will prompt you for the low and high ends of the band of interest, how many points within the band to analyse, the IF (BFO) frequency and the number of harmonics that you want the analysis to look at. Then it crunches the numbers, and displays any "hits" that occur within 10% of the band edges. If there are no hits, it dumps you back to the beginning (exit with "control-C".)
Here's a screen shot of running an analysis of the 40m band (in 1 Hz increments) and an IF of 6.144 MHz, running out to the 100th harmonics. This took about 2 seconds for the computer to crunch the numbers and give an "all clear".
Here's one where I chose a bad IF frequency so that it'll show some "hits":
I literally had this written within a couple of hours of writing my first "Hello World" in C++. It helped that I understood the math and some basic programming concepts, but yeah - this is something anyone can do, so there's no reason to be intimidated by it.
I promise, I'll get back to the Real Radio Stuff in my next post; I just wanted to write this one to show an example of how a computer and **very little** knowledge of programming can be a useful weapon in the homebrewer's arsenal.
73 Steve N8NM
Now that I'm "officially" finished with the SR-16 project, I'm working on ideas for the next one, which will be an even more ambitious attempt at a "contest grade" multi-band HF transceiver.
In building the 30m rig, I initially made a bad choice of IF frequency - 13.51 Mhz - which placed the 2nd harmonic of the VFO smack in the middle of the band. The easy fix was to move the IF to 13.56 so that the harmonic of the VFO fell outside of the band, but that also required additional bandpass filtering to manage the now out-of-band spur. Moving forward, I'm determined to avoid that by analyzing my choice of frequencies and avoiding those that interact unpleasantly.
This requires repeated calculations, something I hate doing but also something computers are pretty good at. So, knowing enough to be dangerous, I wrote a little C++ program to crunch the numbers:
#include <iostream>
using namespace std;
int main ()
{
float lo;
float lowend;
float highend;
float step;
float rf;
int harmonic= 1;
float spur;
float range;
int harmonicNumber;
cout << "Please enter the LOWEST receive/transmit frequency in MHz: ";
cin >> lowend;
cout << "Please enter the HIGHEST receive/transmit frequency in MHz: ";
cin >> highend;
cout << "Please enter the STEP in MHz ";
cin >> step;
cout << "Please enter the IF frequency in MHz: ";
cin >> rf;
cout << "Please enter the number of harmonics to extend to ";
cin >> harmonicNumber;
cout << "The tuning range you entered is " << lowend <<" to"<<" MHz.\n";
cout << "The IF you entered is " << rf <<".\n";
cout << "Analyzing to the " <<harmonicNumber << "th Harmonics... \n";
for(range = lowend; range <= highend; range = range + step)
{
//lo = rf - range; // low side injection
lo = rf + range; //high side injection
for(harmonic=1;harmonic <=harmonicNumber;harmonic ++)
{
spur = lo * harmonic;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the LO ("<<lo<<") is: " << spur << ".\n";
}
spur = rf * harmonic;
if ((harmonic > 1) && (spur > (lowend * .9)) && (spur < (highend * 1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the IF ("<<rf<<") is: " << spur << ".\n";
}
spur=lo*harmonic+rf;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the " << harmonic <<" harmonic of the LO ("<<lo<<") + the IF ("<<rf<<") is: " << spur << ".\n";
}
spur = lo*harmonic - rf;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
if (spur>0)
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the LO ("<<lo<<")- the IF ("<<rf<<") is: "<<spur<<".\n";
}
}
spur=rf*harmonic+lo;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the IF ("<<rf<<") + the LO ("<<lo<<") is: "<<spur<<".\n";
}
spur=rf*harmonic-lo;
if ((harmonic > 1) && (spur > (lowend*.9)) && (spur < (highend*1.1)))
{
if (spur>0)
{
cout<<"Warning!!! When tuned to " << range <<"; the "<<harmonic <<" harmonic of the IF ("<<rf<<") - the LO ("<<lo<<") is: "<<spur<<".\n";
}
}
}
}
main();
return 0;
}
If this looks like gibberish, here's something that I hope will be encouraging: I'm not a programmer, not terribly bright, and figured out how to do this in a couple of hours. If I can do it, anyone can!
Anyway, this program runs in the Linux terminal and will prompt you for the low and high ends of the band of interest, how many points within the band to analyse, the IF (BFO) frequency and the number of harmonics that you want the analysis to look at. Then it crunches the numbers, and displays any "hits" that occur within 10% of the band edges. If there are no hits, it dumps you back to the beginning (exit with "control-C".)
Here's a screen shot of running an analysis of the 40m band (in 1 Hz increments) and an IF of 6.144 MHz, running out to the 100th harmonics. This took about 2 seconds for the computer to crunch the numbers and give an "all clear".
Here's one where I chose a bad IF frequency so that it'll show some "hits":
I literally had this written within a couple of hours of writing my first "Hello World" in C++. It helped that I understood the math and some basic programming concepts, but yeah - this is something anyone can do, so there's no reason to be intimidated by it.
I promise, I'll get back to the Real Radio Stuff in my next post; I just wanted to write this one to show an example of how a computer and **very little** knowledge of programming can be a useful weapon in the homebrewer's arsenal.
73 Steve N8NM
This would have saved me from the "Intermediate Frequency of Death" problem that I suffered with my 20/40 BITX rig (that became instead a 20 meter rig.) Bravo Steve!
ReplyDelete