Merged from trunk:

------------------------------------------------------------------------
r7861 | k9an | 2017-07-12 22:49:39 +0100 (Wed, 12 Jul 2017) | 1 line

Use quarter-symbol steps for time sync. Lower sync threshold. Implement subtraction and two pass decoding. Use osd2 only near nfqso.
------------------------------------------------------------------------
r7862 | k9an | 2017-07-13 01:28:57 +0100 (Thu, 13 Jul 2017) | 1 line

Fix NHSYM.
------------------------------------------------------------------------
r7863 | k9an | 2017-07-13 01:31:52 +0100 (Thu, 13 Jul 2017) | 1 line

Fix a comment. No code changes.
------------------------------------------------------------------------
r7864 | k9an | 2017-07-13 01:43:56 +0100 (Thu, 13 Jul 2017) | 1 line

Fix another bounds error.
------------------------------------------------------------------------
r7879 | k1jt | 2017-07-14 17:02:01 +0100 (Fri, 14 Jul 2017) | 1 line

Code cleanup and test ofFT8 decodes with erasures.  Do not use on the air.
------------------------------------------------------------------------
r7881 | k1jt | 2017-07-14 19:19:48 +0100 (Fri, 14 Jul 2017) | 1 line

Fix nutc in jt9; alternative sync value for late-start FT8 signals.
------------------------------------------------------------------------
r7882 | k9an | 2017-07-14 20:22:53 +0100 (Fri, 14 Jul 2017) | 1 line

Move ft8apset to a separate file.
------------------------------------------------------------------------
r7884 | k9an | 2017-07-14 20:35:22 +0100 (Fri, 14 Jul 2017) | 1 line

Add ft8apset.f90.
------------------------------------------------------------------------
r7885 | k9an | 2017-07-14 20:46:04 +0100 (Fri, 14 Jul 2017) | 1 line

Update call to ft8b.
------------------------------------------------------------------------
r7886 | k9an | 2017-07-14 21:12:29 +0100 (Fri, 14 Jul 2017) | 1 line

More work on ap.
------------------------------------------------------------------------
r7887 | k9an | 2017-07-14 23:09:50 +0100 (Fri, 14 Jul 2017) | 1 line

More work on AP. Deep decode is unstable - not for use on the air.
------------------------------------------------------------------------
r7890 | k9an | 2017-07-15 01:33:25 +0100 (Sat, 15 Jul 2017) | 1 line

Turn off ap.
------------------------------------------------------------------------
r7891 | k9an | 2017-07-15 02:49:44 +0100 (Sat, 15 Jul 2017) | 1 line

Add some more items to the lun 81 diagnostics.
------------------------------------------------------------------------
r7892 | k9an | 2017-07-15 15:21:18 +0100 (Sat, 15 Jul 2017) | 1 line

Properly calculate metrics for non-ap bits that reside in symbols that contain ap bits.
------------------------------------------------------------------------
r7893 | k9an | 2017-07-15 16:43:41 +0100 (Sat, 15 Jul 2017) | 1 line

Use overlap and add to apply reference filter/amplitude equalization.
------------------------------------------------------------------------
r7894 | k9an | 2017-07-15 16:46:46 +0100 (Sat, 15 Jul 2017) | 1 line

Improve a comment.
------------------------------------------------------------------------
r7895 | k9an | 2017-07-16 01:10:37 +0100 (Sun, 16 Jul 2017) | 1 line

Make refspec filter causal for overlap and add.
------------------------------------------------------------------------
r7911 | k9an | 2017-07-16 16:56:06 +0100 (Sun, 16 Jul 2017) | 1 line

More work on Deep decoding.
------------------------------------------------------------------------
r7917 | k9an | 2017-07-16 18:08:09 +0100 (Sun, 16 Jul 2017) | 1 line

Properly round the printed snr.
------------------------------------------------------------------------
r7925 | k9an | 2017-07-18 02:12:11 +0100 (Tue, 18 Jul 2017) | 1 line

Work on ap decoding. Diagnostic write enabled.
------------------------------------------------------------------------
r7926 | k9an | 2017-07-18 16:22:20 +0100 (Tue, 18 Jul 2017) | 1 line

Fix a bug in AP decoding when iaptype=2. Decrease time-sync search range to +/- 1.5s. Fix a big with erasure decoding.
------------------------------------------------------------------------
r7927 | k1jt | 2017-07-20 00:23:20 +0100 (Thu, 20 Jul 2017) | 1 line

Remove slider next to audio level meter.
------------------------------------------------------------------------
r7928 | k1jt | 2017-07-20 16:15:00 +0100 (Thu, 20 Jul 2017) | 6 lines

1. Alt+F8 arms "Call 1st" as if a CQ had been sent.
2. "Call 1st" label turns red when armed to respond to a caller.
3. Suppress some recognizable false decodes, send them to cumulative file
   "data_dir/false_decodes.txt".
4. Reduce sleep delay in decoder() to 10 ms.

------------------------------------------------------------------------
r7929 | k1jt | 2017-07-20 20:23:17 +0100 (Thu, 20 Jul 2017) | 1 line

Fix wording in list of keyboard shortcuts.
------------------------------------------------------------------------
r7930 | k1jt | 2017-07-20 20:25:08 +0100 (Thu, 20 Jul 2017) | 2 lines

Comment out diagnostic write.

------------------------------------------------------------------------
r7931 | k9an | 2017-07-20 22:08:36 +0100 (Thu, 20 Jul 2017) | 1 line

Only print dupes if SNR is higher than what has already been printed.
------------------------------------------------------------------------
r7932 | k9an | 2017-07-21 23:02:06 +0100 (Fri, 21 Jul 2017) | 1 line

Add to the list of allowed keywords in jtmsg.f90.
------------------------------------------------------------------------
r7933 | k9an | 2017-07-22 04:01:09 +0100 (Sat, 22 Jul 2017) | 1 line

Add variables lapon and napwid to control ap decoding. Reconfigure the logic for AP decoding and ordered-statistics decoding.
------------------------------------------------------------------------
r7934 | k9an | 2017-07-22 14:21:03 +0100 (Sat, 22 Jul 2017) | 1 line

Prevent a certain type of non-standard message from being flagged as a false decode.
------------------------------------------------------------------------
r7935 | k9an | 2017-07-22 18:12:48 +0100 (Sat, 22 Jul 2017) | 1 line

More informative end-of-line annotation for AP decodes.
------------------------------------------------------------------------
r7936 | k9an | 2017-07-24 15:23:22 +0100 (Mon, 24 Jul 2017) | 1 line

Bring msk144d2 more up to date. Runs now, but still needs more work.
------------------------------------------------------------------------
r7937 | k1jt | 2017-07-24 15:48:16 +0100 (Mon, 24 Jul 2017) | 2 lines

Correct the spacing between marked lowest and highest FT8 tones for RxFreq (green) and TxFreq (red). 

------------------------------------------------------------------------
r7938 | bsomervi | 2017-07-24 20:27:14 +0100 (Mon, 24 Jul 2017) | 4 lines

Add double clickable push button and radio button widgets

These emit  doubleClicked signal  when double-clicked,  otherwise they
are identical to their super-classes.
------------------------------------------------------------------------
r7939 | bsomervi | 2017-07-24 20:27:23 +0100 (Mon, 24 Jul 2017) | 42 lines

Add the  option to ALT+click  a decoded CQ  or QRZ message  which only
moves the Rx  frequency to theirs, this facilitates  calling a station
who is busy and may have  many callers on their frequency. Updated the
corresponding mouse shortcuts help text.

Allow for times with seconds when parsing fast mode and FT8 decodes.

Exclude the RR73 grid square from  and grid validation or matching, it
is not a grid square any more as  far as WSJT-X is concerned, it is an
RRR substitute.

Add a  simple state  machine for  QSO progress  such that  replies and
auto-sequencing can be better controlled.

Get compound callsign edge cases working again and allow QSOs from and
to compound callsign holders working in as many situations as possible
including  auto-sequencing and  FT8 auto-reply  mode.  This  does mean
that a  "DE W6/K1ABC DM93"  type message close to  a callers Tx  or Rx
frequency will be taken  as a reply to a CQ call  despite it not being
explicitly addressed back to the  CQ caller. Compound callsigns should
work in MSK144 contest  mode also as well as in  short code modes with
some  minor  restrictions   (short  codes  will  not   be  used  where
configuration demands that  a message be used to send  a full compound
callsign).

Auto sequencing  has been made  generic such that  it can be  used for
more than one mode if desired.

Allow the use of free text messages to sign off in auto sequenced QSOs
without the message  being overwritten by the  sequencer. Double click
actions have  been added to the  Tx5 radio and push  buttons to revert
back to the default standard 73 message.

Make DisplayText  class interface  more idiomatic  C++ and  simplify a
bit.

Fixed  some  displayed widget  arrangements  for  different modes  and
sub-modes  so that  they  are  consistent when  starting  up and  when
switching mode or sub-mode.

This is  a big change which  has been extensively tested  but no doubt
there will also be some new defects introduced.
------------------------------------------------------------------------
r7940 | bsomervi | 2017-07-25 17:51:19 +0100 (Tue, 25 Jul 2017) | 1 line

Fix issue with Tx5 not being generated with a new DX Call
------------------------------------------------------------------------
r7941 | bsomervi | 2017-07-25 17:51:27 +0100 (Tue, 25 Jul 2017) | 1 line

Fix country name display that broke in r7939
------------------------------------------------------------------------
r7942 | bsomervi | 2017-07-25 17:51:34 +0100 (Tue, 25 Jul 2017) | 1 line

Ensure JT9 lowest decode frequency spin box is disabled when not available
------------------------------------------------------------------------
r7943 | bsomervi | 2017-07-25 17:51:42 +0100 (Tue, 25 Jul 2017) | 4 lines

Pick up tail-enders when completing a call 1st QSO after re-enabling auto Tx

Allow  any message  to  start  a QSO  so  long as  we  are  not in  an
auto-reply QSO.
------------------------------------------------------------------------
r7944 | bsomervi | 2017-07-25 17:51:49 +0100 (Tue, 25 Jul 2017) | 1 line

Exclude all decode quality markers from internal decode parsing and matching
------------------------------------------------------------------------
r7945 | k9an | 2017-07-25 20:06:05 +0100 (Tue, 25 Jul 2017) | 1 line

Move '?' quality warning to message(22:22).
------------------------------------------------------------------------
r7946 | k9an | 2017-07-25 21:55:13 +0100 (Tue, 25 Jul 2017) | 1 line

Reject candiates with fewer than 7 correct hard-decoded sync symbols.
------------------------------------------------------------------------
r7947 | bsomervi | 2017-07-26 02:38:37 +0100 (Wed, 26 Jul 2017) | 1 line

Force Settings tab to Radio tab when navigating there from a rig error message
------------------------------------------------------------------------
r7948 | bsomervi | 2017-07-26 02:38:44 +0100 (Wed, 26 Jul 2017) | 1 line

Correct the highlighting of the Call 1st check box label
------------------------------------------------------------------------
r7949 | bsomervi | 2017-07-26 02:38:57 +0100 (Wed, 26 Jul 2017) | 5 lines

Option to skip using grid reply message

Enable and disable  by double-clicking the Tx1 button  or the adjacent
radio button.  Tx1 message shows  grayed out  when the Tx1  message is
elided.
------------------------------------------------------------------------
r7950 | bsomervi | 2017-07-26 02:39:04 +0100 (Wed, 26 Jul 2017) | 6 lines

Option to use RR73 grid message as RRR message substitutes

Enable or  disable by double-clicking  the Tx4 button or  the adjacent
radio button. Is auto disabled by a band change as it is expected that
the user  reassess the  conditions to see  if message  repetitions are
unlikely to be needed.
------------------------------------------------------------------------
r7951 | bsomervi | 2017-07-26 02:39:11 +0100 (Wed, 26 Jul 2017) | 1 line

Fix highlighting of the call first check box label
------------------------------------------------------------------------
r7952 | bsomervi | 2017-07-26 02:39:23 +0100 (Wed, 26 Jul 2017) | 1 line

Better behavior and tool tips for Txn buttons and radio buttons
------------------------------------------------------------------------
r7953 | bsomervi | 2017-07-26 02:39:30 +0100 (Wed, 26 Jul 2017) | 1 line

Auto Tx stop when calling a CQer who answers another station on your Tx frequency
------------------------------------------------------------------------
r7954 | bsomervi | 2017-07-26 11:56:12 +0100 (Wed, 26 Jul 2017) | 1 line

Add menu option to turn on AP decoding in FT8 mode
------------------------------------------------------------------------
r7955 | k9an | 2017-07-26 14:05:34 +0100 (Wed, 26 Jul 2017) | 1 line

Enable AP for any decoding level.
------------------------------------------------------------------------
r7956 | k1jt | 2017-07-26 14:44:31 +0100 (Wed, 26 Jul 2017) | 1 line

Remove obsolete test program.
------------------------------------------------------------------------
r7957 | bsomervi | 2017-07-26 22:18:59 +0100 (Wed, 26 Jul 2017) | 11 lines

Use the low confidence decode quality marker to elide spots and pass info via UDP

The UDP  decode and reply message  have been augmented with  a boolean
flag denoting a  low confidence decode when set.  Existing clients can
safely use the  reply message without passing the flag  as the default
value will  still action  messages that have  high confidence.  If low
confidence decodes  are to be passed  back via the reply  message then
the low  confidence flag must be  included and correctly set  to match
the original decode.

See NetworkMessage.hpp for message fields and meanings.
------------------------------------------------------------------------
r7958 | bsomervi | 2017-07-26 22:19:21 +0100 (Wed, 26 Jul 2017) | 3 lines

Add QSO state machine state and tx audio offset to parameters passed to slow decoders

Required to pick best AP masks in FT8 decoder
------------------------------------------------------------------------
r7959 | bsomervi | 2017-07-26 23:03:02 +0100 (Wed, 26 Jul 2017) | 1 line

Extend grids looked up from CALL3.TXT from 4 to 6-digits if first 4 match
------------------------------------------------------------------------
r7960 | k9an | 2017-07-27 16:35:40 +0100 (Thu, 27 Jul 2017) | 1 line

nQSOProgress now controls AP decoding. Needs testing - may not be stable with AP enabled.
------------------------------------------------------------------------
r7961 | k9an | 2017-07-27 19:07:54 +0100 (Thu, 27 Jul 2017) | 1 line

Correct some logic so that AP is only on when selected and so that AP decodes of type 4 or greater are limited to the vicinity of nfqso or nftx.
------------------------------------------------------------------------
r7962 | k1jt | 2017-07-27 19:57:53 +0100 (Thu, 27 Jul 2017) | 2 lines

Remove unused arguments from the call to fix_contest_msg().

------------------------------------------------------------------------
r7963 | k1jt | 2017-07-27 21:17:30 +0100 (Thu, 27 Jul 2017) | 1 line

Working on some features for NA VHF contests.  Not finished!
------------------------------------------------------------------------
r7964 | bsomervi | 2017-07-28 01:00:42 +0100 (Fri, 28 Jul 2017) | 1 line

Fix syntax error in statement function definition
------------------------------------------------------------------------
r7965 | bsomervi | 2017-07-28 02:20:22 +0100 (Fri, 28 Jul 2017) | 6 lines

Revert "Extend grids looked up from CALL3.TXT from 4 to 6-digits if first 4 match"

Bad idea, need to  find a better way to extend  grids to 6-digits from
CALL3.TXT.

This reverts commit r7959
------------------------------------------------------------------------
r7968 | k9an | 2017-07-28 16:35:17 +0100 (Fri, 28 Jul 2017) | 1 line

Comment out diagnostic write to lun 81.
------------------------------------------------------------------------
r7969 | k1jt | 2017-07-28 16:50:13 +0100 (Fri, 28 Jul 2017) | 2 lines

Make 72-bit "contest mode" available in FT8 as well as MSK144.

------------------------------------------------------------------------
r7970 | bsomervi | 2017-07-29 00:25:32 +0100 (Sat, 29 Jul 2017) | 7 lines

Change tolerances for auto stop and auto-sequence of some messages

FT8 auto-stop  will only react to  messages within +/- 50Hz  of our Tx
frequency.

Auto-sequence on  "DE ..." and free  text 73 messages will  respond if
they are within 25Hz of our Tx or Rx frequency.
------------------------------------------------------------------------
r7971 | bsomervi | 2017-07-31 02:28:25 +0100 (Mon, 31 Jul 2017) | 1 line

Add extra hidden string length argument to genft8 interface
------------------------------------------------------------------------
r7972 | bsomervi | 2017-07-31 02:28:33 +0100 (Mon, 31 Jul 2017) | 5 lines

Fix FT8 call first behaviour with "Lock Tx=Rx"

Call first combined with "Lock Tx=Rx" (why would anyone consider doing
that!)   should continue  on the  Tx  frequency of  the station  being
worked and not be switched another calling station's frequency.
------------------------------------------------------------------------
r7973 | k1jt | 2017-08-01 19:01:27 +0100 (Tue, 01 Aug 2017) | 1 line

Utility for generating figure for QST/RadCom article.
------------------------------------------------------------------------
r7974 | k1jt | 2017-08-01 19:16:01 +0100 (Tue, 01 Aug 2017) | 2 lines

Tidy up some details for 72-bit contest mode in FT8.

------------------------------------------------------------------------
r7975 | k1jt | 2017-08-01 19:46:12 +0100 (Tue, 01 Aug 2017) | 2 lines

Don't highlight FT8 contest-mode Tx3 message as a free-text message.

------------------------------------------------------------------------
r7976 | k1jt | 2017-08-01 20:32:54 +0100 (Tue, 01 Aug 2017) | 2 lines

Fix the "F4" shortcut description; add usage advuice to "Lock Tx=Rx" tool tip.

------------------------------------------------------------------------
r7980 | k1jt | 2017-08-02 15:05:37 +0100 (Wed, 02 Aug 2017) | 2 lines

Enable "nagain" for FT8, as in other modes.

------------------------------------------------------------------------
r7987 | k1jt | 2017-08-02 20:23:42 +0100 (Wed, 02 Aug 2017) | 2 lines

Updates to the WSJT-X User Guide for Version 1.8.

------------------------------------------------------------------------
r7988 | k1jt | 2017-08-02 20:27:43 +0100 (Wed, 02 Aug 2017) | 2 lines

Add several new screen shots.

------------------------------------------------------------------------
r7989 | k1jt | 2017-08-02 21:43:06 +0100 (Wed, 02 Aug 2017) | 2 lines

Allow auto-seq in QRA64 mode; updates to User Guide.

------------------------------------------------------------------------
r7992 | bsomervi | 2017-08-03 12:23:07 +0100 (Thu, 03 Aug 2017) | 7 lines

Fix an issue with VFO tuning while running Doppler correction

Holding down  the SHIFT  key while  tuning the  rig should  update the
nominal  sked frequency,  not holding  done the  SHIFT key  should not
update the  sked frequency. This  is not  yet perfect and  sometimes a
change to the nominal sked frequency can  get through but it is a rare
as yet unfound race condition.
------------------------------------------------------------------------
r7993 | k9an | 2017-08-03 15:46:21 +0100 (Thu, 03 Aug 2017) | 1 line

1. Use norder=3 for nagain, 2. Renumber aptypes.
------------------------------------------------------------------------
r7994 | k1jt | 2017-08-03 15:48:59 +0100 (Thu, 03 Aug 2017) | 2 lines

Remove the "Weak" checkbox from GUI, it's not implemented. 

------------------------------------------------------------------------
r7995 | k1jt | 2017-08-03 16:12:30 +0100 (Thu, 03 Aug 2017) | 2 lines

More updates to the WSJT-X User Guide.

------------------------------------------------------------------------



git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx-1.8@7996 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2017-08-03 16:42:10 +00:00
parent eb69241151
commit c669046be1
93 changed files with 2186 additions and 1049 deletions

View File

@ -260,6 +260,8 @@ set (wsjt_qt_CXXSRCS
CallsignValidator.cpp
SplashScreen.cpp
EqualizationToolsDialog.cpp
DoubleClickablePushButton.cpp
DoubleClickableRadioButton.cpp
)
set (wsjt_qtmm_CXXSRCS
@ -376,6 +378,7 @@ set (wsjt_FSRCS
lib/fsk4hf/chkcrc10.f90
lib/fsk4hf/chkcrc12.f90
lib/fsk4hf/chkcrc12a.f90
lib/chkcall.f90
lib/chkhist.f90
lib/chkmsg.f90
lib/chkss2.f90
@ -433,6 +436,7 @@ set (wsjt_FSRCS
lib/fqso_first.f90
lib/freqcal.f90
lib/fsk4hf/fsk4hf.f90
lib/fsk4hf/ft8apset.f90
lib/fsk4hf/ft8b.f90
lib/fsk4hf/ft8_downsample.f90
lib/fsk4hf/ft8sim.f90
@ -473,6 +477,7 @@ set (wsjt_FSRCS
lib/iscat.f90
lib/jplsubs.f
lib/jt9fano.f90
lib/jtmsg.f90
lib/ldpcsim144.f90
lib/fsk4hf/ldpcsim120.f90
lib/fsk4hf/ldpcsim168.f90

View File

@ -603,6 +603,7 @@ QDir Configuration::data_dir () const {return m_->data_dir_;}
QDir Configuration::writeable_data_dir () const {return m_->writeable_data_dir_;}
QDir Configuration::temp_dir () const {return m_->temp_dir_;}
void Configuration::select_tab (int index) {m_->ui_->configuration_tabs->setCurrentIndex (index);}
int Configuration::exec () {return m_->exec ();}
bool Configuration::is_active () const {return m_->isVisible ();}

View File

@ -73,6 +73,7 @@ public:
QWidget * parent = nullptr);
~Configuration ();
void select_tab (int);
int exec ();
bool is_active () const;

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>521</width>
<width>536</width>
<height>507</height>
</rect>
</property>
@ -188,6 +188,12 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
@ -237,6 +243,12 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
@ -301,6 +313,12 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
@ -390,6 +408,12 @@ quiet period when decoding is done.</string>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
@ -1882,6 +1906,12 @@ for assessing propagation and system performance.</string>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
@ -2178,6 +2208,12 @@ Right click for insert and delete options.</string>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
@ -2198,6 +2234,12 @@ Right click for insert and delete options.</string>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
@ -2300,7 +2342,7 @@ Right click for insert and delete options.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Exchange 4-character grid locators instead of reports. See User Guide for details.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>MSK144 Contest Mode</string>
<string>FT8 and MSK144 Contest Mode</string>
</property>
</widget>
</item>
@ -2595,9 +2637,9 @@ soundcard changes</string>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="TX_mode_button_group"/>
</buttongroups>
</ui>

View File

@ -0,0 +1,14 @@
#include "DoubleClickablePushButton.hpp"
#include "moc_DoubleClickablePushButton.cpp"
DoubleClickablePushButton::DoubleClickablePushButton (QWidget * parent)
: QPushButton {parent}
{
}
void DoubleClickablePushButton::mouseDoubleClickEvent (QMouseEvent * event)
{
Q_EMIT doubleClicked ();
QPushButton::mouseDoubleClickEvent (event);
}

View File

@ -0,0 +1,27 @@
#ifndef DOUBLE_CLICKABLE_PUSH_BUTTON_HPP_
#define DOUBLE_CLICKABLE_PUSH_BUTTON_HPP_
#include <QPushButton>
//
// DoubleClickablePushButton - QPushButton that emits a mouse double
// click signal
//
// Clients should be aware of the QWidget::mouseDoubleClickEvent()
// notes about receipt of mouse press and mouse release events.
//
class DoubleClickablePushButton
: public QPushButton
{
Q_OBJECT
public:
DoubleClickablePushButton (QWidget * = nullptr);
Q_SIGNAL void doubleClicked ();
protected:
void mouseDoubleClickEvent (QMouseEvent *) override;
};
#endif

View File

@ -0,0 +1,14 @@
#include "DoubleClickableRadioButton.hpp"
#include "moc_DoubleClickableRadioButton.cpp"
DoubleClickableRadioButton::DoubleClickableRadioButton (QWidget * parent)
: QRadioButton {parent}
{
}
void DoubleClickableRadioButton::mouseDoubleClickEvent (QMouseEvent * event)
{
Q_EMIT doubleClicked ();
QRadioButton::mouseDoubleClickEvent (event);
}

View File

@ -0,0 +1,27 @@
#ifndef DOUBLE_CLICKABLE_RADIO_BUTTON_HPP_
#define DOUBLE_CLICKABLE_RADIO_BUTTON_HPP_
#include <QRadioButton>
//
// DoubleClickableRadioButton - QRadioButton that emits a mouse double
// click signal
//
// Clients should be aware of the QWidget::mouseDoubleClickEvent()
// notes about receipt of mouse press and mouse release events.
//
class DoubleClickableRadioButton
: public QRadioButton
{
Q_OBJECT
public:
DoubleClickableRadioButton (QWidget * = nullptr);
Q_SIGNAL void doubleClicked ();
protected:
void mouseDoubleClickEvent (QMouseEvent *) override;
};
#endif

View File

@ -151,11 +151,13 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
quint32 delta_frequency;
QByteArray mode;
QByteArray message;
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
bool low_confidence {false};
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message >> low_confidence;
if (check_status (in) != Fail)
{
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence);
}
}
break;
@ -366,13 +368,14 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
}
void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message_text)
, QString const& mode, QString const& message_text, bool low_confidence)
{
if (m_->server_port_ && !m_->server_string_.isEmpty ())
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_, m_->schema_};
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
<< message_text.toUtf8 () << low_confidence;
m_->send_message (out, message);
}
}

View File

@ -53,7 +53,7 @@ public:
, QString const& dx_grid, bool watchdog_timeout, QString const& sub_mode
, bool fast_mode);
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
Q_SLOT void WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power);
Q_SLOT void clear_decodes ();
@ -70,7 +70,7 @@ public:
// this signal is emitted if the server sends us a reply, the only
// reply supported is reply to a prior CQ or QRZ message
Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message_text);
, QString const& message_text, bool low_confidence);
// this signal is emitted if the server has requested a replay of
// all decodes

View File

@ -241,11 +241,14 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
quint32 delta_frequency;
QByteArray mode;
QByteArray message;
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
bool low_confidence;
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode
>> message >> low_confidence;
if (check_status (in) != Fail)
{
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence);
}
}
break;
@ -396,14 +399,15 @@ void MessageServer::start (port_type port, QHostAddress const& multicast_group_a
}
}
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text)
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text, bool low_confidence)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_};
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
out << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
<< message_text.toUtf8 () << low_confidence;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}

View File

@ -46,7 +46,7 @@ public:
// note that the client is not obliged to take any action and only
// takes any action if the decode is present and is a CQ or QRZ message
Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
// ask the client with identification 'id' to replay all decodes
Q_SLOT void replay (QString const& id);
@ -69,7 +69,8 @@ public:
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode);
Q_SIGNAL void client_closed (QString const& id);
Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message);
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence);
Q_SIGNAL void WSPR_decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power);
Q_SIGNAL void qso_logged (QString const& id, QDateTime timeOff, QString const& dx_call, QString const& dx_grid

View File

@ -156,13 +156,19 @@
* Delta frequency (Hz) quint32
* Mode utf8
* Message utf8
* Low confidence bool
*
* The decode message is sent when a new decode is completed, in
* this case the 'New' field is true. It is also used in response
* to a "Replay" message where each old decode in the "Band
* activity" window, that has not been erased, is sent in order
* as a one of these messages with the 'New' field set to
* false. See the "Replay" message below for details of usage.
* as a one of these messages with the 'New' field set to false.
* See the "Replay" message below for details of usage. Low
* confidence decodes are flagged in protocols where the decoder
* has knows that a decode has a higher than normal probability
* of being false, they should not be reported on publicly
* accessible services without some attached warning or further
* validation.
*
*
* Clear Out 3 quint32
@ -184,6 +190,7 @@
* Delta frequency (Hz) quint32
* Mode utf8
* Message utf8
* Low confidence bool
*
* In order for a server to provide a useful cooperative service
* to WSJT-X it is possible for it to initiate a QSO by sending

View File

@ -244,7 +244,7 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
, QString const& /*message*/)
, QString const& /*message*/, bool /*low_confidence*/)
{
if (client_id == id_)
{

View File

@ -33,7 +33,7 @@ public:
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode);
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message);
, QString const& message, bool low_confidence);
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift
, QString const& callsign, QString const& grid, qint32 power);

View File

@ -17,13 +17,19 @@ namespace
QT_TRANSLATE_NOOP ("DecodesModel", "DF"),
QT_TRANSLATE_NOOP ("DecodesModel", "Md"),
QT_TRANSLATE_NOOP ("DecodesModel", "Message"),
QT_TRANSLATE_NOOP ("DecodesModel", "Confidence"),
};
QString confidence_string (bool low_confidence)
{
return low_confidence ? QT_TRANSLATE_NOOP ("DecodesModel", "low") : QT_TRANSLATE_NOOP ("DecodesModel", "high");
}
QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool is_fast)
, bool low_confidence, bool is_fast)
{
auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")};
time_item->setData (time);
@ -44,8 +50,11 @@ namespace
auto md = new QStandardItem {mode};
md->setTextAlignment (Qt::AlignHCenter);
auto confidence = new QStandardItem {confidence_string (low_confidence)};
confidence->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, new QStandardItem {message}};
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, new QStandardItem {message}, confidence};
Q_FOREACH (auto& item, row)
{
item->setEditable (false);
@ -57,7 +66,7 @@ namespace
}
DecodesModel::DecodesModel (QObject * parent)
: QStandardItemModel {0, 7, parent}
: QStandardItemModel {0, sizeof (headings) / sizeof (headings[0]), parent}
{
int column {0};
for (auto const& heading : headings)
@ -68,7 +77,7 @@ DecodesModel::DecodesModel (QObject * parent)
void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message
, bool is_fast)
, bool low_confidence, bool is_fast)
{
if (!is_new)
{
@ -83,7 +92,8 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
&& item (row, 3)->data ().toFloat () == delta_time
&& item (row, 4)->data ().toUInt () == delta_frequency
&& data (index (row, 5)).toString () == mode
&& data (index (row, 6)).toString () == message)
&& data (index (row, 6)).toString () == message
&& data (index (row, 7)).toString () == confidence_string (low_confidence))
{
return;
}
@ -96,12 +106,12 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
if (target_row >= 0)
{
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, delta_frequency, mode
, message, is_fast));
, message, low_confidence, is_fast));
return;
}
}
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, is_fast));
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, low_confidence, is_fast));
}
void DecodesModel::clear_decodes (QString const& client_id)
@ -124,7 +134,8 @@ void DecodesModel::do_reply (QModelIndex const& source)
, item (row, 3)->data ().toFloat ()
, item (row, 4)->data ().toInt ()
, data (index (row, 5)).toString ()
, data (index (row, 6)).toString ());
, data (index (row, 6)).toString ()
, confidence_string (true) == data (index (row, 7)).toString ());
}
#include "moc_DecodesModel.cpp"

View File

@ -32,12 +32,13 @@ public:
explicit DecodesModel (QObject * parent = nullptr);
Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message, bool is_fast);
, quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool is_fast);
Q_SLOT void clear_decodes (QString const& client_id);
Q_SLOT void do_reply (QModelIndex const& source);
Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message);
, QString const& mode, QString const& message, bool low_confidence);
};
#endif

View File

@ -91,9 +91,9 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time
, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode
, QString const& message) {
, QString const& message, bool low_confidence) {
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message
, dock_widgets_[id]->fast_mode ());});
, low_confidence, dock_widgets_[id]->fast_mode ());});
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
connect (server_, &MessageServer::clear_decodes, decodes_model_, &DecodesModel::clear_decodes);
connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes);

View File

@ -69,13 +69,13 @@ public:
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime time, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message)
, QString const& message, bool low_confidence)
{
if (client_id == id_)
{
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency
<< "mode:" << mode;
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high");
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl;
}
}

View File

@ -26,7 +26,10 @@ extern struct dec_data {
int nutc; //UTC as integer, HHMM
bool ndiskdat; //true ==> data read from *.wav file
int ntrperiod; //TR period (seconds)
int nQSOProgress; /* QSO state machine state */
int nfqso; //User-selected QSO freq (kHz)
int nftx; /* Transmit audio offset where
replies might be expected */
bool newdat; //true ==> new data, must do long FFT
int npts8; //npts for c0() array
int nfa; //Low decode limit (Hz)
@ -38,6 +41,8 @@ extern struct dec_data {
int nsubmode;
bool nagain;
int ndepth;
bool lapon;
int napwid;
int ntxmode;
int nmode;
int minw;

View File

@ -3,6 +3,11 @@
#include <QStringList>
#include <QRegularExpression>
extern "C" {
bool stdmsg_(const char* msg, int len);
}
QString DecodedText::CQersCall()
{
// extract the CQer's call TODO: does this work with all call formats?
@ -37,12 +42,12 @@ QString DecodedText::CQersCall()
bool DecodedText::isJT65()
{
return _string.indexOf("#") == column_mode;
return _string.indexOf("#") == column_mode + padding_;
}
bool DecodedText::isJT9()
{
return _string.indexOf("@") == column_mode;
return _string.indexOf("@") == column_mode + padding_;
}
bool DecodedText::isTX()
@ -51,9 +56,14 @@ bool DecodedText::isTX()
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
}
bool DecodedText::isLowConfidence ()
{
return QChar {'?'} == _string.mid (padding_ + column_qsoText + 21, 1);
}
int DecodedText::frequencyOffset()
{
return _string.mid(column_freq,4).toInt();
return _string.mid(column_freq + padding_,4).toInt();
}
int DecodedText::snr()
@ -64,7 +74,7 @@ int DecodedText::snr()
float DecodedText::dt()
{
return _string.mid(column_dt,5).toFloat();
return _string.mid(column_dt + padding_,5).toFloat();
}
/*
@ -79,7 +89,7 @@ float DecodedText::dt()
// find and extract any report. Returns true if this is a standard message
bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report)
{
QString msg=_string.mid(column_qsoText).trimmed();
QString msg=_string.mid(column_qsoText + padding_).trimmed();
if(msg.length() < 1) return false;
msg = msg.left (22).remove (QRegularExpression {"[<>]"});
int i1=msg.indexOf('\r');
@ -124,7 +134,7 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
QString DecodedText::call()
{
auto call = _string;
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText);
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
int i = call.indexOf(" ");
return call.mid(0,i);
}
@ -134,7 +144,7 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid)
{
auto msg = _string;
if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText);
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
int i1 = msg.indexOf (" ");
call = msg.mid (i1 + 1);
int i2 = call.indexOf (" ");

View File

@ -15,79 +15,79 @@
/*
0123456789012345678901234567890123456789
^ ^ ^ ^ ^ ^
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
^ ^ ^ ^ ^ ^
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
0605 Tx 1259 # CQ VK3ACF QF22
0605 Tx 1259 # CQ VK3ACF QF22
*/
class DecodedText
{
public:
// These define the columns in the decoded text where fields are to be found.
// We rely on these columns being the same in the fortran code (lib/decoder.f90) that formats the decoded text
enum Columns { column_time = 0,
column_snr = 5,
column_dt = 9,
column_freq = 14,
column_mode = 19,
column_qsoText = 22 };
void operator=(const QString &rhs)
{
_string = rhs;
padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds
};
void operator=(const QByteArray &rhs)
{
_string = rhs;
padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds
};
void operator=(const QString &rhs)
{
_string = rhs;
};
void operator=(const QByteArray &rhs)
{
_string = rhs;
};
void operator+=(const QString &rhs)
{
_string += rhs;
};
void operator+=(const QString &rhs)
{
_string += rhs;
};
QString string() { return _string; };
QString string() { return _string; };
int indexOf(QString s) { return _string.indexOf(s); };
int indexOf(QString s, int i) { return _string.indexOf(s,i); };
QString mid(int f, int t) { return _string.mid(f,t); };
QString left(int i) { return _string.left(i); };
int indexOf(QString s) { return _string.indexOf(s); };
int indexOf(QString s, int i) { return _string.indexOf(s,i); };
QString mid(int f, int t) { return _string.mid(f,t); };
QString left(int i) { return _string.left(i); };
void clear() { _string.clear(); };
void clear() { _string.clear(); };
QString CQersCall();
QString CQersCall();
bool isJT65();
bool isJT9();
bool isTX();
bool isLowConfidence ();
int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency
int snr();
float dt();
bool isJT65();
bool isJT9();
bool isTX();
int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency
int snr();
float dt();
// find and extract any report. Returns true if this is a standard message
// find and extract any report. Returns true if this is a standard message
bool report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report);
// get the first text word, usually the call
QString call();
// get the first message text word, usually the call
QString call();
// get the second word, most likely the de call and the third word, most likely grid
void deCallAndGrid(/*out*/QString& call, QString& grid);
// get the second word, most likely the de call and the third word, most likely grid
void deCallAndGrid(/*out*/QString& call, QString& grid);
int timeInSeconds();
int timeInSeconds();
// returns a string of the SNR field with a leading + or - followed by two digits
QString report();
// returns a string of the SNR field with a leading + or - followed by two digits
QString report();
private:
QString _string;
// These define the columns in the decoded text where fields are to be found.
// We rely on these columns being the same in the fortran code (lib/decoder.f90) that formats the decoded text
enum Columns {column_time = 0,
column_snr = 5,
column_dt = 9,
column_freq = 14,
column_mode = 19,
column_qsoText = 22 };
QString _string;
int padding_;
};
extern "C" { bool stdmsg_(const char* msg, int len); }
#endif // DECODEDTEXT_H

View File

@ -40,8 +40,8 @@ void DisplayText::setContentFont(QFont const& font)
void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
{
bool ctrl = (e->modifiers() & Qt::ControlModifier);
bool shift = (e->modifiers() & Qt::ShiftModifier);
emit(selectCallsign(shift,ctrl));
bool alt = (e->modifiers() & Qt::AltModifier);
emit(selectCallsign(alt,ctrl));
QTextEdit::mouseDoubleClickEvent(e);
}
@ -72,24 +72,24 @@ void DisplayText::appendText(QString const& text, QString const& bg)
}
void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg,
QString DisplayText::_appendDXCCWorkedB4(QString message, QString const& callsign, QString * bg,
LogBook logBook, QColor color_CQ,
QColor color_DXCC,
QColor color_NewCall)
{
QString call = t1.CQersCall ();
QString call = callsign;
QString countryName;
bool callWorkedBefore;
bool countryWorkedBefore;
if(call.length()==2) {
int i0=t1.indexOf("CQ "+call);
call=t1.mid(i0+6,-1);
int i0=message.indexOf("CQ "+call);
call=message.mid(i0+6,-1);
i0=call.indexOf(" ");
call=call.mid(0,i0);
}
if(call.length()<3) return;
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return;
if(call.length()<3) return message;
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message;
logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore);
int charsAvail = 48;
@ -97,31 +97,31 @@ void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg,
// the decoder (seems) to always generate 41 chars. For a normal CQ call, the last five are spaces
// TODO this magic 37 characters is also referenced in MainWindow::doubleClickOnCall()
int nmin=37;
int i=t1.indexOf(" CQ ");
int k=t1.string().mid(i+4,3).toInt();
int i=message.indexOf(" CQ ");
int k=message.mid(i+4,3).toInt();
if(k>0 and k<999) nmin += 4;
int s3 = t1.indexOf(" ",nmin);
int s3 = message.indexOf(" ",nmin);
if (s3 < nmin) s3 = nmin; // always want at least the characters to position 35
s3 += 1; // convert the index into a character count
t1 = t1.left(s3); // reduce trailing white space
message = message.left(s3); // reduce trailing white space
charsAvail -= s3;
if (charsAvail > 4)
{
if (!countryWorkedBefore) // therefore not worked call either
{
t1 += "!";
bg=color_DXCC.name();
message += "!";
*bg = color_DXCC.name();
}
else
if (!callWorkedBefore) // but have worked the country
{
t1 += "~";
bg=color_NewCall.name();
message += "~";
*bg = color_NewCall.name();
}
else
{
t1 += " "; // have worked this call before
bg=color_CQ.name();
message += " "; // have worked this call before
*bg = color_CQ.name();
}
charsAvail -= 1;
@ -155,8 +155,9 @@ void DisplayText::_appendDXCCWorkedB4(DecodedText& t1, QString& bg,
countryName.replace ("Guantanamo Bay", "U.S.A.");
}
t1 += countryName;
message += countryName;
}
return message;
}
void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall,
@ -181,11 +182,13 @@ void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall,
or decodedText.indexOf (" " + myCall + ">") >= 0)) {
bg=color_MyCall.name();
}
// if enabled add the DXCC entity and B4 status to the end of the preformated text line t1
// if enabled add the DXCC entity and B4 status to the end of the
// preformated text line t1
auto message = decodedText.string ();
if (displayDXCCEntity && CQcall)
_appendDXCCWorkedB4(/*mod*/decodedText,bg,logBook,color_CQ,
color_DXCC,color_NewCall);
appendText(decodedText.string(),bg);
message = _appendDXCCWorkedB4 (message, decodedText.CQersCall (), &bg, logBook, color_CQ,
color_DXCC, color_NewCall);
appendText (message, bg);
}

View File

@ -23,7 +23,7 @@ public:
void displayQSY(QString text);
signals:
void selectCallsign(bool shift, bool ctrl);
void selectCallsign(bool alt, bool ctrl);
public slots:
void appendText(QString const& text, QString const& bg = "white");
@ -32,7 +32,7 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *e);
private:
void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook,
QString _appendDXCCWorkedB4(QString message, QString const& callsign, QString * bg, LogBook logBook,
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
QTextCharFormat m_charFormat;

View File

@ -63,6 +63,7 @@ set (UG_IMGS
images/170709_135615.wav.png
images/AstroData_2.png
images/Astronomical_data.png
images/auto-seq.png
images/band-settings.png
images/colors.png
images/config-menu.png
@ -104,6 +105,7 @@ set (UG_IMGS
images/setup-menu.png
images/special-mouse-commands.png
images/status-bar-a.png
images/tools-menu.png
images/traditional-msg-box.png
images/tx-macros.png
images/view-menu.png

View File

@ -1,46 +1,57 @@
A text box entitled Astronomical Data provides information needed for
tracking the sun or moon, compensating for EME Doppler shift, and
estimating EME Doppler spread and path degradation. Toggle the
*Astronomical data* on the *View* menu to display or hide this window.
image::AstroData_2.png[align="center",alt="Astronomical Data"]
Available information includes the current UTC *Date* and time; *Az*
and *El*, azimuth and elevation of the moon at your own location, in
degrees; *SelfDop*, *Width*, and *Delay*, the Doppler shift, full
limb-to-limb Doppler spread in Hz, and delay of your own EME echoes in
seconds; and *DxAz* and *DxEl*, *DxDop*, and *DxWid*, corresponding
parameters for a station located at the *DX Grid* entered on the main
window. These numbers are followed by *Dec*, the declination of the
moon; *SunAz* and *SunEl*, the azimuth and elevation of the Sun;
*Freq*, your stated operating frequency in MHz; *Tsky*, the estimated
sky background temperature in the direction of the moon, scaled to the
operating frequency; *Dpol*, the spatial polarization offset in
degrees; *MNR*, the maximum non-reciprocity of the EME path in dB,
owing to a combination of Faraday rotation and spatial polarization;
and finally *Dgrd*, an estimate of the signal degradation in dB,
relative to the best possible time with the moon at perigee in a cold
part of the sky.
The state of the art for establishing three-dimensional locations of
the sun, moon, and planets at a specified time is embodied in a
numerical model of the solar system maintained at the Jet Propulsion
Laboratory. The model has been numerically integrated to produce
tabular data that can be interpolated with very high accuracy. For
example, the celestial coordinates of the moon or a planet can be
determined at a specified time to within about 0.0000003 degrees. The
JPL ephemeris tables and interpolation routines have been incorporated
into _WSJT-X_. Further details on accuracy, especially concerning
calculated EME Doppler shifts, are described in {lunarEchoes} for
November-December, 2016.
The sky background temperatures reported by _WSJT-X_ are derived from
the all-sky 408 MHz map of Haslam et al. (Astronomy and Astrophysics
Supplement Series, 47, 1, 1982), scaled by frequency to the -2.6
power. This map has angular resolution of about 1 degree, and of
course most amateur EME antennas have much broader beamwidths than
this. Your antenna will therefore smooth out the hot spots
considerably, and the observed extremes of sky temperature will be
less. Unless you understand your sidelobes and ground reflections
extremely well, it is unlikely that more accurate sky temperatures
would be of much practical use.
A text box entitled Astronomical Data provides information needed for
tracking the sun or moon, compensating for EME Doppler shift, and
estimating EME Doppler spread and path degradation. Toggle the
*Astronomical data* on the *View* menu to display or hide this window.
image::AstroData_2.png[align="center",alt="Astronomical Data"]
Available information includes the current UTC *Date* and time; *Az*
and *El*, azimuth and elevation of the moon at your own location, in
degrees; *SelfDop*, *Width*, and *Delay*, the Doppler shift, full
limb-to-limb Doppler spread in Hz, and delay of your own EME echoes in
seconds; and *DxAz* and *DxEl*, *DxDop*, and *DxWid*, corresponding
parameters for a station located at the *DX Grid* entered on the main
window. These numbers are followed by *Dec*, the declination of the
moon; *SunAz* and *SunEl*, the azimuth and elevation of the Sun;
*Freq*, your stated operating frequency in MHz; *Tsky*, the estimated
sky background temperature in the direction of the moon, scaled to the
operating frequency; *Dpol*, the spatial polarization offset in
degrees; *MNR*, the maximum non-reciprocity of the EME path in dB,
owing to a combination of Faraday rotation and spatial polarization;
and finally *Dgrd*, an estimate of the signal degradation in dB,
relative to the best possible time with the moon at perigee in a cold
part of the sky.
On the higher microwave bands, where Faraday rotation is minimal and
linear polarization is often used, spatial offset will reduce signal
levels. Some stations have implemented mechanical polarisation
adjustment to overcome this loss, and the amount of rotation needed is
predicted in real time by the value of *Dpol*. Positive Dpol means
that the antenna should be rotated in a clockwise direction looking
from behind the antenna towards the moon. For a dish antenna, the
feed should similarly be rotated clockwise looking into the mouth of
the feed. A negative value for Dpol means anticlockwise rotation.
The state of the art for establishing three-dimensional locations of
the sun, moon, and planets at a specified time is embodied in a
numerical model of the solar system maintained at the Jet Propulsion
Laboratory. The model has been numerically integrated to produce
tabular data that can be interpolated with very high accuracy. For
example, the celestial coordinates of the moon or a planet can be
determined at a specified time to within about 0.0000003 degrees. The
JPL ephemeris tables and interpolation routines have been incorporated
into _WSJT-X_. Further details on accuracy, especially concerning
calculated EME Doppler shifts, are described in {lunarEchoes} for
November-December, 2016.
The sky background temperatures reported by _WSJT-X_ are derived from
the all-sky 408 MHz map of Haslam et al. (Astronomy and Astrophysics
Supplement Series, 47, 1, 1982), scaled by frequency to the -2.6
power. This map has angular resolution of about 1 degree, and of
course most amateur EME antennas have much broader beamwidths than
this. Your antenna will therefore smooth out the hot spots
considerably, and the observed extremes of sky temperature will be
less. Unless you understand your sidelobes and ground reflections
extremely well, it is unlikely that more accurate sky temperatures
would be of much practical use.

View File

@ -18,16 +18,23 @@ double-clicking on decoded text or a signal in the waterfall. They
can also be adjusted using the spinner controls.
* You can force Tx frequency to the current Rx frequency by clicking
the *Tx<-Rx* button, and vice-versa for *Rx<-Tx*. Check the box *Lock
Tx=Rx* to make the frequencies always track one another. The
on-the-air frequency of your lowest JT9 or JT65 tone is the sum of
dial frequency and audio Tx frequency.
the *Tx<-Rx* button, and vice-versa for *Rx<-Tx*. The on-the-air
frequency of your lowest JT9 or JT65 tone is the sum of dial frequency
and audio Tx frequency.
* Check the box *Lock Tx=Rx* to make the frequencies always track one
another.
TIP: In general we do not recommend using *Lock Tx=Rx* since it
encourages poor radio etiquette when running a frequency. With *Lock
Tx=Rx* checked, your own Tx frequency will move around following your
encourages poor radio etiquette when running a frequency. With this
box checked, your own Tx frequency will move around following your
callers.
* For modes lacking a multi-decode feature, or when *Enable
VHF/UHF/Microwave features* has been checked on the *Settings ->
General* tab, the *F Tol* control sets a frequency toilerance range
over which decoding will be attempted, centered on the Rx frequency.
* The *Report* control lets you change a signal report that has been
inserted automatically. Typical reports for the various modes fall in
the range 30 to +20 dB. Remember that JT65 reports saturate at an
@ -37,13 +44,36 @@ TIP: Consider reducing power if your QSO partner reports your
signal above -5 dB in one of the _WSJT-X_ slow modes. These are
supposed to be weak signal modes!
* With *Split operation* activated on the *Settings -> Radio* tab, you
can activate the spinner control *Tx CQ nnn* by checking the box to
its right. The program will then generate something like `CQ nnn
K1ABC FN42` for your CQ message, where `nnn` is the kHz portion of
your current operating frequency. Your CQ message *Tx6* will then be
transmitted at the calling frequency selected in the *Tx CQ nnn* spinner
control. All other messages will be transmitted at your current
operating frequency. On reception, when you double-click on a message
like `CQ nnn K1ABC FN42` your rig will QSY to the specified frequency
so you can call the station at his specified response frequency.
* In some circumstances, especially on VHF and higher bands, you can
select a supported submode of the active mode by using the *Submode*
control. The *Sync* control sets a minimum threshold for establishing
time and frequency synchronization with a received signal.
* Spinner control *T/R xx s* sets sequence lengths for transmission
and reception in ISCAT, MSK144, and the fast JT9 modes.
* With *Split operation* activated on the *Settings -> Radio* tab, in
MSK144 and the fast JT9 submodes you can activate the spinner control
*Tx CQ nnn* by checking the box to its right. The program will then
generate something like `CQ nnn K1ABC FN42` for your CQ message, where
`nnn` is the kHz portion of your current operating frequency. Your CQ
message *Tx6* will then be transmitted at the calling frequency
selected in the *Tx CQ nnn* spinner control. All other messages will
be transmitted at your current operating frequency. On reception,
when you double-click on a message like `CQ nnn K1ABC FN42` your rig
will QSY to the specified frequency so you can call the station at his
specified response frequency.
* Checkboxes at bottom center of the main window control special
features for particular operating modes:
** *Sh* enables shorthand messages in JT4, JT65, and MSK144 modes
** *Fast* enables fast JT9 submodes
** *Auto Seq* enables auto-sequencing of Tx messages
** *Call 1st* enables automatic response to the first decoded
responder to your CQ
** *Tx6* toggles between two types of shorthand messages in JT4 mode

View File

@ -18,10 +18,9 @@ recognized ADIF format, for example 630m, 20m, or 70cm. The band-name
format works only if a working frequency has been set for that band
and mode, in which case the first such match is selected.
TIP: You can also enter a frequency increment in kHz above the
currently displayed integer MHz. For example, if the displayed
frequency is 10,368.100, enter `165k` (don't forget the `k`!) to QSY
to 10,368.165.
* You can also enter a frequency increment in kHz above the currently
displayed integer MHz. For example, if the displayed frequency is
10,368.100, enter `165k` (don't forget the `k`!) to QSY to 10,368.165.
* A small colored circle appears in green if the CAT control is
activated and functional. The green circle contains the character S
@ -34,10 +33,6 @@ split transmit frequency. When using _WSJT-X_ with such radios you
should not change the current VFO, split status or dial frequency
using controls on the radio.
* The slider adjacent to the level meter can be used to adjust the
signal level sent to the Fast Graph. If *Flatten* is not checked,
the same is true for the Wide Graph.
* If *DX Grid* contains a valid Maidenhead locator, the corresponding
great-circle azimuth and distance from your location are displayed.

View File

@ -24,7 +24,7 @@ Many users prefer to create and use entries on the *Configurations*
menu for switching between modes. Simply *Clone* the *Default* entry,
*Rename* it as desired, and then make all desired settings for that
configuration. These settings will be restored whenever you select
that entry.
that configuration.
[[VIEW_MENU]]
==== View Menu
@ -43,6 +43,9 @@ image::decode-menu.png[align="left",alt="Decode Menu"]
==== Save Menu
image::save-menu.png[align="left",alt="Save Menu"]
==== Tools Menu
image::tools-menu.png[align="left",alt="Tools Menu"]
[[HELP_MENU]]
==== Help Menu
image::help-menu.png[align="left",alt="Help Menu"]

View File

@ -29,6 +29,12 @@ pre-stored messages entered on the *Settings | Tx Macros* tab.
Pressing *Enter* on a modified message #5 automatically adds that
message to the stored macros.
* In some circumstances it may be desirable to make your QSOs as
shiort as possible. To configure the program to start contacts with
message #2, disable message #1 by double-clicking on its round
radio-button or rectangular *Tx 1* button. Similarly, to send RR73
rather than RRR for message #4, double-click on one of its buttons.
The second arrangement of controls for generating and selecting
Tx messages appears on *Tab 2* of the Message Control Panel:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -47,6 +47,26 @@ compound callsign. It should be obvious that the JT4, JT9, and JT65
protocols are not designed or well suited for extensive conversations
or rag-chewing.
=== Auto-Sequencing
The slow modes JT4, JT9, JT65, and QRA64 allow nearly 10 seconds at
the end of each one-minute receiving sequence in which you can inspect
decoded messages and decide how to reply. With its 15-second T/R
cycles, FT8 allows only about two seconds for this task. For this
reason a basic auto-sequencing feature is offered. Check *Auto Seq*
on the main window to enable this feature:
image::auto-seq.png[align="center",alt="AutoSeq"]
When calling CQ you may also choose to check the box *Call 1st*.
_WSJT-X_ will then respond automatically to the first decoded
responder to your CQ.
TIP: When *Auto-Seq* is enabled the program will de-activate *Enable
Tx* at the end of each QSO. We do not want _WSJT-X_ to make fully
automated QSOs.
[[COMP-CALL]]
=== Compound Callsigns

View File

@ -3,7 +3,9 @@
For quick reference, here's a short list of features and capabilities
added to _WSJT-X_ since Version 1.7.0:
- New modes: *FT8* and *FreqCal*
- New mode *FT8* designed for fast QSOs
- New tool *FreqCal* for accurate frequency calibration of your radio
- Improved decoding performance for JT65, QRA64, and MSK144
@ -11,18 +13,19 @@ added to _WSJT-X_ since Version 1.7.0:
- Experimental amplitude and phase equalization for MSK144
- Options to minimize screen space used by the *Main* and *Wide Graph*
- Options to minimize screen space used by *Main* and *Wide Graph*
windows
- New set of suggested default frequencies specific to the three IARU
Regions.
- Enhanced scheme for managing table of default operating frequencies
- Enhanced scheme for managing table of suggested default operating
frequencies
- Improved CAT control for many rigs, including those controlled
- Improved CAT control for many radios, including those controlled
through Commander or OmniRig.
- Bug fixes and tweaks to the user interface
- Bug fixes and tweaks to user interface
=== Documentation Conventions

View File

@ -1,3 +1,55 @@
=== AP Decoding
With the QRA64 decoder Nico Palermo, IV3NWV, introduced a technique
for decoding with the aid of information that naturally accumulates
during a minimal QSO. This _a priori_ (AP) information can be
used to increase the sensitivity of the decoder.
When an operator decides to answer a CQ, he already knows his own
callsign and that of his potential QSO partner. He therefore knows
what to expect for at least 56 of the 72 message bits in a
standard-format response to his call. The _WSJT-X_ decoders for QRA64
and FT8 can use these AP bits to decode messages containing them with
higher sensitivity than otherwise possible.
We have implemented AP decoding in slightly different ways in QRA64
and FT8. To provide some explicit examples for users, we provide here
a brief description of the FT8 behavior.
The FT8 decoder always tries first to decode a signal without using
any AP information. If this attempt fails, and if *Enable AP* is
checked on the *Decode* menu, a second attempt hypothesizes that the
message contains callsigns MyCall and DxCall. If the QSO has
progressed to the point where signal reports have been exchanged, a
third attempt hypothesizes that the message contains the known
callsigns followed by RRR, RR73, or 73.
AP decoding attempts effectively set the AP bits to the hypothesized
values, as if they had been received perfectly. The decoder then
proceeds to determine whether the remaining message and parity bits
are consistent with the hypothesized AP bits. If a codeword is found
that the decoder judges to have high (but not overwhelmingly high)
probability of being correct, a ? character is appended when the
decoded message is displayed.
Successful AP decodes are always labeled with an end-of-line indicator
of the form aP, where P is one of the single-digit AP decoding types
listed in Table 1. For example, an a2 designator says that the
successful decode used MyCall as hypothetically known information.
[[AP_INFO_TABLE]]
.AP information types
[width="25%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|P | Message components
|1 | CQ &#160; &#160; ? &#160; &#160; ?
|2 | MyCall &#160; &#160; ? &#160; &#160; ?
|3 | MyCall DxCall &#160; &#160; ?
|4 | MyCall DxCall RRR
|5 | MyCall DxCall 73
|6 | MyCall DxCall RR73
|===============================================
=== Decoded Lines
Displayed information accompanying decoded messages generally includes UTC,
@ -14,7 +66,7 @@ summarized in the following Table:
[width="50%",cols="h,3*^",frame=topbot,options="header"]
|===========================================
|Mode |Mode character|Sync character|End of line information
|FT8 | ~ | |
|FT8 | ~ | | aP
|JT4 | $ | *, # | f, fN, dNC
|JT9 | @ | |
|JT65 | # | |
@ -28,14 +80,18 @@ Sync character::
`#` - Alternate sync
End of line information::
`a` - Decoded with aid of some a priori (AP) information
`C` - Confidence indicator [ISCAT and Deep Search; (0-9,*)] +
`d` - Deep Search algorithm +
`f` - Franke-Taylor or Fano algorithm +
`M` - Message length (characters) +
`N` - Number of Rx intervals or frames averaged +
`P` - Number indicating type of AP information (Table 1, above) +
`R` - Return code from QRA64 decoder +
`T` - Length of analyzed region (s)
=== Reference Spectrum
WSJT-X provides a tool that can be used to determine the detailed

View File

@ -11,9 +11,9 @@ purposes a good setting is 6 or 7.
decodes using Deep Search. Higher numbers will display results
with lower confidence levels.
- Check *MSK144 Contest Mode* to cause generation and auto-sequencing
of MSK144 messages with four-character grid locators in place of signal
reports.
- Check *FT8 and MSK144 Contest Mode* to enable generation and
auto-sequencing of MSK144 messages with four-character grid locators
in place of signal reports.
- Check *Two-pass decoding* to enable a second decoding pass after
signals producing first-pass decodes have been subtracted from the

View File

@ -3,8 +3,11 @@
image::settings-general.png[align="center",alt="Settings Window"]
Select the *General* tab on the *Settings* window. Under _Station
Details_, enter your callsign and 4-digit or preferably 6-digit grid
locator. This information will be sufficient for initial tests.
Details_ enter your callsign, grid locator (preferably the 6-character
locator) and IARU Region number. Region 1 is Europe, Africa, the
Middle East, and Northern Asia; Region 2 the Americas; and Region 3
Southern Asia and the Pacific. This information will be sufficient
for initial tests.
Meanings of remaining options on the *General* tab should be
self-explanatory after you have made some QSOs using _WSJT-X_. You

View File

@ -21,14 +21,13 @@ about 5 kHz. This choice has the desirable effect of allowing the
JT65 and JT9 sub-bands simultaneously on most HF bands. Further
details are provided in the <<TUTORIAL,Basic Operating Tutorial>>. A
wider displayed bandwidth may also be helpful at VHF and above, where
JT4, JT65, and QRA64 signals are found over much wider ranges of
frequencies.
FT8, JT4, JT65, and QRA64 signals may be found over much wider ranges
of frequencies.
- If you have only a standard SSB filter you wont be able to display
more than about 2.7 kHz bandwidth. Depending on the exact dial
frequency setting, on HF bands you can display the full sub-band
generally used for one mode (JT65 or JT9) and part of the sub-band for
the other mode.
generally used for one mode.
- Of course, you might prefer to concentrate on one mode at a time,
setting your dial frequency to (say) 14.074 for FT8, 14.076 for JT65,

View File

@ -6,22 +6,45 @@
.Wide Graph Settings:
- *Bins/Pixel* = 4
- *Bins/Pixel* = 4, *Start* = 200 Hz, *N Avg* = 2
- Adjust the width of the Wide Graph window so that the upper
frequency limit is approximately 2500 Hz.
frequency limit is approximately 2600 Hz.
.Open a Wave File:
- Select *File | Open* and navigate to +...\save\samples\FT8\170709_135615.wav+.
The waterfall should look something like this:
- Select *File | Open* and navigate to
+...\save\samples\FT8\170709_135615.wav+. The waterfall and decoded
text window should look something like the following screen shots:
[[X15]]
image::170709_135615.wav.png[align="left",alt="Wide Graph Decode 170709_135615"]
- You should see decodes of the three FT8 signals in the *Band Activity*
text box, as shown below:
image::ft8_decodes.png[align="left"]
- Click with the mouse anywhere on the waterfall display. The green Rx
frequency marker will jump to your selected frequency, and the Rx
frequency control on the main window will be updated accordingly.
- Do the same thing with the Shift key held down. Now the red Tx
frequency marker and its associated control on the main window will
follow your frequency selections.
- Do the same thing with the Ctrl key held down. Now the both colored
markers and both spinner controls will follow your selections.
- Double-clicking at any frequency on the waterfall does all the
things just described and also invokes the decoder in a small range
around that frequency.
- Now double-click on any of the the lines of decoded text in the main
window. Unless you have *My Call* set to K1JT or KY7M on the
*Settings -> General* tab, all three lines will show the same
behavior, setting both RxFreq and TxFreq to the frequency of the
selected message. However, if MyCall is set to K1JT then clicking on
a message directed to K1JT will move only the Rx frequency setting.
This behavior is desirable so that you will not inadvertently change
your Tx frequency to that of a tail-ender who called you somewhere
else in the FT8 subband.
IMPORTANT: When finished with this Tutorial, dont forget to re-enter
your own callsign as *My Call* on the *Settings | General* tab.

View File

@ -1,9 +1,6 @@
_WSJT-X_ v1.8 suppports a number of features designed for use
on the VHF and higher bands. These features now include:
- *FT8*, a mode optimized for weak, fading signals such as those often
encountered with multi-hop sporadic E propagation on 50 MHz.
- *JT4*, a mode particularly useful for EME on the microwave bands
- *JT9* fast modes, useful for scatter propagation on VHF bands
@ -24,9 +21,6 @@ propagation
- *Doppler tracking*, which becomes increasingly important for EME
on bands above 1.2 GHz.
- *Auto-sequencing* of transmitted messages for FT8 and the fast modes
with forward error control
[[VHF_SETUP]]
=== VHF Setup
@ -114,7 +108,11 @@ is generally used for EME on the 5.7 and 10 GHz bands.
- For EME QSOs some operators use short-form JT4 messages consisting
of a single tone. To activate automatic generation of these messages,
check the box labeled *Sh*.
check the box labeled *Sh*. This also enables the generation of a
single tone at 1000Hz by selecting Tx6, to assist in finding signals
initially. The box labeled *Tx6* toggles the Tx6 message from 1000Hz
to 1250Hz to indicate to the other station that you are ready to
receive messages.
- Select *Deep* from the *Decode* menu. You may also choose to
*Enable averaging* over successive transmissions and/or *Enable deep
@ -157,15 +155,15 @@ image::JT65B.png[align="center",alt="JT65B"]
=== QRA64
QRA64 is an experimental mode in Version 1.7 of _WSJT-X_. The mode is
QRA64 is an experimental mode in Version 1.8 of _WSJT-X_. The mode is
designed especially for EME on VHF and higher bands; its operation is
generally similar to JT65. The following screen shot shows an example
of a QRA64C transmission from DL7YC recorded at G3WDG over the EME
path at 24 GHz. Doppler spread on the path was 78 Hz, so although the
signal is reasonably strong its tones are broadened enough to make
them hard to see on the waterfall. The red curve shows that the
decoder has achieved synchronization with a signal at approximately
967 Hz.
generally similar to JT4 and JT65. The following screen shot shows an
example of a QRA64C transmission from DL7YC recorded at G3WDG over the
EME path at 24 GHz. Doppler spread on the path was 78 Hz, so although
the signal is reasonably strong its tones are broadened enough to make
them hard to see on the waterfall. The triangular red marker below
the frequency scale shows that the decoder has achieved
synchronization with a signal at approximately 967 Hz.
image::QRA64.png[align="center",alt="QRA64"]
@ -183,12 +181,19 @@ most likely value for each of the message's 12 six-bit information
symbols. A decode is declared only when the total probability for all
12 symbols has converged to an unambiguous value very close to 1.
TIP: In _WSJT-X_ Version 1.7 QRA64 is different from JT65 in that the
decoder attempts to find and decode only a single signal in the
receiver passband. If many signals are present you may be able to
decode them by double-clicking on the lowest tone of each one in the
waterfall. A multi-decoder like those for JT65 and JT9 has not
yet been written.
For EME QSOs some operators use short-form QRA64 messages consisting
of a single tone. To activate automatic generation of these messages,
check the box labeled *Sh*. This also enables the generation of a
single tone at 1000Hz by selecting Tx6, to assist in finding signals
initially, as the QRA64 tones are often not visible on the waterfall.
The box labeled *Tx6* switches the Tx6 message from 1000Hz to 1250Hz
to indicate to the other station that you are ready to receive messages.
TIP: QRA64 is different from JT65 in that the decoder attempts to find
and decode only a single signal in the receiver passband. If many
signals are present you may be able to decode them by double-clicking
on the lowest tone of each one in the waterfall.
=== ISCAT
@ -207,7 +212,7 @@ longer at distances close to the upper limit. But with patience, 100
Watts or more, and a single yagi it can usually be done. The
following screen shot shows two 15-second MSK144 transmissions from
W5ADD during a 50 MHz QSO with K1JT, at a distance of about 1800 km
(1100 mi). The decoded segments have been encircled on the *Fast
(1100 mi). The decoded segments have been marked on the *Fast
Graph* spectral display.
image::MSK144.png[align="center",alt="MSK144"]

View File

@ -9,26 +9,32 @@ subroutine addit(itone,nfsample,nsym,nsps,ifreq,sig,dat)
fsample=12000.d0 !Sample rate (Hz)
dt=1.d0/fsample !Sample interval (s)
twopi=8.d0*atan(1.d0)
dphi=0.
f=ifreq
phi=0.
k=12000 !Start audio at t = 1.0 s
ntot=nsym*tsym/dt
t=0.
isym0=-1
do i=1,ntot
t=t+dt
isym=nint(t/tsym) + 1
if(isym.ne.isym0) then
freq=f + itone(isym)*baud
dphi=twopi*freq*dt
isym0=isym
endif
phi=phi + dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
k=k+1
dat(k)=dat(k) + sig*sin(xphi)
iters=1
if(nsym.eq.79) iters=2
do iter=1,iters
f=ifreq
phi=0.
ntot=nsym*tsym/dt
k=12000 !Start audio at t = 1.0 s
t=0.
if(nsym.eq.79) k=12000 + (iter-1)*12000*30 !Special case for FT8
isym0=-1
do i=1,ntot
t=t+dt
isym=nint(t/tsym) + 1
if(isym.ne.isym0) then
freq=f + itone(isym)*baud
dphi=twopi*freq*dt
isym0=isym
endif
phi=phi + dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
k=k+1
dat(k)=dat(k) + sig*sin(xphi)
enddo
enddo
return

View File

@ -11,8 +11,10 @@ program allsim
integer*2 iwave(NMAX) !Generated waveform (no noise)
integer itone(206) !Channel symbols (values 0-8)
integer icw(250)
integer*1 msgbits(87)
logical*1 bcontest
real*4 dat(NMAX)
character message*22,msgsent*22,arg*8
character message*22,msgsent*22,arg*8,mygrid*6
nargs=iargc()
if(nargs.ne.1) then
@ -24,6 +26,8 @@ program allsim
read(arg,*) snrdb !S/N in dB (2500 hz reference BW)
message='CQ KA2ABC FN20'
mygrid='FN20 '
bcontest=.false.
rmsdb=25.
rms=10.0**(0.05*rmsdb)
sig=10.0**(0.05*snrdb)
@ -56,11 +60,14 @@ program allsim
call gen4(message,0,msgsent,itone,itype)
call addit(itone,11025,206,2520,1200,sig,dat) !JT4
call genft8(message,mygrid,bcontest,msgsent,msgbits,itone)
call addit(itone,12000,79,1920,1400,sig,dat) !FT8
call genqra64(message,0,msgsent,itone,itype)
call addit(itone,12000,84,6912,1400,sig,dat) !QRA64
call addit(itone,12000,84,6912,1600,sig,dat) !QRA64
call gen65(message,0,msgsent,itone,itype)
call addit(itone,11025,126,4096,1600,sig,dat) !JT65
call addit(itone,11025,126,4096,1800,sig,dat) !JT65
iwave(1:npts)=nint(rms*dat(1:npts))

58
lib/chkcall.f90 Normal file
View File

@ -0,0 +1,58 @@
subroutine chkcall(w,bc,cok)
! Check "w" to see if it could be a valid standard callsign or a valid
! compound callsign.
! Return base call "bc" and a logical "cok" indicator.
character w*13 !A putative callsign
character bc*6 !Base call (tentative)
character c*1
logical cok,isdigit,isletter
isdigit(c)=(ichar(c).ge.ichar('0')) .and. (ichar(c).le.ichar('9'))
isletter(c)=(ichar(c).ge.ichar('A')) .and. (ichar(c).le.ichar('Z'))
cok=.true.
bc=w(1:6)
n1=len_trim(w)
if(n1.gt.11) go to 100
if(index(w,'.').ge.1) go to 100
if(index(w,'+').ge.1) go to 100
if(index(w,'-').ge.1) go to 100
if(index(w,'?').ge.1) go to 100
if(n1.gt.6 .and. index(w,'/').le.0) go to 100
i0=index(w,'/')
if(max(i0-1,n1-i0).gt.6) go to 100 !Base call must be < 7 characters
if(i0.ge.2 .and. i0.le.n1-1) then !Extract base call from compound call
if(i0-1.le.n1-i0) bc=w(i0+1:n1)//' '
if(i0-1.gt.n1-i0) bc=w(1:i0-1)//' '
endif
nbc=len_trim(bc)
if(nbc.gt.6) go to 100 !Base call should have no more than 6 characters
! One of first two characters (c1 or c2) must be a letter
if((.not.isletter(bc(1:1))) .and. (.not.isletter(bc(2:2)))) go to 100
if(bc(1:1).eq.'Q') go to 100 !Calls don't start with Q
! Must have a digit in 2nd or 3rd position
i1=0
if(isdigit(bc(2:2))) i1=2
if(isdigit(bc(3:3))) i1=3
if(i1.eq.0) go to 100
! Callsign must have a suffix of 1-3 letters
if(i1.eq.nbc) go to 100
n=0
do i=i1+1,nbc
j=ichar(bc(i:i))
if(j.lt.ichar('A') .or. j.gt.ichar('Z')) go to 100
n=n+1
enddo
if(n.ge.1 .and. n.le.3) go to 200
100 cok=.false.
200 return
end subroutine chkcall

91
lib/contest72.f90 Normal file
View File

@ -0,0 +1,91 @@
program contest72
use packjt
integer dat(12)
logical text,bcontest,ok
character*22 msg,msg0,msg1
character*72 ct1,ct2
character*12 callsign1,callsign2
character*1 c0
character*42 c
character*6 mygrid
data c/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ +-./?'/
data bcontest/.true./
data mygrid/"EM48 "/
! itype Message Type
!--------------------
! 1 Standardd message
! 2 Type 1 prefix
! 3 Type 1 suffix
! 4 Type 2 prefix
! 5 Type 2 suffix
! 6 Free text
! -1 Does not decode correctly
nargs=iargc()
if(nargs.eq.0) open(10,file='contest_msgs.txt',status='old')
nn=0
do imsg=1,9999
if(nargs.eq.1) then
if(imsg.gt.1) exit
call getarg(1,msg0)
else
read(10,1001,end=999) msg0
1001 format(a22)
endif
msg=msg0
if(bcontest) call to_contest_msg(msg0,msg)
call packmsg(msg,dat,itype)
call unpackmsg(dat,msg1)
call fix_contest_msg(mygrid,msg1)
ok=msg1.eq.msg0
if(msg0.eq.' ') then
write(*,1002)
else
if(jt_c2(1:1).eq.'W') msg0=' '//msg0(1:20)
nn=nn+1
write(*,1002) nn,msg0,ok,jt_itype,jt_nc1,jt_nc2,jt_ng,jt_k1,jt_k2
1002 format(i1,'. ',a22,L2,i2,2i10,i6,2i8)
if(index(msg1,' 73 ').gt.4) nn=0
endif
if(.not.ok) print*,msg0,msg1
if(itype.lt.0 .or. itype.eq.6) cycle
if(msg(1:3).eq.'CQ ') then
m=2
write(ct1,1010) dat
1010 format(12b6.6)
! write(*,1014) ct1
1014 format(a72)
cycle
endif
i1=index(msg,'<')
if(i1.eq.1) then
m=0
cycle
endif
if(i.ge.5) then
m=3
cycle
endif
if(msg(1:6).eq.'73 CQ ') then
m=4
cycle
endif
call packmsg(msg,dat,itype)
write(ct1,1010) dat
call packtext(msg,nc1,nc2,ng)
! write(ct2,1012) nc1,nc2,ng+32768
!1012 format(2b28.28,b16.16)
! write(*,1014) ct1
! write(*,1014) ct2
! write(*,1014)
enddo
999 end program contest72

View File

@ -61,7 +61,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
if(ios.ne.0) then
nfail=nfail+1
if(nfail.le.3) then
call sleep_msec(100)
call sleep_msec(10)
go to 10
endif
endif
@ -70,11 +70,11 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
! We're in FT8 mode
call timer('decft8 ',0)
newdat=params%newdat
call my_ft8%decode(ft8_decoded,id2,params%nfqso, &
newdat,params%nutc,params%nfa, &
params%nfb,logical(params%nagain), &
params%ndepth,params%nsubmode, &
params%mycall,params%hiscall,params%hisgrid)
call my_ft8%decode(ft8_decoded,id2,params%nQSOProgress,params%nfqso, &
params%nftx,newdat,params%nutc,params%nfa,params%nfb, &
params%nexp_decode,params%ndepth,logical(params%nagain), &
logical(params%lapon),params%napwid,params%mycall, &
params%mygrid,params%hiscall,params%hisgrid)
call timer('decft8 ',1)
go to 800
endif
@ -390,7 +390,7 @@ contains
end select
end subroutine jt9_decoded
subroutine ft8_decoded (this,sync,snr,dt,freq,nbadcrc,decoded)
subroutine ft8_decoded (this,sync,snr,dt,freq,decoded,nap,qual)
use ft8_decode
implicit none
@ -399,17 +399,24 @@ contains
integer, intent(in) :: snr
real, intent(in) :: dt
real, intent(in) :: freq
integer, intent(in) :: nbadcrc
character(len=22), intent(in) :: decoded
if(nbadcrc.eq.0) then
write(*,1000) params%nutc,snr,dt,nint(freq),decoded
1000 format(i6.6,i4,f5.1,i5,' ~ ',1x,a22)
write(13,1002) params%nutc,nint(sync),snr,dt,freq,0,decoded
1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a22,' FT8')
call flush(6)
call flush(13)
integer, intent(in) :: nap
real, intent(in) :: qual
character*2 annot
character*22 decoded0
decoded0=decoded
annot=' '
if(nap.ne.0) then
write(annot,'(a1,i1)') 'a',nap
if(qual.lt.0.17) decoded0(22:22)='?'
endif
write(*,1000) params%nutc,snr,dt,nint(freq),decoded0,annot
1000 format(i6.6,i4,f5.1,i5,' ~ ',1x,a22,1x,a2)
write(13,1002) params%nutc,nint(sync),snr,dt,freq,0,decoded0
1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a22,' FT8')
call flush(6)
call flush(13)
select type(this)
type is (counting_ft8_decoder)

View File

@ -1,16 +1,20 @@
subroutine fix_contest_msg(mycall,mygrid,hiscall,msg)
subroutine fix_contest_msg(mygrid,msg)
! If msg is "mycall hiscall grid1" and distance from mygrid to grid1 is more
! thsn 10000 km, change "grid1" to "R grid2" where grid2 is the antipodes
! of grid1.
! If distance from mygrid to grid1 is more thsn 10000 km, change "grid1"
! to "R grid2" where grid2 is the antipodes of grid1.
character*6 mycall,mygrid,hiscall
character*6 mygrid
character*22 msg
character*6 g1,g2
logical isgrid
isgrid(g1)=g1(1:1).ge.'A' .and. g1(1:1).le.'R' .and. g1(2:2).ge.'A' .and. &
g1(2:2).le.'R' .and. g1(3:3).ge.'0' .and. g1(3:3).le.'9' .and. &
g1(4:4).ge.'0' .and. g1(4:4).le.'9' .and. g1(1:4).ne.'RR73'
n=len(trim(msg))
if(n.lt.4) return
g1=msg(n-3:n)//' '
if(isgrid(g1)) then
call azdist(mygrid,g1,0.d0,nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter)

View File

@ -1,4 +1,4 @@
subroutine bpdecode174(llr,apmask,maxiterations,decoded,cw,nharderror)
subroutine bpdecode174(llr,apmask,maxiterations,decoded,cw,nharderror,iter)
!
! A log-domain belief propagation decoder for the (174,87) code.
!

View File

@ -7,5 +7,6 @@ parameter (NSPS=1920) !Samples per symbol at 12000 S/s
parameter (NZ=NSPS*NN) !Samples in full 15 s waveform (151,680)
parameter (NMAX=15*12000) !Samples in iwave (180,000)
parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
parameter (NHSYM=2*NMAX/NH1-1) !Number of symbol spectra (1/2-sym steps)
parameter (NSTEP=NSPS/4) !Rough time-sync step size
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
parameter (NDOWN=60) !Downsample factor

30
lib/fsk4hf/ft8apset.f90 Normal file
View File

@ -0,0 +1,30 @@
subroutine ft8apset(mycall12,mygrid6,hiscall12,hisgrid6,bcontest,apsym,iaptype)
parameter(NAPM=4,KK=87)
character*12 mycall12,hiscall12
character*22 msg,msgsent
character*6 mycall,hiscall
character*6 mygrid6,hisgrid6
character*4 hisgrid
logical bcontest
integer apsym(KK)
integer*1 msgbits(KK)
integer itone(KK)
mycall=mycall12(1:6)
hiscall=hiscall12(1:6)
hisgrid=hisgrid6(1:4)
if(len_trim(hiscall).eq.0) then
iaptype=1
hiscall="K9AN"
else
iaptype=2
endif
hisgrid=hisgrid6(1:4)
! if(len_trim(hisgrid).eq.0) hisgrid="EN50"
if(index(hisgrid," ").eq.0) hisgrid="EN50"
msg=mycall//' '//hiscall//' '//hisgrid
call genft8(msg,mygrid6,bcontest,msgsent,msgbits,itone)
apsym=2*msgbits-1
return
end subroutine ft8apset

View File

@ -1,29 +1,75 @@
subroutine ft8b(dd0,newdat,nfqso,ndepth,icand,sync0,f1,xdt,apsym,nharderrors, &
dmin,nbadcrc,message,xsnr)
subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
lsubtract,nagain,iaptype,mygrid6,bcontest,sync0,f1,xdt,apsym,nharderrors,&
dmin,nbadcrc,ipass,iera,message,xsnr)
use timer_module, only: timer
include 'ft8_params.f90'
parameter(NRECENT=10,NP2=2812)
character message*22,msgsent*22
character*12 recent_calls(NRECENT)
character*6 mygrid6
logical bcontest
real a(5)
real s1(0:7,ND),s2(0:7,NN)
real ps(0:7)
real rxdata(3*ND),llr(3*ND),llrap(3*ND) !Soft symbols
real rxdata(3*ND),rxdatap(3*ND)
real llr(3*ND),llra(3*ND),llr0(3*ND),llrap(3*ND) !Soft symbols
real dd0(15*12000)
integer*1 decoded(KK),apmask(3*ND),cw(3*ND)
integer*1 msgbits(KK)
integer apsym(KK),rr73(11)
integer apsym(KK)
integer mcq(28),mde(28),mrrr(16),m73(16),mrr73(16)
integer itone(NN)
integer icos7(0:6),ip(1)
integer nappasses(0:5) ! the number of decoding passes to use for each QSO state
integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now
complex cd0(3200)
complex ctwk(32)
complex csymb(32)
logical newdat
data rr73/-1,1,1,1,1,1,1,-1,1,1,-1/
logical first,newdat,lsubtract,lapon,nagain
data icos7/2,5,6,0,4,1,3/
data mcq/1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,1,0,0,1/
data mrrr/0,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1/
data m73/0,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0/
data mde/1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0,0,1/
data mrr73/0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,1/
data first/.true./
save nappasses,naptypes
max_iterations=40
norder=2
if(ndepth.eq.3 .and. abs(nfqso-f1).lt.10.0) norder=3
if(first) then
mcq=2*mcq-1
mde=2*mde-1
mrrr=2*mrrr-1
m73=2*m73-1
mrr73=2*mrr73-1
nappasses(0)=2
nappasses(1)=2
nappasses(2)=2
nappasses(3)=4
nappasses(4)=4
nappasses(5)=3
! iaptype
!------------------------
! 1 CQ ??? ???
! 2 MyCall ??? ???
! 3 MyCall DxCall ???
! 4 MyCall DxCall RRR
! 5 MyCall DxCall 73
! 6 MyCall DxCall RR73
! 7 ??? DxCall ???
naptypes(0,1:4)=(/1,2,0,0/)
naptypes(1,1:4)=(/2,3,0,0/)
naptypes(2,1:4)=(/2,3,0,0/)
naptypes(3,1:4)=(/3,4,5,6/)
naptypes(4,1:4)=(/3,4,5,6/)
naptypes(5,1:4)=(/3,1,2,0/) !?
first=.false.
endif
max_iterations=30
nharderrors=-1
fs2=12000.0/NDOWN
dt2=1.0/fs2
twopi=8.0*atan(1.0)
@ -34,9 +80,9 @@ subroutine ft8b(dd0,newdat,nfqso,ndepth,icand,sync0,f1,xdt,apsym,nharderrors,
call ft8_downsample(dd0,newdat,f1,cd0) !Mix f1 to baseband and downsample
call timer('ft8_down',1)
i0=nint(xdt*fs2) !Initial guess for start of signal
i0=nint((xdt+0.5)*fs2) !Initial guess for start of signal
smax=0.0
do idt=i0-16,i0+16 !Search over +/- half a symbol
do idt=i0-8,i0+8 !Search over +/- one quarter symbol
call sync8d(cd0,idt,ctwk,0,sync)
if(sync.gt.smax) then
smax=sync
@ -78,6 +124,26 @@ subroutine ft8b(dd0,newdat,nfqso,ndepth,icand,sync0,f1,xdt,apsym,nharderrors,
call four2a(csymb,32,1,-1,1)
s2(0:7,k)=abs(csymb(1:8))
enddo
! sync quality check
is1=0
is2=0
is3=0
do k=1,7
ip=maxloc(s2(:,k))
if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s2(:,k+36))
if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s2(:,k+72))
if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1
enddo
! hard sync sum - max is 21
nsync=is1+is2+is3
if(nsync .le. 6) then ! bail out
nbadcrc=1
return
endif
j=0
do k=1,NN
if(k.le.7) cycle
@ -93,9 +159,54 @@ subroutine ft8b(dd0,newdat,nfqso,ndepth,icand,sync0,f1,xdt,apsym,nharderrors,
r1=max(ps(1),ps(3),ps(5),ps(7))-max(ps(0),ps(2),ps(4),ps(6))
r2=max(ps(2),ps(3),ps(6),ps(7))-max(ps(0),ps(1),ps(4),ps(5))
r4=max(ps(4),ps(5),ps(6),ps(7))-max(ps(0),ps(1),ps(2),ps(3))
rxdata(3*j-2)=r4
rxdata(3*j-1)=r2
rxdata(3*j)=r1
i4=3*j-2
i2=3*j-1
i1=3*j
rxdata(i4)=r4
rxdata(i2)=r2
rxdata(i1)=r1
rxdatap(i4)=r4
rxdatap(i2)=r2
rxdatap(i1)=r1
if(nQSOProgress .eq. 0 .or. nQSOProgress .eq. 5) then
! When bits 88:115 are set as ap bits, bit 115 lives in symbol 39 along
! with no-ap bits 116 and 117. Take care of metrics for bits 116 and 117.
if(j.eq.39) then ! take care of bits that live in symbol 39
if(apsym(28).lt.0) then
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
else
rxdatap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
rxdatap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
endif
endif
endif
! When bits 116:143 are set as ap bits, bit 115 lives in symbol 39 along
! with ap bits 116 and 117. Take care of metric for bit 115.
! if(j.eq.39) then ! take care of bit 115
! iii=2*(apsym(29)+1)/2 + (apsym(30)+1)/2 ! known values of bits 116 & 117
! if(iii.eq.0) rxdatap(i4)=ps(4)-ps(0)
! if(iii.eq.1) rxdatap(i4)=ps(5)-ps(1)
! if(iii.eq.2) rxdatap(i4)=ps(6)-ps(2)
! if(iii.eq.3) rxdatap(i4)=ps(7)-ps(3)
! endif
! bit 144 lives in symbol 48 and will be 1 if it is set as an ap bit.
! take care of metrics for bits 142 and 143
if(j.eq.48) then ! bit 144 is always 1
rxdatap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
rxdatap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
endif
! bit 154 lives in symbol 52 and will be 0 if it is set as an ap bit
! take care of metrics for bits 155 and 156
if(j.eq.52) then ! bit 154 will be 0 if it is set as an ap bit.
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
endif
enddo
rxav=sum(rxdata)/(3.0*ND)
@ -107,84 +218,141 @@ subroutine ft8b(dd0,newdat,nfqso,ndepth,icand,sync0,f1,xdt,apsym,nharderrors,
rxsig=sqrt(rx2av)
endif
rxdata=rxdata/rxsig
ss=0.84
llr=2.0*rxdata/(ss*ss)
! Let's just assume that rxsig is OK for rxdatap too...
rxdatap=rxdatap/rxsig
! do iap=0,3
do iap=0,0 !### Temporary ###
if(iap.eq.0) then
apmask=0
apmask(160:162)=1
llrap=llr
llrap(160:162)=5.0*apsym(73:75)/ss
elseif(iap.eq.1) then
apmask=0
apmask(88:115)=1 ! mycall
apmask(160:162)=1 ! 3 extra bits
llrap=0.0
llrap(88:115)=5.0*apsym(1:28)/ss
llrap(160:162)=5.0*apsym(73:75)/ss
where(apmask.eq.0) llrap=llr
elseif(iap.eq.2) then
apmask=0
apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(160:162)=1 ! 3 extra bits
llrap=0.0
llrap(88:143)=5.0*apsym(1:56)/ss
llrap(160:162)=5.0*apsym(73:75)/ss
where(apmask.eq.0) llrap=llr
elseif(iap.eq.3) then
apmask=0
apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(144:154)=1 ! RRR or 73
apmask(160:162)=1 ! 3 extra bits
llrap=0.0
llrap(88:143)=5.0*apsym(1:56)/ss
llrap(144:154)=5.0*rr73/ss
llrap(160:162)=5.0*apsym(73:75)/ss
where(apmask.eq.0) llrap=llr
endif
cw=0
call timer('bpd174 ',0)
call bpdecode174(llrap,apmask,max_iterations,decoded,cw,nharderrors)
call timer('bpd174 ',1)
dmin=0.0
if(nharderrors.lt.0 .and. ndepth.ge.2) then
call timer('osd174 ',0)
call osd174(llrap,norder,decoded,cw,nharderrors,dmin)
call timer('osd174 ',1)
endif
nbadcrc=1
message=' '
xsnr=-99.0
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
if( nharderrors.ge.0 .and. dmin.le.30.0 .and. nharderrors .lt. 30) then
call chkcrc12a(decoded,nbadcrc)
else
nharderrors=-1
cycle
endif
if(nbadcrc.eq.0) then
call extractmessage174(decoded,message,ncrcflag,recent_calls,nrecent)
call genft8(message,msgsent,msgbits,itone)
! call subtractft8(dd0,itone,f1,xdt2)
xsig=0.0
xnoi=0.0
do i=1,79
xsig=xsig+s2(itone(i),i)**2
ios=mod(itone(i)+4,7)
xnoi=xnoi+s2(ios,i)**2
enddo
xsnr=0.001
if( xnoi.gt.0 .and. xnoi.lt.xsig ) xsnr=xsig/xnoi-1.0
xsnr=10.0*log10(xsnr)-27.0
if( xsnr .lt. -24.0 ) xsnr=-24.0
! write(50,3050) icand,sync0,f1,xdt,nharderrors,dmin,message,iap
!3050 format(i3,3f10.3,i5,f10.3,2x,a22,i3)
return
endif
ss=0.84
llr0=2.0*rxdata/(ss*ss)
llra=2.0*rxdatap/(ss*ss) ! llr's for use with ap
apmag=4.0
! pass #
!------------------------------
! 1 regular decoding
! 2 erase 24
! 3 erase 48
! 4 ap pass 1
! 5 ap pass 2
! 6 ap pass 3
! 7 ap pass 4, etc.
if(lapon) then
npasses=3+nappasses(nQSOProgress)
else
npasses=3
endif
do ipass=1,npasses
llr=llr0
if(ipass.ne.2 .and. ipass.ne.3) nblank=0
if(ipass.eq.2) nblank=24
if(ipass.eq.3) nblank=48
if(nblank.gt.0) llr(1:nblank)=0.
if(ipass.le.3) then
apmask=0
llrap=llr
iaptype=0
endif
if(ipass .gt. 3) then
iaptype=naptypes(nQSOProgress,ipass-3)
if(iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle
if(iaptype.eq.1 .or. iaptype.eq.2 ) then ! AP,???,???
apmask=0
apmask(88:115)=1 ! first 28 bits are AP
apmask(144)=1 ! not free text
llrap=llr
if(iaptype.eq.1) llrap(88:115)=apmag*mcq/ss
if(iaptype.eq.2) llrap(88:115)=apmag*apsym(1:28)/ss
llrap(116:117)=llra(116:117)
llrap(142:143)=llra(142:143)
llrap(144)=-apmag/ss
endif
if(iaptype.eq.3) then ! mycall, dxcall, ???
apmask=0
apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(144)=1 ! not free text
llrap=llr
llrap(88:143)=apmag*apsym(1:56)/ss
llrap(144)=-apmag/ss
endif
if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then
apmask=0
apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(144:159)=1 ! RRR or 73 or RR73
llrap=llr
llrap(88:143)=apmag*apsym(1:56)/ss
if(iaptype.eq.4) llrap(144:159)=apmag*mrrr/ss
if(iaptype.eq.5) llrap(144:159)=apmag*m73/ss
if(iaptype.eq.6) llrap(144:159)=apmag*mrr73/ss
endif
if(iaptype.eq.7) then ! ???, dxcall, ???
apmask=0
apmask(116:143)=1 ! hiscall
apmask(144)=1 ! not free text
llrap=llr
llrap(115)=llra(115)
llrap(116:143)=apmag*apsym(29:56)/ss
llrap(144)=-apmag/ss
endif
endif
cw=0
call timer('bpd174 ',0)
call bpdecode174(llrap,apmask,max_iterations,decoded,cw,nharderrors, &
niterations)
call timer('bpd174 ',1)
dmin=0.0
if(ndepth.eq.3 .and. nharderrors.lt.0) then
norder=1
if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then
if(ipass.le.3 .and. .not.nagain) then
norder=2
else ! norder=3 for nagain and AP decodes
norder=3
endif
endif
call timer('osd174 ',0)
call osd174(llrap,apmask,norder,decoded,cw,nharderrors,dmin)
call timer('osd174 ',1)
endif
nbadcrc=1
message=' '
xsnr=-99.0
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
if(any(decoded(75:75).ne.0)) cycle !Reject if any of the 3 extra bits are nonzero
if(nharderrors.ge.0 .and. nharderrors+dmin.lt.60.0 .and. &
.not.(sync.lt.2.0 .and. nharderrors.gt.35) .and. &
.not.(ipass.gt.1 .and. nharderrors.gt.39) .and. &
.not.(ipass.eq.3 .and. nharderrors.gt.30) &
) then
call chkcrc12a(decoded,nbadcrc)
else
nharderrors=-1
cycle
endif
if(nbadcrc.eq.0) then
call extractmessage174(decoded,message,ncrcflag,recent_calls,nrecent)
call genft8(message,mygrid6,bcontest,msgsent,msgbits,itone)
if(lsubtract) call subtractft8(dd0,itone,f1,xdt2)
xsig=0.0
xnoi=0.0
do i=1,79
xsig=xsig+s2(itone(i),i)**2
ios=mod(itone(i)+4,7)
xnoi=xnoi+s2(ios,i)**2
enddo
xsnr=0.001
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.0
xsnr=10.0*log10(xsnr)-27.0
if(xsnr .lt. -24.0) xsnr=-24.0
return
endif
enddo
return
end subroutine ft8b

View File

@ -8,19 +8,23 @@ program ft8sim
type(hdr) h !Header for .wav file
character arg*12,fname*17,sorm*1
character msg*22,msgsent*22
character*6 mygrid6
logical bcontest
complex c0(0:NMAX-1)
complex c(0:NMAX-1)
integer itone(NN)
integer*1 msgbits(KK)
integer*2 iwave(NMAX) !Generated full-length waveform
integer*2 iwave(NMAX) !Generated full-length waveform
data mygrid6/'EM48 '/
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.8) then
print*,'Usage: ft8sim "message" sorm f0 DT fdop del nfiles snr'
print*,'Usage: ft8sim "message" s|m f0 DT fdop del nfiles snr'
print*,'Example: ft8sim "K1ABC W9XYZ EN37" m 1500.0 0.0 0.1 1.0 10 -18'
print*,'sorm: "s" for single signal at 1500 Hz, "m" for 25 signals'
print*,'s|m: "s" for single signal at 1500 Hz, "m" for 25 signals'
print*,'f0 is ignored when sorm = m'
print*,'Make nfiles negative to invoke 72-bit contest mode.'
go to 999
endif
call getarg(1,msg) !Message to be transmitted
@ -48,6 +52,8 @@ program ft8sim
call getarg(8,arg)
read(arg,*) snrdb !SNR_2500
bcontest=nfiles.lt.0
nfiles=abs(nfiles)
twopi=8.0*atan(1.0)
fs=12000.0 !Sample rate (Hz)
dt=1.0/fs !Sample interval (s)
@ -60,7 +66,8 @@ program ft8sim
if(snrdb.gt.90.0) sig=1.0
txt=NN*NSPS/12000.0
call genft8(msg,msgsent,msgbits,itone) !Source-encode, then get itone()
! Source-encode, then get itone()
call genft8(msg,mygrid6,bcontest,msgsent,msgbits,itone)
write(*,1000) f0,xdt,txt,snrdb,bw,msgsent
1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, &
' BW:',f4.1,2x,a22)

View File

@ -1,4 +1,4 @@
subroutine genft8(msg,msgsent,msgbits,itone)
subroutine genft8(msg,mygrid,bcontest,msgsent,msgbits,itone)
! Encode an FT8 message, producing array itone().
@ -6,8 +6,10 @@ subroutine genft8(msg,msgsent,msgbits,itone)
use packjt
include 'ft8_params.f90'
character*22 msg,msgsent
character*6 mygrid,g1,g2,g3,g4
character*87 cbits
! logical checksumok
logical*1 bcontest
logical isgrid
integer*4 i4Msg6BitWords(12) !72-bit message as 6-bit words
integer*1 msgbits(KK),codeword(3*ND)
integer*1, target:: i1Msg8BitBytes(11)
@ -15,8 +17,42 @@ subroutine genft8(msg,msgsent,msgbits,itone)
integer icos7(0:6)
data icos7/2,5,6,0,4,1,3/ !Costas 7x7 tone pattern
isgrid(g1)=g1(1:1).ge.'A' .and. g1(1:1).le.'R' .and. g1(2:2).ge.'A' .and. &
g1(2:2).le.'R' .and. g1(3:3).ge.'0' .and. g1(3:3).le.'9' .and. &
g1(4:4).ge.'0' .and. g1(4:4).le.'9' .and. g1(1:4).ne.'RR73'
if(bcontest) then
i0=index(msg,' R ') + 3 !Check for ' R ' in message
g1=msg(i0:i0+3)//' '
if(isgrid(g1)) then !Check for ' R grid'
call grid2deg(g1,dlong,dlat)
dlong=dlong+180.0
if(dlong.gt.180.0) dlong=dlong-360.0
dlat=-dlat
call deg2grid(dlong,dlat,g2) !g2=antipodes grid
msg=msg(1:i0-3)//g2(1:4) !Send message with g2
endif
endif
call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
if(bcontest) then
i1=index(msgsent(8:22),' ') + 8
g3=msgsent(i1:i1+3)//' '
if(isgrid(g3)) then
call azdist(mygrid,g3,0.d0,nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter)
if(ndkm.gt.10000) then
call grid2deg(g3,dlong,dlat)
dlong=dlong+180.0
if(dlong.gt.180.0) dlong=dlong-360.0
dlat=-dlat
call deg2grid(dlong,dlat,g4)
msgsent=msgsent(1:i1-1)//'R '//g4(1:4)
endif
endif
endif
i3bit=0 !### temporary ###
write(cbits,1000) i4Msg6BitWords,32*i3bit
1000 format(12b6.6,b8.8)

View File

@ -1,9 +1,10 @@
subroutine osd174(llr,norder,decoded,cw,nhardmin,dmin)
subroutine osd174(llr,apmask,norder,decoded,cw,nhardmin,dmin)
!
! An ordered-statistics decoder for the (174,87) code.
!
include "ldpc_174_87_params.f90"
integer*1 apmask(N),apmaskr(N)
integer*1 gen(K,N)
integer*1 genmrb(K,N),g2(N,K)
integer*1 temp(K),m0(K),me(K),mi(K)
@ -36,6 +37,8 @@ endif
! re-order received vector to place systematic msg bits at the end
rx=llr(colorder+1)
apmaskr=apmask(colorder+1)
! hard decode the received word
hdec=0
@ -71,7 +74,7 @@ do id=1,K ! diagonal element indices
endif
do ii=1,K
if( ii .ne. id .and. genmrb(ii,id) .eq. 1 ) then
genmrb(ii,1:N)=mod(genmrb(ii,1:N)+genmrb(id,1:N),2)
genmrb(ii,1:N)=ieor(genmrb(ii,1:N),genmrb(id,1:N))
endif
enddo
exit
@ -91,6 +94,7 @@ hdec=hdec(indices) ! hard decisions from received symbols
m0=hdec(1:K) ! zero'th order message
absrx=absrx(indices)
rx=rx(indices)
apmaskr=apmaskr(indices)
s1=sum(absrx(1:K))
s2=sum(absrx(K+1:N))
@ -110,22 +114,24 @@ do iorder=1,norder
mi(K-iorder+1:K)=1
iflag=0
do while(iflag .ge. 0 )
dpat=sum(mi*absrx(1:K))
nt=nt+1
if( dpat .lt. thresh ) then ! reject unlikely error patterns
me=ieor(m0,mi)
call mrbencode(me,ce,g2,N,K)
nxor=ieor(ce,hdec)
dd=sum(nxor*absrx)
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
thresh=rho*dmin
if(all(iand(apmaskr(1:K),mi).eq.0)) then ! reject patterns with ap bits
dpat=sum(mi*absrx(1:K))
nt=nt+1
if( dpat .lt. thresh ) then ! reject unlikely error patterns
me=ieor(m0,mi)
call mrbencode(me,ce,g2,N,K)
nxor=ieor(ce,hdec)
dd=sum(nxor*absrx)
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
thresh=rho*dmin
endif
else
nrejected=nrejected+1
endif
else
nrejected=nrejected+1
endif
endif
! get the next test error pattern, iflag will go negative
! when the last pattern with weight iorder has been generated
call nextpat(mi,k,iorder,iflag)

View File

@ -10,7 +10,7 @@ subroutine subtractft8(dd,itone,f0,dt)
use timer_module, only: timer
parameter (NMAX=15*12000,NFRAME=1920*79)
parameter (NFFT=NMAX,NFILT=400)
parameter (NFFT=NMAX,NFILT=1400)
real*4 dd(NMAX), window(-NFILT/2:NFILT/2)
complex cref,camp,cfilt,cw
integer itone(79)

View File

@ -1,7 +1,8 @@
subroutine sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand)
include 'ft8_params.f90'
parameter (JZ=31) !DT up to +/- 2.5 s
! Search over +/- 1.5s relative to 0.5s TX start time.
parameter (JZ=38)
complex cx(0:NH1)
real s(NH1,NHSYM)
real savg(NH1)
@ -18,16 +19,13 @@ subroutine sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
data icos7/2,5,6,0,4,1,3/ !Costas 7x7 tone pattern
equivalence (x,cx)
! Compute symbol spectra at half-symbol steps.
! Compute symbol spectra, stepping by NSTEP steps.
savg=0.
istep=NSPS/2 !960
tstep=istep/12000.0 !0.08 s
tstep=NSTEP/12000.0
df=12000.0/NFFT1 !3.125 Hz
! Compute symbol spectra at half-symbol steps
fac=1.0/300.0
do j=1,NHSYM
ia=(j-1)*istep + 1
ia=(j-1)*NSTEP + 1
ib=ia+NSPS-1
x(1:NSPS)=fac*dd(ia:ib)
x(NSPS+1:)=0.
@ -45,25 +43,41 @@ subroutine sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
ia=max(1,nint(nfa/df))
ib=nint(nfb/df)
nssy=NSPS/NSTEP ! # steps per symbol
nfos=NFFT1/NSPS ! # frequency bin oversampling factor
jstrt=0.5/tstep
do i=ia,ib
do j=-JZ,JZ
t=0.
t0=0.
do j=-JZ,+JZ
ta=0.
tb=0.
tc=0.
t0a=0.
t0b=0.
t0c=0.
do n=0,6
k=j+2*n
if(k.ge.1) then
t=t + s(i+2*icos7(n),k)
t0=t0 + sum(s(i:i+12:2,k))
k=j+jstrt+nssy*n
if(k.ge.1.and.k.le.NHSYM) then
ta=ta + s(i+nfos*icos7(n),k)
t0a=t0a + sum(s(i:i+nfos*6:nfos,k))
endif
t=t + s(i+2*icos7(n),k+72)
t0=t0 + sum(s(i:i+12:2,k+72))
if(k+144.le.NHSYM) then
t=t + s(i+2*icos7(n),k+144)
t0=t0 + sum(s(i:i+12:2,k+144))
tb=tb + s(i+nfos*icos7(n),k+nssy*36)
t0b=t0b + sum(s(i:i+nfos*6:nfos,k+nssy*36))
if(k+nssy*72.le.NHSYM) then
tc=tc + s(i+nfos*icos7(n),k+nssy*72)
t0c=t0c + sum(s(i:i+nfos*6:nfos,k+nssy*72))
endif
enddo
t=ta+tb+tc
t0=t0a+t0b+t0c
t0=(t0-t)/6.0
sync2d(i,j)=t/t0
sync_abc=t/t0
t=tb+tc
t0=t0b+t0c
t0=(t0-t)/6.0
sync_bc=t/t0
sync2d(i,j)=max(sync_abc,sync_bc)
enddo
enddo
@ -84,8 +98,7 @@ subroutine sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
candidate0=0.
k=0
syncmin=2.0
do i=1,100
do i=1,200
n=ia + indx(iz+1-i) - 1
if(red(n).lt.syncmin) exit
if(k.lt.200) k=k+1
@ -115,13 +128,21 @@ subroutine sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
fac=20.0/maxval(s)
s=fac*s
! Sort by sync
! call indexx(candidate0(3,1:ncand),ncand,indx)
! Sort by frequency
call indexx(candidate0(1,1:ncand),ncand,indx)
k=1
! do i=ncand,1,-1
do i=1,ncand
j=indx(i)
candidate(1,i)=abs(candidate0(1,j))
candidate(2,i)=candidate0(2,j)
candidate(3,i)=candidate0(3,j)
if( candidate0(3,j) .ge. syncmin .and. candidate0(2,j).ge.-1.5 ) then
candidate(1,k)=abs(candidate0(1,j))
candidate(2,k)=candidate0(2,j)
candidate(3,k)=candidate0(3,j)
k=k+1
endif
enddo
ncand=k-1
return
end subroutine sync8

View File

@ -7,7 +7,7 @@ module ft8_decode
end type ft8_decoder
abstract interface
subroutine ft8_decode_callback (this,sync,snr,dt,freq,nbadcrc,decoded)
subroutine ft8_decode_callback (this,sync,snr,dt,freq,decoded,nap,qual)
import ft8_decoder
implicit none
class(ft8_decoder), intent(inout) :: this
@ -15,93 +15,125 @@ module ft8_decode
integer, intent(in) :: snr
real, intent(in) :: dt
real, intent(in) :: freq
integer, intent(in) :: nbadcrc
character(len=22), intent(in) :: decoded
integer, intent(in) :: nap
real, intent(in) :: qual
end subroutine ft8_decode_callback
end interface
contains
subroutine decode(this,callback,iwave,nfqso,newdat,nutc,nfa, &
nfb,nagain,ndepth,nsubmode,mycall12,hiscall12,hisgrid6)
!use wavhdr
subroutine decode(this,callback,iwave,nQSOProgress,nfqso,nftx,newdat, &
nutc,nfa,nfb,nexp_decode,ndepth,nagain,lapon,napwid,mycall12, &
mygrid6,hiscall12,hisgrid6)
! use wavhdr
use timer_module, only: timer
include 'fsk4hf/ft8_params.f90'
!type(hdr) h
! type(hdr) h
class(ft8_decoder), intent(inout) :: this
procedure(ft8_decode_callback) :: callback
real s(NH1,NHSYM)
real candidate(3,200)
real dd(15*12000)
logical, intent(in) :: newdat, nagain
logical, intent(in) :: lapon,nagain
logical newdat,lsubtract,ldupe,bcontest
character*12 mycall12, hiscall12
character*6 hisgrid6
character*6 mygrid6,hisgrid6
integer*2 iwave(15*12000)
integer apsym(KK)
character datetime*13,message*22
character*22 allmessages(100)
integer allsnrs(100)
save s,dd
bcontest=iand(nexp_decode,128).ne.0
this%callback => callback
write(datetime,1001) nutc !### TEMPORARY ###
1001 format("000000_",i6.6)
if(index(hisgrid6," ").eq.0) hisgrid6="EN50"
call ft8apset(mycall12,hiscall12,hisgrid6,apsym)
call ft8apset(mycall12,mygrid6,hiscall12,hisgrid6,bcontest,apsym,iaptype)
dd=iwave
call timer('sync8 ',0)
call sync8(dd,nfa,nfb,nfqso,s,candidate,ncand)
call timer('sync8 ',1)
ndecodes=0
allmessages=' '
allsnrs=0
ifa=nfa
ifb=nfb
if(nagain) then
ifa=nfqso-10
ifb=nfqso+10
endif
syncmin=2.0
do icand=1,ncand
sync=candidate(3,icand)
if(sync.lt.syncmin) cycle
f1=candidate(1,icand)
xdt=candidate(2,icand)
nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ###
call timer('ft8b ',0)
call ft8b(dd,newdat,nfqso,ndepth,icand,sync,f1,xdt,apsym,nharderrors, &
dmin,nbadcrc,message,xsnr)
nsnr=xsnr
xdt=xdt-0.6
call timer('ft8b ',1)
if (associated(this%callback)) call this%callback(sync,nsnr,xdt, &
f1,nbadcrc,message)
! write(*,'(f7.2,i5,f7.2,f9.1,i5,f7.2,2x,a22)') sync,nsnr,xdt,f1,nharderrors,dmin,message
! write(13,1110) datetime,0,nsnr,xdt,f1,nharderrors,dmin,message
!1110 format(a13,2i4,f6.2,f7.1,i4,' ~ ',f6.2,2x,a22,' FT8')
! write(51,3051) xdt,f1,sync,dmin,nsnr,nharderrors,nbadcrc,message
!3051 format(4f9.1,3i5,2x,a22)
! flush(51)
enddo
!h=default_header(12000,NMAX)
!open(10,file='subtract.wav',status='unknown',access='stream')
!iwave=nint(dd)
!write(10) h,iwave
!close(10)
return
! For now:
! ndepth=1: no subtraction, 1 pass, belief propagation only
! ndepth=2: subtraction, 2 passes, belief propagation only
! ndepth=3: subtraction, 2 passes, bp+osd2 at and near nfqso
if(ndepth.eq.1) npass=1
if(ndepth.ge.2) npass=2
do ipass=1,npass
newdat=.true. ! Is this a problem? I hijacked newdat.
if(ipass.eq.1) then
lsubtract=.true.
if(ndepth.eq.1) lsubtract=.false.
syncmin=1.5
else
lsubtract=.false.
syncmin=1.5
endif
call timer('sync8 ',0)
call sync8(dd,ifa,ifb,syncmin,nfqso,s,candidate,ncand)
call timer('sync8 ',1)
do icand=1,ncand
sync=candidate(3,icand)
f1=candidate(1,icand)
xdt=candidate(2,icand)
nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ###
call timer('ft8b ',0)
call ft8b(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,apsym, &
nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
nsnr=nint(xsnr)
xdt=xdt-0.5
hd=nharderrors+dmin
call timer('ft8b ',1)
if(nbadcrc.eq.0) then
call jtmsg(message,iflag)
if(bcontest) call fix_contest_msg(mygrid6,message)
if(iand(iflag,16).ne.0) message(22:22)='?'
if(iand(iflag,15).eq.0) then
ldupe=.false.
do id=1,ndecodes
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
enddo
if(.not.ldupe) then
ndecodes=ndecodes+1
allmessages(ndecodes)=message
allsnrs(ndecodes)=nsnr
endif
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
! iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
! xdt,nint(f1),message
! flush(81)
if(.not.ldupe .and. associated(this%callback)) then
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
call this%callback(sync,nsnr,xdt,f1,message,iaptype,qual)
endif
else
write(19,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
xdt,nint(f1),message
1004 format(i6.6,2i4,3i2,2i3,3f6.1,i4,f6.2,i5,2x,a22)
flush(19)
endif
endif
enddo
! h=default_header(12000,NMAX)
! open(10,file='subtract.wav',status='unknown',access='stream')
! iwave=nint(dd)
! write(10) h,iwave
! close(10)
enddo
return
end subroutine decode
end module ft8_decode
subroutine ft8apset(mycall12,hiscall12,hisgrid6,apsym)
parameter(NAPM=4,KK=87)
character*12 mycall12,hiscall12
character*22 msg,msgsent
character*6 mycall,hiscall
character*6 hisgrid6
character*4 hisgrid
integer apsym(KK)
integer*1 msgbits(KK)
integer itone(KK)
mycall=mycall12(1:6)
hiscall=hiscall12(1:6)
hisgrid=hisgrid6(1:4)
msg=mycall//' '//hiscall//' '//hisgrid
call genft8(msg,msgsent,msgbits,itone)
apsym=2*msgbits-1
return
end subroutine ft8apset

View File

@ -41,13 +41,17 @@ subroutine genmsk144(msg0,mygrid,ichk,bcontest,msgsent,i4tone,itype)
data first/.true./
save
if( first ) then
isgrid(g1)=g1(1:1).ge.'A' .and. g1(1:1).le.'R' .and. g1(2:2).ge.'A' .and. &
g1(2:2).le.'R' .and. g1(3:3).ge.'0' .and. g1(3:3).le.'9' .and. &
g1(4:4).ge.'0' .and. g1(4:4).le.'9' .and. g1(1:4).ne.'RR73'
if(first) then
first=.false.
nsym=128
pi=4.*atan(1.0)
pi=4.0*atan(1.0)
twopi=8.*atan(1.0)
do i=1,12
pp(i)=sin( (i-1)*pi/12 )
pp(i)=sin((i-1)*pi/12)
enddo
endif
@ -174,14 +178,3 @@ subroutine genmsk144(msg0,mygrid,ichk,bcontest,msgsent,i4tone,itype)
999 return
end subroutine genmsk144
logical function isgrid(g1)
character*4 g1
isgrid=g1(1:1).ge.'A' .and. g1(1:1).le.'R' .and. g1(2:2).ge.'A' .and. &
g1(2:2).le.'R' .and. g1(3:3).ge.'0' .and. g1(3:3).le.'9' .and. &
g1(4:4).ge.'0' .and. g1(4:4).le.'9'
return
end function isgrid

View File

@ -161,6 +161,8 @@ program jt9
! Import FFTW wisdom, if available
wisfile=trim(data_dir)//'/jt9_wisdom.dat'// C_NULL_CHAR
iret=fftwf_import_wisdom_from_filename(wisfile)
open(19,file=trim(data_dir)//'/false_decodes.txt',status='unknown', &
position='append')
ntry65a=0
ntry65b=0
@ -187,7 +189,7 @@ program jt9
if(infile(i1-5:i1-5).eq.'_') then
read(infile(i1-4:i1-1),*,err=1) nutc
else
read(infile(i1-6:i1-3),*,err=1) nutc
read(infile(i1-6:i1-1),*,err=1) nutc
endif
go to 2
1 nutc=0
@ -238,8 +240,8 @@ program jt9
ingain=0
call timer('symspec ',0)
nminw=1
call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, &
ihsym,npts8,pxdbmax)
call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb, &
s,df3,ihsym,npts8,pxdbmax)
call timer('symspec ',1)
endif
nhsym0=nhsym
@ -260,9 +262,11 @@ program jt9
shared_data%params%kin=64800
shared_data%params%nzhsym=181
shared_data%params%ndepth=ndepth
shared_data%params%lapon=.true.
shared_data%params%napwid=75
shared_data%params%dttol=3.
shared_data%params%minsync=0 !### TEST ONLY
! shared_data%params%minsync=0 !### TEST ONLY
! shared_data%params%nfqso=1500 !### TEST ONLY
! mycall="G3WDG " !### TEST ONLY
! hiscall="VK7MO " !### TEST ONLY

View File

@ -9,7 +9,9 @@
integer(c_int) :: nutc
logical(c_bool) :: ndiskdat
integer(c_int) :: ntr
integer(c_int) :: nQSOProgress ! See MainWindow::m_QSOProgress for values
integer(c_int) :: nfqso
integer(c_int) :: nftx
logical(c_bool) :: newdat
integer(c_int) :: npts8
integer(c_int) :: nfa
@ -21,6 +23,8 @@
integer(c_int) :: nsubmode
logical(c_bool) :: nagain
integer(c_int) :: ndepth
logical(c_bool) :: lapon
integer(c_int) :: napwid
integer(c_int) :: ntxmode
integer(c_int) :: nmode
integer(c_int) :: minw

131
lib/jtmsg.f90 Normal file
View File

@ -0,0 +1,131 @@
subroutine jtmsg(msg,iflag)
! Attempts to identify false decodes in JT-style messages.
! Returns iflag with sum of bits as follows:
! ------------------------------------------
! 1 Grid/Report invalid
! 2 Second callsign invalid
! 4 First callsign invalid
! 8 Very unlikely free text
! 16 Questionable free text
! 0 Message is probably OK
! ------------------------------------------
character*22 msg,t
character*13 w1,w2,w3,w
character*6 bc1,bc2,bc3
character*1 c
logical c1ok,c2ok,c3ok,isdigit,isletter,isgrid4
! Statement functions
isdigit(c)=(ichar(c).ge.ichar('0')) .and. (ichar(c).le.ichar('9'))
isletter(c)=(ichar(c).ge.ichar('A')) .and. (ichar(c).le.ichar('Z'))
isgrid4(w)=(len_trim(w).eq.4 .and. &
ichar(w(1:1)).ge.ichar('A') .and. ichar(w(1:1)).le.ichar('R') .and. &
ichar(w(2:2)).ge.ichar('A') .and. ichar(w(2:2)).le.ichar('R') .and. &
ichar(w(3:3)).ge.ichar('0') .and. ichar(w(3:3)).le.ichar('9') .and. &
ichar(w(4:4)).ge.ichar('0') .and. ichar(w(4:4)).le.ichar('9'))
t=trim(msg) !Temporary copy of msg
nt=len_trim(t)
! Check for standard messages
! Insert underscore in "CQ AA " to "CQ ZZ ", "CQ nnn " to make them one word.
if(t(1:3).eq.'CQ ' .and. isletter(t(4:4)) .and. &
isletter(t(5:5)) .and. t(6:6).eq.' ') t(3:3)='_'
if(t(1:3).eq.'CQ ' .and. isdigit(t(4:4)) .and. &
isdigit(t(5:5)) .and. isdigit(t(6:6)) .and. t(7:7).eq.' ') t(3:3)='_'
! Parse first three words
w1=' '
w2=' '
w3=' '
i1=index(t,' ')
if(i1.gt.0) w1(1:i1-1)=t(1:i1-1)
t=t(i1+1:)
i2=index(t,' ')
if(i2.gt.0) w2(1:i2-1)=t(1:i2-1)
t=t(i2+1:)
i3=index(t,' ')
if(i3.gt.0) w3(1:i3-1)=t(1:i3-1)
if(w1(1:3).eq.'CQ ' .or. w1(1:3).eq.'CQ_' .or. w1(1:3).eq.'DE ' .or. &
w1(1:4).eq.'QRZ ') then
! CQ/DE/QRZ: Should have one good callsign in w2 and maybe a grid/rpt in w3
call chkcall(w2,bc2,c2ok)
iflag=0
if(.not.c2ok) iflag=iflag+2
if(len_trim(w3).ne.0 .and. (.not.isgrid4(w3))) iflag=iflag+1
if(w1(1:3).eq.'DE ' .and. c2ok) iflag=0
if(iflag.eq.0) return
endif
! Check for two calls and maybe a grid, rpt, R+rpr, RRR, or 73
iflag=0
call chkcall(w1,bc1,c1ok)
call chkcall(w2,bc2,c2ok)
if(.not.c1ok) iflag=iflag+4
if(.not.c2ok) iflag=iflag+2
if(len_trim(w3).ne.0 .and. (.not.isgrid4(w3)) .and. &
w3(1:1).ne.'+' .and. w3(1:1).ne.'-' .and. &
w3(1:2).ne.'R+' .and. w3(1:2).ne.'R-' .and. &
w3(1:3).ne.'73 ' .and. w3(1:4).ne.'RRR ') iflag=iflag+1
call chkcall(w3,bc3,c3ok)
! Allow(?) non-standard messages of the form CQ AS OC K1JT
if(w1(1:3).eq.'CQ_'.and.isletter(w2(1:1)).and.isletter(w2(2:2)).and. &
w2(3:3).eq.' '.and.c3ok) iflag=0
if(iflag.eq.0 .or. nt.gt.13) return
! Check for plausible free text
nc=0
np=0
do i=1,13
c=msg(i:i)
if(c.ne.' ') nc=nc+1 !Number of non-blank characters
if(c.eq.'+') np=np+1 !Number of punctuation characters
if(c.eq.'-') np=np+1
if(c.eq.'.') np=np+1
if(c.eq.'/') np=np+1
if(c.eq.'?') np=np+1
enddo
nb=13-nc !Number of blanks
iflag=16 !Mark as potentially questionable
if(nc.ge.12 .or. (nc.ge.11 .and. np.gt.0)) then
iflag=8 !Unlikely free text, flag it
endif
! Save messages containing some common words
if(msg(1:3).eq.'CQ ') iflag=0
if(index(msg,'DE ').gt.0) iflag=0
if(index(msg,'TU ').gt.0) iflag=0
if(index(msg,' TU').gt.0) iflag=0
if(index(msg,'73 ').gt.0) iflag=0
if(index(msg,' 73').gt.0) iflag=0
if(index(msg,'TNX').gt.0) iflag=0
if(index(msg,'THX').gt.0) iflag=0
if(index(msg,'EQSL').gt.0) iflag=0
if(index(msg,'LOTW').gt.0) iflag=0
if(index(msg,'DECOD').gt.0) iflag=0
if(index(msg,'CHK').gt.0) iflag=0
if(index(msg,'CLK').gt.0) iflag=0
if(index(msg,'CLOCK').gt.0) iflag=0
if(index(msg,'LOG').gt.0) iflag=0
if(index(msg,'QRM').gt.0) iflag=0
if(index(msg,'QSY').gt.0) iflag=0
if(index(msg,'TEST').gt.0) iflag=0
if(index(msg,'CQDX').gt.0) iflag=0
if(index(msg,'CALL').gt.0) iflag=0
if(index(msg,'QRZ').gt.0) iflag=0
if(index(msg,'AUTO').gt.0) iflag=0
if(index(msg,'PHOTO').gt.0) iflag=0
if(index(msg,'HYBRID').gt.0) iflag=0
if(c1ok .and. w1(1:6).eq.bc1) iflag=0
if(c2ok .and. w2(1:6).eq.bc2) iflag=0
if(nb.ge.4) iflag=0
return
end subroutine jtmsg

View File

@ -9,6 +9,7 @@ program msk144d2
character c
character*80 line
character*512 datadir
character*500 infile
character*12 mycall,hiscall
character*6 mygrid
@ -17,7 +18,7 @@ program msk144d2
logical :: display_help=.false.
logical*1 bShMsgs
logical*1 bcontest
logical*1 brxequal
logical*1 btrain
logical*1 bswl
type(wav_header) :: wav
@ -25,6 +26,8 @@ program msk144d2
integer*2 id2(30*12000)
integer*2 ichunk(7*1024)
real*8 pcoeffs(5)
type (option) :: long_options(9) = [ &
option ('ndepth',.true.,'c','ndepth',''), &
option ('dxcall',.true.,'d','hiscall',''), &
@ -45,8 +48,10 @@ program msk144d2
hiscall=''
bShMsgs=.false.
bcontest=.false.
brxequal=.false.
btrain=.false.
bswl=.false.
datadir='.'
pcoeffs=0.d0
do
call getopt('c:d:ef:hm:n:rs',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.)
@ -69,7 +74,7 @@ program msk144d2
case ('n')
read (optarg(:narglen), *) ntol
case ('r')
brxequal=.true.
btrain=.true.
case ('s')
bShMsgs=.true.
end select
@ -111,7 +116,7 @@ program msk144d2
tt=sum(float(abs(id2(i:i+7*512-1))))
if( tt .ne. 0.0 ) then
call mskrtd(ichunk,nutc,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall,bShMsgs, &
bcontest,brxequal,bswl,line)
bcontest,btrain,pcoeffs,bswl,datadir,line)
if( index(line,"&") .ne. 0 .or. &
index(line,"^") .ne. 0 .or. &
index(line,"!") .ne. 0 .or. &

View File

@ -209,7 +209,7 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
if(.not. bshdecode) then
call update_hasharray(recent_calls,nrecent,nhasharray)
! Should we call fix_contest_msg() only if bcontest is true?
call fix_contest_msg(mycall(1:6),mygrid,hiscall(1:6),msgreceived)
call fix_contest_msg(mygrid,msgreceived)
endif
write(line,1020) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived, &
navg,ncorrected,eyeopening,char(0)

View File

@ -1,5 +1,9 @@
module packjt
! These variables are accessible from outside via "use packjt":
integer jt_itype,jt_nc1,jt_nc2,jt_ng,jt_k1,jt_k2
character*6 jt_c1,jt_c2,jt_c3
contains
subroutine packbits(dbits,nsymd,m0,sym)
@ -494,8 +498,17 @@ subroutine packbits(dbits,nsymd,m0,sym)
ng=ng+32768
! Encode data into 6-bit words
20 continue
20 continue
if(itype.ne.6) itype=max(nv2a,nv2b)
jt_itype=itype
jt_c1=c1
jt_c2=c2
jt_c3=c3
jt_k1=k1
jt_k2=k2
jt_nc1=nc1
jt_nc2=nc2
jt_ng=ng
dat(1)=iand(ishft(nc1,-22),63) !6 bits
dat(2)=iand(ishft(nc1,-16),63) !6 bits
dat(3)=iand(ishft(nc1,-10),63) !6 bits

View File

@ -1,17 +1,14 @@
subroutine refspectrum(id2,id2b,kk,bclear,brefspec,buseref,fname)
subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
! Input:
! id2 i*2 Raw 16-bit integer data, 12000 Hz sample rate
! brefspec logical True when accumulating a reference spectrum
parameter (NFFT=6912,NH=NFFT/2,NPOLYLOW=400,NPOLYHIGH=2600)
integer*2 id2(NFFT),id2b(120*12000)
integer*2 id2(NFFT)
logical*1 bclear,brefspec,buseref,blastuse
real x0(0:NH-1) !Input samples
real x1(0:NH-1) !Output samples (delayed by one block)
real x0s(0:NH-1) !Saved upper half of input samples
real x1s(0:NH-1) !Saved upper half of output samples
real xs(0:NH-1) !Saved upper half of input chunk convolved with h(t)
real x(0:NFFT-1) !Work array
real*4 w(0:NFFT-1) !Window function
real*4 s(0:NH) !Average spectrum
@ -19,6 +16,7 @@ subroutine refspectrum(id2,id2b,kk,bclear,brefspec,buseref,fname)
real*8 xfit(1500),yfit(1500),sigmay(1500),a(5),chisqr !Polyfit arrays
logical first
complex cx(0:NH) !Complex frequency-domain work array
complex cfil(0:NH)
character*(*) fname
common/spectra/syellow(6827),ref(0:NH),filter(0:NH)
equivalence(x,cx)
@ -34,8 +32,7 @@ subroutine refspectrum(id2,id2b,kk,bclear,brefspec,buseref,fname)
nsave=0
s=0.0
filter=1.0
x0s=0.
x1s=0.
xs=0.
first=.false.
endif
if(bclear) s=0.
@ -134,21 +131,27 @@ subroutine refspectrum(id2,id2b,kk,bclear,brefspec,buseref,fname)
30 do i=1,NH
read(16,1005,err=100,end=100) freq,s(i),ref(i),fil(i),filter(i)
enddo
! Make the filter causal for overlap and add.
cx(0)=0.0
cx(1:NH)=fil(1:NH)/NFFT
call four2a(x,NFFT,1,1,-1)
x=cshift(x,-400)
x(800:NH)=0.0
call four2a(cx,NFFT,1,-1,0)
cfil=cx
100 close(16)
110 continue
endif
x0=id2(1:NH)
x(0:NH-1)=x0s !Previous 2nd half to new 1st half
x(NH:NFFT-1)=x0 !New 2nd half
x0s=x0 !Save the new 2nd half
x=w*x !Apply window
call four2a(x,NFFT,1,-1,0) !r2c FFT (to frequency domain)
cx=fil*cx
call four2a(cx,NFFT,1,1,-1) !c2r FFT (back to time domain)
x1=x1s + x(0:NH-1) !Add previous segment's 2nd half
! id2(1:NH)=nint(x1)
if(kk.ge.6912) id2b(kk-6192+1:kk-6192+NH)=nint(x1)
x1s=x(NH:NFFT-1) !Save the new 2nd half
! Use overlap and add method to apply causal reference filter.
x(0:NH-1)=id2(1:NH)
x(NH:NFFT-1)=0.0
x=x/NFFT
call four2a(x,NFFT,1,-1,0)
cx=cfil*cx
call four2a(cx,NFFT,1,1,-1)
x(0:NH-1)=x(0:NH-1)+xs
xs=x(NH:NFFT-1)
id2(1:NH)=nint(x(0:NH-1))
endif
blastuse=buseref

View File

@ -1,76 +0,0 @@
program t3
parameter (NBLK=3456,NZ=10*NBLK)
real x0(NZ)
real x1(NZ)
twopi=8.0*atan(1.0)
dphi=twopi*1000.0/12000.0
phi=0.
do i=1,NZ
phi=phi+dphi
x0(i)=sin(phi)
if(mod(i,10007).eq.100) x0(i)=2.0
enddo
do j=1,10
ib=j*NBLK
ia=ib-NBLK+1
call filter(x0(ia:ib),x1(ia:ib))
enddo
x1(1:NZ-NBLK)=x1(NBLK+1:NZ)
do i=1,NZ-NBLK
write(13,1001) i,x0(i),x1(i),x1(i)-x0(i)
1001 format(i6,3f13.9)
enddo
end program t3
subroutine filter(x0,x1)
! Process time-domain data sequentially, optionally using a frequency-domain
! filter to alter the spectrum.
! NB: uses a sin^2 window with 50% overlap.
parameter (NFFT=6912,NH=NFFT/2)
real x0(0:NH-1) !Input samples
real x1(0:NH-1) !Output samples (delayed by one block)
real x0s(0:NH-1) !Saved upper half of input samples
real x1s(0:NH-1) !Saved upper half of output samples
real x(0:NFFT-1) !Work array
real*4 w(0:NFFT-1) !Window function
real f(0:NH) !Filter to be applied
real*4 s(0:NH) !Average spectrum
logical first
complex cx(0:NH) !Complex frequency-domain work array
equivalence (x,cx)
data first/.true./
save
if(first) then
pi=4.0*atan(1.0)
do i=0,NFFT-1
ww=sin(i*pi/NFFT)
w(i)=ww*ww/NFFT
enddo
s=0.0
f=1.0
x0s=0.
x1s=0.
first=.false.
endif
x(0:NH-1)=x0s !Previous 2nd half to new 1st half
x(NH:NFFT-1)=x0 !New 2nd half
x0s=x0 !Save the new 2nd half
x=w*x !Apply window
call four2a(x,NFFT,1,-1,0) !r2c FFT (to frequency domain)
cx=f*cx
call four2a(cx,NFFT,1,1,-1) !c2r FFT (back to time domain)
x1=x1s + x(0:NH-1) !Add previous segment's 2nd half
x1s=x(NH:NFFT-1) !Save the new 2nd half
return
end subroutine filter

27
lib/to_contest_msg.f90 Normal file
View File

@ -0,0 +1,27 @@
subroutine to_contest_msg(msg0,msg)
! If the message has "R grid4" istead of "grid4", remove the "R "
! and substitute the diametrically opposite grid.
character*6 g1,g2
character*22 msg0,msg
logical isgrid
isgrid(g1)=g1(1:1).ge.'A' .and. g1(1:1).le.'R' .and. g1(2:2).ge.'A' .and. &
g1(2:2).le.'R' .and. g1(3:3).ge.'0' .and. g1(3:3).le.'9' .and. &
g1(4:4).ge.'0' .and. g1(4:4).le.'9' .and. g1(1:4).ne.'RR73'
i0=index(msg0,' R ') + 3 !Check for ' R ' in message
g1=msg0(i0:i0+3)//' '
if(isgrid(g1)) then !Check for ' R grid'
call grid2deg(g1,dlong,dlat)
dlong=dlong+180.0
if(dlong.gt.180.0) dlong=dlong-360.0
dlat=-dlat
call deg2grid(dlong,dlat,g2) !g2=antipodes grid
msg=msg0(1:i0-3)//g2(1:4) !Send message with g2
else
msg=msg0
endif
return
end subroutine to_contest_msg

File diff suppressed because it is too large Load Diff

View File

@ -156,16 +156,22 @@ private slots:
void set_dateTimeQSO(int m_ntx);
void set_ntx(int n);
void on_txrb1_toggled(bool status);
void on_txrb1_doubleClicked ();
void on_txrb2_toggled(bool status);
void on_txrb3_toggled(bool status);
void on_txrb4_toggled(bool status);
void on_txrb4_doubleClicked ();
void on_txrb5_toggled(bool status);
void on_txrb5_doubleClicked ();
void on_txrb6_toggled(bool status);
void on_txb1_clicked();
void on_txb1_doubleClicked ();
void on_txb2_clicked();
void on_txb3_clicked();
void on_txb4_clicked();
void on_txb4_doubleClicked ();
void on_txb5_clicked();
void on_txb5_doubleClicked ();
void on_txb6_clicked();
void on_lookupButton_clicked();
void on_addButton_clicked();
@ -184,7 +190,6 @@ private slots:
void on_actionQuickDecode_toggled (bool);
void on_actionMediumDecode_toggled (bool);
void on_actionDeepestDecode_toggled (bool);
void on_inGain_valueChanged(int n);
void bumpFqso(int n);
void on_actionErase_ALL_TXT_triggered();
void on_actionErase_wsjtx_log_adi_triggered();
@ -239,7 +244,6 @@ private slots:
void on_cbTx6_toggled(bool b);
void on_cbMenus_toggled(bool b);
void on_cbFirst_toggled(bool b);
void on_cbWeak_toggled(bool b);
void on_cbAutoSeq_toggled(bool b);
void networkError (QString const&);
void on_ClrAvgButton_clicked();
@ -300,7 +304,7 @@ private:
private:
void astroUpdate ();
void writeAllTxt(QString message);
void FT8_AutoSeq(QString message);
void auto_sequence (QString const& message, unsigned start_tolerance, unsigned stop_tolerance);
void hideMenus(bool b);
NetworkAccessManager m_network_manager;
@ -364,6 +368,7 @@ private:
qint32 m_waterfallAvg;
qint32 m_ntx;
bool m_gen_message_is_cq;
bool m_send_RR73;
qint32 m_timeout;
qint32 m_XIT;
qint32 m_setftx;
@ -447,6 +452,17 @@ private:
bool m_bQRAsyncWarned;
bool m_bDoubleClicked;
bool m_bCallingCQ;
bool m_bAutoReply;
enum
{
CALLING,
REPLYING,
REPORT,
ROGER_REPORT,
ROGERS,
SIGNOFF
}
m_QSOProgress;
int m_ihsym;
int m_nzap;
@ -558,7 +574,7 @@ private:
void writeSettings();
void createStatusBar();
void updateStatusBar();
void genStdMsgs(QString rpt);
void genStdMsgs(QString rpt, bool unconditional = false);
void genCQMsg();
void clearDX ();
void lookup();
@ -574,7 +590,7 @@ private:
void pskPost(DecodedText decodedtext);
void displayDialFrequency ();
void transmitDisplay (bool);
void processMessage(QString const& messages, qint32 position, bool ctrl);
void processMessage(QString const& messages, qint32 position, bool ctrl = false, bool alt = false);
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
void replayDecodes ();
void postDecode (bool is_new, QString const& message);

View File

@ -761,16 +761,6 @@ QLabel[oob=&quot;true&quot;] {
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbWeak">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Call the weakest decoded responder to my CQ.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Weak</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbTx6">
<property name="enabled">
@ -838,7 +828,7 @@ QLabel[oob=&quot;true&quot;] {
<item>
<widget class="QCheckBox" name="cbTxLock">
<property name="toolTip">
<string>Tx frequency tracks Rx frequency</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Tx frequency tracks Rx frequency. &lt;/p&gt;&lt;p&gt;Not recommeded for general use!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Lock Tx=Rx</string>
@ -975,7 +965,7 @@ QLabel[oob=&quot;true&quot;] {
<item row="1" column="0">
<widget class="QCheckBox" name="txFirstCheckBox">
<property name="toolTip">
<string>Check to Tx in even minutes, uncheck for odd minutes</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Tx even/1st</string>
@ -1097,9 +1087,9 @@ QLabel[oob=&quot;true&quot;] {
</widget>
</item>
<item row="1" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
<widget class="QRadioButton" name="txrb1">
<widget class="DoubleClickableRadioButton" name="txrb1">
<property name="toolTip">
<string>Send this message in next Tx interval</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send this message in next Tx interval&lt;/p&gt;&lt;p&gt;Double click to toggle the use of the Tx1 message to start a QSO with a station&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
@ -1113,7 +1103,7 @@ QLabel[oob=&quot;true&quot;] {
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="txb1">
<widget class="DoubleClickablePushButton" name="txb1">
<property name="maximumSize">
<size>
<width>30</width>
@ -1121,7 +1111,7 @@ QLabel[oob=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>Switch to this Tx message NOW</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch to this Tx message NOW&lt;/p&gt;&lt;p&gt;Double click to toggle the use of the Tx1 message to start a QSO with a station&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
@ -1235,9 +1225,9 @@ QLabel[oob=&quot;true&quot;] {
</widget>
</item>
<item row="4" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
<widget class="QRadioButton" name="txrb4">
<widget class="DoubleClickableRadioButton" name="txrb4">
<property name="toolTip">
<string>Send this message in next Tx interval</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send this message in next Tx interval&lt;/p&gt;&lt;p&gt;Double-click to toggle between RRR and RR73 messages in Tx4&lt;/p&gt;&lt;p&gt;RR73 messages should only be used when you are reasonably confident that no message repititions will be required&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
@ -1251,7 +1241,7 @@ QLabel[oob=&quot;true&quot;] {
</widget>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="txb4">
<widget class="DoubleClickablePushButton" name="txb4">
<property name="maximumSize">
<size>
<width>30</width>
@ -1259,7 +1249,7 @@ QLabel[oob=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>Switch to this Tx message NOW</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch to this Tx message NOW&lt;/p&gt;&lt;p&gt;Double-click to toggle between RRR and RR73 messages in Tx4&lt;/p&gt;&lt;p&gt;RR73 messages should only be used when you are reasonably confident that no message repititions will be required&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Tx &amp;4</string>
@ -1292,9 +1282,9 @@ list. The list can be maintained in Settings (F2).</string>
</widget>
</item>
<item row="5" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
<widget class="QRadioButton" name="txrb5">
<widget class="DoubleClickableRadioButton" name="txrb5">
<property name="toolTip">
<string>Send this message in next Tx interval</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send this message in next Tx interval&lt;/p&gt;&lt;p&gt;Double-click to reset to the standard 73 message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
@ -1308,7 +1298,7 @@ list. The list can be maintained in Settings (F2).</string>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="txb5">
<widget class="DoubleClickablePushButton" name="txb5">
<property name="maximumSize">
<size>
<width>30</width>
@ -1316,7 +1306,7 @@ list. The list can be maintained in Settings (F2).</string>
</size>
</property>
<property name="toolTip">
<string>Switch to this Tx message NOW</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch to this Tx message NOW&lt;/p&gt;&lt;p&gt;Double-click to reset to the standard 73 message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Tx &amp;5</string>
@ -1935,28 +1925,6 @@ list. The list can be maintained in Settings (F2).</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QSlider" name="inGain">
<property name="toolTip">
<string>Digital gain for graph windows</string>
</property>
<property name="minimum">
<number>-50</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>20</number>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QWidget" name="DX_controls_widget" native="true">
<property name="sizePolicy">
@ -2409,6 +2377,7 @@ QPushButton[state=&quot;ok&quot;] {
<addaction name="separator"/>
<addaction name="actionInclude_averaging"/>
<addaction name="actionInclude_correlation"/>
<addaction name="actionEnable_AP"/>
<addaction name="actionEnable_AP_DXcall"/>
</widget>
<widget class="QMenu" name="menuSave">
@ -2943,9 +2912,6 @@ QPushButton[state=&quot;ok&quot;] {
<property name="text">
<string>Enable AP for DX Call</string>
</property>
<property name="shortcut">
<string/>
</property>
</action>
<action name="actionFreqCal">
<property name="checkable">
@ -3011,6 +2977,14 @@ QPushButton[state=&quot;ok&quot;] {
<string>FT8</string>
</property>
</action>
<action name="actionEnable_AP">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable AP</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@ -3040,6 +3014,16 @@ QPushButton[state=&quot;ok&quot;] {
<extends>QSpinBox</extends>
<header>RestrictedSpinBox.hpp</header>
</customwidget>
<customwidget>
<class>DoubleClickableRadioButton</class>
<extends>QRadioButton</extends>
<header>DoubleClickableRadioButton.hpp</header>
</customwidget>
<customwidget>
<class>DoubleClickablePushButton</class>
<extends>QPushButton</extends>
<header>DoubleClickablePushButton.hpp</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>logQSOButton</tabstop>
@ -3051,7 +3035,6 @@ QPushButton[state=&quot;ok&quot;] {
<tabstop>autoButton</tabstop>
<tabstop>stopTxButton</tabstop>
<tabstop>tuneButton</tabstop>
<tabstop>inGain</tabstop>
<tabstop>dxCallEntry</tabstop>
<tabstop>dxGridEntry</tabstop>
<tabstop>lookupButton</tabstop>

View File

@ -18,7 +18,10 @@
locator to Dx Grid; change Rx and Tx frequencies to<br/>
decoded signal's frequency; generate standard messages.<br/>
If first callsign is your own, Tx frequency is not<br/>
changed unless Ctrl is held down when double-clicking.
changed unless Ctrl is held down when double-clicking.<br/>
<br/>
Hold down Alt to only move the Rx frequency when<br/>
double-clicking to reply to a CQ or QRZ caller.
</td>
</tr>
<tr>

View File

@ -361,7 +361,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
float bw=9.0*12000.0/m_nsps; //JT9
if(m_mode=="FT8") bw=8*12000.0/1920.0; //FT8
if(m_mode=="FT8") bw=7*12000.0/1920.0; //FT8
if(m_mode=="JT4") { //JT4
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)

View File

@ -1,9 +1,9 @@
<table cellspacing=1>
<tr><td><b>F1 </b></td><td>Online User's Guide</td></tr>
<tr><td><b>Ctrl+F1 </b></td><td>About WSJT-X</td></tr>
<tr><td><b>F2 </b></td><td>Open configuration window</td></tr>
<tr><td><b>F2 </b></td><td>Open settings window</td></tr>
<tr><td><b>F3 </b></td><td>Display keyboard shortcuts</td></tr>
<tr><td><b>F4 </b></td><td>Clear DX Call, DX Grid, Tx messages 1-5</td></tr>
<tr><td><b>F4 </b></td><td>Clear DX Call, DX Grid, Tx messages 1-4</td></tr>
<tr><td><b>Alt+F4 </b></td><td>Exit program</td></tr>
<tr><td><b>F5 </b></td><td>Display special mouse commands</td></tr>
<tr><td><b>F6 </b></td><td>Open next file in directory</td></tr>

View File

@ -360,7 +360,7 @@ void WideGraph::setRxBand (QString const& band)
else
{
ui->fSplitSpinBox->setValue (m_fMinPerBand.value (band, 2500).toUInt ());
ui->fSplitSpinBox->setEnabled (true);
ui->fSplitSpinBox->setEnabled (m_mode=="JT9+JT65");
}
ui->widePlot->setRxBand(band);
setRxRange ();