Um für meine SDR Anlage insbesondere den Empfang von Langwellen zu ermöglichen, ist die Idee entstanden eine drehbare Multibandantenne zu konstruieren. Da der Platz unter dem Garagendach begrenzt ist, habe ich mich für eine magnetische loop Antenne entschieden.
Die Rahmenantenne hat eine Diagonale von 50cm. Das Funktionsprinzip der Antenne beruht darauf die Drahtwicklungen mit einem Drehkondensator abzugleichen, und dann mit einer einzigen Windung das Signal auszukoppeln. Die Windungen der Spule werden mit 0,6 mm Kupferlackdraht und die Auskoppelwindung mit einfachem Klingeldraht ausgeführt. Das Bild unten zeigt den Schaltplan schematisch.
Mit Hilfe zweier Schaltrelais lassen sich mehrere Windungen kombinieren, so dass Empfang von Kurz-, Mittel- und Langwelle möglich ist. Dem Drehkondensator kann ein weiterer, fester Kondensator mit einem dritten Relais parallel geschaltet werden, um so innerhalb einen Bandes das obere bzw untere Frequenzband erreichen zu können.
Die Berechnungen mit dem Magnet-Loopantennenrechner von DG0KW seien hier exemplarisch für Mittelwelle vorgestellt. Bei 10 Windungen und der oberen Bandgrenze von 1,5MHz reicht die Eigenkapazität der Antenne als Kondensator.
Um die untere Bandgrenze bei 0,5MHz zu erreichen muss ein Kondensator von ~500pF parallel zum 500pF Drehko geschaltet werden
Das nächste Bild zeigt die Antenne von hinten. Im unteren Teil sind die drei bereits beschriebenen Relais, die das Umschalten zwischen Lang-, Mittel-, und Kurzwelle sowie zwischen High- und Lowband ermöglichen zu sehen. Ein Schrittmotor dreht den 500pF VariCap. Auch der dazugehörige Motortreiber wurde auf die Rückseite montiert.
Die Antenne ist drehbar gelagert, und kann mit einem weiteren Schrittmotor über einen Kettenriemen um bis zu 90° gedreht werden. Ein Messingrohr dient als mechanischer Anschlag und zugleich als Schaltkontakt um die Nullposition der Antenne erkennen zu können.
Im montierten Zustand sieht das Ganze dann so aus.
Angesteuert wird die Antenne über ein Phyton Script das auf dem Rasperberry der SDR Anlage läuft. Nach Aufruf des Programms wird zunächst sowohl der VariCap als auch die Antenne selbst in ihre Ausgangsposition gefahren. Die Schrittweite lässt sich im jeweiligen Eingabefeld einstellen, und durch Drücken auf die entsprechende Schaltfläche lassen sich die Kapazität bzw die Drehposition vergrößern oder verkleinern.
Die Verbindung zur GPIO Kontaktleiste des Raspberry erfolgt über zwei 8-polige Telefonkabel mit folgender Farbkodierung.
Abschließend sei noch das PythonScript zur Antennenkontrolle gezeigt. Viel Spaß damit...
#Note: Runs with phyton3 only
#!/usr/bin/python
import sys
import time
import RPi.GPIO as GPIO
from tkinter import *
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
#define settings for Relais
GPIO.setup(3,GPIO.OUT) #Relais 1 for KW/MW/LW band switch
GPIO.setup(5,GPIO.OUT) #Relais 2 for KW/MW/LW band switch
GPIO.setup(7,GPIO.OUT) #Relais 3 for Low/High band switch
#define settings of GUI
window = Tk()
window.title("Antenna Control Panel")
# define global variable for last VariCap motor step
VariCapSeqPos=0
# define global variable for last Antenna motor step
AntennaSeqPos=0
# define global variable for current capacitance of VariCap
TotalCapa=0
# define global variable of antenna position
AntennaPos=0
# Reminder to Reset VariCap and Antenna at start of Program in case of no auto reset
# ResetRemind_label = Label(window, text="Please reset Varicap and Antenna before start...", foreground="red")
ResetRemind_label = Label(window, text="")
#define Reset Vari Cap button
def ResetVariCap():
global VariCapSeqPos
#run stepper full speed >540pF counter clock wise until stop signal (pin16) appears
VariCapSeqPos=MotorVariCap(1, 550, -1, VariCapSeqPos)
global TotalCapa
TotalCapa=0
TotalCapa_label.config(text="Total Capa 0 pF", foreground="black" )
ResetRemind_label.config(text="")
ResetVariCap_button = Button(window, text="Reset VariCap", foreground="black", command=lambda: ResetVariCap())
#define Reset Antenna Rotation button
def ResetAntenna():
global AntennaSeqPos
#run stepper full speed >90 deg counter clock wise until stop signal (pin29) appears
AntennaSeqPos=MotorAntenna(2, 95, -1, AntennaSeqPos)
global AntennaPos
AntennaPos=0
AntennaPos_label.config(text="Antenna Position 0 deg", foreground="black" )
ResetRemind_label.config(text="")
ResetAntennaRot_button = Button(window, text="Reset Antenna Rotation", foreground="black", command=lambda: ResetAntenna() )
#define KW/MW/LW switch
def setLW():
GPIO.output(3, False)
GPIO.output(5, False)
def setMW():
GPIO.output(3, False)
GPIO.output(5, True)
def setKW():
GPIO.output(3, True)
GPIO.output(5, False)
i = IntVar() #Link Radiobutton With The Variable=i.
i.set(3) #'LW' is default value
setLW
# Disconnect coil 2 and 3 for 'KW'
KW_radiobutton = Radiobutton(window, text="KW", value=1, variable=i, command=setKW)
# Disconnect coil 3 for 'MW'
MW_radiobutton = Radiobutton(window, text="MW", value=2, variable=i, command=setMW)
# Use all coils for 'LW'
LW_radiobutton = Radiobutton(window, text="LW", value=3, variable=i, command=setLW)
#define HighBand/LowBand switch
j = IntVar() #Link Radiobutton With The Variable=j.
j.set(1) # 'Low Band' is default value
GPIO.output(7, True)
#Low Band, pin7 (Relais 3) on, additional Capa parallel to VariCap
LowBand_radiobutton = Radiobutton(window, text="Low Band", foreground="black", value=1, variable=j, command=lambda: GPIO.output(7, True))
#High Band, pin7 (Relais 3) off, no additional Capa
HighBand_radiobutton = Radiobutton(window, text="High Band", foreground="black", value=2, variable=j, command=lambda: GPIO.output(7, False))
# Define capa input box
ChangeCapa_label = Label(window, text="Change Capa by (pF) ", foreground="black" )
CapaInputBox = Entry(window, bd=5, width=10)
TotalCapa_label = Label(window)
def ChangeCapaUp_action():
entry_text = CapaInputBox.get()
if entry_text.isdigit():
entry=int(entry_text)
#global TotalCapa
#TotalCapa += entry
#move motor slowly clock wise
global VariCapSeqPos
VariCapSeqPos=MotorVariCap(7, entry, 1, VariCapSeqPos)
TotalCapa_label.config(text="Total Capa " + str(round(TotalCapa)) + " pF", foreground="black")
def ChangeCapaDown_action():
entry_text = CapaInputBox.get()
if entry_text.isdigit():
entry=int(entry_text)
#move motor slowly clock wise
global VariCapSeqPos
VariCapSeqPos=MotorVariCap(7, entry, -1, VariCapSeqPos)
#global TotalCapa
#TotalCapa -= entry
TotalCapa_label.config(text="Total Capa " + str(round(TotalCapa)) + " pF", foreground="black")
# Define CapaChangeUp button
CapaChangeUp_button = Button(window, text="Up", foreground="black", command=ChangeCapaUp_action)
# Define CapaChangeDown button
CapaChangeDown_button = Button(window, text="Down", foreground="black", command=ChangeCapaDown_action)
# Define AntennaRot input box
AntennaRot_label = Label(window, text="Rotate Antenna by (deg) ", foreground="black")
AntennaInputBox = Entry(window, bd=5, width=10)
AntennaPos_label = Label(window)
def ChangeAntennaUp_action():
entry_text = AntennaInputBox.get()
if entry_text.isdigit():
entry=int(entry_text)
#move motor slowly clock wise
global AntennaSeqPos
AntennaSeqPos=MotorAntenna(7, entry, 1, AntennaSeqPos)
AntennaPos_label.config(text="Antenna Position " + str(round(AntennaPos)) + " deg", foreground="black")
def ChangeAntennaDown_action():
entry_text = AntennaInputBox.get()
if entry_text.isdigit():
entry=int(entry_text)
#move motor slowly clock wise
global AntennaSeqPos
AntennaSeqPos=MotorAntenna(7, entry, -1, AntennaSeqPos)
AntennaPos_label.config(text="Antenna Position " + str(round(AntennaPos)) + " deg", foreground="black")
# Define AntennaChangeUp button
AntennaChangeUp_button = Button(window, text="Up", foreground="black", command=ChangeAntennaUp_action)
# Define AntennaChangeDown button
AntennaChangeDown_button = Button(window, text="Down", foreground="black", command=ChangeAntennaDown_action)#
# Define 'Exit' button
Exit_button = Button(window, text="Quit", foreground="black", command=window.quit)
# Arrange components in window
ResetRemind_label.grid(sticky="W", row=0, column=0)
ResetVariCap_button.grid(sticky="W", row=1, column =0)
ResetAntennaRot_button.grid(sticky="W", row=1, column =1)
KW_radiobutton.grid(sticky="W", row=2, column =0)
MW_radiobutton.grid(sticky="W", row=2, column=1)
LW_radiobutton.grid(sticky="W", row=2, column=3)
HighBand_radiobutton.grid(sticky="W", row=3, column =0)
LowBand_radiobutton.grid(sticky="W", row=3, column=1)
ChangeCapa_label.grid(sticky="W", row = 4, column = 0)
CapaInputBox.grid(sticky="W", row = 4, column = 1)
CapaChangeUp_button.grid(sticky="W", row = 4, column = 2)
CapaChangeDown_button.grid(sticky="W", row = 4, column = 3)
TotalCapa_label.grid(sticky="W", row = 5, column = 0, columnspan = 2)
AntennaRot_label.grid(sticky="W", row = 6, column = 0)
AntennaInputBox.grid(sticky="W", row = 6, column = 1)
AntennaChangeUp_button.grid(sticky="W", row = 6, column = 2)
AntennaChangeDown_button.grid(sticky="W", row = 6, column = 3)
AntennaPos_label.grid(sticky="W", row = 7, column = 0, columnspan = 3)
Exit_button.grid(sticky="W", row = 8, column = 4)
#define settings for VariCap StepperMotor
aVariCapMotorPins = [12, 15, 11, 13]
# Set all pins as output
for pin in aVariCapMotorPins:
GPIO.setup(pin,GPIO.OUT)
GPIO.output(pin, False)
#switch 16 against GND on VariCap
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)
#define settings for Antenna Motor
aAntennaMotorPins = [31, 33, 35, 37]
# Set all pins as output
for pin in aAntennaMotorPins:
GPIO.setup(pin,GPIO.OUT)
GPIO.output(pin, False)
#switch 29 against GND on Antenna
GPIO.setup(29, GPIO.IN, pull_up_down = GPIO.PUD_UP)
aSequence = [
[1,0,0,1],
[1,0,0,0],
[1,1,0,0],
[0,1,0,0],
[0,1,1,0],
[0,0,1,0],
[0,0,1,1],
[0,0,0,1]
]
def MotorVariCap(speed, cap, iDirection, start):
global TotalCapa
global aSequence
global aVariCapMotorPins
iNumSteps = len(aSequence)
#waiting time in between steps
fWaitTime = int(speed) / float(1000)
# 1024 steps is 90 degrees, 5416 steps is max capa of 540pF
iSteps = int(int(cap) * 10.0293411)
# motor starts at a specific position from the aSequence list
iVariCapSeqPos = int(start)
for step in range(0,iSteps):
if GPIO.input(16) == GPIO.LOW and iDirection == -1:
break
if TotalCapa > 540:
TotalCapa = 540
break
for iPin in range(0, 4):
iRealPin = aVariCapMotorPins[iPin]
if aSequence[iVariCapSeqPos][iPin] != 0:
GPIO.output(iRealPin, True)
else:
GPIO.output(iRealPin, False)
iVariCapSeqPos += iDirection
if (iVariCapSeqPos >= iNumSteps):
iVariCapSeqPos = 0
if (iVariCapSeqPos < 0):
iVariCapSeqPos = iNumSteps + iDirection
# Adjust TotalCapa
if iDirection == 1:
TotalCapa += (cap/iSteps)
else:
TotalCapa -= (cap/iSteps)
# wait
time.sleep(fWaitTime)
for pin in aVariCapMotorPins:
GPIO.output(pin, False)
# Return the position from the aSequence list which should have been the
# next position, if the previous loop was not ended
return (iVariCapSeqPos)
def MotorAntenna(speed, deg, iDirection, start):
global AntennaPos
global aSequence
global aAntennaMotorPins
iNumSteps = len(aSequence)
#waiting time in between steps
fWaitTime = int(speed) / float(1000)
# 1024 steps is 90 degrees of motor, 225 degrees of motor is 90 degrees of Antenna, 16/40
iSteps = int(int(deg) * 28.4444444444)
# motor starts at a specific position from the aSequence list
iAntennaSeqPos = int(start)
for step in range(0,iSteps):
if GPIO.input(29) == GPIO.LOW and iDirection == -1:
break
if AntennaPos > 90:
AntennaPos = 90
break
for iPin in range(0, 4):
iRealPin = aAntennaMotorPins[iPin]
if aSequence[iAntennaSeqPos][iPin] != 0:
GPIO.output(iRealPin, True)
else:
GPIO.output(iRealPin, False)
iAntennaSeqPos += iDirection
if (iAntennaSeqPos >= iNumSteps):
iAntennaSeqPos = 0
if (iAntennaSeqPos < 0):
iAntennaSeqPos = iNumSteps + iDirection
# Adjust TotalCapa
if iDirection == 1:
AntennaPos += (deg/iSteps)
else:
AntennaPos -= (deg/iSteps)
# wait
time.sleep(fWaitTime)
for pin in aAntennaMotorPins:
GPIO.output(pin, False)
# Return the position from the aSequence list which should have been the
# next position, if the previous loop was not ended
return (iAntennaSeqPos)
ResetRemind_label.config(text="Resetting VariCap...", foreground="red")
ResetVariCap()
ResetRemind_label.config(text="Resetting Antenna...", foreground="red")
ResetAntenna()
ResetRemind_label.config(text="")
mainloop()
Keine Kommentare:
Kommentar veröffentlichen