mirror of
https://github.com/wavelog/wavelog.git
synced 2026-03-22 10:24:14 +00:00
[Sat Sked] Can now predict sat skeds
This commit is contained in:
@@ -234,12 +234,32 @@ class Satellite extends CI_Controller {
|
||||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
public function searchpasses() {
|
||||
public function searchPasses() {
|
||||
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
|
||||
try {
|
||||
$result = $this->get_tle_for_predict();
|
||||
$this->calcpass($result);
|
||||
$tle = $this->get_tle_for_predict();
|
||||
$yourgrid = $this->security->xss_clean($this->input->post('yourgrid'));
|
||||
$altitude = $this->security->xss_clean($this->input->post('altitude'));
|
||||
$date = $this->security->xss_clean($this->input->post('date'));
|
||||
$minelevation = $this->security->xss_clean($this->input->post('minelevation'));
|
||||
$timezone = $this->security->xss_clean($this->input->post('timezone'));
|
||||
$data = $this->calcPass($tle, $yourgrid, $altitude, $date, $minelevation, $timezone);
|
||||
|
||||
$this->load->view('satellite/passtable', $data);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
header("Content-type: application/json");
|
||||
echo json_encode(['ok' => 'Error', 'message' => $e->getMessage() . $e->getCode()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function searchSkedPasses() {
|
||||
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
|
||||
try {
|
||||
$tle = $this->get_tle_for_predict();
|
||||
$this->calcSkedPass($tle);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
header("Content-type: application/json");
|
||||
@@ -255,7 +275,7 @@ class Satellite extends CI_Controller {
|
||||
return $this->satellite_model->get_tle($sat);
|
||||
}
|
||||
|
||||
function calcpass($sat_tle) {
|
||||
function calcPass($sat_tle, $yourgrid, $altitude, $date, $minelevation, $timezone) {
|
||||
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
|
||||
require_once "./src/predict/Predict.php";
|
||||
@@ -267,9 +287,9 @@ class Satellite extends CI_Controller {
|
||||
// The observer or groundstation is called QTH in ham radio terms
|
||||
$predict = new Predict();
|
||||
$qth = new Predict_QTH();
|
||||
$qth->alt = $this->security->xss_clean($this->input->post('altitude')); // Altitude in meters
|
||||
$qth->alt = $altitude; // Altitude in meters
|
||||
|
||||
$strQRA = $this->security->xss_clean($this->input->post('yourgrid'));
|
||||
$strQRA = $yourgrid;
|
||||
|
||||
if ((strlen($strQRA) % 2 == 0) && (strlen($strQRA) <= 10)) { // Check if QRA is EVEN (the % 2 does that) and smaller/equal 8
|
||||
$strQRA = strtoupper($strQRA);
|
||||
@@ -285,7 +305,7 @@ class Satellite extends CI_Controller {
|
||||
if(!$this->load->is_loaded('Qra')) {
|
||||
$this->load->library('Qra');
|
||||
}
|
||||
$homecoordinates = $this->qra->qra2latlong($this->security->xss_clean($this->input->post('yourgrid')));
|
||||
$homecoordinates = $this->qra->qra2latlong($yourgrid);
|
||||
|
||||
$qth->lat = $homecoordinates[0];
|
||||
$qth->lon = $homecoordinates[1];
|
||||
@@ -295,11 +315,11 @@ class Satellite extends CI_Controller {
|
||||
$tle = new Predict_TLE($sat_tle->satellite, $temp[0], $temp[1]); // Instantiate it
|
||||
$sat = new Predict_Sat($tle); // Load up the satellite data
|
||||
|
||||
$now = $this->get_daynum_from_date($this->security->xss_clean($this->input->post('date'))); // get the current time as Julian Date (daynum)
|
||||
$now = $this->get_daynum_from_date($date); // get the current time as Julian Date (daynum)
|
||||
|
||||
// You can modify some preferences in Predict(), the defaults are below
|
||||
//
|
||||
$predict->minEle = intval($this->security->xss_clean($this->input->post('minelevation'))); // Minimum elevation for a pass
|
||||
$predict->minEle = intval($minelevation); // Minimum elevation for a pass
|
||||
$predict->timeRes = 1; // Pass details: time resolution in seconds
|
||||
$predict->numEntries = 20; // Pass details: number of entries per pass
|
||||
// $predict->threshold = -6; // Twilight threshold (sun must be at this lat or lower)
|
||||
@@ -308,8 +328,6 @@ class Satellite extends CI_Controller {
|
||||
$results = $predict->get_passes($sat, $qth, $now, 1);
|
||||
$filtered = $predict->filterVisiblePasses($results);
|
||||
|
||||
$zone = $this->security->xss_clean($this->input->post('timezone'));
|
||||
|
||||
// Get Date format
|
||||
if ($this->session->userdata('user_date_format')) {
|
||||
// If Logged in and session exists
|
||||
@@ -322,9 +340,73 @@ class Satellite extends CI_Controller {
|
||||
$format = $custom_date_format . ' H:i:s';
|
||||
|
||||
$data['filtered'] = $filtered;
|
||||
$data['zone'] = $zone;
|
||||
$data['zone'] = $timezone;
|
||||
$data['format'] = $format;
|
||||
$this->load->view('satellite/passtable', $data);
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
function calcSkedPass($sat_tle) {
|
||||
if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); }
|
||||
|
||||
$tle = $this->get_tle_for_predict();
|
||||
|
||||
$yourgrid = $this->security->xss_clean($this->input->post('yourgrid'));
|
||||
$altitude = $this->security->xss_clean($this->input->post('altitude'));
|
||||
$date = $this->security->xss_clean($this->input->post('date'));
|
||||
$minelevation = $this->security->xss_clean($this->input->post('minelevation'));
|
||||
$timezone = $this->security->xss_clean($this->input->post('timezone'));
|
||||
|
||||
$homePass = $this->calcPass($tle, $yourgrid, $altitude, $date, $minelevation, $timezone);
|
||||
|
||||
$skedgrid = $this->security->xss_clean($this->input->post('skedgrid'));
|
||||
$minskedelevation = $this->security->xss_clean($this->input->post('minskedelevation'));
|
||||
|
||||
$skedPass = $this->calcPass($tle, $skedgrid, 0, $date, $minskedelevation, $timezone);
|
||||
|
||||
// Get Date format
|
||||
if ($this->session->userdata('user_date_format')) {
|
||||
// If Logged in and session exists
|
||||
$custom_date_format = $this->session->userdata('user_date_format');
|
||||
} else {
|
||||
// Get Default date format from /config/wavelog.php
|
||||
$custom_date_format = $this->config->item('qso_date_format');
|
||||
}
|
||||
|
||||
$data['format'] = $custom_date_format . ' H:i:s';
|
||||
|
||||
$data['overlaps'] = $this->findOverlaps($homePass, $skedPass);
|
||||
$data['zone'] = $timezone;
|
||||
$data['yourgrid'] = $yourgrid;
|
||||
$data['skedgrid'] = $skedgrid;
|
||||
|
||||
$this->load->view('satellite/skedtable', $data);
|
||||
}
|
||||
|
||||
function findOverlaps($homePass, $skedPass) {
|
||||
$overlaps = []; // Store overlapping passes
|
||||
|
||||
foreach ($homePass['filtered'] as $pass1) {
|
||||
foreach ($skedPass['filtered'] as $pass2) {
|
||||
if ($this->checkOverlap($pass1, $pass2)) {
|
||||
$overlaps[] = [
|
||||
'grid1' => $pass1,
|
||||
'grid2' => $pass2
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $overlaps;
|
||||
}
|
||||
|
||||
function checkOverlap($pass1, $pass2) {
|
||||
// Calculate the overlap condition
|
||||
$start = max($pass1->visible_aos, $pass2->visible_aos); // Latest start time
|
||||
$end = min($pass1->visible_los, $pass2->visible_los); // Earliest end time
|
||||
|
||||
return $start <= $end; // True if intervals overlap
|
||||
}
|
||||
|
||||
public static function get_daynum_from_date($date) {
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
<div class="card-body">
|
||||
<form class="d-flex align-items-center">
|
||||
<div class="row">
|
||||
<?php if ($satellites) { ?>
|
||||
|
||||
<h4>Your station</h4>
|
||||
<div class="mb-3 w-auto">
|
||||
<label class="my-1 me-sm-2 w-auto" id="satslabel" for="satslist"><?= __("Min. Satellite Elevation"); ?></label>
|
||||
<label class="my-1 me-sm-2 w-auto" id="minelevation" for="minelevation"><?= __("Min. Satellite Elevation"); ?></label>
|
||||
<input class="my-1 me-sm-2 w-auto form-control" id="minelevation" type="number" min="0" max="90" name="minelevation" value="0" />
|
||||
</div>
|
||||
<div class="mb-3 w-auto">
|
||||
@@ -477,7 +480,7 @@
|
||||
<label class="my-1 me-sm-2 w-auto" for="mintime"><?= __("Min. time"); ?></label>
|
||||
<select class="my-1 me-sm-2 w-auto form-select" id="mintime" name="mintime">
|
||||
<?php for ($i = 0; $i <= 24; $i += 1): ?>
|
||||
<option value="<?= $i ?>" <?= $i === 8 ? 'selected' : '' ?>><?= $i ?>:00</option>
|
||||
<option value="<?= $i ?>" <?= $i === 00 ? 'selected' : '' ?>><?= $i ?>:00</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
@@ -485,7 +488,7 @@
|
||||
<label class="my-1 me-sm-2 w-auto" for="maxtime"><?= __("Max. time"); ?></label>
|
||||
<select class="my-1 me-sm-2 w-auto form-select" id="maxtime" name="maxtime">
|
||||
<?php for ($i = 0; $i <= 24; $i += 1): ?>
|
||||
<option value="<?= $i ?>" <?= $i === 22 ? 'selected' : '' ?>><?= $i ?>:00</option>
|
||||
<option value="<?= $i ?>" <?= $i === 24 ? 'selected' : '' ?>><?= $i ?>:00</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
@@ -497,9 +500,41 @@
|
||||
} ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="addskedpartner" style="display:none" class="row">
|
||||
<h4>Sked partner</h2>
|
||||
<div class="mb-3 w-auto">
|
||||
<label class="my-1 me-sm-2 w-auto" id="minskedelevationlabel" for="minskedelevation"><?= __("Min. Satellite Elevation"); ?></label>
|
||||
<input class="my-1 me-sm-2 w-auto form-control" id="minskedelevation" type="number" min="0" max="90" name="minskedelevation" value="0" />
|
||||
</div>
|
||||
<div class="mb-3 w-auto">
|
||||
<label class="my-1 me-sm-2 w-auto" for="minskedazimuth"><?= __("Min. Azimuth"); ?></label>
|
||||
<select class="my-1 me-sm-2 w-auto form-select" id="minskedazimuth" name="minskedazimuth">
|
||||
<?php for ($i = 0; $i <= 350; $i += 10): ?>
|
||||
<option value="<?= $i ?>" <?= $i === 0 ? 'selected' : '' ?>><?= $i ?> °</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 w-auto">
|
||||
<label class="my-1 me-sm-2 w-auto" for="maxskedazimuth"><?= __("Max. Azimuth"); ?></label>
|
||||
<select class="my-1 me-sm-2 w-auto form-select" id="maxskedazimuth" name="maxskedazimuth">
|
||||
<?php for ($i = 10; $i <= 360; $i += 10): ?>
|
||||
<option value="<?= $i ?>" <?= $i === 360 ? 'selected' : '' ?>><?= $i ?> °</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 w-auto">
|
||||
<label class="my-1 me-sm-2 w-auto" for="skedgrid"><?= __("Gridsquare"); ?></label>
|
||||
<input class="my-1 me-sm-2 w-auto form-control" id="skedgrid" type="text" name="skedgrid" value=""/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<button id="plot" type="button" name="searchpass" class="btn-sm btn btn-primary me-1 ld-ext-right ld-ext-right-plot" onclick="searchpasses()"><?= __("Load predictions"); ?><div class="ld ld-ring ld-spin"></div></button>
|
||||
<button id="plot" type="button" name="searchpass" class="btn-sm btn btn-primary me-1 ld-ext-right ld-ext-right-plot" onclick="searchpasses()"><i class="fas fa-search"></i> <?= __("Load predictions"); ?><div class="ld ld-ring ld-spin"></div></button>
|
||||
<button id="addsked" type="button" name="addsked" class="btn-sm btn btn-success me-1 ld-ext-right ld-ext-right-plot" onclick="addskedpartner()"><i class="fa fa-plus"></i> <?= __("Add sked partner"); ?><div class="ld ld-ring ld-spin"></div></button>
|
||||
<?php } else { ?>
|
||||
<?= __("No TLE information detected. Please update TLE's.")?>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div id="resultpasses">
|
||||
|
||||
|
||||
102
application/views/satellite/skedtable.php
Normal file
102
application/views/satellite/skedtable.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
if (!empty($overlaps)) {
|
||||
echo '<table style="width:100%" class="table-sm table table-bordered table-hover table-striped table-condensed text-center">';
|
||||
echo '<thead>
|
||||
<tr>
|
||||
<th>' . __("Grid") . '</th>
|
||||
<th>' . __("Satellite") . '</th>
|
||||
<th>' . __("AOS Time") . '</th>
|
||||
<th>' . __("Duration") . '</th>
|
||||
<th>' . __("AOS Azimuth") . '</th>
|
||||
<th>' . __("Max Elevation") . '</th>
|
||||
<th>' . __("LOS Time") . '</th>
|
||||
<th>' . __("LOS Azimuth") . '</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($overlaps as $overlap) {
|
||||
echo '<tr>';
|
||||
echo '<td>' . $yourgrid . '</td>';
|
||||
echo '<td>' . $overlap['grid1']->satname . '</td>';
|
||||
echo '<td>' . Predict_Time::daynum2readable($overlap['grid1']->visible_aos, $zone, $format) . '</td>';
|
||||
echo '<td>' . returntimediff(Predict_Time::daynum2readable($overlap['grid1']->visible_aos, $zone, $format), Predict_Time::daynum2readable($overlap['grid1']->visible_los, $zone, $format), $format) . '</td>';
|
||||
$aos_az = round($overlap['grid1']->visible_aos_az);
|
||||
echo '<td>' . $aos_az . ' ° (' . azDegreesToDirection($overlap['grid1']->visible_aos_az) . ')<span style="margin-left: 10px; display: inline-block; transform: rotate('.(-45+$aos_az).'deg);"><i class="fas fa-location-arrow fa-xs"></i></span></td>';
|
||||
$max_el = round($overlap['grid1']->max_el);
|
||||
echo '<td>' . $max_el . ' °<span style="margin-left: 10px; display: inline-block; transform: rotate(-'.$max_el.'deg);"><i class="fas fa-arrow-right fa-xs"></i></span></td>';
|
||||
echo '<td>' . Predict_Time::daynum2readable($overlap['grid1']->visible_los, $zone, $format) . '</td>';
|
||||
$los_az = round($overlap['grid1']->visible_los_az);
|
||||
echo '<td>' . $los_az . ' ° (' . azDegreesToDirection($overlap['grid1']->visible_los_az) . ')<span style="margin-left: 10px; display: inline-block; transform: rotate('.(-45+$los_az).'deg);"><i class="fas fa-location-arrow fa-xs"></i></span></td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td>' . $skedgrid . '</td>';
|
||||
echo '<td>' . $overlap['grid2']->satname . '</td>';
|
||||
echo '<td>' . Predict_Time::daynum2readable($overlap['grid2']->visible_aos, $zone, $format) . '</td>';
|
||||
echo '<td>' . returntimediff(Predict_Time::daynum2readable($overlap['grid2']->visible_aos, $zone, $format), Predict_Time::daynum2readable($overlap['grid2']->visible_los, $zone, $format), $format) . '</td>';
|
||||
$aos_az = round($overlap['grid2']->visible_aos_az);
|
||||
echo '<td>' . $aos_az . ' ° (' . azDegreesToDirection($overlap['grid2']->visible_aos_az) . ')<span style="margin-left: 10px; display: inline-block; transform: rotate('.(-45+$aos_az).'deg);"><i class="fas fa-location-arrow fa-xs"></i></span></td>';
|
||||
$max_el = round($overlap['grid2']->max_el);
|
||||
echo '<td>' . $max_el . ' °<span style="margin-left: 10px; display: inline-block; transform: rotate(-'.$max_el.'deg);"><i class="fas fa-arrow-right fa-xs"></i></span></td>';
|
||||
echo '<td>' . Predict_Time::daynum2readable($overlap['grid2']->visible_los, $zone, $format) . '</td>';
|
||||
$los_az = round($overlap['grid2']->visible_los_az);
|
||||
echo '<td>' . $los_az . ' ° (' . azDegreesToDirection($overlap['grid2']->visible_los_az) . ')<span style="margin-left: 10px; display: inline-block; transform: rotate('.(-45+$los_az).'deg);"><i class="fas fa-location-arrow fa-xs"></i></span></td>';
|
||||
echo '</tr>';
|
||||
|
||||
echo "<tr><td colspan='8'>---</td></tr>"; // Separator row
|
||||
}
|
||||
|
||||
echo "</tbody>";
|
||||
echo "</table>";
|
||||
} else {
|
||||
echo "<p>No overlapping passes found.</p>";
|
||||
}
|
||||
|
||||
echo '<table style="width:100%" class="table-sm table table-bordered table-hover table-striped table-condensed text-center">';
|
||||
echo '<thead>
|
||||
<tr>
|
||||
<th>' . __("Satellite") . '</th>
|
||||
<th>' . __("Date") . '</th>
|
||||
<th>' . __("Sked AOS Time") . '</th>
|
||||
<th>' . __("Sked LOS Time") . '</th>
|
||||
<th>' . __("Duration") . '</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($overlaps as $overlap) {
|
||||
// Example data (replace these with real calculations or data from the arrays)
|
||||
$satellite = $overlap['grid1']->satname; // Replace with your satellite name
|
||||
$skedDate = Predict_Time::daynum2readable($overlap['grid1']->visible_aos, $zone, $format); // Example sked date
|
||||
|
||||
$skedAOS = $overlap['grid1']->visible_aos < $overlap['grid2']->visible_aos ? $overlap['grid2']->visible_aos : $overlap['grid1']->visible_aos;
|
||||
$skedLOS = $overlap['grid1']->visible_los < $overlap['grid2']->visible_los ? $overlap['grid1']->visible_los : $overlap['grid2']->visible_los;
|
||||
|
||||
echo '<tr>';
|
||||
echo "<td>". $satellite . "</td>";
|
||||
echo "<td></td>";
|
||||
echo "<td>" . Predict_Time::daynum2readable($skedAOS, $zone, $format) . "</td>";
|
||||
echo "<td>" . Predict_Time::daynum2readable($skedLOS, $zone, $format) . "</td>";
|
||||
echo "<td>" . returntimediff(Predict_Time::daynum2readable($skedAOS, $zone, $format), Predict_Time::daynum2readable($skedLOS, $zone, $format), $format) . "</td>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
|
||||
function returntimediff($start, $end, $format) {
|
||||
$datetime1 = DateTime::createFromFormat($format, $end);
|
||||
$datetime2 = DateTime::createFromFormat($format, $start);
|
||||
$interval = $datetime1->diff($datetime2);
|
||||
|
||||
$diff = sprintf('%02d', (($interval->h*60)+$interval->i)).':'.sprintf('%02d', $interval->s).' '.__("min");
|
||||
|
||||
return $diff;
|
||||
}
|
||||
|
||||
function azDegreesToDirection($az = 0) {
|
||||
$i = floor($az / 22.5);
|
||||
$m = (22.5 * (2 * $i + 1)) / 2;
|
||||
$i = ($az >= $m) ? $i + 1 : $i;
|
||||
|
||||
return trim(substr('N NNENE ENEE ESESE SSES SSWSW WSWW WNWNW NNWN ', $i * 3, 3));
|
||||
}
|
||||
@@ -1,6 +1,20 @@
|
||||
function searchpasses() {
|
||||
$.ajax({
|
||||
url: base_url + 'index.php/satellite/searchpasses',
|
||||
if ($('#addskedpartner').is(':hidden')) {
|
||||
loadPasses();
|
||||
} else {
|
||||
let skedgrid = $("#skedgrid").val();
|
||||
if (skedgrid == '') {
|
||||
return;
|
||||
}
|
||||
loadSkedPasses();
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
function loadPasses() {
|
||||
$.ajax({
|
||||
url: base_url + 'index.php/satellite/searchPasses',
|
||||
type: 'post',
|
||||
data: {'sat': $("#satlist").val(),
|
||||
'yourgrid': $("#yourgrid").val(),
|
||||
@@ -21,3 +35,38 @@ function searchpasses() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadSkedPasses() {
|
||||
$.ajax({
|
||||
url: base_url + 'index.php/satellite/searchSkedPasses',
|
||||
type: 'post',
|
||||
data: {'sat': $("#satlist").val(),
|
||||
'yourgrid': $("#yourgrid").val(),
|
||||
'minelevation': $("#minelevation").val(),
|
||||
'minazimuth': $("#minazimuth").val(),
|
||||
'maxazimuth': $("#maxazimuth").val(),
|
||||
'altitude': $("#altitude").val(),
|
||||
'timezone': $("#timezone").val(),
|
||||
'date': $("#date").val(),
|
||||
'mintime': $("#mintime").val(),
|
||||
'maxtime': $("#maxtime").val(),
|
||||
'skedgrid': $("#skedgrid").val(),
|
||||
'minskedelevation': $("#minskedelevation").val(),
|
||||
},
|
||||
success: function (html) {
|
||||
$("#resultpasses").html(html);
|
||||
},
|
||||
error: function(e) {
|
||||
modalloading=false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addskedpartner() {
|
||||
if ($('#addskedpartner').is(':hidden')) {
|
||||
$('#addskedpartner').show();
|
||||
} else {
|
||||
$('#addskedpartner').hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user