Fixed jumping frequency by better signal frequency tweaking after sync
This commit is contained in:
parent
aee8de2b64
commit
6f111cdb73
@ -1,6 +1,6 @@
|
|||||||
subroutine baselinejs8(s,nfa,nfb,sbase)
|
subroutine baselinejs8(s,nfa,nfb,sbase)
|
||||||
|
|
||||||
! Fit baseline to spectrum (for FT8)
|
! Fit baseline to spectrum (for JS8)
|
||||||
! Input: s(npts) Linear scale in power
|
! Input: s(npts) Linear scale in power
|
||||||
! Output: sbase(npts) Baseline
|
! Output: sbase(npts) Baseline
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
subroutine genjs8(msg,mygrid,bcontest,i3bit,msgsent,msgbits,itone)
|
subroutine genjs8(msg,mygrid,bcontest,i3bit,msgsent,msgbits,itone)
|
||||||
|
|
||||||
! Encode an FT8 message, producing array itone().
|
! Encode an JS8 message, producing array itone().
|
||||||
|
|
||||||
use crc
|
use crc
|
||||||
use packjt
|
use packjt
|
||||||
|
@ -137,7 +137,7 @@ subroutine js8dec(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
|||||||
delf=ifr*0.5
|
delf=ifr*0.5
|
||||||
dphi=twopi*delf*dt2
|
dphi=twopi*delf*dt2
|
||||||
phi=0.0
|
phi=0.0
|
||||||
do i=1,NDOWNSPS
|
do i=1,(4*NSPS/NDOWN)
|
||||||
ctwk(i)=cmplx(cos(phi),sin(phi))
|
ctwk(i)=cmplx(cos(phi),sin(phi))
|
||||||
phi=mod(phi+dphi,twopi)
|
phi=mod(phi+dphi,twopi)
|
||||||
enddo
|
enddo
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
subroutine syncjs8d(cd0,i0,ctwk,itwk,sync)
|
subroutine syncjs8d(cd0,i0,ctwk,itwk,sync)
|
||||||
! Compute sync power for a complex, downsampled FT8 signal.
|
! Compute sync power for a complex, downsampled JS8 signal.
|
||||||
|
|
||||||
!include 'js8_params.f90'
|
!include 'js8_params.f90'
|
||||||
|
|
||||||
|
@ -4127,6 +4127,14 @@ void MainWindow::decodeDone ()
|
|||||||
m_blankLine=true;
|
m_blankLine=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<int> generateOffsets(int minOffset, int maxOffset){
|
||||||
|
QList<int> offsets;
|
||||||
|
for(int i = minOffset; i <= maxOffset; i++){
|
||||||
|
offsets.append(i);
|
||||||
|
}
|
||||||
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::readFromStdout() //readFromStdout
|
void MainWindow::readFromStdout() //readFromStdout
|
||||||
{
|
{
|
||||||
while(proc_js8.canReadLine()) {
|
while(proc_js8.canReadLine()) {
|
||||||
@ -4203,12 +4211,11 @@ void MainWindow::readFromStdout() //readFromStdout
|
|||||||
int offset = decodedtext.frequencyOffset();
|
int offset = decodedtext.frequencyOffset();
|
||||||
|
|
||||||
if(!m_bandActivity.contains(offset)){
|
if(!m_bandActivity.contains(offset)){
|
||||||
QList<int> offsets = {
|
int range = 10;
|
||||||
// offset - 60, offset - 61, offset - 62, offset - 63, offset - 64, offset - 65, offset - 66, offset - 67, offset - 68, offset - 69,
|
if(m_nSubMode == Varicode::JS8CallFast){ range = 15; }
|
||||||
// offset + 60, offset + 61, offset + 62, offset + 63, offset + 64, offset + 65, offset + 66, offset + 67, offset + 68, offset + 69,
|
if(m_nSubMode == Varicode::JS8CallTurbo){ range = 30; }
|
||||||
offset - 1, offset - 2, offset - 3, offset - 4, offset - 5, offset - 6, offset - 7, offset - 8, offset - 9, offset - 10,
|
QList<int> offsets = generateOffsets(offset-10, offset+10);
|
||||||
offset + 1, offset + 2, offset + 3, offset + 4, offset + 5, offset + 6, offset + 7, offset + 8, offset + 9, offset + 10
|
|
||||||
};
|
|
||||||
foreach(int prevOffset, offsets){
|
foreach(int prevOffset, offsets){
|
||||||
if(!m_bandActivity.contains(prevOffset)){ continue; }
|
if(!m_bandActivity.contains(prevOffset)){ continue; }
|
||||||
m_bandActivity[offset] = m_bandActivity[prevOffset];
|
m_bandActivity[offset] = m_bandActivity[prevOffset];
|
||||||
@ -4340,6 +4347,7 @@ void MainWindow::readFromStdout() //readFromStdout
|
|||||||
logHeardGraph(cmd.from, cmd.to);
|
logHeardGraph(cmd.from, cmd.to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// merge any existing buffer to this frequency
|
||||||
hasExistingMessageBuffer(cmd.freq, true, nullptr);
|
hasExistingMessageBuffer(cmd.freq, true, nullptr);
|
||||||
|
|
||||||
if(cmd.to == m_config.my_callsign()){
|
if(cmd.to == m_config.my_callsign()){
|
||||||
@ -4538,12 +4546,12 @@ bool MainWindow::hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffs
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> offsets = {
|
int range = 10;
|
||||||
//offset - 60, offset - 61, offset - 62, offset - 63, offset - 64, offset - 65, offset - 66, offset - 67, offset - 68, offset - 69,
|
if(m_nSubMode == Varicode::JS8CallFast){ range = 15; }
|
||||||
//offset + 60, offset + 61, offset + 62, offset + 63, offset + 64, offset + 65, offset + 66, offset + 67, offset + 68, offset + 69,
|
if(m_nSubMode == Varicode::JS8CallTurbo){ range = 30; }
|
||||||
offset - 1, offset - 2, offset - 3, offset - 4, offset - 5, offset - 6, offset - 7, offset - 8, offset - 9, offset - 10,
|
|
||||||
offset + 1, offset + 2, offset + 3, offset + 4, offset + 5, offset + 6, offset + 7, offset + 8, offset + 9, offset + 10
|
QList<int> offsets = generateOffsets(offset-range, offset+range);
|
||||||
};
|
|
||||||
foreach(int prevOffset, offsets){
|
foreach(int prevOffset, offsets){
|
||||||
if(!m_messageBuffer.contains(prevOffset)){ continue; }
|
if(!m_messageBuffer.contains(prevOffset)){ continue; }
|
||||||
|
|
||||||
@ -4559,6 +4567,13 @@ bool MainWindow::hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffs
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::hasClosedExistingMessageBuffer(int offset){
|
||||||
|
int range = 10;
|
||||||
|
if(m_nSubMode == Varicode::JS8CallFast){ range = 15; }
|
||||||
|
if(m_nSubMode == Varicode::JS8CallTurbo){ range = 30; }
|
||||||
|
return offset - range <= m_lastClosedMessageBufferOffset && m_lastClosedMessageBufferOffset <= offset + range;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::logCallActivity(CallDetail d, bool spot){
|
void MainWindow::logCallActivity(CallDetail d, bool spot){
|
||||||
// don't log empty calls
|
// don't log empty calls
|
||||||
if(d.call.trimmed().isEmpty()){
|
if(d.call.trimmed().isEmpty()){
|
||||||
@ -9953,10 +9968,15 @@ void MainWindow::processRxActivity() {
|
|||||||
d.utcTimestamp = qMin(d.utcTimestamp, lastCompound.utcTimestamp);
|
d.utcTimestamp = qMin(d.utcTimestamp, lastCompound.utcTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if(hasClosedExistingMessageBuffer(d.freq)){
|
||||||
|
// incremental typeahead should just be displayed...
|
||||||
|
// TODO: should the buffer be reopened?
|
||||||
|
shouldDisplay = true;
|
||||||
|
|
||||||
} else if(d.isDirected && d.text.contains("<....>")){
|
} else if(d.isDirected && d.text.contains("<....>")){
|
||||||
// if this is a _partial_ directed message, skip until the complete call comes through.
|
// if this is a _partial_ directed message, skip until the complete call comes through.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if(d.isDirected && d.text.contains(": HB ")){ // TODO: HEARTBEAT
|
} else if(d.isDirected && d.text.contains(": HB ")){ // TODO: HEARTBEAT
|
||||||
// if this is a heartbeat, process elsewhere...
|
// if this is a heartbeat, process elsewhere...
|
||||||
continue;
|
continue;
|
||||||
@ -10135,6 +10155,9 @@ void MainWindow::processCompoundActivity() {
|
|||||||
|
|
||||||
m_rxCommandQueue.append(buffer.cmd);
|
m_rxCommandQueue.append(buffer.cmd);
|
||||||
m_messageBuffer.remove(freq);
|
m_messageBuffer.remove(freq);
|
||||||
|
|
||||||
|
// TODO: only if to me?
|
||||||
|
m_lastClosedMessageBufferOffset = freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10158,20 +10181,24 @@ void MainWindow::processBufferedActivity() {
|
|||||||
if(!buffer.msgs.isEmpty()){
|
if(!buffer.msgs.isEmpty()){
|
||||||
dt = qMax(dt, buffer.msgs.last().utcTimestamp);
|
dt = qMax(dt, buffer.msgs.last().utcTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the buffer has messages older than 1 minute, and we still haven't closed it, let's mark it as the last frame
|
||||||
if(dt.secsTo(DriftingDateTime::currentDateTimeUtc()) > 60 && !buffer.msgs.isEmpty()){
|
if(dt.secsTo(DriftingDateTime::currentDateTimeUtc()) > 60 && !buffer.msgs.isEmpty()){
|
||||||
// if the buffer has messages older than 1 minute, and we still haven't closed it, let's just mark it as the last frame
|
|
||||||
buffer.msgs.last().bits |= Varicode::JS8CallLast;
|
buffer.msgs.last().bits |= Varicode::JS8CallLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// but, if the buffer is older than 1.5 minutes, and we still haven't closed it, just remove it and skip
|
||||||
if(dt.secsTo(DriftingDateTime::currentDateTimeUtc()) > 90){
|
if(dt.secsTo(DriftingDateTime::currentDateTimeUtc()) > 90){
|
||||||
// but, if the buffer is older than 2 minutes, and we still haven't closed it, just remove it
|
|
||||||
m_messageBuffer.remove(freq);
|
m_messageBuffer.remove(freq);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the buffer has no messages, skip
|
||||||
if (buffer.msgs.isEmpty()) {
|
if (buffer.msgs.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the buffered message hasn't seen the last message, skip
|
||||||
if ((buffer.msgs.last().bits & Varicode::JS8CallLast) != Varicode::JS8CallLast) {
|
if ((buffer.msgs.last().bits & Varicode::JS8CallLast) != Varicode::JS8CallLast) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -10220,6 +10247,7 @@ void MainWindow::processBufferedActivity() {
|
|||||||
|
|
||||||
// regardless of valid or not, remove the "complete" buffered message from the buffer cache
|
// regardless of valid or not, remove the "complete" buffered message from the buffer cache
|
||||||
m_messageBuffer.remove(freq);
|
m_messageBuffer.remove(freq);
|
||||||
|
m_lastClosedMessageBufferOffset = freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +137,7 @@ public slots:
|
|||||||
void playSoundFile(const QString &path);
|
void playSoundFile(const QString &path);
|
||||||
bool hasExistingMessageBufferToMe(int *pOffset);
|
bool hasExistingMessageBufferToMe(int *pOffset);
|
||||||
bool hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffset);
|
bool hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffset);
|
||||||
|
bool hasClosedExistingMessageBuffer(int offset);
|
||||||
void logCallActivity(CallDetail d, bool spot=true);
|
void logCallActivity(CallDetail d, bool spot=true);
|
||||||
void logHeardGraph(QString from, QString to);
|
void logHeardGraph(QString from, QString to);
|
||||||
QString lookupCallInCompoundCache(QString const &call);
|
QString lookupCallInCompoundCache(QString const &call);
|
||||||
@ -843,6 +844,7 @@ private:
|
|||||||
QMap<int, int> m_rxFrameBlockNumbers; // freq -> block
|
QMap<int, int> m_rxFrameBlockNumbers; // freq -> block
|
||||||
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
|
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
|
||||||
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
|
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
|
||||||
|
int m_lastClosedMessageBufferOffset;
|
||||||
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
|
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
|
||||||
QMap<QString, QDateTime> m_aprsCallCache;
|
QMap<QString, QDateTime> m_aprsCallCache;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user