Magnetic Loop Controller

  • 1
  • Praise
  • Updated 3 years ago
I built a transmitting magnetic loop several years ago.  I used an Arduino UNO with an ethernet shield to control the 25 turn vacuum variable capacitor.  I wrote a piece of VB code that interfaced with HDSDR to get the VFO and send the appropriate stepper position to the Arduino via TCP.  When using my Kenwood TS-530s I had to use my VB code to manually enter the VFO.  It worked, but not as well as I would have liked.

Enter client/server radio.  I bought my 6300 a couple months ago and decided to update my controller.  I had already decided to upgrade to the Arduino MEGA 2560 several months before because I had to remove some important pieces due to the limited space on the UNO.  I also 3D printed the vacuum variable mounts and switched to a geared stepper and accessory shaft to determine the starting point of the cap.  It was much better than aluminum angle and tie straps.  After looking at the API and playing around with telnet sessions to the 6300, I figured it wouldn't be too difficult to eliminate my PC software and move it directly to Arduino and have it follow the 6300.  I set it up so that it only follows the ANT1 antenna, and only if the slice is set to TX.  A simple subscribe to the the slice events gave me what I needed.  I initially had trouble reliably parsing the incoming text from the 6300 until I dumped everything to a FIFO queue first, then process the queue later.  It has been sitting on my desk for a couple weeks with the latest updates, following the 6300 as I follow the stepper DIR on my scope.  Recent non-stop rain has prevented it's deployment, not to mention the constant tweaks that I can't ever seem to be "done" with.  At this point I think it's pretty solid, although I can still think of several things I could add.  At some point I have to plug it back in.  The further enhancements I want to make will have to wait until I change the platform to a raspberry pi and reuse my UNO for stepper control.

I want a built-in tune function.  I don't think the Arduino has enough power to read the SWR in real time, so the pi will do that.  Since I'm using a mapping of frequency to stepper position, this tends to drift slightly with various conditions, such as weather and even objects near the antenna.  Frequencies in between the mapping points have their stepper positions calculated.  I can still use my VB software to manually tweak the position for a lower SWR, but I don't want to rely on any desktop software.  The pi will include a tune function that will adjust the cap to the lowest SWR when the TUNE button is pressed in SSDR.  When the tune power is 2 watts it will tune the slice specific frequency.  When it's set to 1 watt, the controller will change the frequency on the Flex to each map point and determine the lowest SWR and record the stepper position.  I haven't figured this part out yet, but I'm sure it's possible. 

With HDSDR the controller worked perfectly.  I could click a few bands over and watch the bump in the noise floor walk across the band to the set frequency.  Based on my testing it works just as well, except it won't matter what client I use.  It can be SSDR, or one of the excellent clients I've seen people working on in the forums.  Please don't forget to add the TUNE button to those custom clients.  When I get more antennas, I may add an automatic switcher and switch based on frequency and antenna port.  Perhaps something like switching to the APRS frequency on 30m will automatically switch in the dedicated 30m receive loop.  No need to limit to just switching based on band.

So here's my loop controller code for the Arduino.  It's not pretty and was never intended to be seen by anyone, but it may prove useful for someone that just wants to setup something simple that will follow their Flex 6000 SDR.  It was easier than I thought, but the limitations of the platform does present some challenges.

https://www.dropbox.com/s/ee4cbz69jjsztng/LoopController.ino?dl=0


Steve
KD8QWT
Photo of Steve - KD8QWT

Steve - KD8QWT

  • 74 Posts
  • 14 Reply Likes

Posted 4 years ago

  • 1
Photo of L.Kubis

L.Kubis

  • 83 Posts
  • 20 Reply Likes
Have a look at Loftur's site --
https://sites.google.com/site/lofturj/to-automatically-tune-a-magnetic-loop-antenna

Loftur also runs a Yahoo Group site where he publishes more data on his controller.

Lloyd
VE3ERQ
Photo of Steve - KD8QWT

Steve - KD8QWT

  • 74 Posts
  • 14 Reply Likes
An unforeseen benefit to my original design was the ease of using the Flex as the server.  The controller is still a server to telnet while using the Flex as a server for the info I needed for the loop.  It only cost me time to add the code.
Photo of David Scobie

David Scobie

  • 18 Posts
  • 1 Reply Like
Steve, did you ever implement the PI for the built-in tune function?
I've built a couple of Loftur's controllers and integrated a bank of relays to switch the control lines. 

His is a great little design and works fine with the traditional Icom transceiver. There is an swr/pwr meter tap in the coax, reporting back to the controller, which is redundant with the flex, especially with two antennas.  I've played around with a couple of ethernet shields and an outboard arduino using Enzo's work as a starting point, but it is a bit too much of a kludge; now it's time to build a Flex specific solution.

As winter approaches, I would like to use the extra indoor time to do what you described.  I have two loops, (160-30M / 20M-6M) and want them both to track, according to their designed frequency range. I think a crossover frequency, and having the correct ant selected in the slice, toggles the relay between steppers.  Multiple slices and stuff is too confusing for me just yet... maybe that will be easy, maybe not.

As you point out, I also notice the loop resonance drifts a few Kc over time + temp, so a quick re-tuning regime would be a dandy thing.

If I'm thinking about this correctly, an initial config routine would build/fill a look up table for the relative positions of the steppers on ant1/2 with tune updating the table on demand. 
I haven't fully fleshed out the polling; I think that would require a bit of trial and error work to come up with something responsive but not too chatty.
If the steppers and tuning response is fairly linear, the flex frequency info would continue to track/drive the steppers through the no transmitting spectrum.  It will be interesting to see how accurate and usable this would be. I've already built and use a PA0RDT active antenna on RXa so as to see the band and then drive the loop(s) to points of interest manually, so out of band accuracy isn't a show stopper.

Thoughts?
73 de Dave, VA3AE
Photo of Steve - KD8QWT

Steve - KD8QWT

  • 74 Posts
  • 14 Reply Likes
Unfortunately I've not had the time to do much with this project.  All I was able to accomplish was to use the existing Arduino Mega and have it follow the Flex slice with the transmit enabled for the antenna port I was watching.  At that point I had already started my satellite rotator project and didn't want to be working on two development projects at the same time.  I decided at the time to stick with Arduino Mega rather than the pi, but I wasn't having much luck with it keeping up with the ethernet packets coming from the Flex.  It just wasn't as reliable as I had hoped and have since been relying on manual positioning via telnet.  Once the rotators are complete and outside rotating I'm going to jump back on this project.  I may have to try the pi or even switch to a Due.  It will be a good winter project and can't wait to really get into it.

Yes, an initial config containing a position to frequency map works quite well.  I have used this for a few years.  Unfortunately the tuning is not linear.  The best bet is to have specific map points at frequencies you use often, then rely on calculations to figure out the position based on the the next highest and next lowest mapped position.  It's not linear, but it can be linear enough, especially if you have several map points within the band.  Just using a map and calculating the in between positions has proven to be quite accurate.  Out of band accuracy can be useful for short wave listening.  It can make a huge difference on receive, especially if you can manually drift the tune point around.  Where mappings prove problematic is when the Q starts to become extremely narrow.  With my loop on 80m for example, just a few steps will jump the swr from excellent to unusable on transmit. 

For 2 steppers, I don't think I would use a relay to switch power between the steppers.  It would be better to use 2 separate stepper drivers and drive them off different pins.  A good driver will allow you to power down the stepper to save power.  You could even have them both run on automatic based on their frequency ranges and use a remote switch to switch the coax between the two antennas.  Maintain 2 sets of maps, one for each antenna.  Subscribing to the slice events will send notifications when something changes, like the frequency the slice is set to.  Then position each stepper based on it's mapping, assuming the frequency is inside it's range. 

I think the reliability issues i had was due to a flaky router I had at the time.  When it worked it was awesome.  Once I get it solid, I'll start watching the SWR and see if the Mega has enough horsepower to keep up.  If not, then the Due will prob be plan B.  Plan C would be a pi.  Right now I'm Flexless because I'm waiting on the 6500 I traded up to.  Then I'll have 4 slices I can watch.
Photo of IW7DMH, Enzo

IW7DMH, Enzo

  • 353 Posts
  • 84 Reply Likes
Hello Steve,

you did a great job with your controller code! I just want to confirm that the Due board has enough power to read the SWR in real time and provide immediate feedback to your controller.
From your first post, six months ago, I made a lot of improvements to my Due libraries: once you have an instance of you rig you can use one of the exposed methods in the FlexRig class. You can read the following meters as well:

MET_S_A
MET_S_B
MET_SWR
MET_FPWR
MET_MIC_PEAK
MET_COMP_PEAK

They are stored in a structure array calculated about 10 times per second so I think it can be used in your project.
I use these meters in my controller Gui code and, as you can see from youtube videos, meter bars are very reliable and responsive.

If you like to test or inspect in depth my Due libraries I'll be glad to help you.

73' Enzo
iw7dmh

------------------------------


    //Methods
    void set_headphone_gain(int val);   
    void set_sidetone_onoff(int value);
    void set_breakin_onoff(int value);
    void set_iambic_onoff(int value);
    void set_vox_onoff(int value);
    void set_dexp_onoff(int value);
    void set_proc_onoff(int value);
    void set_monitor_onoff(int value);   
    void setRxAntenna(int sliceId, String value);
    void setTxAntenna(int sliceId, String value);
    void setPreampGain(int panId, int value);
    void setTxEqMode(int value);
    void setRxEqMode(int value);   
    void setBand(int panId,int value);
    void setMode(int sliceId,String value);   
    void setTx(int sliceId,int active);
    void setActiveSlice(int sliceId,int active);
    void removeSlice(int sliceId);
    void createSlice(float freq,String antenna,String mode);
    void removePanadapter(int panId);
    void createPanadapter(float freq);
    void setFreq(int sliceId, int freq);   
    void setAgcMode(int sliceId, String value);   
    void setDisplayPanWeightAverage(int panId,int value);
    void setPanafallAutoBlack(int panFallId,int value);   
    void setNr(int sliceId,int active);
    void setWnb(int sliceId,int active);
    void setApf(int sliceId,int active);
    void setAnf(int sliceId,int active);   
    void setRit(int sliceId,int active);
    void setXit(int sliceId,int active);   
    void setAudioMute(int sliceId,int active);   
    void setAgcOffLevel(int sliceId,int active);
    void setAgcThreshold(int sliceId,int active);   
    void setLineoutMute(int active);
    void setHeadphoneMute(int active);   
    void setBandWidth(int sliceId,int low,int high);   
    //Encoders methods
    void setWnbLevel(int sliceId,int value);
    void setNrLevel(int sliceId,int value);
    void setApfLevel(int sliceId,int value);
    void setAnfLevel(int sliceId,int value);
    void setPanAverage(int panId,int value);
    void setRitFreq(int sliceId,int value);
    void setXitFreq(int sliceId,int value);
    void setPanFps(int panId,int value);
    void setRxFiltLow(int sliceId,int value);
    void setRxFiltShift(int sliceId,int value);
    void setWatBlackLevel(int watId,int value);
    void setRxFiltHigh(int sliceId,int value);
    void setRxFiltWidth(int sliceId,int value);
    void setWatGradientId(int watId,int value);
    void setAudioGain(int sliceId,int value);
    void setAudioPan(int sliceId,int value);
    void setWatLineDuration(int watId,int value);   
    void setWatColorGain(int watId,int value);   
    void setCwSpeed(int value);
    void setCwPitch(int value);
    void setCwBreakinInDelay(int value);
    void setCwMonitorGain(int value);
    void setCwMonitorPan(int value);   
    void setMicLevel(int value);
    void setSbMonitorGain(int value);
    void setCompanderLevel(int value);
    void setVoxLevel(int value);
    void setVoxDelay(int value);
    void setAmCarrier(int value);
    void setTransmitLow(int value);
    void setTransmitHigh(int value);
    void setPanBandwidth(int panId,float value);
    void setLineoutGain(int value);
    void setHeadphoneGain(int value);
    void setRfPower(int value);
    void setTunePower(int value);
    void setPanMinDbm(int panId,float value);
    void setPanMaxDbm(int panId,float value);   
    void setPanCenter(int panId,float value);   
    void setEqControl(String type,String freq,int value);
    void setMoxState(int value);
    void setTuneState(int value);
Photo of Steve - KD8QWT

Steve - KD8QWT

  • 74 Posts
  • 14 Reply Likes
Thanks Enzo.  I figured the Due board has enough power to do what I want just based on your controller.  I planned on heavily relying on your excellent libraries.

I actually bought 2 Due boards a month ago.  The second one is being used by my satellite rotator project.  I'm still Flexless as I'm waiting for the 6500 I traded up to, so I'm hoping to jump back into this in December.

73' Steve
Photo of Lee

Lee, Elmer

  • 677 Posts
  • 285 Reply Likes
Nice article!

73  W9OY
Photo of David Scobie

David Scobie

  • 18 Posts
  • 1 Reply Like
Hi Steve et al. 
I thought about things after all the helpful responses, and here is what I am hoping to "due".

I've ordered and just received my Arduino due.  I've also got http://shop.protoneer.co.nz/  the protoneer shield for the 4988s.  It has room for four pololu 4988 carriers. https://www.pololu.com/product/1182 

I believe I saw in your code you used a Big Easy, but IIUC there isn't' any difference WRT your code.  Since I want to control two loops, one on ANT1 and the other an ANT2, this multi GRBL style shield is dandy.  I also have wiznet shields, so I can get started right away.
If this all goes well, I might try getting a board(s) made up through oshpark or dirtypcbs. 

I've been asked by a friend to cad up another project in eagle and we are going to use an arduino  reflow-toaster to produce a run of the design, so we can potentially kill two stones with one bird.... yes it is probably unnecessary but I like to dream.

I've been thinking about how to get the SWR. 

From what Enzo said, the radio's delivery of the metering packets is around 10/sec. I hope this is sufficient compute the SWR on the fly.  I have a couple of bridges made up from Loftur's <TF3LJ> loop controller, so we can always compare the performance if needed.

I'd like to begin to test.  Any suggestions?

Dave
(Edited)
Photo of David Scobie

David Scobie

  • 18 Posts
  • 1 Reply Like
Hi Enzo!
I've managed to clear some other work out of the way and I have come back to the Flex-DUE project.
Perhaps you can help me sort out a few things...
I am able to poll the radio for various parameters!!! 
There is an odd behaviour.
Arduino IDE Version 1.6.7
Your Libraries Ver 1.5
I can only connect if the connect, if the Nickname and Callsign text boxes contain a maximum of 4 characters each.  Otherwise, I never get to the point where it returns "Connected"

I traced the interesting stanza to FlexRig.cpp Line 528.   
If I I let "i" be a larger value, (164 for example) I can get more on the same line, but execution seems to be unreliable ... which makes sense,
Here's a cut and paste of how it looks with the characters flex and VA3AE entered into the radio setup text boxes.
Thoughts?
73 de Dave
==========Flex Rig=============
IP Address:192.168.2.165
Model Name:FLEX-6500
Serial:0XXX-XXXX-6500-XXXX
Version:1.6.17.7
NickName:=flex callsign=VA3
connecting to Flex rig:192.168.2.165.
Connected
==VERSION (connect)==
1.2.0.0
==HANDLE (connect)==
E31E7A5D==>LISTENING FOR VITA49 PACKETS
C0|sub tx all
C1|sub atu all
C2|sub meter all
Photo of IW7DMH, Enzo

IW7DMH, Enzo

  • 353 Posts
  • 84 Reply Likes
...
If I I let "i" be a larger value, (164 for example) I can get more on the same line, but execution seems to be unreliable ... which makes sense,
...
It is a not the safe way to go over this issue. In this way you most probably write some bytes over the array limit and this exaplain the bad behaviour you have experienced int the next execution.
Data structures are defined in the FlexLib.h to store the maximun character number you can find in a UDP discovering packet.
See the lines from 72 to 75.
...
char modelName[36];      //Model Name
char serial[36];         //Serial Number
char nickName[36];       //Nick Name
char softVersion[32];    //Software Version
char handle[8];          //Handle assigned to the client
...

I suggest you to sniff the UDP discover packet using Wireshark or simply uncommenting some Serial.println( statements in the :findAFlex() method.

I suppose there is a difference in the starting offset I am using in the code because in my setup I have more than 4 characters in the NickName and Callign fields. 

Let me know.

73' Enzo
iw7dmh
Photo of David Scobie

David Scobie

  • 18 Posts
  • 1 Reply Like
Hi Enzo, I agree and I wasn't going to permanently change the offset there,  I might be pulling an important keystone out of your archway!

I just saw the line and confirmed by altering the offset that was where you were reading/putting data I was interested in.

Yes, Flexlib.h:72-75 was where I first looked, and I tried changing the length of the char variables and recompiling but i didn't' see any change or improvement, and I was a bit confused; then I started poking around further afield.

I have also twice tried to start fresh to make sure I hadn't inadvertently buggered something up.  I have removed/deleted all the libs and references, started with a clean untar of the libs and wrote a short test with FindaFlex.  As long as I keep the nickname and callsign variables under 8 characters total, I get the exact same repeatable behaviour. 
I am testing with these variables: (slightly formatted as it wan't pasting well in this page)
//Serial.println("=========================");
// Serial.print("The Transmit Antenna Port is: ");Serial.println(fRig.slice[i].txant);      
// Serial.print("The Receive Antenna Port is: ");Serial.println(fRig.slice[i].rxant);
// Serial.print("The S-Meter Reading is: ");
Serial.print(fRig.metersValue[MET_S_A]);Serial.println(" dBm");
//Serial.print("The Frequency is: ");Serial.println(fRig.slice[i].RF_frequency);
//Serial.print("The SWR is: ");Serial.println(fRig.metersValue[MET_SWR]);  
//Serial.println("=========================");

I also observe some random characters in the beginning/top of the output and sometimes with the data I'm retrieving.  I have one DUE and two wiznet51xx's which I have swapped to see if it was a hardware thing... it doesn't change with winet51xx's.  

<Tangent> I also have a few Teensy3.x, which I might even test as it could run your code for us, since it has the MK20DX256VLH7 Cortex-M4 32bit processor.  Less memory but some eeprom..... might work in my application, but probably not your remote head.
</Tangent> 

Could there be some subtle differences in the flexlib API 1.6.x?  I have been running that since it came out.
I'll set a couple of hours aside this week to delve into this a bit more.
Enzo, Thanks very much for your support in my tinkering,

Dave
Photo of IW7DMH, Enzo

IW7DMH, Enzo

  • 353 Posts
  • 84 Reply Likes
Ok Dave,

in my projects I have used only original Arduino Ethernet shield. Using wiznet shield caused me only headcaches.
Going back to the issue I suggest you to sniff the UDP packet using Wireshark.
Other friends are using the 6500 and the 1.6 with no problems at all.

Enzo
Photo of David Scobie

David Scobie

  • 18 Posts
  • 1 Reply Like
I wanted to mention that the method for tuning the antenna is evolving.

At this time, I am writing a routine that is an initial calibration setup.
It measures and adjusts the antenna for best SWR at as many frequencies as is reasonable in each band/antenna combination, The defaults, such as Radio Serial #, TX_antenna for upper lower ranges,  values get entered in a config.h

The DUE tests and records those TX_ANTx/Frequency/stepper-count values in a lookup table.
Next, when I change frequency and request the radio to TUNE, the DUE gets the frequency and TX_ANTx, drives the stepper to that previously recorded value, and confirms with the radio that we are using the correct transmit antenna. 
Then I invoke tf3lj/Loftur's proven method "find_best_swr"
//-----------------------------------------------------------------------------------------//
Find Best SWR - by sampling, summing and squaring a number of SWR values and comparing with a previous similar sum-square, advancing one sample at a time. once this sum-square value is larger than the previous one, and midpoint SWR (SWR value measured at sample_buffer_size/2 samples earlier) is at an acceptable level, then return TRUE, else return FALSE 
Relies on sample[] being seeded with 999 values before initial SWR search.
//-----------------------------------------------------------------------------------------//
The new value is for that TX_ANTx/Frequency/stepper-count is updated in the lookup table.   If the Frequency is not in a band I can transmit on, I will do a best guess or perhaps elect to use my Flexcontrol Knob to manually drive the steppers... haven't decided on the manual control other than in the serial console program yet.

It is initially for my loops, but I see dong this for screwdriver antennas and even a long-wire tuner, or other exotic things....

Hope this helps,
Dave