This commit is contained in:
Chris Lewandowski 2017-01-12 20:43:47 +00:00 committed by GitHub
commit 6196c241fa
7 changed files with 788 additions and 54 deletions

View File

@ -1,15 +1,22 @@
rtlsdr-automated-wxsat-capture
==============================
This is an old script, please check new autowx which has been rewritten and performs better. Thanks!
==============================
This is a fork of dr. Paul Brewer awesome program.
Automate Recording of Low Earth Orbit NOAA Weather Satellites
These are some automation scripts I am developing in python for weather satellite hobbyist use.
These are some automation scripts dr. Paul Brewer done in python for weather satellite hobbyist use.
I just added few options adapted it to recent tools.
License: GPLv2 or any later version
assumptions: Linux-based computer, rtl-sdr usb dongle, stationary antenna, experienced python user
goal: record wav files for later processing
goal: record wav files for later processing, postprocess wav file and generate image
prerequistes: working rtl-sdr, predict (text based, not gpredict) setup with correct ground station coordinates, sox
@ -17,25 +24,75 @@ NO WARRANTY: ALL USE IS AT THE RISK OF THE USER. These are scripts I use for h
be pre-requisites or system configuration differences which you will need to resolve in order to make use of these scripts in your project. To do so requires patience and and, quite often, previous experience programming python
and/or maintaining Linux-based rtl-sdr software.
This program also uses software which has no clear licensing information (wx).
##FILES
###LICENSE
General Public License version 2.0, or any later version
###dotpredict-predict.tle
Modification of PREDICT's TLE file to provide orbit data for weather satellites NOAA-18,NOAA-19
to get coverage of missing satellites into predict's default config
###BASIC usage info
You'll need to install predict and wxtoimg packages. For installing predict please follow your distro instructions: for example in Debian:
```
sudo apt-get install predict
```
or in openSuSE:
```
sudo zypper in predict
```
or use package manager provided with your distro.
As for wxtoimg I strongly recomment grabbing .tar.gz package and unpacking it to your /usr/local/ dir. Packages are provided on wxtoimg website.
Next step is to dry-run predict - it should create files which you'll need to replace, edit location info (used in wxmap), and run update-kepplers.sh. More info below.
###predict TLEs
These are in tles/ folder - modification of PREDICT's files to provide orbit data for weather satellites NOAA-15, NOAA-18, NOAA-19 to get coverage of missing satellites into predict's default config. Please edit qth to reflect your station position.
Example values are provided.
Copy as follows:
```
mv dotpredict-predict.tle ~/.predict/predict.tle
```
cp tles/predict.qth ~/.predict/predict.qth
cp tles/predict.tle ~/.predict/predict.tle
cp tles/predict.db ~/.predict/predict.db
```
edit qth:
```
nano ~/.predict/predict.qth
```
or run predict, press G to change Ground Station Location.
###noaacapture.py
This is the main python script. It will calculate the time
of the next pass for recording. It expects to call rtl_fm to do the
recording and sox to convert the file to .wav
recording and sox to convert the file to .wav. It can create spectrogram of the pass using sox (not the RTL_POWER!).
Station options are read from qth file now.
####A few words about the options.
* satellites - this is a list of satellites you want to capture, this needs to be the same name as in TLE file.
* freqs - frequencies of centre of the APT signal.
* dongleGain - set this to the desired gain of the dongle, leave "0" if you want AGC.
* dongleShift - set this to the dongle PPM shift, can be negative.
* dongleIndex - set this to the index of your dongle, of you have only one - leave it unchanged.
* sample - "sample rate", option "-s" for rtl_fm - this is the width of the recorded signal. Please keep in mind that APT is 34kHz but you should include few kHz for doppler shift. This will change when the doppler tool is used.
* wavrate - sample rate of the WAV file used to generate JPEGs. Should be 11025.
####Directories: directories used for misc. files
* recdir - this is a directory containing RAW and WAV files.
* specdir - this is a directory holding spectrogram files created from the pass (PNG).
* imgdir - where to put output JPG images.
* mapDir - directory for autogenerated maps (these are generated using wxmap using values from predict.qth).
####Misc options, not all are used right now
* wxAddOverlay - whether create overlay maps on all pictures. It slows down image generation.
* wxEnhHVC - should program do HVC image. Possible values are "yes", "y" and "1" for YES, any other value will not create HVC image.
* wxEnhHVCT - should program do HVCT image. Possible values are "yes", "y" and "1" for YES, any other value will not create HVCT image.
* createSpectro - should program create spectrogram files for the pass? Useful for debugging images. Possible values are "yes", "y" and "1" for YES, any other value will not create spectro.
* runDoppler - should we do the doppler shift using "doppler" tool? Not needed for wxtoimg as it seems it does the correction itself.
###pypredict.py
This is a short python module for extracting the AOS/LOS times

View File

@ -1,11 +1,163 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import datetime
from time import gmtime, strftime
import pypredict
import subprocess
import os
import re
satellites = ['NOAA-18','NOAA-19','NOAA-15']
freqs = [137912500, 137100000, 137620000]
sample = '44100'
##
## Config header, sorry
## TODO: Better config system
##
# Satellite names in TLE plus their frequency
satellites = ['NOAA 18','NOAA 15','NOAA 19']
freqs = [137912500, 137620000, 137100000]
# Dongle gain
dongleGain='48.0'
#
# Dongle PPM shift, hopefully this will change to reflect different PPM on freq
dongleShift='53'
#
# Dongle index, is there any rtl_fm allowing passing serial of dongle? Unused right now
dongleIndex='0'
#
# Sample rate, width of recorded signal - should include few kHz for doppler shift
sample ='44100'
sampleMeteor='200000'
# Sample rate of the wav file. Shouldn't be changed
wavrate='11025'
#
# Should I remove RAWs after transcoding?
removeRAW='yes'
# Directories used in this program
# wxtoimg install dir
wxInstallDir='/usr/local/bin'
# Recording dir, used for RAW and WAV files
#
recdir='/opt/wxsat/rec'
#
# Spectrogram directory, this would be optional in the future
#
specdir='/opt/wxsat/spectro'
#
# Output image directory
#
imgdir='/opt/wxsat/img'
#
# Map file directory
#
mapDir='/opt/wxsat/maps'
# Options for wxtoimg
# Create map overlay?
wxAddOverlay='yes'
# Image outputs
wxEnhHVC='no'
wxEnhHVCT='no'
wxEnhMSA='no'
wxEnhMCIR='yes'
# Other tunables
# Turning it off creates empty logs...
wxQuietOutput='no'
# Decode all despite low signal?
wxDecodeAll='yes'
# JPEG quality
wxJPEGQuality='75'
# Adding overlay text
wxAddTextOverlay='no'
wxOverlayText='autowxsat'
# Overlay offset - wxtoimg
# Negative value - push LEFT/UP
# Positive value - push RIGHT/DOWN
wxOverlayOffsetX='0'
wxOverlayOffsetY='0'
#
# Various options
# Should this script create spectrogram : yes/no
createSpectro='yes'
# Use doppler shift for correction, not used right now - leave as is
runDoppler='no'
# Minimum elevation
minElev='9'
##
# SCP Config, works best with key authorization
#
SCP_USER='SCP_USER'
SCP_HOST='SCP_HOST'
SCP_DIR='SCP_DIR'
# Send LOG with imagefile?
LOG_SCP='n'
# Send image to remote server?
IMG_SCP='n'
###############################
### ##
### Here be dragons. ##
### ##
###############################
# Read qth file for station data
stationFileDir=os.path.expanduser('~')
stationFilex=stationFileDir+'/.predict/predict.qth'
stationFile=open(stationFilex, 'r')
stationData=stationFile.readlines()
stationName=str(stationData[0]).rstrip().strip()
stationLat=str(stationData[1]).rstrip().strip()
stationLon=str(stationData[2]).rstrip().strip()
stationAlt=str(stationData[3]).rstrip().strip()
stationFile.close()
stationLonNeg=float(stationLon)*-1
##
## Color output declarations
##
class bcolors:
HEADER = '\033[95m'
CYAN = '\033[96m'
YELLOW = '\033[93m'
RED = '\033[91m'
OKBLUE = '\033[94m'
OKGREEN = '\033[97m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
GRAY = '\033[37m'
UNDERLINE = '\033[4m'
logLineStart=bcolors.BOLD+bcolors.HEADER+"***>\t"+bcolors.ENDC+bcolors.OKGREEN
logLineEnd=bcolors.ENDC
##
## Other stuff
##
if wxQuietOutput in ('yes', 'y', '1'):
wxQuietOpt='-q'
else:
wxQuietOpt='-C wxQuiet:no'
if wxDecodeAll in ('yes', 'y', '1'):
wxDecodeOpt='-A'
else:
wxDecodeOpt='-C wxDecodeAll:no'
if wxAddTextOverlay in ('yes', 'y', '1'):
wxAddText='-k '+wxOverlayText
else:
wxAddText='-C wxOther:noOverlay'
##
## Execution loop declaration
##
def runForDuration(cmdline, duration):
try:
@ -16,33 +168,308 @@ def runForDuration(cmdline, duration):
print "OS Error during command: "+" ".join(cmdline)
print "OS Error: "+e.strerror
def recordFM(freq, fname, duration):
# still experimenting with options - unsure as to best settings
##
## FM Recorder definition
##
def recordFM(freq, fname, duration, xfname):
print bcolors.GRAY
xfNoSpace=xfname.replace(" ","")
cmdline = ['rtl_fm',\
'-f',str(freq),\
'-s',sample,\
'-g','43',\
'-F','9',\
'-A','fast',\
'-E','dc',\
fname+'.raw']
'-f',str(freq),\
'-s',sample,\
'-g',dongleGain,\
'-F','9',\
'-A','fast',\
'-E','dc',\
'-E','offset',\
'-p',dongleShift,\
recdir+'/'+xfNoSpace+'-'+fname+'.raw' ]
runForDuration(cmdline, duration)
##
## Recorder with doppler shift correction.
## Absolutely TODO!
##
def recordDOP(freq, fname, duration, xfname):
xfNoSpace=xfname.replace(" ","")
cmdline = ['iqrecord.sh', \
'-f', str(freq), \
'-s', str('1024000'), \
'-g', dongleGain, \
'-p', dongleShift, \
# '-m', stationFileDir+'/.predict/predict.tle', \
'-m', '/tmp/weather.txt', \
'-r', xfname, \
'-T', stationLat, \
'-L', str(stationLonNeg), \
'-A', stationAlt, \
'-d', wavrate, \
'-z', recdir+'/'+xfNoSpace+'-'+fname+'.wav']
runForDuration(cmdline, duration)
##
## TODO: Meteor M2 tests, no luck
##
def recordMETEOR(freq, fname, duration, xfname):
xfNoSpace=xfname.replace(" ","")
cmdline = ['rtl_fm',\
'-f',str(freq),\
'-s',sampleMeteor,\
'-g',dongleGain,\
'-F','9',\
'-A','fast',\
'-E','dc',\
'-E','offset',\
'-p',dongleShift,\
recdir+'/'+xfNoSpace+'-'+fname+'.raw' ]
runForDuration(cmdline, duration)
##
## Status builder. Crazy shit.
##
def writeStatus(freq, aosTime, losTime, losTimeUnix, recordTime, xfName, maxElev, status):
statFile=open('/tmp/rec_info', 'w+')
if status in ('RECORDING'):
statFile.write("ODBIOR;tak;"+str(xfName)+' AOS@'+str(aosTime)+' LOS@'+str(losTime)+' REC@'+str(recordTime)+'s. max el.@'+str(maxElev)+'°')
elif status in ('DECODING'):
statFile.write('ODBIOR;nie;Dekodowanie '+str(xfName))
elif status in ('WAITING'):
statFile.write('ODBIOR;nie;'+str(xfName)+' (AOS@'+str(aosTime)+') @'+str(maxElev)+'° elev. max')
elif status in ('TOOLOW'):
statFile.write('ODBIOR;nie;'+str(xfName)+' (AOS@'+str(aosTime)+') zbyt nisko ('+str(maxElev)+'°), czekam '+str(recordTime)+'s.')
statFile.close
##
## Transcoding module
##
def transcode(fname):
cmdline = ['sox','-t','raw','-r',sample,'-es','-b','16','-c','1','-V1',fname+'.raw',fname+'.wav','rate',wavrate]
xfNoSpace=xfname.replace(" ","")
print logLineStart+'Transcoding...'+bcolors.YELLOW
cmdline = ['sox','-t','raw','-r',sample,'-es','-b','16','-c','1','-V1',recdir+'/'+xfNoSpace+'-'+fname+'.raw',recdir+'/'+xfNoSpace+'-'+fname+'.wav','rate',wavrate]
subprocess.call(cmdline)
if removeRAW in ('yes', 'y', '1'):
print logLineStart+bcolors.ENDC+bcolors.RED+'Removing RAW data'+logLineEnd
os.remove(recdir+'/'+xfNoSpace+'-'+fname+'.raw')
##
## Doppler calculation
##
def doppler(fname,emergeTime):
cmdline = ['doppler',
'-d','',\
'--tlefile', '~/.predict/predict.tle',\
'--tlename', xfname,\
'--location', 'lat='+stationLat+',lon='+stationLon+',alt='+stationAlt,\
'--freq ', +str(freq),\
'-i', 'i16',\
'-s', sample ]
subprocess.call(cmdline)
def decode(fname):
cmdline = ['/root/atpdec-1.7/atpdec',fname+'.wav']
##
## Overlay map creator, still buggy
## TODO: ?
##
def createoverlay(fname,aosTime,satName):
print logLineStart+'Creating Map Overlay...'+logLineEnd
aosTimeO=int(aosTime)+int('20')
cmdline = ['wxmap',
'-T',satName,\
'-G',stationFileDir+'/.predict/',\
'-H','predict.tle',\
'-M','0',\
'-o', \
'-L',stationLat+'/'+str(stationLonNeg)+'/'+stationAlt,\
str(aosTimeO), mapDir+'/'+str(fname)+'-map.png']
#print cmdline
overlay_log = open(mapDir+'/'+str(fname)+'-map.png.txt',"w+")
subprocess.call(cmdline, stderr=overlay_log, stdout=overlay_log)
overlay_log.close()
# for line in open(mapDir+'/'+str(fname)+'-map.png.txt',"r").readlines():
# res=line.replace("\n", "")
# res2=re.sub(r"(\d)", r"\033[96m\1\033[94m", res)
# print logLineStart+bcolors.OKBLUE+res2+logLineEnd
##
## Various NOAA picture decoders
## This uses wxtoimg and predict (too!), so these need to be running well!!
##
def decode(fname,aosTime,satName,maxElev):
xfNoSpace=xfname.replace(" ","")
satTimestamp = int(fname)
fileNameC = datetime.datetime.fromtimestamp(satTimestamp).strftime('%Y%m%d-%H%M')
if wxAddOverlay in ('yes', 'y', '1'):
print logLineStart+bcolors.OKBLUE+'Creating overlay map'+logLineEnd
createoverlay(fname,aosTime,satName)
print logLineStart+'Creating basic image with overlay map'+logLineEnd
m = open(imgdir+'/'+satName+'/'+fileNameC+'-normal-map.jpg.txt',"w+")
### header
m.write('\nSAT: '+str(xfNoSpace)+', Elevation max: '+str(maxElev)+', Date: '+str(fname)+'\n')
##
## Copy file contents
##
for psikus in open(mapDir+'/'+str(fname)+'-map.png.txt',"r").readlines():
res=psikus.replace("\n", " \n")
m.write(res)
cmdline = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-t','NOAA','-Q '+wxJPEGQuality,recdir+'/'+xfNoSpace+'-'+fname+'.wav',imgdir+'/'+satName+'/'+fileNameC+'-normal-map.jpg']
# print cmdline
subprocess.call(cmdline, stderr=m, stdout=m)
# m.write('\nMax elevation was: '+str(maxElev)+'\n')
m.close()
for line in open(imgdir+'/'+satName+'/'+fileNameC+'-normal-map.jpg.txt',"r").readlines():
res=line.replace("\n", "")
res2=re.sub(r"(\d)", r"\033[96m\1\033[94m", res)
print logLineStart+bcolors.OKBLUE+res2+logLineEnd
if wxEnhHVC in ('yes', 'y', '1'):
print 'Creating HVC image'
hvc_log = open(imgdir+'/'+satName+'/'+fileNameC+'-hvc-map.jpg.txt',"w+")
hvc_log.write('\nHVC SAT: '+str(xfNoSpace)+', Elevation max: '+str(maxElev)+', Date: '+str(fname)+'\n')
cmdline_hvc = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-K','-o','-R1','-Q '+wxJPEGQuality,'-e','HVC','-m',mapDir+'/'+fname+'-map.png,'+wxOverlayOffetX+','+wxOverlayOffsetY,recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-hvc-map.jpg']
subprocess.call(cmdline_hvc, stderr=hvc_log, stdout=hvc_log)
if LOG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending HVC flight and decode logs..."+bcolors.YELLOW
for psikus in open(mapDir+'/'+str(fname)+'-map.png.txt',"r").readlines():
res=psikus.replace("\n", " \n")
hvc_log.write(res)
cmdline_scp_log = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-hvc-map.jpg.txt',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-hvc-map.jpg.txt' ]
subprocess.call(cmdline_scp_log)
if IMG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending HVC image with overlay map... "+bcolors.YELLOW
cmdline_scp_img = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-hvc-map.jpg',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-hvc-map.jpg' ]
subprocess.call(cmdline_scp_img)
print logLineStart+"Wysłano, przechodzę dalej"+logLineEnd
if wxEnhHVCT in ('yes', 'y', '1'):
print logLineStart+'Creating HVCT image'+logLineEnd
cmdline_hvct = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','HVCT','-m',mapDir+'/'+fname+'-map.png',recdir+'/'+xfNoSpace+'-'+fname+'.wav',imgdir+'/'+satName+'/'+fileNameC+'-hvct.jpg']
subprocess.call(cmdline_hvct)
if wxEnhMSA in ('yes', 'y', '1'):
print logLineStart+'Creating MSA image'+logLineEnd
msa_log = open(imgdir+'/'+satName+'/'+fileNameC+'-msa-map.jpg.txt',"w+")
msa_log.write('\nMSA SAT: '+str(xfNoSpace)+', Elevation max: '+str(maxElev)+', Date: '+str(fname)+'\n')
cmdline_msa = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','MSA','-m',mapDir+'/'+fname+'-map.png,'+wxOverlayOffsetX+','+wxOverlayOffsetY,recdir+'/'+xfNoSpace+'-'+fname+'.wav',imgdir+'/'+satName+'/'+fileNameC+'-msa-map.jpg']
subprocess.call(cmdline_msa, stderr=msa_log, stdout=msa_log)
if LOG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending MSA flight and decode logs..."+bcolors.YELLOW
for psikus in open(mapDir+'/'+str(fname)+'-map.png.txt',"r").readlines():
res=psikus.replace("\n", " \n")
msa_log.write(res)
cmdline_scp_log = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-msa-map.jpg.txt',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-msa-map.jpg.txt' ]
subprocess.call(cmdline_scp_log)
if IMG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending MSA image with overlay map... "+bcolors.YELLOW
cmdline_scp_img = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-msa-map.jpg',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-msa-map.jpg' ]
subprocess.call(cmdline_scp_img)
print logLineStart+"Wysłano, przechodzę dalej"+logLineEnd
if wxEnhMCIR in ('yes', 'y', '1'):
print logLineStart+'Creating MCIR image'+logLineEnd
mcir_log = open(imgdir+'/'+satName+'/'+fileNameC+'-mcir-map.jpg.txt',"w+")
mcir_log.write('\nMCIR SAT: '+str(xfNoSpace)+', Elevation max: '+str(maxElev)+', Date: '+str(fname)+'\n')
cmdline_mcir = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','MCIR','-m',mapDir+'/'+fname+'-map.png,'+wxOverlayOffsetX+','+wxOverlayOffsetY,recdir+'/'+xfNoSpace+'-'+fname+'.wav',imgdir+'/'+satName+'/'+fileNameC+'-mcir-map.jpg']
subprocess.call(cmdline_mcir, stderr=mcir_log, stdout=mcir_log)
if LOG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending MCIR flight and decode logs..."+bcolors.YELLOW
for psikus in open(mapDir+'/'+str(fname)+'-map.png.txt',"r").readlines():
res=psikus.replace("\n", " \n")
mcir_log.write(res)
cmdline_scp_log = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-mcir-map.jpg.txt',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-mcir-map.jpg.txt' ]
subprocess.call(cmdline_scp_log)
if IMG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending MCIR image with overlay map... "+bcolors.YELLOW
cmdline_scp_img = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-mcir-map.jpg',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-mcir-map.jpg' ]
subprocess.call(cmdline_scp_img)
print logLineStart+"Wysłano, przechodzę dalej"+logLineEnd
if LOG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending flight and decode logs..."+bcolors.YELLOW
cmdline_scp_log = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-normal-map.jpg.txt',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-normal-map.jpg.txt' ]
subprocess.call(cmdline_scp_log)
if IMG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending base image with map: "+bcolors.YELLOW
cmdline_scp_img = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-normal-map.jpg',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-normal-map.jpg' ]
subprocess.call(cmdline_scp_img)
print logLineStart+"Sending OK, go on..."+logLineEnd
else:
print logLineStart+'Creating basic image without map'+logLineEnd
r = open(imgdir+'/'+satName+'/'+fileNameC+'-normal.jpg.txt',"w+")
cmdline = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-t','NOAA',recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-normal.jpg']
r.write('\nSAT: '+str(xfNoSpace)+', Elevation max: '+str(maxElev)+', Date: '+str(fname)+'\n')
subprocess.call(cmdline, stderr=r, stdout=r)
r.close()
for line in open(imgdir+'/'+satName+'/'+fileNameC+'-normal.jpg.txt',"r").readlines():
res=line.replace("\n", "")
res2=re.sub(r"(\d)", r"\033[96m\1\033[94m", res)
print logLineStart+bcolors.OKBLUE+res2+logLineEnd
if wxEnhHVC in ('yes', 'y', '1'):
print 'Creating HVC image'
cmdline_hvc = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','HVC',recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-hvc.jpg']
subprocess.call(cmdline_hvc)
if wxEnhHVCT in ('yes', 'y', '1'):
print 'Creating HVCT image'
cmdline_hvct = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','HVCT',recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-hvct.jpg']
subprocess.call(cmdline_hvct)
if wxEnhMSA in ('yes', 'y', '1'):
print 'Creating MSA image'
cmdline_msa = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','MSA',recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-msa.jpg']
subprocess.call(cmdline_msa)
if wxEnhMCIR in ('yes', 'y', '1'):
print 'Creating MCIR image'
cmdline_mcir = [ wxInstallDir+'/wxtoimg',wxQuietOpt,wxDecodeOpt,wxAddText,'-o','-R1','-Q '+wxJPEGQuality,'-e','MCIR',recdir+'/'+xfNoSpace+'-'+fname+'.wav', imgdir+'/'+satName+'/'+fileNameC+'-mcir.jpg']
subprocess.call(cmdline_mcir)
if LOG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending flight and decode logs..."+bcolors.YELLOW
cmdline_scp_log = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-normal.jpg.txt',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-normal.jpg.txt' ]
subprocess.call(cmdline_scp_log)
if IMG_SCP in ('yes', 'y', '1'):
print logLineStart+"Sending base image without overlay map... "+bcolors.YELLOW
cmdline_scp_img = [ '/usr/bin/scp',imgdir+'/'+satName+'/'+fileNameC+'-normal.jpg',SCP_USER+'@'+SCP_HOST+':'+SCP_DIR+'/'+satName.replace(" ","\ ")+'-'+fileNameC+'-normal.jpg' ]
subprocess.call(cmdline_scp_img)
print logLineStart+"Sent, go on..."+logLineEnd
##
## Record and transcode wave file
##
def recordWAV(freq,fname,duration,xfname):
if xfname in ('NOAA 15', 'NOAA 19', 'NOAA 18'):
recordFM(freq,fname,duration,xfname)
transcode(fname)
if createSpectro in ('yes', 'y', '1'):
spectrum(fname)
elif xfname in ('METEOR-M2'):
recordMETEOR(freq,fname,duration,xfname)
if createSpectro in ('yes', 'y', '1'):
spectrum(fname)
##
## Spectrum creation module
##
def spectrum(fname):
xfNoSpace=xfname.replace(" ","")
print logLineStart+'Creating flight spectrum'+logLineEnd
cmdline = ['sox',recdir+'/'+xfNoSpace+'-'+fname+'.wav', '-n', 'spectrogram','-o',specdir+'/'+xfNoSpace+'-'+fname+'.png']
subprocess.call(cmdline)
def recordWAV(freq,fname,duration):
recordFM(freq,fname,duration)
transcode(fname)
def spectrum(fname,duration):
cmdline = ['rtl_power','-f','137000000:138000000:1000','-i','1m','-g','40',fname+'.csv']
runForDuration(cmdline,duration)
##
## Passage finder loop
##
def findNextPass():
predictions = [pypredict.aoslos(s) for s in satellites]
@ -52,19 +479,89 @@ def findNextPass():
freqs[nextIndex],\
predictions[nextIndex])
##
## Now magic
##
while True:
(satName, freq, (aosTime, losTime)) = findNextPass()
(satName, freq, (aosTime, losTime,maxElev)) = findNextPass()
now = time.time()
towait = aosTime-now
if towait>0:
print "waiting "+str(towait)+" seconds for "+satName
time.sleep(towait)
# dir= sat name and filename = start time
fname='./'+satName+'/'+str(aosTime)
print "beginning pass "+fname+" predicted end "+str(losTime)
recordWAV(freq,fname,losTime-aosTime)
decode(fname) # make picture
# spectrum(fname,losTime-aosTime)
print "finished pass "+fname+" at "+str(time.time())
time.sleep(60.0)
aosTimeCnv=strftime('%H:%M:%S', time.localtime(aosTime))
emergeTimeUtc=strftime('%Y-%m-%dT%H:%M:%S', time.gmtime(aosTime))
losTimeCnv=strftime('%H:%M:%S', time.localtime(losTime))
dimTimeUtc=strftime('%Y-%m-%dT%H:%M:%S', time.gmtime(losTime))
##
## OK, now we have to decide what if recording or sleeping
##
if towait>0:
print logLineStart+"waiting "+bcolors.CYAN+str(towait).split(".")[0]+bcolors.OKGREEN+" seconds (emerging "+bcolors.CYAN+aosTimeCnv+bcolors.OKGREEN+") for "+bcolors.YELLOW+satName+bcolors.OKGREEN+" @ "+bcolors.CYAN+str(maxElev)+bcolors.OKGREEN+"° el."+logLineEnd
writeStatus(freq,aosTimeCnv,losTimeCnv,aosTime,towait,satName,maxElev,'WAITING')
time.sleep(towait)
##
## If the script broke - or it was recording other one - and a bird is already passing by - change record time to real one
##
if aosTime<now:
recordTime=losTime-now
if recordTime<1:
recordTime=1
elif aosTime>=now:
recordTime=losTime-aosTime
if recordTime<1:
recordTime=1
##
## Dirty, but for now we'll name recordings and images by Unix timestamp.
##
if maxElev>int(minElev):
fname=str(aosTime)
xfname=satName
## Own place scripts.
## TODO: Own process
##
# subprocess.call('sudo /etc/init.d/pymultimonaprs stop', shell=True)
print logLineStart+"Beginning pass of "+bcolors.YELLOW+satName+bcolors.OKGREEN+" at "+bcolors.CYAN+str(maxElev)+"°"+bcolors.OKGREEN+" elev.\n"+logLineStart+"Predicted start "+bcolors.CYAN+aosTimeCnv+bcolors.OKGREEN+" and end "+bcolors.CYAN+losTimeCnv+bcolors.OKGREEN+".\n"+logLineStart+"Will record for "+bcolors.CYAN+str(recordTime).split(".")[0]+bcolors.OKGREEN+" seconds."+logLineEnd
writeStatus(freq,aosTimeCnv,losTimeCnv,str(losTime),str(recordTime).split(".")[0],satName,maxElev,'RECORDING')
##
## Let's record
##
recordWAV(freq,fname,recordTime,xfname)
## DEBUG
##
# recordWAV(freq,fname,5,xfname)
## recordDOP(freq,fname,recordTime,xfname)
##
print logLineStart+"Decoding data"+logLineEnd
####
if xfname in ('NOAA 15', 'NOAA 19', 'NOAA 18'):
writeStatus(freq,aosTimeCnv,losTimeCnv,str(losTime),str(recordTime).split(".")[0],satName,maxElev,'DECODING')
decode(fname,aosTime,satName,maxElev) # make picture
###
print logLineStart+"Finished pass of "+bcolors.YELLOW+satName+bcolors.OKGREEN+" at "+bcolors.CYAN+losTimeCnv+bcolors.OKGREEN+". Sleeping for"+bcolors.CYAN+" 10"+bcolors.OKGREEN+" seconds"+logLineEnd
##
## Is this really needed?
##
## TODO: Call custom script
# subprocess.call('sudo /etc/init.d/pymultimonaprs start', shell=True)
#
else:
###
### Satellite is too low...
### Let's sleep and just wait..
###
print logLineStart+bcolors.ENDC+bcolors.WARNING+"Too low for good reception ("+bcolors.CYAN+str(minElev)+"°"+bcolors.WARNING+" > max: "+bcolors.CYAN+str(maxElev)+"°"+bcolors.WARNING+" elev. )\n\tSleeping for "+bcolors.CYAN+str(recordTime)+bcolors.WARNING+" seconds..."+logLineEnd
writeStatus(freq,aosTimeCnv,losTimeCnv,aosTime,recordTime,satName,maxElev,'TOOLOW')
time.sleep(recordTime)
## Main loop done
##
## Sleep for a moment...
## And do everything again
time.sleep(10.0)

View File

@ -12,11 +12,24 @@ class missingSatellitePredictionError(Exception):
def aoslos(satname):
lines = subprocess.check_output(['predict','-p',satname]).split("\n")
result = []
for line in lines:
data = line.split()
# print data
if len(data)>10: # Mhm. It's 11 or 12 columns...
result.extend([int(data[j]) for j in [4]])
# print result
if len(result)>1:
maxElev=max(result)
else:
maxElev=int('1')
try:
aosTime=int(lines[0].split()[0])
aosTime=int(lines[0].split()[0])
losTime=int(lines[-2].split()[0])
if losTime>aosTime:
return (aosTime,losTime)
return (aosTime,losTime,maxElev)
elif losTime==aosTime:
return (aosTime,losTime,maxElev)
except Exception:
pass
raise missingSatellitePredictionError()

85
tles/predict.db Normal file
View File

@ -0,0 +1,85 @@
NOAA-15
25338
No alat, alon
APT Downlink
0.0, 0.0
137.620, 137.620
No weekly schedule
No orbital schedule
HRPT Downlink
0.0, 0.0
1702.5, 1702.5
No weekly schedule
No orbital schedule
end
NOAA-18
28654
No alat, alon
APT Downlink
0.0, 0.0
137.912, 137.912
No weekly schedule
No orbital schedule
HRPT Downlink
0.0, 0.0
1707.0, 1707.0
No weekly schedule
No orbital schedule
end
NOAA-19
33591
No alat, alon
APT Downlink
0.0, 0.0
137.100, 137.100
No weekly schedule
No orbital schedule
HRPT Downlink
0.0, 0.0
1698.0, 1698.0
No weekly schedule
No orbital schedule
end
ISS
25544
No alat, alon
ARISS VHF Packet Radio Mailbox
145.990, 145.990
145.800, 145.800
No weekly schedule
No orbital schedule
Region 2/3 ARISS VHF-FM Voice
144.490, 144.490
145.800, 145.800
No weekly schedule
No orbital schedule
Region 1 ARISS VHF-FM Voice
145.200, 145.200
145.800, 145.800
No weekly schedule
No orbital schedule
ARISS UHF-FM Voice
437.500, 437.500
437.500, 437.500
No weekly schedule
No orbital schedule
Crossband Repeater
437.800, 437.800
145.800, 145.800
No weekly schedule
No orbital schedule
TsUP FM Voice Downlink
0.0, 0.0
143.625, 143.625
No weekly schedule
No orbital schedule
end
PCSAT
26931
No alat, alon
1200 baud AFSK APRS Digipeater (PCSAT-1)
145.827, 145.827
145.827, 145.827
No weekly schedule
No orbital schedule
end

4
tles/predict.qth Normal file
View File

@ -0,0 +1,4 @@
STATIONNAME
53.3404
15.0579
12

72
tles/predict.tle Normal file
View File

@ -0,0 +1,72 @@
PCSAT (NO-44)
1 26931U 01043C 16101.51428131 .00000003 00000-0 33045-4 0 9995
2 26931 67.0497 127.4986 0007566 266.4517 93.5719 14.30398708758465
NOAA 15
1 25338U 98030A 16102.55225998 .00000051 00000-0 40264-4 0 9992
2 25338 98.7836 106.5678 0011053 25.5612 334.6112 14.25716200931492
NOAA 18
1 28654U 05018A 16102.46702789 .00000011 00000-0 31633-4 0 9994
2 28654 99.1984 107.6617 0013978 198.0761 161.9914 14.12278223561314
NOAA 19
1 33591U 09005A 16102.48187738 .00000109 00000-0 84443-4 0 9998
2 33591 99.0334 58.7333 0014866 49.5621 310.6844 14.12060479369729
ISS
1 25544U 98067A 16102.53660880 .00005936 00000-0 95761-4 0 9991
2 25544 51.6438 30.4633 0002692 57.3056 284.3900 15.54440683994607
METEOR-M2
1 40069U 14037A 16102.42233223 -.00000027 00000-0 76883-5 0 9992
2 40069 98.7136 158.6274 0006227 30.3731 329.7812 14.20628231 91250
METEOR-M1
1 35865U 09049A 16102.52408863 .00000013 00000-0 24675-4 0 9997
2 35865 98.4630 136.5338 0001928 356.8564 3.2602 14.22061154340742
ESTCUBE-1
1 39161U 13021C 16102.48493412 .00000471 00000-0 83640-4 0 9999
2 39161 98.0494 187.5543 0011061 82.8497 277.3974 14.71611977157259
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02
1 00000U 00 0.00000000 .00000000 00000-0 00000-0 0 03
2 00000 0.0000 0.0000 0000000 0.0000 0.0000 0.00000000 02

View File

@ -1,11 +1,17 @@
#!/bin/bash
# mostly from PREDICT man page by KB2BD
# Suitable as a cron.weekly script
mkdir -p /tmp/keps
cd /tmp/keps
rm -f amateur.txt visual.txt weather.txt
wget -qr www.celestrak.com/NORAD/elements/amateur.txt -O amateur.txt
wget -qr www.celestrak.com/NORAD/elements/visual.txt -O visual.txt
wget -qr www.celestrak.com/NORAD/elements/weather.txt -O weather.txt
/usr/bin/predict -u amateur.txt visual.txt weather.txt
#rm /tmp/weather.txt
#wget -qr www.celestrak.com/NORAD/elements/weather.txt -O /tmp/weather.txt
rm /tmp/noaa.txt
wget -qr https://www.celestrak.com/NORAD/elements/noaa.txt -O /tmp/noaa.txt
rm /tmp/amateur.txt
wget -qr https://www.celestrak.com/NORAD/elements/amateur.txt -O /tmp/amateur.txt
rm /tmp/cubesat.txt
wget -qr https://www.celestrak.com/NORAD/elements/cubesat.txt -O /tmp/cubesat.txt
rm /tmp/weather.txt
wget -qr https://www.celestrak.com/NORAD/elements/weather.txt -O /tmp/weather.txt
/usr/bin/predict -u /tmp/noaa.txt /tmp/amateur.txt /tmp/weather.txt /tmp/cubesat.txt