Implement a configurable minimum horizon in network
This commit adds a "horizon" configuration item to stations. This allows station owners to set a minimum horizon to avoid a noisy or obstructed floor level. The default minimum horizon is set to 10, which is still fairly low for a satellite pass that could be captured but given the appropriate setup someone may be successful setting it lower. The horizon field is honored in both the calculation of upcoming passes in the station view as well as excluding any "below horizon" passes in prediction_windows. In addition, the db migration will set a minimum horizon of "10" for all existing stations in the network. This is the horizon that was hard-coded for the upcoming passes view so the only change to the end user will be the behavior of window prediction matching the upcoming passes (along with the ability to configure their minimum horizon, of course).merge-requests/218/head
parent
79f7ec1d0c
commit
b9f549cf0c
|
@ -7,5 +7,6 @@ class StationForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Station
|
model = Station
|
||||||
fields = ['name', 'image', 'alt',
|
fields = ['name', 'image', 'alt',
|
||||||
'lat', 'lng', 'qthlocator', 'antenna', 'active']
|
'lat', 'lng', 'qthlocator',
|
||||||
|
'horizon', 'antenna', 'active']
|
||||||
image = forms.ImageField(required=False)
|
image = forms.ImageField(required=False)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-03-19 00:49
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('base', '0003_auto_20160119_1856'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='station',
|
||||||
|
name='horizon',
|
||||||
|
field=models.PositiveIntegerField(default=10, help_text=b'In degrees above 0'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -57,6 +57,7 @@ class Station(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
active = models.BooleanField(default=False)
|
active = models.BooleanField(default=False)
|
||||||
last_seen = models.DateTimeField(null=True, blank=True)
|
last_seen = models.DateTimeField(null=True, blank=True)
|
||||||
|
horizon = models.PositiveIntegerField(help_text='In degrees above 0', default=10)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-active', '-last_seen']
|
ordering = ['-active', '-last_seen']
|
||||||
|
|
|
@ -213,49 +213,54 @@ def prediction_windows(request, sat_id, start_date, end_date):
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
if ephem.Date(tr).datetime() < end_date:
|
# no match if the sat will not rise above the configured min horizon
|
||||||
if ephem.Date(ts).datetime() > end_date:
|
elevation = format(math.degrees(altt), '.0f')
|
||||||
ts = end_date
|
if float(elevation) >= station.horizon:
|
||||||
keep_digging = False
|
if ephem.Date(tr).datetime() < end_date:
|
||||||
else:
|
if ephem.Date(ts).datetime() > end_date:
|
||||||
time_start_new = ephem.Date(ts).datetime() + timedelta(minutes=1)
|
ts = end_date
|
||||||
observer.date = time_start_new.strftime("%Y-%m-%d %H:%M:%S.%f")
|
keep_digging = False
|
||||||
|
else:
|
||||||
|
time_start_new = ephem.Date(ts).datetime() + timedelta(minutes=1)
|
||||||
|
observer.date = time_start_new.strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||||
|
|
||||||
# Adjust or discard window if overlaps exist
|
# Adjust or discard window if overlaps exist
|
||||||
window_start = make_aware(ephem.Date(tr).datetime(), utc)
|
window_start = make_aware(ephem.Date(tr).datetime(), utc)
|
||||||
window_end = make_aware(ephem.Date(ts).datetime(), utc)
|
window_end = make_aware(ephem.Date(ts).datetime(), utc)
|
||||||
window = _resolve_overlaps(station, window_start, window_end)
|
window = _resolve_overlaps(station, window_start, window_end)
|
||||||
if window:
|
if window:
|
||||||
if not station_match:
|
if not station_match:
|
||||||
station_windows = {
|
station_windows = {
|
||||||
'id': station.id,
|
'id': station.id,
|
||||||
'name': station.name,
|
'name': station.name,
|
||||||
'window': []
|
'window': []
|
||||||
}
|
}
|
||||||
station_match = True
|
station_match = True
|
||||||
window_start = window[0]
|
window_start = window[0]
|
||||||
window_end = window[1]
|
window_end = window[1]
|
||||||
station_windows['window'].append(
|
|
||||||
{
|
|
||||||
'start': window_start.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
|
||||||
'end': window_end.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
|
||||||
'az_start': azr
|
|
||||||
})
|
|
||||||
# In case our window was split in two
|
|
||||||
try:
|
|
||||||
window_start = window[2]
|
|
||||||
window_end = window[3]
|
|
||||||
station_windows['window'].append(
|
station_windows['window'].append(
|
||||||
{
|
{
|
||||||
'start': window_start.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
'start': window_start.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||||
'end': window_end.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
'end': window_end.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||||
'az_start': azr
|
'az_start': azr
|
||||||
})
|
})
|
||||||
except:
|
# In case our window was split in two
|
||||||
pass
|
try:
|
||||||
|
window_start = window[2]
|
||||||
|
window_end = window[3]
|
||||||
|
station_windows['window'].append(
|
||||||
|
{
|
||||||
|
'start': window_start.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||||
|
'end': window_end.strftime("%Y-%m-%d %H:%M:%S.%f"),
|
||||||
|
'az_start': azr
|
||||||
|
})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# window start outside of window bounds
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
# window start outside of window bounds
|
# did not rise above user configured horizon
|
||||||
break
|
break
|
||||||
|
|
||||||
if station_match:
|
if station_match:
|
||||||
|
@ -361,9 +366,9 @@ def station_view(request, id):
|
||||||
azimuth = format(math.degrees(azr), '.0f')
|
azimuth = format(math.degrees(azr), '.0f')
|
||||||
passid += 1
|
passid += 1
|
||||||
|
|
||||||
# show only if >= 10 degrees and in next 6 hours
|
# show only if >= configured horizon and in next 6 hours
|
||||||
if tr < ephem.date(datetime.today() + timedelta(hours=6)):
|
if tr < ephem.date(datetime.today() + timedelta(hours=6)):
|
||||||
if float(elevation) >= 10:
|
if float(elevation) >= station.horizon:
|
||||||
sat_pass = {'passid': passid,
|
sat_pass = {'passid': passid,
|
||||||
'mytime': str(observer.date),
|
'mytime': str(observer.date),
|
||||||
'debug': observer.next_pass(sat_ephem),
|
'debug': observer.next_pass(sat_ephem),
|
||||||
|
|
|
@ -73,6 +73,12 @@
|
||||||
{{ station.alt }} m
|
{{ station.alt }} m
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="gs-front-line">
|
||||||
|
<span class="label label-default">Min Horizon</span>
|
||||||
|
<span class="gs-front-data">
|
||||||
|
{{ station.horizon }}°
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div class="gs-front-line">
|
<div class="gs-front-line">
|
||||||
<span class="label label-default">Creation Date</span>
|
<span class="label label-default">Creation Date</span>
|
||||||
<span class="gs-front-data"
|
<span class="gs-front-data"
|
||||||
|
|
|
@ -58,6 +58,12 @@
|
||||||
readonly>
|
readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="horizon" class="col-sm-2 control-label">Minimum Horizon</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input value="{{ form.horizon.value }}" id="horizon" type="text" class="form-control" name="horizon" placeholder="Minimum horizon for passes, default 10">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="antennas" class="col-sm-2 control-label">Antennas</label>
|
<label for="antennas" class="col-sm-2 control-label">Antennas</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
|
Loading…
Reference in New Issue