Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
458e43252d | ||
|
|
fd0a8a3d0e | ||
|
|
6c2e9012c4 | ||
|
|
f5c4732eba | ||
|
|
1c209457dc | ||
|
|
7e8a0846f7 | ||
|
|
fb888a2e08 | ||
|
|
78a1ca3d60 | ||
|
|
14a80f09d5 | ||
|
|
1c9f81254b | ||
|
|
76208643a0 | ||
|
|
31ecbce146 | ||
|
|
a1343c1264 |
@@ -1,3 +1,95 @@
|
|||||||
|
Quisk Version 4.2.44 September 2025
|
||||||
|
====================================
|
||||||
|
Quisk now has Pure Signal for the Hermes Lite2. This is baseband predistortion to reduce IMD products.
|
||||||
|
To use it, press "PsCal" for calibration, and "PS" to enable Pure Signal. There are no adjustments needed.
|
||||||
|
More details are in the documentation.
|
||||||
|
|
||||||
|
Quisk Version 4.2.43 September 2025
|
||||||
|
====================================
|
||||||
|
I fixed a bug in the WDSP library NR2 noise reduction feature. I added the "Trained" method of NR2.
|
||||||
|
Quisk uses the WDSP library for the NR2 noise reduction and the SNB noise blanker. The WDSP library must be available
|
||||||
|
for these features to work. For windows, the library is included. For Linux you must build it by changing to the
|
||||||
|
quisk/wdsp directory and entering "make". The library is used in-place and no installation is necessary.
|
||||||
|
The new "trained" method of NR2 is included. Press the NR2 button twice to select "NR2t".
|
||||||
|
|
||||||
|
I added documentation for the new FreeDV mode RADE. See http://james.ahlstrom.name/rade.html.
|
||||||
|
The default IMD magnitude is now 100%.
|
||||||
|
|
||||||
|
Quisk Version 4.2.42 April 2025
|
||||||
|
================================
|
||||||
|
I fixed a bug in the Kenwood IF CAT command. Thanks Nick! I moved the Pulse server IP address to the Sound screen.
|
||||||
|
I added a CAT method to imitate the Elecraft K4 command set over a TCP port. Quisk now has four CAT controls. To
|
||||||
|
make this clearer I added more documentation to the Remote screen.
|
||||||
|
|
||||||
|
Quisk Version 4.2.41 January 2025
|
||||||
|
==================================
|
||||||
|
I made some improvements to the top-level Config/Radios screen. There is now an option to
|
||||||
|
make a new radio by copying settings from an existing radio. I worked around a bug in wxPython
|
||||||
|
and gtk3 that caused drawing problems on the config screens. This problem is not present on Windows.
|
||||||
|
|
||||||
|
Quisk Version 4.2.40 November 2024
|
||||||
|
===================================
|
||||||
|
Python 3.13 eliminated the telnetlib module, so I wrote a replacement. I fixed a bug in window sizing.
|
||||||
|
If you use the Dx Cluster feature, please report any problems. Dx Cluster used to use the telnetlib module
|
||||||
|
but is now new code.
|
||||||
|
|
||||||
|
I updated the install to Python 3.13. Please report any problems with Python 3.13.
|
||||||
|
|
||||||
|
Quisk Version 4.2.39 October 2024
|
||||||
|
==================================
|
||||||
|
I added an optional Hardware method PollGuiControl(self). If you define this in your Hardware file,
|
||||||
|
the GUI thread will call it frequently. It can be used to set PTT from your hardware.
|
||||||
|
|
||||||
|
I am trying to work around a wxPython quirk that causes mouse wheel tuning to fail. Please test.
|
||||||
|
|
||||||
|
Quisk Version 4.2.38 September 2024
|
||||||
|
====================================
|
||||||
|
This is a bugfix release. I fixed a bug in the Hamlib serial port when using a physical TTY instead
|
||||||
|
of a pseudo-tty. The Hamlib ZZFA command now changes the receive frequency instead of the transmit
|
||||||
|
frequency. I fixed some window sizing issues.
|
||||||
|
|
||||||
|
Quisk Version 4.2.37 August 2024
|
||||||
|
=================================
|
||||||
|
Quisk now has a new option "Fixed tune offset" on the Config/radio/Options screen. This is meant for
|
||||||
|
Softrock radios that need a constant audio frequency to simplify amplitude and phase corrections.
|
||||||
|
The value zero means no change to Quisk tuning. Otherwise enter the fixed frequency offset from center.
|
||||||
|
If you are using the obsolete "mouse_tune_method = 1" please delete it and use this new feature.
|
||||||
|
If you use softrock_tune_vfo.py as your hardware file, you should replace it with softrock/hardware_usb.py.
|
||||||
|
|
||||||
|
Quisk now works on Python 3.12. And I fixed a bug in the small screen graph width.
|
||||||
|
|
||||||
|
Quisk Version 4.2.36 August 2024
|
||||||
|
=================================
|
||||||
|
I added two new color schemes by Michael, DK1MI. The On/Off button color and text color can
|
||||||
|
now be configured. (Michael, send me the final colors). There are a few other small changes.
|
||||||
|
|
||||||
|
Quisk Version 4.2.35 June 2024
|
||||||
|
===============================
|
||||||
|
There is a new item "File play level" on the Config/radio/Sound screen to reduce the volume when playing files.
|
||||||
|
Use it to reduce the volume of the CQ message relative to radio sound.
|
||||||
|
|
||||||
|
Dan, AI2M, provided a patch to compile in MacOS on Apple Silicon. Thanks Dan!
|
||||||
|
|
||||||
|
I am working on better amplitude and phase adjustments when using SoftRock radios. The new corrections
|
||||||
|
screen has a spreadsheet to display the VFO and tune offset. And there is a feature to automatically
|
||||||
|
measure the corrections when using a signal generator as a source. If you use Quisk with SoftRock or similar
|
||||||
|
radios, please let me know what you think.
|
||||||
|
|
||||||
|
Quisk Version 4.2.34 May 2024
|
||||||
|
==============================
|
||||||
|
For the Hermes-Lite2 the inhibit Tx function (CN8) now releases the Spot button.
|
||||||
|
|
||||||
|
Quisk displays the band plan below the X-axis as colored bars, and there are eighteen possible colors.
|
||||||
|
If you hover the mouse over a bar, Quisk now displays the name of the mode. Recall that there is a dialog
|
||||||
|
box so you can set the band plan to what you want.
|
||||||
|
|
||||||
|
Quisk Version 4.2.33 May 2024
|
||||||
|
==============================
|
||||||
|
Added the get_level Hamlib command "l STRENGTH". It returns the S-meter reading. I finally found some Hamlib
|
||||||
|
documentation, often not an easy task. The return value of STRENGTH is in dB with zero dB equal to S9.
|
||||||
|
There are 6 dB per S-unit. So a STRENGTH of 4 is 4dB over S9, and -6, -12, -18 is S8, S7, S6. I also added
|
||||||
|
the corresponding FlexRadio command ZZSM.
|
||||||
|
|
||||||
Quisk Version 4.2.32 April 2024
|
Quisk Version 4.2.32 April 2024
|
||||||
================================
|
================================
|
||||||
I found and fixed a bug in the microphone filters that can result in a buffer overrun. You should update Quisk.
|
I found and fixed a bug in the microphone filters that can result in a buffer overrun. You should update Quisk.
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#Quisk version 4.2.32
|
#Quisk version 4.2.44
|
||||||
from .quisk import main
|
from .quisk import main
|
||||||
|
|||||||
+666
-282
File diff suppressed because it is too large
Load Diff
@@ -73,6 +73,9 @@ h3 {font-size:1.6rem;}
|
|||||||
<li><a href="#Digital">Digital Modes</a></li>
|
<li><a href="#Digital">Digital Modes</a></li>
|
||||||
<li><a href="#Hamlib">Rig Control and Logging</a></li>
|
<li><a href="#Hamlib">Rig Control and Logging</a></li>
|
||||||
<li><a href="#wsjtx">WSJT-X</a></li>
|
<li><a href="#wsjtx">WSJT-X</a></li>
|
||||||
|
<li><a href="#freedv">FreeDV</a></li>
|
||||||
|
<li><a href="#wdsp">NR2 and WDSP</a></li>
|
||||||
|
<li><a href="#pure">Pure Signal</a></li>
|
||||||
<li><a href="#VNA">VNA</a></li>
|
<li><a href="#VNA">VNA</a></li>
|
||||||
<li><a href="#Remote">Remote Operation</a></li>
|
<li><a href="#Remote">Remote Operation</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -81,7 +84,7 @@ h3 {font-size:1.6rem;}
|
|||||||
<div class="contents">
|
<div class="contents">
|
||||||
<h1>
|
<h1>
|
||||||
<a id="Welcome"></a>
|
<a id="Welcome"></a>
|
||||||
Welcome to QUISK (December 2023)
|
Welcome to QUISK (September 2025)
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -194,7 +197,7 @@ Quisk is free open source software written in Python and C. It is hosted on the
|
|||||||
<br>
|
<br>
|
||||||
<p>
|
<p>
|
||||||
If you have Python 3 installed on your computer, just continue to use that version.
|
If you have Python 3 installed on your computer, just continue to use that version.
|
||||||
<b>On Windows Quisk requires Python 3.8 or 3.9 or 3.10 or 3.11.</b>
|
<b>On Windows Quisk requires Python 3.8, 3.9, 3.10, 3.11, 3.12 or 3.13.</b>
|
||||||
If you want to install a more recent version of Python, uninstall the old version first.
|
If you want to install a more recent version of Python, uninstall the old version first.
|
||||||
Running multiple versions of Python is possible but can be confusing and is not necessary.
|
Running multiple versions of Python is possible but can be confusing and is not necessary.
|
||||||
A Quisk installation is needed for each version of Python you have.
|
A Quisk installation is needed for each version of Python you have.
|
||||||
@@ -204,7 +207,7 @@ A Quisk installation is needed for each version of Python you have.
|
|||||||
<p>
|
<p>
|
||||||
Windows does not include Python, so you must first install a recent version of 64-bit Python 3.
|
Windows does not include Python, so you must first install a recent version of 64-bit Python 3.
|
||||||
If you already have 64-bit Python 3 installed, just keep using it.
|
If you already have 64-bit Python 3 installed, just keep using it.
|
||||||
<b>On Windows Quisk requires Python 3.8 or 3.9 or 3.10 or 3.11.</b>
|
<b>On Windows Quisk requires Python 3.8, 3.9, 3.10, 3.11, 3.12 or 3.13.</b>
|
||||||
There may be newer versions of Python, but until support is added, use the versions listed above.
|
There may be newer versions of Python, but until support is added, use the versions listed above.
|
||||||
Python is available from <a href="http://www.python.org/">http://www.python.org</a>.
|
Python is available from <a href="http://www.python.org/">http://www.python.org</a>.
|
||||||
There is an option to <b>Add Python to PATH</b>. You MUST select
|
There is an option to <b>Add Python to PATH</b>. You MUST select
|
||||||
@@ -239,17 +242,24 @@ python -m pip install --upgrade pyserial
|
|||||||
<br><br>
|
<br><br>
|
||||||
python -m pip install --upgrade quisk
|
python -m pip install --upgrade quisk
|
||||||
<br><br>
|
<br><br>
|
||||||
You should then be able to start Quisk with the command "quisk".
|
|
||||||
You can also start Quisk with "python -m quisk".
|
|
||||||
To create a Quisk shortcut on your desktop, right-click an empty space and select "New" and "Shortcut".
|
To create a Quisk shortcut on your desktop, right-click an empty space and select "New" and "Shortcut".
|
||||||
Use "quisk.exe" as the command and "Quisk" as the name.
|
Enter this as the location of the item:
|
||||||
The "quisk.exe" program is in <b>your_install_directory</b>\Scripts.
|
</p>
|
||||||
|
<br>
|
||||||
|
<pre>
|
||||||
|
pythonw -m quisk
|
||||||
|
</pre>
|
||||||
|
<br>
|
||||||
|
<p>
|
||||||
|
and then name the shortcut, perhaps "Quisk".
|
||||||
|
If you check the properties you will see that Windows expanded the location and start directory to the full path.
|
||||||
If you are curious, Quisk and its Python source files are installed in "<b>your_install_directory</b>\Lib\site-packages\quisk".
|
If you are curious, Quisk and its Python source files are installed in "<b>your_install_directory</b>\Lib\site-packages\quisk".
|
||||||
If you change to that directory you can run Quisk with "python quisk.py".
|
If you change to that directory you can run Quisk with "pythonw quisk.py".
|
||||||
</p>
|
</p>
|
||||||
<br>
|
<br>
|
||||||
<p>
|
<p>
|
||||||
To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios.
|
To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios.
|
||||||
|
Add a radio from the list of hardware radios available. Or add the best match.
|
||||||
Then set your sound devices for that radio; the device for the radio speakers, the microphone and so forth. All configuration
|
Then set your sound devices for that radio; the device for the radio speakers, the microphone and so forth. All configuration
|
||||||
is (mostly) from the Config button. Ignore old directions and don't bother with a config file.
|
is (mostly) from the Config button. Ignore old directions and don't bother with a config file.
|
||||||
</p>
|
</p>
|
||||||
@@ -379,6 +389,7 @@ You run Quisk by running the file quisk.py with python3. For example, "python3 /
|
|||||||
You can create a desktop icon to do that, but the method depends on your version of Linux.
|
You can create a desktop icon to do that, but the method depends on your version of Linux.
|
||||||
<b>Never run Quisk with root privelege by using sudo. Fix the permission problem instead.</b>
|
<b>Never run Quisk with root privelege by using sudo. Fix the permission problem instead.</b>
|
||||||
To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios.
|
To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios.
|
||||||
|
Add a radio from the list of hardware radios available. Or add the best match.
|
||||||
Then set your sound devices for that radio; the device for the radio speakers, the microphone and so forth. All configuration
|
Then set your sound devices for that radio; the device for the radio speakers, the microphone and so forth. All configuration
|
||||||
is (mostly) from the Config button. Ignore old directions and don't bother with a config file.
|
is (mostly) from the Config button. Ignore old directions and don't bother with a config file.
|
||||||
To uninstall Quisk, just delete the quisk directory.
|
To uninstall Quisk, just delete the quisk directory.
|
||||||
@@ -526,7 +537,7 @@ When you first install Quisk, you will not have any settings for your radio.
|
|||||||
Press the Config button and go to the Radios screen.
|
Press the Config button and go to the Radios screen.
|
||||||
Then create a radio by specifying the general hardware type and give it a name of your choosing.
|
Then create a radio by specifying the general hardware type and give it a name of your choosing.
|
||||||
For a Hermes-Lite, specify "Hermes" as the hardware type and call it "HL2" (or some other name).
|
For a Hermes-Lite, specify "Hermes" as the hardware type and call it "HL2" (or some other name).
|
||||||
Press "Add" and a new tab for your radio will appear. Look through the various settings on the HL2 tab.
|
Press "Apply" and a new tab for your radio will appear. Look through the various settings on the HL2 tab.
|
||||||
The parameters for the radios are stored in the file quisk_settings.json.
|
The parameters for the radios are stored in the file quisk_settings.json.
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -824,8 +835,14 @@ SoftRock radios use an analog mixer to change the RF signal to stereo audio, and
|
|||||||
A high quality sound card is advisable. The analog mixer is not perfect, and it will be necessary to adjust the I and Q
|
A high quality sound card is advisable. The analog mixer is not perfect, and it will be necessary to adjust the I and Q
|
||||||
signals to equal amplitude and 90 degrees phase difference. Use the Config/Config screen buttons to
|
signals to equal amplitude and 90 degrees phase difference. Use the Config/Config screen buttons to
|
||||||
bring up an adjustment screen. Adjustments must be made for each band, and separately for transmit and receive.
|
bring up an adjustment screen. Adjustments must be made for each band, and separately for transmit and receive.
|
||||||
The adjustment depends on both the VFO frequency and the tuning offset from the VFO. See my paper
|
The adjustment depends on both the VFO frequency and the tuning offset from the VFO.
|
||||||
|
Quisk has an option to fix the tuning offset to a constant and to tune with the hardware.
|
||||||
|
The tuning offset then has a constant correction and it is only necessary to correct for the VFO,
|
||||||
|
a much less sensitive correction.
|
||||||
|
See my paper
|
||||||
<a href="http://james.ahlstrom.name/phase_corr.html">http://james.ahlstrom.name/phase_corr.html</a> for more information.
|
<a href="http://james.ahlstrom.name/phase_corr.html">http://james.ahlstrom.name/phase_corr.html</a> for more information.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
A good strategy is to pick a VFO near the band center, and record corrections at an Rx frequency of -15000, -1000, 1000 and 15000 Hertz.
|
A good strategy is to pick a VFO near the band center, and record corrections at an Rx frequency of -15000, -1000, 1000 and 15000 Hertz.
|
||||||
If the corrections are sensitive to VFO, record the corrections for these same Rx frequencies at VFOs equal to
|
If the corrections are sensitive to VFO, record the corrections for these same Rx frequencies at VFOs equal to
|
||||||
or slightly outside the upper and lower band edges.
|
or slightly outside the upper and lower band edges.
|
||||||
@@ -834,15 +851,20 @@ You can add as many correction points as desired. The corrections are saved in t
|
|||||||
by hand if you are a Python expert. Otherwise you can just read the values.
|
by hand if you are a Python expert. Otherwise you can just read the values.
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
If you fix the tuning offset to a constant, you can create a correction for VFO at the band center, or
|
||||||
|
the center and both edges.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
To create a Receive correction point for a given VFO and frequency, attach a signal generator to the SoftRock through an attenuator,
|
To create a Receive correction point for a given VFO and frequency, attach a signal generator to the SoftRock through an attenuator,
|
||||||
and look at the image on the graph screen. If the signal is 3500 Hertz above the VFO, the image is 3500 Hertz below it.
|
and look at the image on the graph screen. If the signal is 3500 Hertz above the VFO, the image is 3500 Hertz below it.
|
||||||
If you don't have a signal generator, find a strong station on the band and look at its image. Minimize the image by adjusting
|
Choose "Measure" to measure the corrections and then "Add Cell".
|
||||||
the amplitude and phase sliders on the adjustment screen, and then press "Save".
|
If you don't have a signal generator, find a strong station on the band and look at its image. Choose "Manual adjustment".
|
||||||
|
Minimize the image by adjusting the amplitude and phase sliders on the adjustment screen, and then press "Add cell".
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
To create a Transmit correction point for a given VFO and frequency, attach the SoftRock RF output to a spectrum analyzer through an attenuator,
|
To create a Transmit correction point for a given VFO and frequency, attach the SoftRock RF output to a spectrum analyzer through an attenuator,
|
||||||
and look at the image. If you don't have a spectrum analyzer use a second receiver tuned to the image. Minimize the image by adjusting
|
and look at the image. If you don't have a spectrum analyzer use a second receiver tuned to the image. Minimize the image by adjusting
|
||||||
the amplitude and phase sliders on the adjustment screen, and then press "Save".
|
the amplitude and phase sliders on the adjustment screen, and then press "Add cell".
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
</p>
|
</p>
|
||||||
@@ -1468,21 +1490,32 @@ show the devices being used. Change the Fldigi playback to QuiskDigitalInput, an
|
|||||||
Monitor of QuiskDigitalOutput. Then everything should work. You do not need to use pavucontrol again because PulseAudio will
|
Monitor of QuiskDigitalOutput. Then everything should work. You do not need to use pavucontrol again because PulseAudio will
|
||||||
remember the settings.
|
remember the settings.
|
||||||
<br>
|
<br>
|
||||||
|
<br>
|
||||||
|
Michael, DK1MI/N1BSD, has written a nice description of how to set up Fldigi. It is available
|
||||||
|
at his site <a href="https://dk1mi.radio/quisk-fldigi/">https://dk1mi.radio/quisk-fldigi/</a>.
|
||||||
|
<br>
|
||||||
<br>
|
<br>
|
||||||
If your digital program only uses Alsa devices or you don't want to use PulseAudio,
|
If your digital program only uses Alsa devices or you don't want to use PulseAudio,
|
||||||
you can use the ALSA loopback device.
|
you can use the ALSA loopback device.
|
||||||
It works the same way as the Windows VAC. First create the loopback device with this command:
|
It works the same way as the Windows VAC. First create the loopback device with this command:
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
<pre>
|
<pre>
|
||||||
sudo modprobe snd-aloop index=19
|
sudo modprobe snd-aloop index=19
|
||||||
</pre>
|
</pre>
|
||||||
|
<br>
|
||||||
|
<p>
|
||||||
The "index" is the card number, and it is best to use a number higher than your regular cards.
|
The "index" is the card number, and it is best to use a number higher than your regular cards.
|
||||||
The loopback device will be gone on the next restart.
|
The loopback device will be gone on the next restart.
|
||||||
You can create the loopback device every time the system starts, but the way to do that depends on your version of Linux.
|
You can create the loopback device every time the system starts, but the way to do that depends on your version of Linux.
|
||||||
You could add this line to /etc/modprobe.d/alsa-base.conf:
|
You could add this line to /etc/modprobe.d/alsa-base.conf:
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
<pre>
|
<pre>
|
||||||
options snd-aloop index=19
|
options snd-aloop index=19
|
||||||
</pre>
|
</pre>
|
||||||
|
<br>
|
||||||
|
<p>
|
||||||
Or you could add snd-aloop to /etc/modules or put the modprobe command in /etc/rc.local instead.
|
Or you could add snd-aloop to /etc/modules or put the modprobe command in /etc/rc.local instead.
|
||||||
Restart Linux. Now you can enter "cat /proc/asound/cards" to
|
Restart Linux. Now you can enter "cat /proc/asound/cards" to
|
||||||
print out your sound cards, and you should see a "Loopback" card listed.
|
print out your sound cards, and you should see a "Loopback" card listed.
|
||||||
@@ -1497,6 +1530,7 @@ Your audio is now connected and you
|
|||||||
should be able to receive digital signals. Be sure to test your
|
should be able to receive digital signals. Be sure to test your
|
||||||
transmit signal off the air. You may need to reduce power to
|
transmit signal off the air. You may need to reduce power to
|
||||||
improve linearity.
|
improve linearity.
|
||||||
|
</p>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -1572,6 +1606,46 @@ For Linux, use the pulseaudio devices:
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
<h2 id="freedv">FreeDV Digital Voice</h2>
|
||||||
|
<p>
|
||||||
|
The <a href="https://freedv.org/">FreeDV project</a> has produced a new and exciting digital voice mode, the
|
||||||
|
<a href="https://github.com/drowe67/radae/blob/main/doc/rade_intro_waveform.pdf">Radio Autoencoder RADE</a>.
|
||||||
|
The RADE mode is a real advance. It has a small peak to average power radio. And its digital constellation is not
|
||||||
|
discrete dots but rather a continuous analog pattern. It works great and sounds great!
|
||||||
|
You can make digital voice QSO's by using the FreeDV-GUI program. It runs in its own window and connects to your
|
||||||
|
HF radio using the same virtual audio connections used by other digital programs such as WSJT-X.
|
||||||
|
I wrote a <a href="http://james.ahlstrom.name/rade.html">guide to using FreeDV-GUI</a> to make it easier to install and use it.
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
|
<h2 id="wdsp">NR2 and WDSP</h2>
|
||||||
|
<p>
|
||||||
|
Quisk uses the WDSP library for the NR2 noise reduction and the SNB noise blanker. The WDSP library must be available
|
||||||
|
for these features to work. For windows, the library is included. For Linux you must build it by changing to the
|
||||||
|
quisk/wdsp directory and entering "make". The library is used in-place and no installation is necessary.
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
|
<p>
|
||||||
|
The new "trained" method of NR2 is included. Press the NR2 button twice to select "NR2t".
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
|
<h2 id="pure">Pure Signal</h2>
|
||||||
|
<p>
|
||||||
|
Pure Signal is a term used to describe baseband predistortion, a technique used to reduce IMD products
|
||||||
|
caused by a non-linear power amp. Pure Signal is available for the Hermes Lite2.
|
||||||
|
To use it first press the PsCal button to create a calibration. This will key a two second CW carrier.
|
||||||
|
Then press PS to enable corrections. You can view the result by using the "FDX" button to see the Tx output.
|
||||||
|
The feature is automatic and no settings are required. You can re-calibrate if you change bands, but this is not
|
||||||
|
really necessary.
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
|
<p>
|
||||||
|
You need to supply a sample of the amplifier output so Pure Signal can correct it. First set the "LNA during Tx dB" to
|
||||||
|
the minimum gain of -12 on the Hermes Hardware screen. This minimizes the preamp gain and the noise picked up from the HL2 board.
|
||||||
|
Then provide a Tx sample much above the remaining board noise but below clipping. Use the FDX button to see the Tx output
|
||||||
|
with and without the Tx sample connected. Twenty or thirty dB over board noise should be enough. To learn how to provide a Tx
|
||||||
|
signal sample, see <a href="https://github.com/softerhardware/Hermes-Lite2/wiki/PureSignal">the HL2 Pure Signal wiki</a>.
|
||||||
|
</p>
|
||||||
|
<br><br>
|
||||||
<h2 id="VNA">Vector Network Analyzer</h2>
|
<h2 id="VNA">Vector Network Analyzer</h2>
|
||||||
<p>
|
<p>
|
||||||
If you have my transceiver hardware from 2010 QEX, or the newer HiQSDR
|
If you have my transceiver hardware from 2010 QEX, or the newer HiQSDR
|
||||||
|
|||||||
+80
-32
@@ -1,9 +1,9 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
# This code was contributed by Christof, DJ4CM. Many Thanks!!
|
# This code was contributed by Christof, DJ4CM. Many Thanks!!
|
||||||
|
# Modified November 2024 by N2ADR to remove deprecated telnetlib module.
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
import telnetlib
|
|
||||||
import quisk_conf_defaults as conf
|
import quisk_conf_defaults as conf
|
||||||
|
|
||||||
class DxEntry:
|
class DxEntry:
|
||||||
@@ -81,61 +81,109 @@ class DxEntry:
|
|||||||
|
|
||||||
class DxCluster(threading.Thread):
|
class DxCluster(threading.Thread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.do_init = 1
|
self.error = 'Starting'
|
||||||
|
self.dxSpots = []
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.doQuit = threading.Event()
|
self.doQuit = threading.Event()
|
||||||
self.dxSpots = []
|
|
||||||
self.doQuit.clear()
|
self.doQuit.clear()
|
||||||
|
self.dxLock = threading.Lock()
|
||||||
|
self.addr = conf.dxClHost + ':' + str(conf.dxClPort)
|
||||||
|
self.msg_no_spots = "No DX Cluster data from " + self.addr
|
||||||
|
self.msg_one_spot = '1 DX spot received from ' + self.addr
|
||||||
|
self.msg_spots = ' DX spots received from ' + self.addr
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.telnetInit()
|
|
||||||
self.telnetConnect()
|
self.telnetConnect()
|
||||||
|
if self.error:
|
||||||
|
self.sock.close()
|
||||||
|
return
|
||||||
while not self.doQuit.isSet():
|
while not self.doQuit.isSet():
|
||||||
try:
|
try:
|
||||||
self.telnetRead()
|
by = self.sock.recv(1024)
|
||||||
|
except TimeoutError:
|
||||||
|
continue
|
||||||
except:
|
except:
|
||||||
self.tn.close()
|
by = b''
|
||||||
time.sleep(20)
|
if by:
|
||||||
|
with self.dxLock:
|
||||||
|
self.bytes += by
|
||||||
|
else:
|
||||||
|
self.sock.close()
|
||||||
|
self.error = "Restarting " + self.addr
|
||||||
|
time.sleep(2)
|
||||||
if not self.doQuit.isSet():
|
if not self.doQuit.isSet():
|
||||||
self.telnetConnect()
|
self.telnetConnect()
|
||||||
self.tn.close()
|
if self.error:
|
||||||
|
self.sock.close()
|
||||||
def setListener (self, listener):
|
return
|
||||||
self.listener = listener
|
self.sock.close()
|
||||||
|
|
||||||
def telnetInit(self):
|
|
||||||
self.tn = telnetlib.Telnet()
|
|
||||||
|
|
||||||
def telnetConnect(self):
|
def telnetConnect(self):
|
||||||
|
self.bytes = bytearray(0)
|
||||||
|
self.error = 'Starting'
|
||||||
|
self.sock = socket.socket()
|
||||||
|
self.sock.settimeout(20)
|
||||||
|
try:
|
||||||
|
self.sock.connect( (conf.dxClHost, conf.dxClPort) )
|
||||||
|
except:
|
||||||
|
self.error = "Failed to connect to " + self.addr
|
||||||
|
return
|
||||||
|
self.sock.settimeout(1)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
try:
|
try:
|
||||||
self.tn.open(conf.dxClHost, conf.dxClPort, 10)
|
self.bytes += self.sock.recv(1024)
|
||||||
self.tn.read_until(b"login:", 10)
|
|
||||||
self.tn.write(conf.user_call_sign.encode('utf-8', errors='ignore') + b"\n") # user_call_sign may be Unicode
|
|
||||||
break
|
|
||||||
except:
|
except:
|
||||||
time.sleep(0.5)
|
pass
|
||||||
|
if b"login:" in self.bytes:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.error = 'No "login:" prompt from ' + self.addr
|
||||||
|
return
|
||||||
|
self.sock.sendall(conf.user_call_sign.encode('utf-8', errors='ignore') + b"\r\n")
|
||||||
if conf.dxClPassword:
|
if conf.dxClPassword:
|
||||||
self.tn.read_until(b"Password: ")
|
for i in range(10):
|
||||||
self.tn.write(conf.dxClPassword.encode('utf-8', errors='ignore') + b"\n")
|
try:
|
||||||
|
self.bytes += self.sock.recv(1024)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if b"Password:" in self.bytes:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.error = 'No "Password:" prompt from ' + self.addr
|
||||||
|
return
|
||||||
|
self.sock.sendall(conf.dxClPassword.encode('utf-8', errors='ignore') + b"\r\n")
|
||||||
|
self.error = ''
|
||||||
|
self.bytes = bytearray(0)
|
||||||
|
|
||||||
def telnetRead(self):
|
def Poll(self):
|
||||||
message = self.tn.read_until(b'\n', 60).decode(encoding='utf-8', errors='replace')
|
with self.dxLock:
|
||||||
if self.doQuit.isSet() == False:
|
index = self.bytes.find(b"\n")
|
||||||
dxEntry = DxEntry();
|
if index >= 0:
|
||||||
|
message = self.bytes[0:index + 1]
|
||||||
|
self.bytes = self.bytes[index + 1:]
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
message = message.decode(encoding='utf-8', errors='replace')
|
||||||
|
dxEntry = DxEntry()
|
||||||
if dxEntry.parseMessage(message):
|
if dxEntry.parseMessage(message):
|
||||||
for i, listElement in enumerate(self.dxSpots):
|
for i, listElement in enumerate(self.dxSpots):
|
||||||
if (listElement.equal(dxEntry)):
|
if (listElement.equal(dxEntry)):
|
||||||
listElement.join (dxEntry)
|
listElement.join (dxEntry)
|
||||||
return
|
return True
|
||||||
if listElement.isExpired():
|
if listElement.isExpired():
|
||||||
del (self.dxSpots[i])
|
del (self.dxSpots[i])
|
||||||
self.dxSpots.append(dxEntry)
|
self.dxSpots.append(dxEntry)
|
||||||
if self.listener:
|
return True
|
||||||
self.listener()
|
|
||||||
|
|
||||||
def getHost(self):
|
|
||||||
return self.tn.host + ':' + str(self.tn.port)
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.doQuit.set()
|
self.doQuit.set()
|
||||||
|
|
||||||
|
def dxStatus(self):
|
||||||
|
if self.error:
|
||||||
|
return self.error
|
||||||
|
nSpots = len(self.dxSpots)
|
||||||
|
if nSpots == 0:
|
||||||
|
return self.msg_no_spots
|
||||||
|
elif nSpots == 1:
|
||||||
|
return self.msg_one_spot
|
||||||
|
return str(nSpots) + self.msg_spots
|
||||||
|
|||||||
@@ -642,7 +642,9 @@ class Hardware(BaseHardware):
|
|||||||
tx_level = self.conf.tx_level[self.band]
|
tx_level = self.conf.tx_level[self.band]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
tx_level = self.conf.tx_level.get(None, 127) # The default
|
tx_level = self.conf.tx_level.get(None, 127) # The default
|
||||||
if self.mode[0:3] in ('DGT', 'FDV'): # Digital modes; change power by a percentage
|
if not self.mode:
|
||||||
|
reduc = self.application.tx_level
|
||||||
|
elif self.mode[0:3] in ('DGT', 'FDV'): # Digital modes; change power by a percentage
|
||||||
reduc = self.application.digital_tx_level
|
reduc = self.application.digital_tx_level
|
||||||
else:
|
else:
|
||||||
reduc = self.application.tx_level
|
reduc = self.application.tx_level
|
||||||
|
|||||||
+30
-3
@@ -8,6 +8,7 @@ from __future__ import absolute_import
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import math, wx, time
|
import math, wx, time
|
||||||
|
import _quisk as QS
|
||||||
from configure import ComboCtrl
|
from configure import ComboCtrl
|
||||||
|
|
||||||
|
|
||||||
@@ -24,8 +25,14 @@ class BottomWidgets: # Add extra widgets to the bottom of the screen
|
|||||||
def Widgets_0x06(self, app, hardware, conf, frame, gbs, vertBox):
|
def Widgets_0x06(self, app, hardware, conf, frame, gbs, vertBox):
|
||||||
self.num_rows_added = 1
|
self.num_rows_added = 1
|
||||||
start_row = self.start_row
|
start_row = self.start_row
|
||||||
|
self.btnPS = app.QuiskCheckbutton(frame, self.OnBtnPS, text='PS')
|
||||||
|
self.btnPS.Enable(False)
|
||||||
|
gbs.Add(self.btnPS, (start_row, self.start_col), flag=wx.EXPAND)
|
||||||
|
self.btnPsCal = app.QuiskPushbutton(frame, self.OnBtnPsCal, 'PS Cal')
|
||||||
|
self.btnPsCal.active = False
|
||||||
|
gbs.Add(self.btnPsCal, (start_row, self.start_col + 1), flag=wx.EXPAND)
|
||||||
self.atu_ctrl = ComboCtrl(frame, "ATU", ["Tune", "Bypass"], True)
|
self.atu_ctrl = ComboCtrl(frame, "ATU", ["Tune", "Bypass"], True)
|
||||||
gbs.Add(self.atu_ctrl, (start_row, self.start_col), (1, 2), flag=wx.EXPAND)
|
gbs.Add(self.atu_ctrl, (start_row, self.start_col + 2), (1, 2), flag=wx.EXPAND)
|
||||||
bw, bh = self.atu_ctrl.GetMinSize()
|
bw, bh = self.atu_ctrl.GetMinSize()
|
||||||
frame.Bind(wx.EVT_COMBOBOX_CLOSEUP, self.OnAtu)
|
frame.Bind(wx.EVT_COMBOBOX_CLOSEUP, self.OnAtu)
|
||||||
init = app.hermes_LNA_dB
|
init = app.hermes_LNA_dB
|
||||||
@@ -33,7 +40,7 @@ class BottomWidgets: # Add extra widgets to the bottom of the screen
|
|||||||
self.sliderLNA.idName = "RfLna"
|
self.sliderLNA.idName = "RfLna"
|
||||||
app.midiControls["RfLna"] = (self.sliderLNA, self.OnLNA)
|
app.midiControls["RfLna"] = (self.sliderLNA, self.OnLNA)
|
||||||
hardware.ChangeLNA(init)
|
hardware.ChangeLNA(init)
|
||||||
gbs.Add(self.sliderLNA, (start_row, self.start_col + 2), (1, 8), flag=wx.EXPAND)
|
gbs.Add(self.sliderLNA, (start_row, self.start_col + 4), (1, 6), flag=wx.EXPAND)
|
||||||
if conf.button_layout == "Small screen":
|
if conf.button_layout == "Small screen":
|
||||||
# Display four data items in a single window
|
# Display four data items in a single window
|
||||||
self.text_temperature = app.QuiskText1(frame, '', bh)
|
self.text_temperature = app.QuiskText1(frame, '', bh)
|
||||||
@@ -93,6 +100,20 @@ class BottomWidgets: # Add extra widgets to the bottom of the screen
|
|||||||
value = self.sliderLNA.GetValue()
|
value = self.sliderLNA.GetValue()
|
||||||
self.hardware.ChangeLNA(value)
|
self.hardware.ChangeLNA(value)
|
||||||
self.application.hermes_LNA_dB = value
|
self.application.hermes_LNA_dB = value
|
||||||
|
def OnBtnPS(self, event):
|
||||||
|
if self.btnPS.GetValue():
|
||||||
|
QS.set_tx_audio(PsEnable=1)
|
||||||
|
self.btnPsCal.Enable(False)
|
||||||
|
else:
|
||||||
|
QS.set_tx_audio(PsEnable=0)
|
||||||
|
self.btnPsCal.Enable(True)
|
||||||
|
def OnBtnPsCal(self, event):
|
||||||
|
if len(self.application.multi_rx_screen.receiver_list) == 0:
|
||||||
|
self.application.multi_rx_screen.OnAddReceiver(event=None, hide_it=True)
|
||||||
|
self.btnPS.Enable(False)
|
||||||
|
self.btnPsCal.active = True
|
||||||
|
self.btnPsCal.SetColor(self.config.color_check_btn)
|
||||||
|
QS.set_tx_audio(PsCal=1)
|
||||||
def Code2Temp(self): # Convert the HermesLite temperature code to the temperature
|
def Code2Temp(self): # Convert the HermesLite temperature code to the temperature
|
||||||
temp = self.hardware.hermes_temperature
|
temp = self.hardware.hermes_temperature
|
||||||
# For best accuracy, 3.26 should be a user's measured 3.3V supply voltage.
|
# For best accuracy, 3.26 should be a user's measured 3.3V supply voltage.
|
||||||
@@ -117,7 +138,13 @@ class BottomWidgets: # Add extra widgets to the bottom of the screen
|
|||||||
return fwd, rev
|
return fwd, rev
|
||||||
else:
|
else:
|
||||||
return rev, fwd
|
return rev, fwd
|
||||||
def UpdateText(self):
|
def UpdateText(self): # Called at intervals
|
||||||
|
# Button state
|
||||||
|
if self.btnPsCal.active:
|
||||||
|
if not QS.get_tx_audio("PsCal"):
|
||||||
|
self.btnPsCal.active = False
|
||||||
|
self.btnPsCal.SetColorNormal()
|
||||||
|
self.btnPS.Enable(True)
|
||||||
# Temperature
|
# Temperature
|
||||||
temp = self.Code2Temp()
|
temp = self.Code2Temp()
|
||||||
temp = (" Temp %3.0f" % temp) + u'\u2103'
|
temp = (" Temp %3.0f" % temp) + u'\u2103'
|
||||||
|
|||||||
@@ -402,6 +402,8 @@ class Hardware(BaseHardware):
|
|||||||
if do_tx:
|
if do_tx:
|
||||||
try:
|
try:
|
||||||
self.rx_udp_socket.send(s)
|
self.rx_udp_socket.send(s)
|
||||||
|
if DEBUG:
|
||||||
|
self.PrintStatus(' Send', self.want_udp_status)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
def SetVNA(self, key_down=None, vna_start=None, vna_stop=None, vna_count=None, do_tx=False):
|
def SetVNA(self, key_down=None, vna_start=None, vna_stop=None, vna_count=None, do_tx=False):
|
||||||
|
|||||||
BIN
Binary file not shown.
+627
-8
@@ -75,6 +75,8 @@ static int vox_level = CLIP16; // VOX trigger level as a number 0 to CLIP16
|
|||||||
static int timeVOX = 2000; // VOX hang time in milliseconds
|
static int timeVOX = 2000; // VOX hang time in milliseconds
|
||||||
static int tx_sample_rate = 48000; // Used for SoapySDR
|
static int tx_sample_rate = 48000; // Used for SoapySDR
|
||||||
static int reverse_tx_sideband;
|
static int reverse_tx_sideband;
|
||||||
|
static int PsEnable = 0;
|
||||||
|
static int PsCal = 0;
|
||||||
|
|
||||||
static int doTxCorrect = 0; // Corrections for UDP sample transmit
|
static int doTxCorrect = 0; // Corrections for UDP sample transmit
|
||||||
static double TxCorrectLevel;
|
static double TxCorrectLevel;
|
||||||
@@ -894,6 +896,8 @@ static void quisk_hermes_tx_add(complex double * cSamples, int tx_count, int key
|
|||||||
if (hermes_read_index >= HERMES_TX_BUF_SHORTS)
|
if (hermes_read_index >= HERMES_TX_BUF_SHORTS)
|
||||||
hermes_read_index -= HERMES_TX_BUF_SHORTS;
|
hermes_read_index -= HERMES_TX_BUF_SHORTS;
|
||||||
}
|
}
|
||||||
|
// Send the transmit samples to the predistortion logic. Modify the samples in place.
|
||||||
|
PreDistort(NULL, NULL, 0, cSamples, tx_count);
|
||||||
hermes_num_samples += tx_count;
|
hermes_num_samples += tx_count;
|
||||||
for (i = 0; i < tx_count; i++) { // Put transmit mic samples into the buffer
|
for (i = 0; i < tx_count; i++) { // Put transmit mic samples into the buffer
|
||||||
hermes_buf[hermes_write_index++] = (short)cimag(cSamples[i]);
|
hermes_buf[hermes_write_index++] = (short)cimag(cSamples[i]);
|
||||||
@@ -909,6 +913,7 @@ void quisk_hermes_tx_send(int tx_socket, int * tx_records)
|
|||||||
{ // Send one UDP block of mic samples using the Metis-Hermes protocol. Timing is from blocks received, rate is 48k.
|
{ // Send one UDP block of mic samples using the Metis-Hermes protocol. Timing is from blocks received, rate is 48k.
|
||||||
// If the key is up we send samples anyway, but the samples are zero.
|
// If the key is up we send samples anyway, but the samples are zero.
|
||||||
int i, j, offset, sent, ratio;
|
int i, j, offset, sent, ratio;
|
||||||
|
int PsInUse;
|
||||||
short s;
|
short s;
|
||||||
unsigned char sendbuf[1032];
|
unsigned char sendbuf[1032];
|
||||||
unsigned char * pt_buf;
|
unsigned char * pt_buf;
|
||||||
@@ -916,6 +921,7 @@ void quisk_hermes_tx_send(int tx_socket, int * tx_records)
|
|||||||
static unsigned char C0_index = 0;
|
static unsigned char C0_index = 0;
|
||||||
complex double cw_samples[63 * 2];
|
complex double cw_samples[63 * 2];
|
||||||
static double writequeue_time0 = 0;
|
static double writequeue_time0 = 0;
|
||||||
|
static unsigned char rx1_freq[4]; // frequency of the first receiver
|
||||||
|
|
||||||
//printf("hermes_tx_send start 1: hermes_num_samples %d\n", hermes_num_samples);
|
//printf("hermes_tx_send start 1: hermes_num_samples %d\n", hermes_num_samples);
|
||||||
if (tx_records == NULL) {
|
if (tx_records == NULL) {
|
||||||
@@ -928,6 +934,7 @@ void quisk_hermes_tx_send(int tx_socket, int * tx_records)
|
|||||||
last_play_state = quisk_play_state;
|
last_play_state = quisk_play_state;
|
||||||
serial_key_samples(NULL, 0);
|
serial_key_samples(NULL, 0);
|
||||||
}
|
}
|
||||||
|
PsInUse = PsEnable || PsCal;
|
||||||
//printf("hermes_tx_send start 2: hermes_num_samples %d\n", hermes_num_samples);
|
//printf("hermes_tx_send start 2: hermes_num_samples %d\n", hermes_num_samples);
|
||||||
ratio = quisk_sound_state.sample_rate / 48000; // send rate is 48 ksps
|
ratio = quisk_sound_state.sample_rate / 48000; // send rate is 48 ksps
|
||||||
//printf ("quisk_hermes_tx_send ratio %d count %d\n", ratio, *tx_records);
|
//printf ("quisk_hermes_tx_send ratio %d count %d\n", ratio, *tx_records);
|
||||||
@@ -971,14 +978,32 @@ void quisk_hermes_tx_send(int tx_socket, int * tx_records)
|
|||||||
sendbuf[13] = quisk_pc_to_hermes[offset++]; // C2
|
sendbuf[13] = quisk_pc_to_hermes[offset++]; // C2
|
||||||
sendbuf[14] = quisk_pc_to_hermes[offset++]; // C3
|
sendbuf[14] = quisk_pc_to_hermes[offset++]; // C3
|
||||||
sendbuf[15] = quisk_pc_to_hermes[offset++]; // C4
|
sendbuf[15] = quisk_pc_to_hermes[offset++]; // C4
|
||||||
if (C0_index == 0) { // Do not change receiver count without stopping Hermes and restarting
|
switch (C0_index) {
|
||||||
|
case 0: // Do not change receiver count without stopping Hermes and restarting
|
||||||
sendbuf[15] = quisk_multirx_count << 3 | 0x04; // Send the old count, not the changed count
|
sendbuf[15] = quisk_multirx_count << 3 | 0x04; // Send the old count, not the changed count
|
||||||
if (hermes_mox_bit) // send filter selection on J16
|
if (hermes_mox_bit) // send filter selection on J16
|
||||||
sendbuf[13] = hermes_filter_tx << 1;
|
sendbuf[13] = hermes_filter_tx << 1;
|
||||||
else
|
else
|
||||||
sendbuf[13] = hermes_filter_rx << 1;
|
sendbuf[13] = hermes_filter_rx << 1;
|
||||||
|
break;
|
||||||
|
case 2: // Rx1 frequency
|
||||||
|
rx1_freq[0] = sendbuf[12];
|
||||||
|
rx1_freq[1] = sendbuf[13];
|
||||||
|
rx1_freq[2] = sendbuf[14];
|
||||||
|
rx1_freq[3] = sendbuf[15];
|
||||||
|
break;
|
||||||
|
case 3: // Rx2 frequency
|
||||||
|
if (PsInUse && hermes_mox_bit) {
|
||||||
|
sendbuf[12] = rx1_freq[0];
|
||||||
|
sendbuf[13] = rx1_freq[1];
|
||||||
|
sendbuf[14] = rx1_freq[2];
|
||||||
|
sendbuf[15] = rx1_freq[3];
|
||||||
}
|
}
|
||||||
else if ( ! quisk_is_vna && C0_index == 9) {
|
break;
|
||||||
|
case 10:
|
||||||
|
if (PsInUse && hermes_mox_bit)
|
||||||
|
sendbuf[13] |= 0x40; // assert pure signal
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (++C0_index > 16)
|
if (++C0_index > 16)
|
||||||
C0_index = 0;
|
C0_index = 0;
|
||||||
@@ -1028,14 +1053,32 @@ void quisk_hermes_tx_send(int tx_socket, int * tx_records)
|
|||||||
sendbuf[525] = quisk_pc_to_hermes[offset++]; // C2
|
sendbuf[525] = quisk_pc_to_hermes[offset++]; // C2
|
||||||
sendbuf[526] = quisk_pc_to_hermes[offset++]; // C3
|
sendbuf[526] = quisk_pc_to_hermes[offset++]; // C3
|
||||||
sendbuf[527] = quisk_pc_to_hermes[offset++]; // C4
|
sendbuf[527] = quisk_pc_to_hermes[offset++]; // C4
|
||||||
if (C0_index == 0) {
|
switch (C0_index) {
|
||||||
|
case 0: // Do not change receiver count without stopping Hermes and restarting
|
||||||
sendbuf[527] = quisk_multirx_count << 3 | 0x04; // Send the old count, not the changed count
|
sendbuf[527] = quisk_multirx_count << 3 | 0x04; // Send the old count, not the changed count
|
||||||
if (hermes_mox_bit) // send filter selection on J16
|
if (hermes_mox_bit) // send filter selection on J16
|
||||||
sendbuf[525] = hermes_filter_tx << 1;
|
sendbuf[525] = hermes_filter_tx << 1;
|
||||||
else
|
else
|
||||||
sendbuf[525] = hermes_filter_rx << 1;
|
sendbuf[525] = hermes_filter_rx << 1;
|
||||||
|
break;
|
||||||
|
case 2: // Rx1 frequency
|
||||||
|
rx1_freq[0] = sendbuf[524];
|
||||||
|
rx1_freq[1] = sendbuf[525];
|
||||||
|
rx1_freq[2] = sendbuf[526];
|
||||||
|
rx1_freq[3] = sendbuf[527];
|
||||||
|
break;
|
||||||
|
case 3: // Rx2 frequency
|
||||||
|
if (PsInUse && hermes_mox_bit) {
|
||||||
|
sendbuf[524] = rx1_freq[0];
|
||||||
|
sendbuf[525] = rx1_freq[1];
|
||||||
|
sendbuf[526] = rx1_freq[2];
|
||||||
|
sendbuf[527] = rx1_freq[3];
|
||||||
}
|
}
|
||||||
else if ( ! quisk_is_vna && C0_index == 9) {
|
break;
|
||||||
|
case 10:
|
||||||
|
if (PsInUse && hermes_mox_bit)
|
||||||
|
sendbuf[525] |= 0x40; // assert pure signal
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (++C0_index > 16)
|
if (++C0_index > 16)
|
||||||
C0_index = 0;
|
C0_index = 0;
|
||||||
@@ -1102,12 +1145,47 @@ static void transmit_udp(complex double * cSamples, int count)
|
|||||||
|
|
||||||
static void transmit_mic_carrier(complex double * cSamples, int count, double level)
|
static void transmit_mic_carrier(complex double * cSamples, int count, double level)
|
||||||
{ // send a CW carrier instead of mic samples
|
{ // send a CW carrier instead of mic samples
|
||||||
|
#if 0
|
||||||
|
// transmit a saw tooth
|
||||||
|
static int up = 1;
|
||||||
|
static int ramp = 0;
|
||||||
|
int i;
|
||||||
|
int max = 5000;
|
||||||
|
static int pause = 5000 / 10;
|
||||||
|
int half_max = (int)(0.1 / 0.2339 * max);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
cSamples[i] = (double)ramp / max * CLIP16;
|
||||||
|
if (ramp == half_max && pause) {
|
||||||
|
pause--;
|
||||||
|
}
|
||||||
|
else if (up) {
|
||||||
|
if (ramp == max) {
|
||||||
|
up = 0;
|
||||||
|
pause = max / 10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ramp += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ramp == 0) {
|
||||||
|
up = 1;
|
||||||
|
pause = max / 10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ramp -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("Ramp %d\n", ramp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
// transmit a carrier equal to the number of samples
|
// transmit a carrier equal to the number of samples
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
cSamples[i] = level * CLIP16;
|
cSamples[i] = level * CLIP16;
|
||||||
#else
|
#endif
|
||||||
|
#if 0
|
||||||
// replace mic samples with a sin wave
|
// replace mic samples with a sin wave
|
||||||
int i;
|
int i;
|
||||||
double freq;
|
double freq;
|
||||||
@@ -1447,14 +1525,31 @@ int quisk_process_microphone(int mic_sample_rate, complex double * cSamples, int
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject * quisk_get_tx_audio(PyObject * self, PyObject * args)
|
||||||
|
{
|
||||||
|
const char * name;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple (args, "s", &name))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (strcmp(name, "PsEnable") == 0)
|
||||||
|
return PyInt_FromLong(PsEnable);
|
||||||
|
if (strcmp(name, "PsCal") == 0)
|
||||||
|
return PyInt_FromLong(PsCal);
|
||||||
|
Py_INCREF (Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject * quisk_set_tx_audio(PyObject * self, PyObject * args, PyObject * keywds)
|
PyObject * quisk_set_tx_audio(PyObject * self, PyObject * args, PyObject * keywds)
|
||||||
{ /* Call with keyword arguments ONLY; change Tx audio parameters */
|
{ /* Call with keyword arguments ONLY; change Tx audio parameters */
|
||||||
static char * kwlist[] = {"vox_level", "vox_time", "mic_clip", "mic_preemphasis", "tx_sample_rate",
|
static char * kwlist[] = {"vox_level", "vox_time", "mic_clip", "mic_preemphasis", "tx_sample_rate",
|
||||||
"reverse_tx_sideband", NULL} ;
|
"reverse_tx_sideband", "PsEnable", "PsCal", NULL} ;
|
||||||
int vlevel = -9999, clevel = -9999;
|
int vlevel = -9999, clevel = -9999;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|iiidii", kwlist,
|
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|iiidiiii", kwlist,
|
||||||
&vlevel, &timeVOX, &clevel, &quisk_mic_preemphasis, &tx_sample_rate, &reverse_tx_sideband))
|
&vlevel, &timeVOX, &clevel, &quisk_mic_preemphasis, &tx_sample_rate, &reverse_tx_sideband,
|
||||||
|
&PsEnable, &PsCal))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (vlevel != -9999)
|
if (vlevel != -9999)
|
||||||
vox_level = (int)(pow(10.0, vlevel / 20.0) * CLIP16); // Convert dB to 16-bit sample
|
vox_level = (int)(pow(10.0, vlevel / 20.0) * CLIP16); // Convert dB to 16-bit sample
|
||||||
@@ -1624,3 +1719,527 @@ static void serial_key_samples(complex double * cSamples, int count) // called f
|
|||||||
cSamples[i] = ampl * CLIP16;
|
cSamples[i] = ampl * CLIP16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spline(double x[], double y[], int n, double yp1, double ypn, double y2[])
|
||||||
|
{
|
||||||
|
int i,k;
|
||||||
|
double p,qn,sig,un,*u;
|
||||||
|
|
||||||
|
u = (double *)malloc(n * sizeof(double));
|
||||||
|
if (yp1 > 0.99e30)
|
||||||
|
y2[1]=u[1]=0.0;
|
||||||
|
else {
|
||||||
|
y2[1] = -0.5;
|
||||||
|
u[1]=(3.0/(x[2]-x[1]))*((y[2]-y[1])/(x[2]-x[1])-yp1);
|
||||||
|
}
|
||||||
|
for (i=2;i<=n-1;i++) {
|
||||||
|
sig=(x[i]-x[i-1])/(x[i+1]-x[i-1]);
|
||||||
|
p=sig*y2[i-1]+2.0;
|
||||||
|
y2[i]=(sig-1.0)/p;
|
||||||
|
u[i]=(y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]);
|
||||||
|
u[i]=(6.0*u[i]/(x[i+1]-x[i-1])-sig*u[i-1])/p;
|
||||||
|
}
|
||||||
|
if (ypn > 0.99e30)
|
||||||
|
qn=un=0.0;
|
||||||
|
else {
|
||||||
|
qn=0.5;
|
||||||
|
un=(3.0/(x[n]-x[n-1]))*(ypn-(y[n]-y[n-1])/(x[n]-x[n-1]));
|
||||||
|
}
|
||||||
|
y2[n]=(un-qn*u[n-1])/(qn*y2[n-1]+1.0);
|
||||||
|
for (k=n-1;k>=1;k--)
|
||||||
|
y2[k]=y2[k]*y2[k+1]+u[k];
|
||||||
|
free(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void polint(double xa[], double ya[], double x, double *y)
|
||||||
|
{
|
||||||
|
int i,m,ns=1;
|
||||||
|
double den,dif,dift,ho,hp,w, dy;
|
||||||
|
double c[4], d[4];
|
||||||
|
|
||||||
|
dif=fabs(x-xa[1]);
|
||||||
|
for (i=1;i<=3;i++) {
|
||||||
|
if ( (dift=fabs(x-xa[i])) < dif) {
|
||||||
|
ns=i;
|
||||||
|
dif=dift;
|
||||||
|
}
|
||||||
|
c[i]=ya[i];
|
||||||
|
d[i]=ya[i];
|
||||||
|
}
|
||||||
|
*y=ya[ns--];
|
||||||
|
for (m=1;m<3;m++) {
|
||||||
|
for (i=1;i<=3-m;i++) {
|
||||||
|
ho=xa[i]-x;
|
||||||
|
hp=xa[i+m]-x;
|
||||||
|
w=c[i+1]-d[i];
|
||||||
|
den = ho - hp;
|
||||||
|
if ( (den=ho-hp) == 0.0)
|
||||||
|
printf("Error in routine polint\n");
|
||||||
|
den=w/den;
|
||||||
|
d[i]=hp*den;
|
||||||
|
c[i]=ho*den;
|
||||||
|
}
|
||||||
|
*y += (dy=(2*ns < (3-m) ? c[ns+1] : d[ns--]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void splint(double xa[], double ya[], double y2a[], int n, double x, double *y)
|
||||||
|
{
|
||||||
|
static int klo = 1;
|
||||||
|
int khi,k;
|
||||||
|
double h,b,a;
|
||||||
|
|
||||||
|
khi = klo + 1;
|
||||||
|
if (x < xa[klo] || x > xa[khi]) {
|
||||||
|
klo=1;
|
||||||
|
khi=n;
|
||||||
|
while (khi-klo > 1) {
|
||||||
|
k=(khi+klo) >> 1;
|
||||||
|
if (xa[k] > x) khi=k;
|
||||||
|
else klo=k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h=xa[khi]-xa[klo];
|
||||||
|
if (h == 0.0)
|
||||||
|
printf("Bad xa input to routine splint\n");
|
||||||
|
a=(xa[khi]-x)/h;
|
||||||
|
b=(x-xa[klo])/h;
|
||||||
|
*y=a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2a[klo]+(b*b*b-b)*y2a[khi])*(h*h)/6.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NUM_BINS 21
|
||||||
|
#define BIN_SPACING (1.0 / (NUM_BINS - 1))
|
||||||
|
#define BIN_TOL (BIN_SPACING * 0.20)
|
||||||
|
#define BLOCK_MSECS 2000 // Time of one data block.
|
||||||
|
#define MILLISECS(x) (48 * (x)) // Convert milliseconds to samples at 48000 samples per second.
|
||||||
|
#define DEBUG_PS 0
|
||||||
|
#define HOLD 0 // Make calibration run permanent
|
||||||
|
#define RX1_GAIN 0.238
|
||||||
|
void PreDistort(complex double * amp_in_samples, complex double * amp_out_samples, int nSamples, complex double * tx_samples, int num_tx)
|
||||||
|
{
|
||||||
|
int i, bin, num_bin_data;
|
||||||
|
double G0, phase, mag_in, mag_out, new_mag, aaa, ppp;
|
||||||
|
double error, xp, xpg, xp0, xpg0;
|
||||||
|
double quadX[4], quadY[4], quadZ[4];
|
||||||
|
complex double in_sample, out_sample;
|
||||||
|
static int state = 0;
|
||||||
|
static int Fault;
|
||||||
|
static int isCalibrated = 0;
|
||||||
|
static int ramp_counter, ramp_count0;
|
||||||
|
static int input_samples = 0;
|
||||||
|
static double tx_to_RX1_gain = 0;
|
||||||
|
static double max_out_mag, starting_phase;
|
||||||
|
#if DEBUG_PS
|
||||||
|
static double clip_tx, clip_mag_in, clip_aaa;
|
||||||
|
#endif
|
||||||
|
#if DEBUG_PS > 2
|
||||||
|
static int old_state;
|
||||||
|
static double time0;
|
||||||
|
#endif
|
||||||
|
static int spline_P_size;
|
||||||
|
static double spline_P_X[NUM_BINS + 1];
|
||||||
|
static double spline_P_mag[NUM_BINS + 1];
|
||||||
|
static double spline_P_mag2[NUM_BINS + 1];
|
||||||
|
static double spline_P_phase[NUM_BINS + 1];
|
||||||
|
static double spline_P_phase2[NUM_BINS + 1];
|
||||||
|
|
||||||
|
struct BPD {
|
||||||
|
int XP_count;
|
||||||
|
double table_XP;
|
||||||
|
double XP_mag;
|
||||||
|
double mag_X;
|
||||||
|
double mag_P;
|
||||||
|
double phase_P;
|
||||||
|
complex double XP_gain;
|
||||||
|
double XP_gain_mag;
|
||||||
|
double XP_gain_phase;
|
||||||
|
};
|
||||||
|
static struct BPD Bins[NUM_BINS];
|
||||||
|
|
||||||
|
static enum {
|
||||||
|
NothingHappens,
|
||||||
|
SendCW,
|
||||||
|
StopCW
|
||||||
|
} tx_state = NothingHappens;
|
||||||
|
|
||||||
|
if (quisk_multirx_count == 0) {
|
||||||
|
state = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (PsCal) {
|
||||||
|
if (state == 0) {
|
||||||
|
isCalibrated = 0;
|
||||||
|
state = 10;
|
||||||
|
#if DEBUG_PS > 2
|
||||||
|
time0 = QuiskTimeSec();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ! PsEnable) {
|
||||||
|
state = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ( ! hermes_mox_bit) {
|
||||||
|
state = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_tx) {
|
||||||
|
input_samples += num_tx;
|
||||||
|
if (isCalibrated) { // perform predistortion of Tx samples; multiply input X by P
|
||||||
|
for (i = 0; i < num_tx; i++) {
|
||||||
|
mag_in = cabs(tx_samples[i]) / CLIP16;
|
||||||
|
splint(spline_P_X, spline_P_mag, spline_P_mag2, spline_P_size, mag_in, &aaa);
|
||||||
|
splint(spline_P_X, spline_P_phase, spline_P_phase2, spline_P_size, mag_in, &ppp);
|
||||||
|
tx_samples[i] *= aaa * cexp(I * ppp);
|
||||||
|
new_mag = mag_in * aaa;
|
||||||
|
if (new_mag > 1.0) {
|
||||||
|
tx_samples[i] /= new_mag;
|
||||||
|
#if DEBUG_PS
|
||||||
|
if (new_mag > 1.0001 && new_mag > clip_tx) {
|
||||||
|
clip_tx = new_mag;
|
||||||
|
clip_mag_in = mag_in;
|
||||||
|
clip_aaa = aaa;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (tx_state) {
|
||||||
|
case NothingHappens:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case SendCW: // Start sending a CW carrier.
|
||||||
|
for (i = 0; i < num_tx; i++) {
|
||||||
|
if (ramp_counter > 0) // slow increase
|
||||||
|
tx_samples[i] = CLIP16 * (1.0 - (double)ramp_counter-- / ramp_count0);
|
||||||
|
else
|
||||||
|
tx_samples[i] = CLIP16;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case StopCW: // Stop sending a CW carrier.
|
||||||
|
for (i = 0; i < num_tx; i++) {
|
||||||
|
if (ramp_counter > 0) // slow decrease
|
||||||
|
tx_samples[i] = (double)CLIP16 * ramp_counter-- / ramp_count0;
|
||||||
|
else
|
||||||
|
tx_samples[i] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nSamples <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if DEBUG_PS > 2
|
||||||
|
if (state != old_state) {
|
||||||
|
aaa = cabs(amp_in_samples[0] / CLIP32);
|
||||||
|
printf("State %2d time %6.3lf sample %12.6f\n", old_state, QuiskTimeSec() - time0, aaa);
|
||||||
|
old_state = state;
|
||||||
|
time0 = QuiskTimeSec();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 0: // Start a timer
|
||||||
|
tx_state = NothingHappens;
|
||||||
|
input_samples = 0;
|
||||||
|
starting_phase = 0;
|
||||||
|
if ( ! HOLD)
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (input_samples >= MILLISECS(200)) {
|
||||||
|
#if DEBUG_PS
|
||||||
|
clip_tx = 0.0;
|
||||||
|
#endif
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++) { // initialize
|
||||||
|
Bins[bin].XP_count = 0;
|
||||||
|
Bins[bin].XP_mag = 0;
|
||||||
|
Bins[bin].XP_gain = 0;
|
||||||
|
}
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 15:
|
||||||
|
if (input_samples >= MILLISECS(BLOCK_MSECS)) {
|
||||||
|
num_bin_data = 0;
|
||||||
|
Fault = 0;
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++) {
|
||||||
|
if (Bins[bin].XP_count) {
|
||||||
|
num_bin_data++;
|
||||||
|
Bins[bin].XP_mag /= Bins[bin].XP_count;
|
||||||
|
Bins[bin].XP_gain /= Bins[bin].XP_count;
|
||||||
|
if (starting_phase == 0 && bin >= NUM_BINS / 2) {
|
||||||
|
starting_phase = carg(Bins[bin].XP_gain);
|
||||||
|
#if DEBUG_PS
|
||||||
|
printf("starting_phase %.3f\n", starting_phase);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PsCal && num_bin_data < NUM_BINS - 4) {
|
||||||
|
printf("PS calibration failed to fill all bins ");
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++)
|
||||||
|
if (Bins[bin].XP_count)
|
||||||
|
printf("1");
|
||||||
|
else
|
||||||
|
printf("0");
|
||||||
|
printf("\n");
|
||||||
|
Fault = 1;
|
||||||
|
}
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i = 0; i < nSamples; i++) {
|
||||||
|
in_sample = amp_in_samples[i] / CLIP32 / RX1_GAIN;
|
||||||
|
mag_in = cabs(in_sample);
|
||||||
|
if (tx_to_RX1_gain < mag_in) {
|
||||||
|
tx_to_RX1_gain = mag_in;
|
||||||
|
#if DEBUG_PS > 2
|
||||||
|
printf("tx RX1 gain %.6f, max_out_mag %.6f\n", tx_to_RX1_gain, max_out_mag);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
bin = (int)(mag_in / BIN_SPACING + 0.5);
|
||||||
|
if ( ! bin)
|
||||||
|
continue;
|
||||||
|
error = fabs(mag_in - Bins[bin].table_XP);
|
||||||
|
if (error < BIN_TOL) {
|
||||||
|
out_sample = amp_out_samples[i] / CLIP32;
|
||||||
|
Bins[bin].XP_gain += out_sample / in_sample;
|
||||||
|
Bins[bin].XP_mag += mag_in;
|
||||||
|
Bins[bin].XP_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state == 15) {
|
||||||
|
if (tx_state != StopCW) {
|
||||||
|
ramp_counter = ramp_count0 = MILLISECS(BLOCK_MSECS - 500);
|
||||||
|
tx_state = StopCW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 16:
|
||||||
|
#if DEBUG_PS
|
||||||
|
if (clip_tx != 0.0) {
|
||||||
|
printf ("clip output sample %.6f, mag_in %.6f, predistort %.6f\n", clip_tx, clip_mag_in, clip_aaa);
|
||||||
|
clip_tx = 0.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (bin = 1; bin < NUM_BINS - 1; bin++) {
|
||||||
|
if (Bins[bin].XP_count > 0) { // This bin has data.
|
||||||
|
Bins[bin].XP_gain_mag = cabs(Bins[bin].XP_gain);
|
||||||
|
phase = carg(Bins[bin].XP_gain) - starting_phase;
|
||||||
|
if (phase < - M_PI)
|
||||||
|
phase += 2 * M_PI;
|
||||||
|
else if (phase > M_PI)
|
||||||
|
phase -= 2 * M_PI;
|
||||||
|
Bins[bin].XP_gain_phase = phase;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Bins[bin].XP_gain_mag = 1.0;
|
||||||
|
Bins[bin].XP_gain_phase = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bins[0].XP_count = 1;
|
||||||
|
Bins[0].XP_mag = 0.0;
|
||||||
|
i = 1;
|
||||||
|
for (bin = 1; bin < 6; bin++) {
|
||||||
|
if (Bins[bin].XP_count) {
|
||||||
|
quadX[i] = Bins[bin].XP_mag;
|
||||||
|
quadY[i] = Bins[bin].XP_gain_mag;
|
||||||
|
quadZ[i] = Bins[bin].XP_gain_phase;
|
||||||
|
if (i == 3)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 3) {
|
||||||
|
polint(quadX, quadY, 0.0, &Bins[0].XP_gain_mag);
|
||||||
|
polint(quadX, quadZ, 0.0, &Bins[0].XP_gain_phase);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Bins[0].XP_gain_mag = 1.0;
|
||||||
|
Bins[0].XP_gain_phase = 0.0;
|
||||||
|
Fault = 1;
|
||||||
|
if (DEBUG_PS || PsCal)
|
||||||
|
printf("Failure to find G0 at zero\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Bins[NUM_BINS - 1].XP_count = 1;
|
||||||
|
Bins[NUM_BINS - 1].XP_mag = 1.0;
|
||||||
|
i = 3;
|
||||||
|
for (bin = NUM_BINS - 2; bin >= NUM_BINS - 6; bin--) {
|
||||||
|
if (Bins[bin].XP_count) {
|
||||||
|
quadX[i] = Bins[bin].XP_mag;
|
||||||
|
quadY[i] = Bins[bin].XP_gain_mag;
|
||||||
|
quadZ[i] = Bins[bin].XP_gain_phase;
|
||||||
|
if (--i == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
polint(quadX, quadY, 1.0, &Bins[NUM_BINS - 1].XP_gain_mag);
|
||||||
|
polint(quadX, quadZ, 1.0, &Bins[NUM_BINS - 1].XP_gain_phase);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Bins[NUM_BINS - 1].XP_gain_mag = 1.0;
|
||||||
|
Bins[NUM_BINS - 1].XP_gain_phase = 0.0;
|
||||||
|
Fault = 1;
|
||||||
|
if (DEBUG_PS || PsCal)
|
||||||
|
printf("Failure to find G0 at one\n");
|
||||||
|
}
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 17:
|
||||||
|
G0 = Bins[NUM_BINS - 1].XP_gain_mag;
|
||||||
|
num_bin_data = 0;
|
||||||
|
xp0 = -1.0;
|
||||||
|
xpg0 = -1.0;
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++) {
|
||||||
|
if (bin == NUM_BINS - 1) {
|
||||||
|
num_bin_data++;
|
||||||
|
Bins[NUM_BINS - 1].mag_P = 1.0;
|
||||||
|
Bins[NUM_BINS - 1].phase_P = - Bins[NUM_BINS - 1].XP_gain_phase;
|
||||||
|
Bins[NUM_BINS - 1].mag_X = 1.0;
|
||||||
|
}
|
||||||
|
else if (Bins[bin].XP_count) {
|
||||||
|
num_bin_data++;
|
||||||
|
Bins[bin].mag_P = G0 / Bins[bin].XP_gain_mag;
|
||||||
|
Bins[bin].phase_P = - Bins[bin].XP_gain_phase;
|
||||||
|
Bins[bin].mag_X = Bins[bin].XP_mag / Bins[bin].mag_P;
|
||||||
|
xp = Bins[bin].mag_X * Bins[bin].mag_P;
|
||||||
|
if (xp < xp0) {
|
||||||
|
if (DEBUG_PS || PsCal)
|
||||||
|
printf("xp is not monotonic at bin %d\n", bin);
|
||||||
|
Fault = 1;
|
||||||
|
}
|
||||||
|
xpg = xp * Bins[bin].XP_gain_mag;
|
||||||
|
if (xpg < xpg0) {
|
||||||
|
if (DEBUG_PS || PsCal)
|
||||||
|
printf("xpg is not monotonic at bin %d\n", bin);
|
||||||
|
Fault = 1;
|
||||||
|
}
|
||||||
|
xp0 = xp;
|
||||||
|
xpg0 = xpg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Bins[bin].mag_P = 0.0;
|
||||||
|
Bins[bin].phase_P = 0.0;
|
||||||
|
Bins[bin].mag_X = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_bin_data < NUM_BINS * 7 / 10) {
|
||||||
|
if (DEBUG_PS || state == 17)
|
||||||
|
printf("Not enough data for corrections %d\n", num_bin_data);
|
||||||
|
Fault = 1;
|
||||||
|
}
|
||||||
|
if ( ! Fault) {
|
||||||
|
#if DEBUG_PS
|
||||||
|
printf("Create a new predistortion\n");
|
||||||
|
#endif
|
||||||
|
spline_P_size = 0;
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++) {
|
||||||
|
if (Bins[bin].XP_count) {
|
||||||
|
spline_P_size++;
|
||||||
|
spline_P_X[spline_P_size] = Bins[bin].mag_X;
|
||||||
|
spline_P_mag[spline_P_size] = Bins[bin].mag_P;
|
||||||
|
spline_P_phase[spline_P_size] = Bins[bin].phase_P;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spline(spline_P_X, spline_P_mag, spline_P_size, 2E30, 2E30, spline_P_mag2);
|
||||||
|
spline(spline_P_X, spline_P_phase, spline_P_size, 2E30, 2E30, spline_P_phase2);
|
||||||
|
}
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 18:
|
||||||
|
#if DEBUG_PS
|
||||||
|
if (Fault)
|
||||||
|
printf("Data for predistortion was rejected\n");
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if ( ! HOLD)
|
||||||
|
state = 1;
|
||||||
|
input_samples = 0;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
isCalibrated = 0;
|
||||||
|
input_samples = 0;
|
||||||
|
quisk_set_key_down(1);
|
||||||
|
max_out_mag = 0;
|
||||||
|
tx_to_RX1_gain = 0;
|
||||||
|
starting_phase = 0;
|
||||||
|
ramp_counter = ramp_count0 = MILLISECS(10);
|
||||||
|
#if DEBUG_PS
|
||||||
|
clip_tx = 0.0;
|
||||||
|
#endif
|
||||||
|
for (bin = 0; bin < NUM_BINS; bin++) {
|
||||||
|
Bins[bin].table_XP = BIN_SPACING * bin;
|
||||||
|
Bins[bin].XP_mag = 0;
|
||||||
|
Bins[bin].XP_count = 0;
|
||||||
|
Bins[bin].XP_gain = 0;
|
||||||
|
}
|
||||||
|
tx_state = SendCW;
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
if (input_samples >= MILLISECS(400)) {
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
if (input_samples >= MILLISECS(50) && cabs(amp_in_samples[0]) / CLIP32 / RX1_GAIN > 0.1) {
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
if (input_samples >= MILLISECS(200)) {
|
||||||
|
state++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i = 0; i < nSamples; i++) {
|
||||||
|
in_sample = amp_in_samples[i] / CLIP32;
|
||||||
|
mag_in = cabs(in_sample);
|
||||||
|
if (tx_to_RX1_gain < mag_in)
|
||||||
|
tx_to_RX1_gain = mag_in;
|
||||||
|
out_sample = amp_out_samples[i] / CLIP32;
|
||||||
|
mag_out = cabs(out_sample);
|
||||||
|
if (max_out_mag < mag_out)
|
||||||
|
max_out_mag = mag_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
#if DEBUG_PS
|
||||||
|
printf("tx RX1 gain %.5f, max_out_mag %.6f\n", tx_to_RX1_gain, max_out_mag);
|
||||||
|
#endif
|
||||||
|
if (fabs(tx_to_RX1_gain - RX1_GAIN) / RX1_GAIN > 1E-2)
|
||||||
|
printf("Measured %.6f and assumed %.6f RX1 gain differ\n", tx_to_RX1_gain, RX1_GAIN);
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
input_samples = 0;
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
quisk_set_key_down(0);
|
||||||
|
tx_state = NothingHappens;
|
||||||
|
PsCal = 0;
|
||||||
|
if ( ! Fault)
|
||||||
|
isCalibrated = 1;
|
||||||
|
input_samples = 0;
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
#
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
# This file is part of the Multus project. See https://www.multus-sdr.com/.
|
||||||
|
# It controls what items appear on the Hardware configuration screen and
|
||||||
|
# provides logic for each radio.
|
||||||
|
|
||||||
|
|
||||||
|
################ Receivers Multus CW, A transceiver from the Multus project.
|
||||||
|
## hardware_file_name Hardware file path, rfile
|
||||||
|
# This is the file that contains the control logic for each radio.
|
||||||
|
#hardware_file_name = "multuspkg/quisk_hardware.py"
|
||||||
|
|
||||||
|
## widgets_file_name Widget file path, rfile
|
||||||
|
# This optional file adds additional controls for the radio.
|
||||||
|
#widgets_file_name = ""
|
||||||
|
|
||||||
|
## rx_max_amplitude_correct Max ampl correct, number
|
||||||
|
# If you get your I/Q samples from a sound card, you will need to correct the
|
||||||
|
# amplitude and phase for inaccuracies in the analog hardware. The correction is
|
||||||
|
# entered using the controls from the "Rx Phase" button on the config screen.
|
||||||
|
# You must enter a positive number. This controls the range of the control.
|
||||||
|
#rx_max_amplitude_correct = 0.2
|
||||||
|
|
||||||
|
## rx_max_phase_correct Max phase correct, number
|
||||||
|
# If you get your I/Q samples from a sound card, you will need to correct the
|
||||||
|
# amplitude and phase for inaccuracies in the analog hardware. The correction is
|
||||||
|
# entered using the controls from the "Rx Phase" button on the config screen.
|
||||||
|
# You must enter a positive number. This controls the range of the control in degrees.
|
||||||
|
#rx_max_phase_correct = 10.0
|
||||||
|
|
||||||
|
## tx_level Tx Level, dict
|
||||||
|
# This is the level of the Tx audio sent to SoftRock hardware after all processing as a percentage
|
||||||
|
# number from 0 to 100.
|
||||||
|
# The level should be below 100 to allow headroom for amplitude and phase adjustments.
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
#tx_level = {}
|
||||||
|
|
||||||
|
## digital_tx_level Digital Tx power %, integer
|
||||||
|
# Digital modes reduce power by the percentage on the config screen.
|
||||||
|
# This is the maximum value of the slider.
|
||||||
|
#digital_tx_level = 100
|
||||||
|
|
||||||
|
## keyer_speed Keyer speed WPM, integer
|
||||||
|
# This sets the keyer speed in words per minute.
|
||||||
|
#keyer_speed = 8
|
||||||
|
#keyer_speed = 13
|
||||||
|
#keyer_speed = 18
|
||||||
|
#keyer_speed = 20
|
||||||
|
#keyer_speed = 30
|
||||||
|
#keyer_speed = 40
|
||||||
|
|
||||||
|
## keyer_type Type of keyer, text choice
|
||||||
|
# Use "Straight" mode for a straight key or a bug. Connect the tip of the key to the transceiver.
|
||||||
|
# Otherwise, select Iambic-A or Iambic-B mode of operation.
|
||||||
|
#keyer_type = "Straight"
|
||||||
|
#keyer_type = "Iambic-A"
|
||||||
|
#keyer_type = "Iambic-B"
|
||||||
|
|
||||||
|
## keyer_space Keyer space, text choice
|
||||||
|
# This sets the type of spacing between elements or letters.
|
||||||
|
# "Element" attempts to provide proper spacing between the elements of a character.
|
||||||
|
# (The keyer always provides proper spacing between elements).
|
||||||
|
# "Letter" turns on letter spacing. This attempts to provide proper spacing between characters.
|
||||||
|
#keyer_space = "Element"
|
||||||
|
#keyer_space = "Letter"
|
||||||
|
|
||||||
|
## keyer_weight Keyer weight, integer choice
|
||||||
|
# A weight of 50% means that the dit time equals the inter-element time, which is standard.
|
||||||
|
# Reducing the weight increases the inter-element time, increasing the weight reduces it.
|
||||||
|
#keyer_weight = 50
|
||||||
|
#keyer_weight = 25
|
||||||
|
#keyer_weight = 75
|
||||||
|
|
||||||
|
## keyer_paddle Keyer paddle, text choice
|
||||||
|
# "Normal" means the left paddle is DIT. "Reverse" means the left paddle is DAH.
|
||||||
|
#keyer_paddle = "Normal"
|
||||||
|
#keyer_paddle = "Reverse"
|
||||||
|
|
||||||
|
import configure
|
||||||
|
import softrock
|
||||||
|
from softrock.hardware_usb import Hardware as BaseHardware
|
||||||
|
from softrock.hardware_usb import IN, OUT, UBYTE2, UBYTE4
|
||||||
|
import _quisk as QS
|
||||||
|
|
||||||
|
DEBUG = 0
|
||||||
|
|
||||||
|
class Hardware(BaseHardware):
|
||||||
|
def __init__(self, app, conf):
|
||||||
|
# Set constant parameters here:
|
||||||
|
conf.usb_vendor_id = 0x16c0
|
||||||
|
conf.usb_product_id = 0x05dc
|
||||||
|
conf.si570_i2c_address = 0x55
|
||||||
|
conf.si570_direct_control = False
|
||||||
|
conf.si570_xtal_freq = 114285000
|
||||||
|
conf.repeater_delay = 0.25
|
||||||
|
self.ptt_count = 200
|
||||||
|
self.ptt_on = 0
|
||||||
|
BaseHardware.__init__(self, app, conf)
|
||||||
|
QS.set_sparams(multus_cw_samples=1)
|
||||||
|
self.use_softrock = True
|
||||||
|
if DEBUG:
|
||||||
|
print ("The name of this radio is", configure.Settings[1])
|
||||||
|
print ("The hardware file type is", conf.hardware_file_type)
|
||||||
|
def TransferOut(self, address, message): # message is a bytes array or an integer 0 to 255
|
||||||
|
if isinstance(message, int):
|
||||||
|
message = message.to_bytes(1, 'big')
|
||||||
|
if self.usb_dev:
|
||||||
|
self.usb_dev.ctrl_transfer(OUT, address, self.si570_i2c_address + 0x700, 0, message)
|
||||||
|
if DEBUG:
|
||||||
|
print ("USB send to 0x%X" % address, message)
|
||||||
|
def TransferIn(self, address, length):
|
||||||
|
if self.usb_dev:
|
||||||
|
recv = self.usb_dev.ctrl_transfer(IN, address, self.si570_i2c_address + 0x700, 0, length)
|
||||||
|
if DEBUG:
|
||||||
|
print ("USB receive from 0x%X" % address, recv)
|
||||||
|
return recv
|
||||||
|
return None
|
||||||
|
def open(self):
|
||||||
|
text = BaseHardware.open(self)
|
||||||
|
self.InitKeyer()
|
||||||
|
return text
|
||||||
|
def ChangeMode(self, mode):
|
||||||
|
ret = BaseHardware.ChangeMode(self, mode)
|
||||||
|
if mode in ("CWL", "CWU"):
|
||||||
|
cw_mode = b'C' # Adding "b" does not affect the value sent
|
||||||
|
if DEBUG:
|
||||||
|
print ("Mode is CW")
|
||||||
|
else:
|
||||||
|
cw_mode = b'U'
|
||||||
|
if DEBUG:
|
||||||
|
print ("Mode is not CW")
|
||||||
|
self.TransferOut(0x70, cw_mode)
|
||||||
|
return ret
|
||||||
|
def PollCwKey(self): # Called frequently from the sound thread to check the CW key status
|
||||||
|
return # Quisk is always in Rx
|
||||||
|
def PollGuiControl(self): # Called frequently from the GUI thread
|
||||||
|
self.ptt_count -= 1
|
||||||
|
if self.ptt_count <= 0:
|
||||||
|
self.ptt_count = 200
|
||||||
|
reply = self.TransferIn(0xA5, 1)
|
||||||
|
if DEBUG:
|
||||||
|
print ("PollGuiControl got", reply)
|
||||||
|
if reply:
|
||||||
|
ptt = reply[0] # This is 255 for error
|
||||||
|
if ptt in (0, 1) and ptt != self.ptt_on:
|
||||||
|
self.ptt_on = ptt
|
||||||
|
self.application.pttButton.SetValue(ptt, True)
|
||||||
|
def InitKeyer(self):
|
||||||
|
# Initialize the keyer parameters
|
||||||
|
conf = self.conf
|
||||||
|
if not hasattr(conf, "keyer_speed"):
|
||||||
|
conf.keyer_speed = 18
|
||||||
|
if not hasattr(conf, "keyer_type"):
|
||||||
|
conf.keyer_type = "Straight"
|
||||||
|
if not hasattr(conf, "keyer_space"):
|
||||||
|
conf.keyer_space = "Element"
|
||||||
|
if not hasattr(conf, "keyer_weight"):
|
||||||
|
conf.keyer_weight = 50
|
||||||
|
if not hasattr(conf, "keyer_paddle"):
|
||||||
|
conf.keyer_paddle = "Normal"
|
||||||
|
# We need to initialize in case the persistent hardware values differ from the Quisk values.
|
||||||
|
for name in ("keyer_speed", "keyer_type", "keyer_space", "keyer_weight", "keyer_paddle", "cwTone"):
|
||||||
|
self.ImmediateChange(name)
|
||||||
|
def ImmediateChange(self, name):
|
||||||
|
BaseHardware.ImmediateChange(self, name)
|
||||||
|
value = getattr(self.conf, name)
|
||||||
|
if DEBUG:
|
||||||
|
print ("ImmediateChange", name, value)
|
||||||
|
if name == "keyer_speed":
|
||||||
|
self.TransferOut(0x7B, value)
|
||||||
|
elif name == "keyer_type":
|
||||||
|
if value == "Straight":
|
||||||
|
mode = 0
|
||||||
|
elif value == "Iambic-A":
|
||||||
|
mode = 1
|
||||||
|
elif value == "Iambic-B":
|
||||||
|
mode = 2
|
||||||
|
else:
|
||||||
|
mode = 0
|
||||||
|
self.TransferOut(0x71, mode)
|
||||||
|
elif name == "keyer_space":
|
||||||
|
if value == "Element":
|
||||||
|
spacing = 0
|
||||||
|
elif value == "Letter":
|
||||||
|
spacing = 1
|
||||||
|
else:
|
||||||
|
spacing = 0
|
||||||
|
self.TransferOut(0x75, spacing)
|
||||||
|
elif name == "keyer_weight":
|
||||||
|
weight = int(value)
|
||||||
|
self.TransferOut(0x77, weight)
|
||||||
|
elif name == "keyer_paddle":
|
||||||
|
if value == "Normal":
|
||||||
|
paddle = 0
|
||||||
|
elif value == "Reverse":
|
||||||
|
paddle = 1
|
||||||
|
else:
|
||||||
|
paddle = 0
|
||||||
|
self.TransferOut(0x73, paddle)
|
||||||
|
elif name == "cwTone":
|
||||||
|
if value < 500:
|
||||||
|
tone_index = 0 # 400 Hz
|
||||||
|
elif 500 <= value < 700:
|
||||||
|
tone_index = 1 # 600 Hz
|
||||||
|
elif 700 <= value < 900:
|
||||||
|
tone_index = 2 # 800 Hz
|
||||||
|
else:
|
||||||
|
tone_index = 3 # 1000 Hz
|
||||||
|
self.TransferOut(0x7F, tone_index)
|
||||||
|
|
||||||
|
|
||||||
@@ -152,6 +152,10 @@ static int quisk_use_sidetone; // is there a sidetone volume control?
|
|||||||
static int hl2_txbuf_errors; // errors in the Hermes-Lite2 Tx buffer
|
static int hl2_txbuf_errors; // errors in the Hermes-Lite2 Tx buffer
|
||||||
static int hl2_txbuf_state; // state machine for errors in the Hermes-Lite2 Tx buffer
|
static int hl2_txbuf_state; // state machine for errors in the Hermes-Lite2 Tx buffer
|
||||||
static int freedv_monitor; // pass the Freedv audio to the speakers instead of to the demodulator
|
static int freedv_monitor; // pass the Freedv audio to the speakers instead of to the demodulator
|
||||||
|
static int softrock_correct_freq; // gain and phase corrections for SoftRock
|
||||||
|
static double softrock_correct_gain;
|
||||||
|
static double softrock_correct_phase;
|
||||||
|
static int softrock_correct_active; // 0 No correction adjustment; 1 Manual adjustment; 2 Calculate Rx corrections
|
||||||
|
|
||||||
static complex double PySampleBuf[SAMP_BUFFER_SIZE]; // buffer for samples returned from Python
|
static complex double PySampleBuf[SAMP_BUFFER_SIZE]; // buffer for samples returned from Python
|
||||||
static int PySampleCount; // count of samples in buffer
|
static int PySampleCount; // count of samples in buffer
|
||||||
@@ -1972,7 +1976,7 @@ static int quisk_process_demodulate(complex double * cSamples, double * dsamples
|
|||||||
ssb_squelch(dsamples, nSamples, quisk_filter_srate, MeasureSquelch + bank);
|
ssb_squelch(dsamples, nSamples, quisk_filter_srate, MeasureSquelch + bank);
|
||||||
d_delay(dsamples, nSamples, bank, SQUELCH_FFT_SIZE);
|
d_delay(dsamples, nSamples, bank, SQUELCH_FFT_SIZE);
|
||||||
}
|
}
|
||||||
quisk_calc_audio_graph(pow(2, 31) - 1, NULL, dsamples, nSamples, 1);
|
//quisk_calc_audio_graph(pow(2, 31) - 1, NULL, dsamples, nSamples, 1);
|
||||||
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p4, 2);
|
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p4, 2);
|
||||||
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
||||||
//quisk_calc_audio_graph(pow(2, 31) - 1, NULL, dsamples, nSamples, 1);
|
//quisk_calc_audio_graph(pow(2, 31) - 1, NULL, dsamples, nSamples, 1);
|
||||||
@@ -2540,6 +2544,7 @@ int quisk_process_samples(complex double * cSamples, int nSamples)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! quisk_is_key_down())
|
||||||
NoiseBlanker(cSamples, nSamples);
|
NoiseBlanker(cSamples, nSamples);
|
||||||
|
|
||||||
// Put samples into the fft input array.
|
// Put samples into the fft input array.
|
||||||
@@ -2752,7 +2757,7 @@ int quisk_process_samples(complex double * cSamples, int nSamples)
|
|||||||
quisk_decim_srate = 48000;
|
quisk_decim_srate = 48000;
|
||||||
}
|
}
|
||||||
// Process the Rx path with the WDSP library
|
// Process the Rx path with the WDSP library
|
||||||
nSamples = wdspFexchange0(QUISK_WDSP_RX, (double *)cSamples, nSamples);
|
nSamples = wdspFexchange0(QUISK_WDSP_RX, cSamples, nSamples);
|
||||||
|
|
||||||
// Interpolate the samples from 48000 sps to the play rate.
|
// Interpolate the samples from 48000 sps to the play rate.
|
||||||
switch (quisk_sound_state.playback_rate / 48000) {
|
switch (quisk_sound_state.playback_rate / 48000) {
|
||||||
@@ -3157,6 +3162,8 @@ static PyObject * get_params(PyObject * self, PyObject * args)
|
|||||||
return PyInt_FromLong(quisk_serial_ptt);
|
return PyInt_FromLong(quisk_serial_ptt);
|
||||||
if (strcmp(name, "hl2_txbuf_errors") == 0)
|
if (strcmp(name, "hl2_txbuf_errors") == 0)
|
||||||
return PyInt_FromLong(hl2_txbuf_errors);
|
return PyInt_FromLong(hl2_txbuf_errors);
|
||||||
|
if (strcmp(name, "softrock_correct_active") == 0)
|
||||||
|
return PyInt_FromLong((long)softrock_correct_active);
|
||||||
if (strcmp(name, "quisk_tx_inhibit") == 0)
|
if (strcmp(name, "quisk_tx_inhibit") == 0)
|
||||||
return PyInt_FromLong((long)quisk_tx_inhibit);
|
return PyInt_FromLong((long)quisk_tx_inhibit);
|
||||||
Py_INCREF (Py_None);
|
Py_INCREF (Py_None);
|
||||||
@@ -3844,6 +3851,43 @@ static int read_rx_udp10(complex double * samp) // Read samples from UDP using t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PreDistort(multirx_cSamples[0], samp, nSamples, NULL, 0); //amp in samples, amp out samples, count
|
||||||
|
#if 0
|
||||||
|
float mag_in, mag_out;
|
||||||
|
complex float gain;
|
||||||
|
complex double * amp_in_samples;
|
||||||
|
complex double * amp_out_samples;
|
||||||
|
static int up = 0;
|
||||||
|
static float old_mag_in = 0;
|
||||||
|
amp_in_samples = multirx_cSamples[0];
|
||||||
|
amp_out_samples = samp;
|
||||||
|
//if (hermes_mox_bit && quisk_multirx_count > 0) {
|
||||||
|
if (quisk_multirx_count == 1) {
|
||||||
|
for (i = 0; i < nSamples; i++) {
|
||||||
|
//mag_in = cabs(amp_in_samples[i]) / 0.236875 / CLIP32;
|
||||||
|
//mag_out = cabs(amp_out_samples[i]) / 0.088037 / CLIP32;
|
||||||
|
mag_in = cabs(amp_in_samples[i]) / CLIP32;
|
||||||
|
mag_out = cabs(amp_out_samples[i]) / CLIP32;
|
||||||
|
//if (0.100 - 0.01 < mag_in && mag_in < 0.100 + 0.01) {
|
||||||
|
//if (mag_in > .001) {
|
||||||
|
if (mag_in > 0.001 && mag_in < 0.234) {
|
||||||
|
if (up && mag_in < old_mag_in) {
|
||||||
|
//printf("\n");
|
||||||
|
up = 0;
|
||||||
|
}
|
||||||
|
else if ( ! up && mag_in > old_mag_in) {
|
||||||
|
//printf("\n");
|
||||||
|
up = 1;
|
||||||
|
}
|
||||||
|
old_mag_in = mag_in;
|
||||||
|
//gain = amp_out_samples[i] / amp_in_samples[i] / (0.088037 / 0.236875);
|
||||||
|
gain = amp_out_samples[i] / amp_in_samples[i];
|
||||||
|
printf("In %12.6f %8.3f Out %12.6f %8.3f Gain %12.6f %8.3f\n",
|
||||||
|
mag_in, cargf(amp_in_samples[i]), mag_out, cargf(amp_out_samples[i]), cabsf(gain), cargf(gain));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if ((quisk_pc_to_hermes[3] >> 3 & 0x7) != quisk_multirx_count && // change in number of receivers
|
if ((quisk_pc_to_hermes[3] >> 3 & 0x7) != quisk_multirx_count && // change in number of receivers
|
||||||
( ! quisk_multirx_count || multirx_fft_next_state == 2)) { // wait until the current FFT is finished
|
( ! quisk_multirx_count || multirx_fft_next_state == 2)) { // wait until the current FFT is finished
|
||||||
quisk_multirx_state = 0; // Do not change receiver count without stopping Hermes and restarting
|
quisk_multirx_state = 0; // Do not change receiver count without stopping Hermes and restarting
|
||||||
@@ -3874,6 +3918,10 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
|||||||
fft_data * ptFFT;
|
fft_data * ptFFT;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
static int block_number=0;
|
static int block_number=0;
|
||||||
|
static complex double dc_average = 0; // Average DC component in samples
|
||||||
|
static complex double dc_sum = 0;
|
||||||
|
static int dc_count = 0;
|
||||||
|
static time_t time0 = 0;
|
||||||
// Data from the receiver is little-endian
|
// Data from the receiver is little-endian
|
||||||
|
|
||||||
if ( ! rx_udp_gain_correct) { // correct for second stage CIC decimation JIM JIM
|
if ( ! rx_udp_gain_correct) { // correct for second stage CIC decimation JIM JIM
|
||||||
@@ -3979,6 +4027,16 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
|||||||
if (xr & 0x100) { // channel 1
|
if (xr & 0x100) { // channel 1
|
||||||
if (quisk_invert_spectrum) // Invert spectrum
|
if (quisk_invert_spectrum) // Invert spectrum
|
||||||
sample = conj(sample);
|
sample = conj(sample);
|
||||||
|
// correct the DC level
|
||||||
|
dc_sum += sample;
|
||||||
|
dc_count++;
|
||||||
|
sample -= dc_average;
|
||||||
|
if (dc_count >= 48000 && time(NULL) != time0) {
|
||||||
|
time0 = time(NULL);
|
||||||
|
dc_average = dc_sum / dc_count;
|
||||||
|
dc_sum = dc_count = 0;
|
||||||
|
//printf ("New DC average %.0lf\n", cabs(dc_average));
|
||||||
|
}
|
||||||
// Put samples into the fft input array.
|
// Put samples into the fft input array.
|
||||||
ptFFT = fft_data_array + fft_data_index;
|
ptFFT = fft_data_array + fft_data_index;
|
||||||
if ( ! (xi & 0x100)) { // zero marker for start of first block
|
if ( ! (xi & 0x100)) { // zero marker for start of first block
|
||||||
@@ -4246,6 +4304,13 @@ static PyObject * change_scan(PyObject * self, PyObject * args) // Called from G
|
|||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject * softrock_corrections(PyObject * self, PyObject * args) // Called from GUI thread
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple (args, "i", &softrock_correct_active))
|
||||||
|
return NULL;
|
||||||
|
return Py_BuildValue("idd", softrock_correct_freq, softrock_correct_gain, softrock_correct_phase);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject * change_rates(PyObject * self, PyObject * args) // Called from GUI thread
|
static PyObject * change_rates(PyObject * self, PyObject * args) // Called from GUI thread
|
||||||
{ // Change to new sample rates
|
{ // Change to new sample rates
|
||||||
|
|
||||||
@@ -5033,6 +5098,135 @@ static PyObject * get_bandscope(PyObject * self, PyObject * args) // Called by t
|
|||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void check_channel_delay(fft_data * ptFft)
|
||||||
|
{
|
||||||
|
int i, maxi, freq;
|
||||||
|
static int count=0, freq0;
|
||||||
|
static double gain=0, phase=0;
|
||||||
|
double d, ampl, maxa;
|
||||||
|
static double complex * samples1=NULL, * samples2;
|
||||||
|
|
||||||
|
if (samples1 == NULL) {
|
||||||
|
samples1 = (double complex *)malloc(fft_size * sizeof(double complex));
|
||||||
|
samples2 = (double complex *)malloc(fft_size * sizeof(double complex));
|
||||||
|
}
|
||||||
|
for (i = 0; i < fft_size; i++) {
|
||||||
|
samples1[i] = creal(ptFft->samples[i]);
|
||||||
|
samples2[i] = cimag(ptFft->samples[i]);
|
||||||
|
}
|
||||||
|
fftw_execute_dft(quisk_fft_plan, samples1, samples1);
|
||||||
|
fftw_execute_dft(quisk_fft_plan, samples2, samples2);
|
||||||
|
maxa = 0;
|
||||||
|
maxi = 0;
|
||||||
|
for (i = 0; i < fft_size / 2; i++) {
|
||||||
|
ampl = cabs(samples1[i]);
|
||||||
|
if (ampl > maxa) {
|
||||||
|
maxa = ampl;
|
||||||
|
maxi = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freq = maxi * fft_sample_rate / fft_size;
|
||||||
|
//freq = maxi * 44100 / fft_size;
|
||||||
|
gain += cabs(samples1[maxi]) / cabs(samples2[maxi]);
|
||||||
|
d = carg(samples1[maxi]) - carg(samples2[maxi]);
|
||||||
|
if (d > M_PI)
|
||||||
|
d -= M_PI * 2;
|
||||||
|
else if(d < - M_PI)
|
||||||
|
d += M_PI * 2;
|
||||||
|
phase += d;
|
||||||
|
count += 1;
|
||||||
|
if (count == 1) {
|
||||||
|
freq0 = freq;
|
||||||
|
}
|
||||||
|
else if (freq != freq0) {
|
||||||
|
gain = phase = count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count > 10) {
|
||||||
|
gain /= count;
|
||||||
|
phase /= count;
|
||||||
|
//printf("Channel delay freq %6d, gain %6.3lf, phase %8.5lf radians, %6.3lf degrees\n",
|
||||||
|
// freq, gain, phase, phase * 57.29578);
|
||||||
|
printf("%6d, %6.3lf, %6.3lf\n", freq, gain, phase * 57.29578);
|
||||||
|
gain = phase = count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void softrock_correct_fft(fft_data * ptFft, int fixit)
|
||||||
|
{ // See i/Q balance in Rocky: https://www.dxatlas.com/Rocky/Advanced.asp
|
||||||
|
double ampl, r1, r2, i1, i2, Zr, Zi, Pwr, Gain, Phase, OutR, OutI, S1R, S1I, S2R, S2I;
|
||||||
|
static double tot_ga=0, tot_ph=0;
|
||||||
|
static int count=0;
|
||||||
|
double maxa = 0;
|
||||||
|
int i, maxi = 0, freq;
|
||||||
|
double complex Z, s1, s2, Hr, Hi, S1, S2;
|
||||||
|
double tim;
|
||||||
|
static double time0 = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < fft_size; i++) {
|
||||||
|
ampl = cabs(ptFft->samples[i]);
|
||||||
|
if (ampl > maxa) {
|
||||||
|
maxa = ampl;
|
||||||
|
maxi = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxi < fft_size / 2)
|
||||||
|
freq = maxi;
|
||||||
|
else
|
||||||
|
freq = maxi - fft_size;
|
||||||
|
freq = freq * fft_sample_rate / fft_size;
|
||||||
|
s1 = ptFft->samples[maxi];
|
||||||
|
s2 = ptFft->samples[fft_size - maxi];
|
||||||
|
Z = s1 * s2;
|
||||||
|
r1 = creal(s1);
|
||||||
|
r2 = creal(s2);
|
||||||
|
i1 = cimag(s1);
|
||||||
|
i2 = cimag(s2);
|
||||||
|
Pwr = r1 * r1 + i1 * i1 + r2 * r2 + i2 * i2;
|
||||||
|
Zr = creal(Z) / Pwr;
|
||||||
|
Zi = cimag(Z) / Pwr;
|
||||||
|
Gain = sqrt((1.0 + 2 * Zr) / (1.0 - 2 * Zr));
|
||||||
|
Phase = asin(Zi * (Gain * Gain + 1.0) / Gain);
|
||||||
|
tot_ga += Gain;
|
||||||
|
tot_ph += Phase;
|
||||||
|
count += 1;
|
||||||
|
tim = QuiskTimeSec();
|
||||||
|
if (tim - time0 >= 0.5) {
|
||||||
|
time0 = tim;
|
||||||
|
softrock_correct_freq = freq;
|
||||||
|
softrock_correct_gain = tot_ga / count;
|
||||||
|
softrock_correct_phase = tot_ph / count;
|
||||||
|
//if (softrock_correct_active)
|
||||||
|
// printf("Freq domain Gain %10.7lf, Phase %10.7lf, %10.7lf, freq %d\n",
|
||||||
|
// softrock_correct_gain, softrock_correct_phase, softrock_correct_phase * 57.29578, freq);
|
||||||
|
tot_ga = tot_ph = count = 0;
|
||||||
|
}
|
||||||
|
if (fixit) {
|
||||||
|
Hr = softrock_correct_gain * cos(softrock_correct_phase);
|
||||||
|
Hi = softrock_correct_gain * sin(softrock_correct_phase);
|
||||||
|
for (i = 1; i < fft_size / 2; i++) {
|
||||||
|
S1 = ptFft->samples[fft_size - i];
|
||||||
|
S2 = ptFft->samples[i];
|
||||||
|
S1R = creal(S1);
|
||||||
|
S1I = cimag(S1);
|
||||||
|
S2R = creal(S2);
|
||||||
|
S2I = cimag(S2);
|
||||||
|
OutR = S2R + S1R - (S2I + S1I) * Hi + (S2R - S1R) * Hr;
|
||||||
|
OutI = S2I - S1I + (S2I + S1I) * Hr + (S2R - S1R) * Hi;
|
||||||
|
ptFft->samples[i] = OutR + I * OutI;
|
||||||
|
S1R = creal(S2);
|
||||||
|
S1I = cimag(S2);
|
||||||
|
S2R = creal(S1);
|
||||||
|
S2I = cimag(S1);
|
||||||
|
OutR = S2R + S1R - (S2I + S1I) * Hi + (S2R - S1R) * Hr;
|
||||||
|
OutI = S2I - S1I + (S2I + S1I) * Hr + (S2R - S1R) * Hi;
|
||||||
|
ptFft->samples[fft_size - i] = OutR + I * OutI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject * get_graph(PyObject * self, PyObject * args) // Called by the GUI thread
|
static PyObject * get_graph(PyObject * self, PyObject * args) // Called by the GUI thread
|
||||||
{
|
{
|
||||||
int i, j, k, m, n, index, ffts, ii, mm, m0, deltam;
|
int i, j, k, m, n, index, ffts, ii, mm, m0, deltam;
|
||||||
@@ -5105,7 +5299,10 @@ static PyObject * get_graph(PyObject * self, PyObject * args) // Called by the G
|
|||||||
// Continue with FFT calculation
|
// Continue with FFT calculation
|
||||||
for (i = 0; i < fft_size; i++) // multiply by window
|
for (i = 0; i < fft_size; i++) // multiply by window
|
||||||
ptFft->samples[i] *= fft_window[i];
|
ptFft->samples[i] *= fft_window[i];
|
||||||
|
//check_channel_delay(ptFft);
|
||||||
fftw_execute_dft(quisk_fft_plan, ptFft->samples, ptFft->samples); // Calculate FFT
|
fftw_execute_dft(quisk_fft_plan, ptFft->samples, ptFft->samples); // Calculate FFT
|
||||||
|
if (softrock_correct_active == 2)
|
||||||
|
softrock_correct_fft(ptFft, 0);
|
||||||
// Create RMS s-meter value at known bandwidth
|
// Create RMS s-meter value at known bandwidth
|
||||||
// The pass band is (rx_tune_freq + filter_start_offset) to += bandwidth
|
// The pass band is (rx_tune_freq + filter_start_offset) to += bandwidth
|
||||||
// d1 is the tune frequency
|
// d1 is the tune frequency
|
||||||
@@ -5156,6 +5353,9 @@ static PyObject * get_graph(PyObject * self, PyObject * args) // Called by the G
|
|||||||
//QuiskPrintf(" %d %.4lf At %5d to %5d place %5d to %5d for block %d\n", fft_size, scan_valid, mm, m, ii, i, ptFft->block);
|
//QuiskPrintf(" %d %.4lf At %5d to %5d place %5d to %5d for block %d\n", fft_size, scan_valid, mm, m, ii, i, ptFft->block);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Zero frequency is at index fft_size / 2.
|
||||||
|
// There are fft_size/2 positive frequencies and fft_size/2-1 negative frequencies.
|
||||||
|
// The frequency at index k and (fft_size - k) are equal except for sign.
|
||||||
count_fft++;
|
count_fft++;
|
||||||
k = 0;
|
k = 0;
|
||||||
for (i = fft_size / 2; i < fft_size; i++) // Negative frequencies
|
for (i = fft_size / 2; i < fft_size; i++) // Negative frequencies
|
||||||
@@ -5981,6 +6181,7 @@ static PyMethodDef QuiskMethods[] = {
|
|||||||
{"get_filter_rate", get_filter_rate, METH_VARARGS, "Return the sample rate used for the filters."},
|
{"get_filter_rate", get_filter_rate, METH_VARARGS, "Return the sample rate used for the filters."},
|
||||||
{"get_tx_filter", quisk_get_tx_filter, METH_VARARGS, "Return the frequency response of the transmit filter."},
|
{"get_tx_filter", quisk_get_tx_filter, METH_VARARGS, "Return the frequency response of the transmit filter."},
|
||||||
{"get_audio_graph", get_audio_graph, METH_VARARGS, "Return a tuple of the audio graph data."},
|
{"get_audio_graph", get_audio_graph, METH_VARARGS, "Return a tuple of the audio graph data."},
|
||||||
|
{"softrock_corrections", softrock_corrections, METH_VARARGS, "Control and return SoftRock amplitude and phase corrections."},
|
||||||
{"measure_frequency", measure_frequency, METH_VARARGS, "Set the method, return the measured frequency."},
|
{"measure_frequency", measure_frequency, METH_VARARGS, "Set the method, return the measured frequency."},
|
||||||
{"measure_audio", measure_audio, METH_VARARGS, "Set the method, return the measured audio voltage."},
|
{"measure_audio", measure_audio, METH_VARARGS, "Set the method, return the measured audio voltage."},
|
||||||
{"get_overrange", get_overrange, METH_VARARGS, "Return the count of overrange (clip) for the ADC."},
|
{"get_overrange", get_overrange, METH_VARARGS, "Return the count of overrange (clip) for the ADC."},
|
||||||
@@ -6027,6 +6228,7 @@ static PyMethodDef QuiskMethods[] = {
|
|||||||
{"XXset_transmit_mode", set_transmit_mode, METH_VARARGS, "Change the radio to transmit mode independent of key_down."},
|
{"XXset_transmit_mode", set_transmit_mode, METH_VARARGS, "Change the radio to transmit mode independent of key_down."},
|
||||||
{"set_volume", set_volume, METH_VARARGS, "Set the audio output volume."},
|
{"set_volume", set_volume, METH_VARARGS, "Set the audio output volume."},
|
||||||
{"set_tx_audio", (PyCFunction)quisk_set_tx_audio, METH_VARARGS|METH_KEYWORDS, "Set the transmit audio parameters."},
|
{"set_tx_audio", (PyCFunction)quisk_set_tx_audio, METH_VARARGS|METH_KEYWORDS, "Set the transmit audio parameters."},
|
||||||
|
{"get_tx_audio", (PyCFunction)quisk_get_tx_audio, METH_VARARGS, "Return some transmit audio parameters."},
|
||||||
{"is_vox", quisk_is_vox, METH_VARARGS, "return the VOX state zero or one."},
|
{"is_vox", quisk_is_vox, METH_VARARGS, "return the VOX state zero or one."},
|
||||||
{"set_split_rxtx", set_split_rxtx, METH_VARARGS, "Set split for rx/tx."},
|
{"set_split_rxtx", set_split_rxtx, METH_VARARGS, "Set split for rx/tx."},
|
||||||
{"set_tune", set_tune, METH_VARARGS, "Set the tuning frequency."},
|
{"set_tune", set_tune, METH_VARARGS, "Set the tuning frequency."},
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ extern PyObject * quisk_sound_errors(PyObject *, PyObject *);
|
|||||||
extern PyObject * quisk_set_file_record(PyObject *, PyObject *);
|
extern PyObject * quisk_set_file_record(PyObject *, PyObject *);
|
||||||
extern PyObject * quisk_set_file_name(PyObject *, PyObject *, PyObject *);
|
extern PyObject * quisk_set_file_name(PyObject *, PyObject *, PyObject *);
|
||||||
extern PyObject * quisk_set_tx_audio(PyObject *, PyObject *, PyObject *);
|
extern PyObject * quisk_set_tx_audio(PyObject *, PyObject *, PyObject *);
|
||||||
|
extern PyObject * quisk_get_tx_audio(PyObject *, PyObject *);
|
||||||
extern PyObject * quisk_is_vox(PyObject *, PyObject *);
|
extern PyObject * quisk_is_vox(PyObject *, PyObject *);
|
||||||
extern PyObject * quisk_set_udp_tx_correct(PyObject *, PyObject *);
|
extern PyObject * quisk_set_udp_tx_correct(PyObject *, PyObject *);
|
||||||
extern PyObject * quisk_set_hermes_filter(PyObject *, PyObject *);
|
extern PyObject * quisk_set_hermes_filter(PyObject *, PyObject *);
|
||||||
@@ -362,7 +363,7 @@ extern PyObject * quisk_wasapi_control_midi(PyObject *, PyObject *, PyObject *);
|
|||||||
// WDSP interface
|
// WDSP interface
|
||||||
#define QUISK_WDSP_RX 1
|
#define QUISK_WDSP_RX 1
|
||||||
extern PyObject * quisk_wdsp_set_parameter(PyObject *, PyObject *, PyObject *);
|
extern PyObject * quisk_wdsp_set_parameter(PyObject *, PyObject *, PyObject *);
|
||||||
extern int wdspFexchange0(int, double *, int);
|
extern int wdspFexchange0(int, complex double *, int);
|
||||||
|
|
||||||
// These function pointers are the Start/Stop/Read interface for
|
// These function pointers are the Start/Stop/Read interface for
|
||||||
// the SDR-IQ and any other C-language extension modules that return
|
// the SDR-IQ and any other C-language extension modules that return
|
||||||
@@ -404,6 +405,7 @@ void * quisk_make_txIQ(struct sound_dev *, int);
|
|||||||
int quisk_play_sidetone(struct sound_dev *);
|
int quisk_play_sidetone(struct sound_dev *);
|
||||||
void quisk_set_play_state(void);
|
void quisk_set_play_state(void);
|
||||||
void quisk_poll_hardware_key(void);
|
void quisk_poll_hardware_key(void);
|
||||||
|
void PreDistort(complex double * amp_in_samples, complex double * amp_out_samples, int nSamples, complex double * tx_samples, int num_tx);
|
||||||
|
|
||||||
// Functions supporting digital voice codecs
|
// Functions supporting digital voice codecs
|
||||||
typedef int (* ty_dvoice_codec_rx)(short *, double *, int, int);
|
typedef int (* ty_dvoice_codec_rx)(short *, double *, int, int);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# All QUISK software is Copyright (C) 2006-2021 by James C. Ahlstrom.
|
# All QUISK software is Copyright (C) 2006-2025 by James C. Ahlstrom.
|
||||||
# This free software is licensed for use under the GNU General Public
|
# This free software is licensed for use under the GNU General Public
|
||||||
# License (GPL), see http://www.opensource.org.
|
# License (GPL), see http://www.opensource.org.
|
||||||
# Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!!
|
# Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!!
|
||||||
@@ -334,6 +334,7 @@ class HamlibHandlerSerial:
|
|||||||
self.public_name = public_name # the public name for the serial port
|
self.public_name = public_name # the public name for the serial port
|
||||||
self.tune_step = 1000
|
self.tune_step = 1000
|
||||||
if sys.platform == 'win32' or public_name.startswith("/dev/"):
|
if sys.platform == 'win32' or public_name.startswith("/dev/"):
|
||||||
|
self.port_is_mod_serial = True # self.port is from the serial module
|
||||||
try:
|
try:
|
||||||
import serial
|
import serial
|
||||||
except:
|
except:
|
||||||
@@ -346,6 +347,7 @@ class HamlibHandlerSerial:
|
|||||||
print ("The serial port %s could not be opened." % public_name)
|
print ("The serial port %s could not be opened." % public_name)
|
||||||
else:
|
else:
|
||||||
import tty
|
import tty
|
||||||
|
self.port_is_mod_serial = False # self.port is a file descriptor
|
||||||
if os.path.lexists(public_name):
|
if os.path.lexists(public_name):
|
||||||
try:
|
try:
|
||||||
os.remove(public_name)
|
os.remove(public_name)
|
||||||
@@ -369,7 +371,7 @@ class HamlibHandlerSerial:
|
|||||||
def open(self):
|
def open(self):
|
||||||
return
|
return
|
||||||
def close(self):
|
def close(self):
|
||||||
if sys.platform == 'win32':
|
if self.port_is_mod_serial:
|
||||||
if self.port:
|
if self.port:
|
||||||
self.port.close()
|
self.port.close()
|
||||||
self.port = None
|
self.port = None
|
||||||
@@ -382,7 +384,7 @@ class HamlibHandlerSerial:
|
|||||||
def Read(self):
|
def Read(self):
|
||||||
if self.port is None:
|
if self.port is None:
|
||||||
return
|
return
|
||||||
if sys.platform == 'win32':
|
if self.port_is_mod_serial:
|
||||||
text = self.port.read(99)
|
text = self.port.read(99)
|
||||||
if not isinstance(text, Q3StringTypes):
|
if not isinstance(text, Q3StringTypes):
|
||||||
text = text.decode('utf-8')
|
text = text.decode('utf-8')
|
||||||
@@ -433,22 +435,14 @@ class HamlibHandlerSerial:
|
|||||||
return
|
return
|
||||||
if isinstance(data, Q3StringTypes):
|
if isinstance(data, Q3StringTypes):
|
||||||
data = data.encode('utf-8', errors='ignore')
|
data = data.encode('utf-8', errors='ignore')
|
||||||
if sys.platform == 'win32':
|
if self.port_is_mod_serial:
|
||||||
self.port.write(data)
|
self.port.write(data)
|
||||||
else:
|
else:
|
||||||
r, w, x = select.select((), (self.port,), (), 0)
|
r, w, x = select.select((), (self.port,), (), 0)
|
||||||
if w:
|
if w:
|
||||||
os.write(self.port, data)
|
os.write(self.port, data)
|
||||||
def set_frequency(self, freq):
|
def set_frequency(self, freq): # This changes the Rx frequency
|
||||||
tune = freq - self.app.VFO
|
self.app.ChangeRxTxFrequency(freq, None)
|
||||||
d = self.app.sample_rate * 45 // 100
|
|
||||||
if -d <= tune <= d: # Frequency is on-screen
|
|
||||||
vfo = self.app.VFO
|
|
||||||
else: # Change the VFO
|
|
||||||
vfo = (freq // 5000) * 5000 - 5000
|
|
||||||
tune = freq - vfo
|
|
||||||
self.app.BandFromFreq(freq)
|
|
||||||
self.app.ChangeHwFrequency(tune, vfo, 'FreqEntry')
|
|
||||||
if HAMLIB_DEBUG: print("New Freq rx,tx", self.app.txFreq + self.app.VFO, self.app.rxFreq + self.app.VFO)
|
if HAMLIB_DEBUG: print("New Freq rx,tx", self.app.txFreq + self.app.VFO, self.app.rxFreq + self.app.VFO)
|
||||||
def ZZAC(self, cmd, data, length): # Set or read tune steps
|
def ZZAC(self, cmd, data, length): # Set or read tune steps
|
||||||
if length == 0:
|
if length == 0:
|
||||||
@@ -591,11 +585,18 @@ class HamlibHandlerSerial:
|
|||||||
mode = self.app.mode
|
mode = self.app.mode
|
||||||
info = cmd
|
info = cmd
|
||||||
info += "%011d" % (self.app.rxFreq + self.app.VFO) # frequency, ZZFA
|
info += "%011d" % (self.app.rxFreq + self.app.VFO) # frequency, ZZFA
|
||||||
|
if len(cmd) == 4: # Flex ZZIF
|
||||||
info += '0000'
|
info += '0000'
|
||||||
if ritFreq < 0: # RIT freq
|
if ritFreq < 0: # RIT freq
|
||||||
info += "-%05d" % -ritFreq
|
info += "-%05d" % -ritFreq
|
||||||
else:
|
else:
|
||||||
info += "+%05d" % ritFreq
|
info += "+%05d" % ritFreq
|
||||||
|
else: # Kenwood IF
|
||||||
|
info += '00000'
|
||||||
|
if ritFreq < 0: # RIT freq
|
||||||
|
info += "-%04d" % -ritFreq
|
||||||
|
else:
|
||||||
|
info += "+%04d" % ritFreq
|
||||||
info += "%d" % rit # RIT status
|
info += "%d" % rit # RIT status
|
||||||
info += '0000'
|
info += '0000'
|
||||||
if QS.is_key_down(): # MOX, key down
|
if QS.is_key_down(): # MOX, key down
|
||||||
@@ -658,6 +659,16 @@ class HamlibHandlerSerial:
|
|||||||
self.app.pttButton.SetValue(0, True)
|
self.app.pttButton.SetValue(0, True)
|
||||||
else:
|
else:
|
||||||
self.Error(cmd, data)
|
self.Error(cmd, data)
|
||||||
|
def ZZSM(self, cmd, data, length): # return the S-meter value in dB * 2; 0 to 260
|
||||||
|
if length == 0: # 0 to 260 is -140 to -10 dB; S9 == -73 dB == 134; dB = ZZSM / 2 - 140
|
||||||
|
i = round((self.app.hamlib_strength + 67) * 2)
|
||||||
|
if i < 0:
|
||||||
|
i = 0
|
||||||
|
elif i > 260:
|
||||||
|
i = 260
|
||||||
|
self.Write('%s%03d;' % (cmd, i))
|
||||||
|
else:
|
||||||
|
self.Error(cmd, data)
|
||||||
def ZZSP(self, cmd, data, length): # the split status
|
def ZZSP(self, cmd, data, length): # the split status
|
||||||
if length == 0:
|
if length == 0:
|
||||||
if self.app.split_rxtx:
|
if self.app.split_rxtx:
|
||||||
@@ -826,6 +837,8 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
"""Send text back to the client."""
|
"""Send text back to the client."""
|
||||||
if isinstance(text, Q3StringTypes):
|
if isinstance(text, Q3StringTypes):
|
||||||
text = text.encode('utf-8', errors='ignore')
|
text = text.encode('utf-8', errors='ignore')
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
print ("Rig2 send", text)
|
||||||
try:
|
try:
|
||||||
self.sock.sendall(text)
|
self.sock.sendall(text)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
@@ -927,11 +940,15 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
if not isinstance(text, Q3StringTypes):
|
if not isinstance(text, Q3StringTypes):
|
||||||
text = text.decode('utf-8')
|
text = text.decode('utf-8')
|
||||||
self.received += text
|
self.received += text
|
||||||
|
if HAMLIB_DEBUG and text:
|
||||||
|
print ("Raw rig2 received:", text)
|
||||||
if '\n' in self.received: # A complete command ending with newline is available
|
if '\n' in self.received: # A complete command ending with newline is available
|
||||||
self.input, self.received = self.received.split('\n', 1) # Split off the command, save any further characters
|
self.input, self.received = self.received.split('\n', 1) # Split off the command, save any further characters
|
||||||
else:
|
else:
|
||||||
return 1
|
return 1
|
||||||
self.input = self.input.strip() # Here is our command line
|
self.input = self.input.strip() # Here is our command line
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
print ("Rig2 received", self.input)
|
||||||
while self.input:
|
while self.input:
|
||||||
# Parse the commands and call the appropriate handlers
|
# Parse the commands and call the appropriate handlers
|
||||||
self.params = ''
|
self.params = ''
|
||||||
@@ -982,8 +999,12 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
if rx:
|
if rx:
|
||||||
rx = rx[0]
|
rx = rx[0]
|
||||||
self.Reply('Frequency', rx.txFreq + rx.VFO, 0)
|
self.Reply('Frequency', rx.txFreq + rx.VFO, 0)
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
print ("GetFreq rx", rx.txFreq, rx.VFO)
|
||||||
else:
|
else:
|
||||||
self.Reply('Frequency', self.app.rxFreq + self.app.VFO, 0)
|
self.Reply('Frequency', self.app.rxFreq + self.app.VFO, 0)
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
print ("GetFreq app", self.app.rxFreq, self.app.txFreq, self.app.VFO)
|
||||||
def SetFreq(self): # The Rx frequency
|
def SetFreq(self): # The Rx frequency
|
||||||
freq = self.GetParamNumber()
|
freq = self.GetParamNumber()
|
||||||
try:
|
try:
|
||||||
@@ -1151,7 +1172,7 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
def GetLevel(self):
|
def GetLevel(self):
|
||||||
name = self.GetParamName()
|
name = self.GetParamName()
|
||||||
if name == '?': # send back supported parameters
|
if name == '?': # send back supported parameters
|
||||||
self.Reply2('AGC AF', 0)
|
self.Reply2('AGC AF STRENGTH', 0)
|
||||||
elif name == 'AGC':
|
elif name == 'AGC':
|
||||||
if self.app.BtnAGC.GetValue():
|
if self.app.BtnAGC.GetValue():
|
||||||
self.Reply2(4, 0)
|
self.Reply2(4, 0)
|
||||||
@@ -1160,6 +1181,9 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
elif name == 'AF':
|
elif name == 'AF':
|
||||||
x = self.app.audio_volume # audio_volume is 0 to 1.000
|
x = self.app.audio_volume # audio_volume is 0 to 1.000
|
||||||
self.Reply2("%.5f" % x, 0)
|
self.Reply2("%.5f" % x, 0)
|
||||||
|
elif name == 'STRENGTH':
|
||||||
|
i = round(self.app.hamlib_strength)
|
||||||
|
self.Reply2(i, 0)
|
||||||
else:
|
else:
|
||||||
self.ErrParam()
|
self.ErrParam()
|
||||||
def SetLevel(self):
|
def SetLevel(self):
|
||||||
@@ -1203,6 +1227,267 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
else:
|
else:
|
||||||
self.ErrParam()
|
self.ErrParam()
|
||||||
|
|
||||||
|
class CatControl:
|
||||||
|
def GetFreqVfo(self, vfoB=False):
|
||||||
|
if vfoB: # The Tx Frequency
|
||||||
|
return self.app.txFreq + self.app.VFO
|
||||||
|
else: # The Rx Frequency
|
||||||
|
rx = self.app.multi_rx_screen.receiver_list
|
||||||
|
if rx:
|
||||||
|
rx = rx[0]
|
||||||
|
return rx.txFreq + rx.VFO
|
||||||
|
else:
|
||||||
|
return self.app.rxFreq + self.app.VFO
|
||||||
|
def SetFreqVfo(self, freq, vfoB=False):
|
||||||
|
if vfoB: # The Tx Frequency
|
||||||
|
self.app.ChangeRxTxFrequency(None, freq)
|
||||||
|
else: # The Rx Frequency
|
||||||
|
# For multiple receivers this controls the first added receiver frequency; else it controls split Rx/Tx frequency.
|
||||||
|
rx = self.app.multi_rx_screen.receiver_list
|
||||||
|
if rx:
|
||||||
|
rx[0].ChangeRxTxFrequency(freq)
|
||||||
|
else:
|
||||||
|
self.app.ChangeRxTxFrequency(freq, None)
|
||||||
|
def GetFilterBW(self):
|
||||||
|
return self.app.filter_bandwidth
|
||||||
|
def SetFilterBW(self, bw):
|
||||||
|
# Choose button closest to requested bandwidth
|
||||||
|
buttons = self.app.filterButns.GetButtons()
|
||||||
|
Lab = buttons[0].GetLabel()
|
||||||
|
diff = abs(int(Lab) - bw)
|
||||||
|
for i in range(1, len(buttons) - 1):
|
||||||
|
label = buttons[i].GetLabel()
|
||||||
|
df = abs(int(label) - bw)
|
||||||
|
if df < diff:
|
||||||
|
Lab = label
|
||||||
|
diff = df
|
||||||
|
self.app.filterButns.SetLabel(Lab, True)
|
||||||
|
|
||||||
|
class ElecraftK4Handler(CatControl): # Test with telnet localhost 9200
|
||||||
|
Mo2CoElecraft = {'LSB':1, 'USB':2, 'CWU':3, 'FM':4, 'AM':5, 'DGT-U':6, 'CWL':7, 'DGT-L':9, 'DGT-FM':4, 'DGT-IQ':6}
|
||||||
|
Co2MoElecraft = {1:'LSB', 2:'USB', 3:'CWU', 4:'FM', 5:'AM', 6:'DGT-U', 7:'CWL', 9:'DGT-L'}
|
||||||
|
def __init__(self, app, conf, sock, address):
|
||||||
|
self.app = app
|
||||||
|
self.conf = conf
|
||||||
|
self.sock = sock
|
||||||
|
sock.settimeout(0.0)
|
||||||
|
self.address = address
|
||||||
|
self.params = '' # params is the string following the command
|
||||||
|
self.received = ''
|
||||||
|
self.cmds = []
|
||||||
|
self.K31Elecraft = False # K31 mode
|
||||||
|
h = self.Handlers = {} # Branch on the first two letters of the command
|
||||||
|
h['AI'] = self.AiAutoInfo
|
||||||
|
h['CW'] = self.CwCWPitch
|
||||||
|
h['DT'] = self.DtDataMode
|
||||||
|
h['FA'] = self.FaFbVfoFreq
|
||||||
|
h['FB'] = self.FaFbVfoFreq
|
||||||
|
h['FT'] = self.FtTxVfo
|
||||||
|
h['FW'] = self.FwFilterBW
|
||||||
|
h['ID'] = self.IdIdent
|
||||||
|
h['IF'] = self.IfInfo
|
||||||
|
h['IS'] = self.IsCenterPitch
|
||||||
|
h['KS'] = self.KsKeyerSpeed
|
||||||
|
h['K3'] = self.K3Elecraft
|
||||||
|
h['LN'] = self.LnLinkVfo
|
||||||
|
h['MD'] = self.MdMode
|
||||||
|
h['OM'] = self.OmOptionModules
|
||||||
|
h['RV'] = self.RvFirmware
|
||||||
|
h['RX'] = self.RxReceive
|
||||||
|
h['SB'] = self.SbSubReceiver
|
||||||
|
h['SM'] = self.SmSmeter
|
||||||
|
h['TX'] = self.TxTransmit
|
||||||
|
def Send(self, text):
|
||||||
|
"""Send text back to the client."""
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
for cmd in self.cmds[0:-1]:
|
||||||
|
print ("CatTcp received: %-10s" % cmd)
|
||||||
|
print ("CatTcp received: %-10s ; sent %s" % (self.cmds[-1], text))
|
||||||
|
del self.cmds[:]
|
||||||
|
text = text.encode('utf-8', errors='ignore')
|
||||||
|
try:
|
||||||
|
self.sock.sendall(text)
|
||||||
|
except socket.error:
|
||||||
|
self.sock.close()
|
||||||
|
self.sock = None
|
||||||
|
def Process(self):
|
||||||
|
"""This is the main processing loop, and is called frequently. It reads and satisfies requests."""
|
||||||
|
if not self.sock:
|
||||||
|
return 0
|
||||||
|
try: # Read any data from the socket
|
||||||
|
text = self.sock.recv(1024)
|
||||||
|
except socket.timeout: # This does not work
|
||||||
|
pass
|
||||||
|
except socket.error: # Nothing to read
|
||||||
|
pass
|
||||||
|
else: # We got some characters
|
||||||
|
text = text.decode('utf-8', errors='ignore')
|
||||||
|
self.received += text
|
||||||
|
if HAMLIB_DEBUG and text:
|
||||||
|
pass #print ("Raw CatTcp received:", text)
|
||||||
|
if ';' in self.received: # A complete command ending with semicolon is available
|
||||||
|
cmd, self.received = self.received.split(';', 1) # Split off the command, save any further characters
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
cmd = cmd.strip() # Here is our command line
|
||||||
|
if len(cmd) < 2:
|
||||||
|
return 1
|
||||||
|
if HAMLIB_DEBUG:
|
||||||
|
self.cmds.append(cmd)
|
||||||
|
base = cmd[0:2].upper()
|
||||||
|
try:
|
||||||
|
handler = self.Handlers[base]
|
||||||
|
except KeyError:
|
||||||
|
self.Send(cmd[0:2] + "?;")
|
||||||
|
#print ("Unknown command", cmd)
|
||||||
|
return 1
|
||||||
|
if len(cmd) == 2:
|
||||||
|
args = ''
|
||||||
|
elif cmd[2] == '$': # base is the first two letters upper case and any following "$"
|
||||||
|
base += '$'
|
||||||
|
args = cmd[3:]
|
||||||
|
else:
|
||||||
|
args = cmd[2:]
|
||||||
|
handler(base, args) # args is the remainder
|
||||||
|
return 1
|
||||||
|
def AiAutoInfo(self, base, args):
|
||||||
|
if not args:
|
||||||
|
self.Send("AI0;")
|
||||||
|
elif args != '0':
|
||||||
|
self.Send("AI0;")
|
||||||
|
def CwCWPitch(self, base, args):
|
||||||
|
pitch = self.conf.cwTone
|
||||||
|
pitch = (pitch + 5) // 10
|
||||||
|
if pitch < 25:
|
||||||
|
pitch = 25
|
||||||
|
elif pitch > 95:
|
||||||
|
pitch = 95
|
||||||
|
self.Send("CW%d;" % pitch)
|
||||||
|
def DtDataMode(self, base, args):
|
||||||
|
self.Send("%s0;" % base)
|
||||||
|
def IdIdent(self, base, args):
|
||||||
|
if args:
|
||||||
|
self.Send("ID?;")
|
||||||
|
else:
|
||||||
|
self.Send("ID017;")
|
||||||
|
#self.Send("IDQuisk;")
|
||||||
|
def IfInfo(self, base, args):
|
||||||
|
rxfreq = self.GetFreqVfo()
|
||||||
|
info = "%011d " % rxfreq # Rx frequency, five blanks
|
||||||
|
ritFreq = self.app.ritScale.GetValue()
|
||||||
|
if ritFreq < 0: # +/- RIT freq
|
||||||
|
info += "-%04d" % -ritFreq
|
||||||
|
else:
|
||||||
|
info += "+%04d" % ritFreq
|
||||||
|
if self.app.ritButton.GetValue(): # RIT status, XIT status, blank "00"
|
||||||
|
info += "10 00"
|
||||||
|
else:
|
||||||
|
info += "00 00"
|
||||||
|
if QS.is_key_down(): # MOX, key down
|
||||||
|
info += '1'
|
||||||
|
else:
|
||||||
|
info += '0'
|
||||||
|
mode = self.Mo2CoElecraft.get(self.app.mode, 2)
|
||||||
|
info += "%d" % mode # Mode 1-9
|
||||||
|
info += '00' # Rx on VFOA, no scan
|
||||||
|
if self.app.split_rxtx: # VFO split status
|
||||||
|
info += '1'
|
||||||
|
else:
|
||||||
|
info += '0'
|
||||||
|
info += '001 ;'
|
||||||
|
self.Send(info)
|
||||||
|
def FaFbVfoFreq(self, base, args):
|
||||||
|
if base[1] in ('B', 'b'):
|
||||||
|
vfoB = True
|
||||||
|
else:
|
||||||
|
vfoB = False
|
||||||
|
if not args: # Get command
|
||||||
|
freq = "%06d" % self.GetFreqVfo(vfoB)
|
||||||
|
self.Send(base + freq + ';')
|
||||||
|
else: # Put command
|
||||||
|
try:
|
||||||
|
freq = int(args)
|
||||||
|
except:
|
||||||
|
self.Send(base + "?;")
|
||||||
|
else:
|
||||||
|
l = len(args)
|
||||||
|
if l <= 2:
|
||||||
|
freq *= 1000000
|
||||||
|
elif l <= 5:
|
||||||
|
freq *= 1000
|
||||||
|
self.SetFreqVfo(freq, vfoB)
|
||||||
|
def FtTxVfo(self, base, args):
|
||||||
|
if not args:
|
||||||
|
if self.app.split_rxtx:
|
||||||
|
self.Send("FT1;")
|
||||||
|
else:
|
||||||
|
self.Send("FT0;")
|
||||||
|
else:
|
||||||
|
# Set split Rx/Tx mode.
|
||||||
|
is_split = self.app.splitButton.GetValue()
|
||||||
|
split = int(args)
|
||||||
|
if split and not is_split:
|
||||||
|
self.app.splitButton.SetValue(split, True)
|
||||||
|
elif is_split and not split:
|
||||||
|
self.app.splitButton.SetValue(split, True)
|
||||||
|
def FwFilterBW(self, base, args):
|
||||||
|
if not args:
|
||||||
|
code = self.GetFilterBW()
|
||||||
|
self.Send("%s%04d;" % (base, (code + 5) // 10))
|
||||||
|
else:
|
||||||
|
self.SetFilterBW(int(args) * 10)
|
||||||
|
def IsCenterPitch(self, base, args):
|
||||||
|
if not args:
|
||||||
|
code = self.GetFilterBW() // 2
|
||||||
|
if self.K31Elecraft:
|
||||||
|
self.Send("%s %04d;" % (base, code))
|
||||||
|
else:
|
||||||
|
code = (code + 5) // 10
|
||||||
|
self.Send("%s%04d;" % (base, code))
|
||||||
|
else:
|
||||||
|
if self.K31Elecraft:
|
||||||
|
self.SetFilterBW(int(args) * 2)
|
||||||
|
else:
|
||||||
|
self.SetFilterBW(int(args) * 2 * 10)
|
||||||
|
def K3Elecraft(self, base, args):
|
||||||
|
if args == '1':
|
||||||
|
self.K31Elecraft = True
|
||||||
|
else:
|
||||||
|
self.K31Elecraft = False
|
||||||
|
def KsKeyerSpeed(self, base, args):
|
||||||
|
if len(base) == 2:
|
||||||
|
self.Send("KS013;")
|
||||||
|
def LnLinkVfo(self, base, args):
|
||||||
|
if args != '0':
|
||||||
|
self.Send("LN0;")
|
||||||
|
def MdMode(self, base, args):
|
||||||
|
if args: # set the mode
|
||||||
|
code = int(args)
|
||||||
|
mode = self.Co2MoElecraft[code]
|
||||||
|
self.app.modeButns.SetLabel(mode, True)
|
||||||
|
else: # return the mode
|
||||||
|
code = self.Mo2CoElecraft.get(self.app.mode, 2)
|
||||||
|
self.Send("%s%d;" % (base, code))
|
||||||
|
def OmOptionModules(self, base, args):
|
||||||
|
self.Send("OM ------------;")
|
||||||
|
def RvFirmware(self, base, args):
|
||||||
|
self.Send("%s99.99;" % base)
|
||||||
|
def RxReceive(self, base, args):
|
||||||
|
self.app.pttButton.SetValue(0, True)
|
||||||
|
def SbSubReceiver(self, base, args):
|
||||||
|
self.Send("SB0;")
|
||||||
|
def SmSmeter(self, base, args):
|
||||||
|
if base[0:3].upper() == "SMH":
|
||||||
|
self.Send(base + "?;")
|
||||||
|
elif args:
|
||||||
|
self.Send(base + "?;")
|
||||||
|
elif self.K31Elecraft:
|
||||||
|
self.Send("SM0000;")
|
||||||
|
else:
|
||||||
|
self.Send("SM00;")
|
||||||
|
def TxTransmit(self, base, args):
|
||||||
|
self.app.pttButton.SetValue(1, True)
|
||||||
|
|
||||||
class SoundThread(threading.Thread):
|
class SoundThread(threading.Thread):
|
||||||
"""Create a second (non-GUI) thread to read, process and play sound."""
|
"""Create a second (non-GUI) thread to read, process and play sound."""
|
||||||
def __init__(self, samples_from_python):
|
def __init__(self, samples_from_python):
|
||||||
@@ -1419,12 +1704,8 @@ class ConfigStatus(wx.ScrolledCanvas):
|
|||||||
self.MakeRow2("Sample interrupts", self.interrupts, cfile)
|
self.MakeRow2("Sample interrupts", self.interrupts, cfile)
|
||||||
self.MakeRow2("Microphone or DGT level dB", level, qfile)
|
self.MakeRow2("Microphone or DGT level dB", level, qfile)
|
||||||
self.MakeRow2("FFT number of points", self.fft_size, err_msg)
|
self.MakeRow2("FFT number of points", self.fft_size, err_msg)
|
||||||
if conf.dxClHost: # connection to dx cluster
|
if application.dxCluster:
|
||||||
nSpots = len(application.dxCluster.dxSpots)
|
msg = application.dxCluster.dxStatus()
|
||||||
if nSpots > 0:
|
|
||||||
msg = str(nSpots) + ' DX spot' + ('' if nSpots==1 else 's') + ' received from ' + application.dxCluster.getHost()
|
|
||||||
else:
|
|
||||||
msg = "No DX Cluster data from %s" % conf.dxClHost
|
|
||||||
self.MakeRow2("FFT number of errors", self.fft_error, msg)
|
self.MakeRow2("FFT number of errors", self.fft_error, msg)
|
||||||
else:
|
else:
|
||||||
self.MakeRow2("FFT number of errors", self.fft_error)
|
self.MakeRow2("FFT number of errors", self.fft_error)
|
||||||
@@ -1879,6 +2160,12 @@ class GraphScreen(wx.Window):
|
|||||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||||
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
||||||
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
|
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
|
||||||
|
# handle bandplan info
|
||||||
|
self.bandplanWindow = wx.PopupWindow (parent)
|
||||||
|
self.bandplanInfo = wx.TextCtrl(self.bandplanWindow, style=wx.TE_READONLY)
|
||||||
|
self.bandplanInfo.SetFont(wx.Font(conf.status_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL,
|
||||||
|
wx.FONTWEIGHT_NORMAL, False, conf.quisk_typeface))
|
||||||
|
self.bandplanWindow.Hide();
|
||||||
self.MakeDisplay()
|
self.MakeDisplay()
|
||||||
def MakeDisplay(self):
|
def MakeDisplay(self):
|
||||||
self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary)
|
self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary)
|
||||||
@@ -2102,7 +2389,7 @@ class GraphScreen(wx.Window):
|
|||||||
"""For mouse clicks in our display, translate to our screen coordinates."""
|
"""For mouse clicks in our display, translate to our screen coordinates."""
|
||||||
mouse_x, mouse_y = event.GetPosition()
|
mouse_x, mouse_y = event.GetPosition()
|
||||||
win = event.GetEventObject()
|
win = event.GetEventObject()
|
||||||
if win is not self:
|
if win and win is not self:
|
||||||
x, y = win.GetPosition().Get()
|
x, y = win.GetPosition().Get()
|
||||||
mouse_x += x
|
mouse_x += x
|
||||||
mouse_y += y
|
mouse_y += y
|
||||||
@@ -2199,6 +2486,7 @@ class GraphScreen(wx.Window):
|
|||||||
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseBtn1', event=event, rx_freq=freq)
|
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseBtn1', event=event, rx_freq=freq)
|
||||||
else:
|
else:
|
||||||
self.ChangeHwFrequency(freq, self.VFO, 'MouseBtn1', event=event)
|
self.ChangeHwFrequency(freq, self.VFO, 'MouseBtn1', event=event)
|
||||||
|
if not self.HasCapture():
|
||||||
self.CaptureMouse()
|
self.CaptureMouse()
|
||||||
def OnLeftUp(self, event):
|
def OnLeftUp(self, event):
|
||||||
if self.HasCapture():
|
if self.HasCapture():
|
||||||
@@ -2212,7 +2500,7 @@ class GraphScreen(wx.Window):
|
|||||||
mouse_x, mouse_y = self.GetMousePosition(event)
|
mouse_x, mouse_y = self.GetMousePosition(event)
|
||||||
if wx.GetKeyState(wx.WXK_SHIFT):
|
if wx.GetKeyState(wx.WXK_SHIFT):
|
||||||
mouse_x -= self.filter_center * self.data_width / sample_rate
|
mouse_x -= self.filter_center * self.data_width / sample_rate
|
||||||
if conf.mouse_tune_method: # Mouse motion changes the VFO frequency
|
if False: #conf.mouse_tune_method: # Mouse motion changes the VFO frequency
|
||||||
x = (mouse_x - self.mouse_x) # Thanks to VK6JBL
|
x = (mouse_x - self.mouse_x) # Thanks to VK6JBL
|
||||||
self.mouse_x = mouse_x
|
self.mouse_x = mouse_x
|
||||||
freq = float(x) * sample_rate / self.data_width
|
freq = float(x) * sample_rate / self.data_width
|
||||||
@@ -2230,6 +2518,44 @@ class GraphScreen(wx.Window):
|
|||||||
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseMotion', event=event, rx_freq=freq2)
|
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseMotion', event=event, rx_freq=freq2)
|
||||||
else: # Mouse motion changes the transmit frequency
|
else: # Mouse motion changes the transmit frequency
|
||||||
self.ChangeHwFrequency(self.txFreq + freq, self.VFO, 'MouseMotion', event=event)
|
self.ChangeHwFrequency(self.txFreq + freq, self.VFO, 'MouseMotion', event=event)
|
||||||
|
else:
|
||||||
|
mouse_x, mouse_y = self.GetMousePosition(event)
|
||||||
|
if not self.in_splitter and self.originY <= mouse_y <= self.originY + self.tick and (
|
||||||
|
self.originX <= mouse_x <= self.originX + self.graph_width):
|
||||||
|
#sample_rate = int(self.sample_rate * self.zoom) # Measure the frequency
|
||||||
|
#freq = float(mouse_x - self.x0) * sample_rate / self.data_width + self.zoom_deltaf + self.VFO
|
||||||
|
#freq = int(freq)
|
||||||
|
#color = None
|
||||||
|
#for start_freq, start_color in application.BandPlan:
|
||||||
|
# if start_freq >= freq:
|
||||||
|
# break
|
||||||
|
# color = start_color
|
||||||
|
dc = wx.ClientDC(self) # Read the pixel at the mouse position
|
||||||
|
pixel = dc.GetPixel(mouse_x, mouse_y)
|
||||||
|
pixel = "#%02X%02X%02X" % (pixel[0], pixel[1], pixel[2])
|
||||||
|
txt = application.BandPlanC2T.get(pixel, '')
|
||||||
|
if pixel == "#000000":
|
||||||
|
pass
|
||||||
|
elif txt:
|
||||||
|
self.bandplanInfo.Clear()
|
||||||
|
self.bandplanInfo.write(txt)
|
||||||
|
width, height = self.bandplanInfo.GetTextExtent(txt)
|
||||||
|
width += self.bandplanInfo.GetCharWidth() * 2
|
||||||
|
height += self.bandplanInfo.GetCharHeight() // 2
|
||||||
|
self.bandplanInfo.SetSize(wx.Size(width, height))
|
||||||
|
self.bandplanWindow.SetClientSize((width, height))
|
||||||
|
rect = self.GetScreenRect()
|
||||||
|
if mouse_x > self.originX + self.graph_width * 3 // 4:
|
||||||
|
self.bandplanWindow.Move(mouse_x + rect.GetX() - width, mouse_y + rect.GetY() - height * 12 // 10)
|
||||||
|
else:
|
||||||
|
self.bandplanWindow.Move(mouse_x + rect.GetX(), mouse_y + rect.GetY() - height * 12 // 10)
|
||||||
|
if not self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Show()
|
||||||
|
else:
|
||||||
|
if self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Hide()
|
||||||
|
elif self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Hide()
|
||||||
def OnWheel(self, event):
|
def OnWheel(self, event):
|
||||||
if conf.freq_spacing:
|
if conf.freq_spacing:
|
||||||
wm = conf.freq_spacing
|
wm = conf.freq_spacing
|
||||||
@@ -2480,12 +2806,10 @@ class WaterfallDisplay(wx.Window):
|
|||||||
self.top_key = 8
|
self.top_key = 8
|
||||||
self.top_size = (self.top_key + 2) * (self.top_key - 1) // 2
|
self.top_size = (self.top_key + 2) * (self.top_key - 1) // 2
|
||||||
# Make the palette
|
# Make the palette
|
||||||
if conf.waterfall_palette == 'B':
|
if conf.waterfall_palette == 'A':
|
||||||
pal2 = conf.waterfallPaletteB
|
|
||||||
elif conf.waterfall_palette == 'C':
|
|
||||||
pal2 = conf.waterfallPaletteC
|
|
||||||
else:
|
|
||||||
pal2 = conf.waterfallPalette
|
pal2 = conf.waterfallPalette
|
||||||
|
else:
|
||||||
|
pal2 = getattr(conf, "waterfallPalette" + conf.waterfall_palette)
|
||||||
red = bytearray(256)
|
red = bytearray(256)
|
||||||
green = bytearray(256)
|
green = bytearray(256)
|
||||||
blue = bytearray(256)
|
blue = bytearray(256)
|
||||||
@@ -2579,7 +2903,7 @@ class WaterfallScreen(wx.SplitterWindow):
|
|||||||
self.y_zero = conf.waterfall_y_zero
|
self.y_zero = conf.waterfall_y_zero
|
||||||
self.zoom_control = 0
|
self.zoom_control = 0
|
||||||
wx.SplitterWindow.__init__(self, frame)
|
wx.SplitterWindow.__init__(self, frame)
|
||||||
self.SetSizeHints(width, -1, width)
|
self.SetSizeHints(width, -1)
|
||||||
self.SetSashGravity(0.50)
|
self.SetSashGravity(0.50)
|
||||||
self.SetMinimumPaneSize(1)
|
self.SetMinimumPaneSize(1)
|
||||||
self.SetSize((width, conf.waterfall_graph_size + 100)) # be able to set sash size
|
self.SetSize((width, conf.waterfall_graph_size + 100)) # be able to set sash size
|
||||||
@@ -2933,7 +3257,7 @@ class MultiReceiverScreen(wx.SplitterWindow):
|
|||||||
self.rx_zero = self.graph
|
self.rx_zero = self.graph
|
||||||
self.Initialize(self.rx_zero)
|
self.Initialize(self.rx_zero)
|
||||||
self.waterfall.Hide()
|
self.waterfall.Hide()
|
||||||
self.SetSizeHints(self.width, -1, self.width)
|
self.SetSizeHints(self.width, -1)
|
||||||
# Calculate control width
|
# Calculate control width
|
||||||
rx_btn = QuiskPushbutton(self, None, "Rx 8....", style=wx.BU_EXACTFIT)
|
rx_btn = QuiskPushbutton(self, None, "Rx 8....", style=wx.BU_EXACTFIT)
|
||||||
self.rx_btn_width, self.rx_btn_height = rx_btn.GetSize().Get()
|
self.rx_btn_width, self.rx_btn_height = rx_btn.GetSize().Get()
|
||||||
@@ -2970,15 +3294,26 @@ class MultiReceiverScreen(wx.SplitterWindow):
|
|||||||
if pane != excpt:
|
if pane != excpt:
|
||||||
pane.play_btn.SetValue(False)
|
pane.play_btn.SetValue(False)
|
||||||
pane.is_playing = False
|
pane.is_playing = False
|
||||||
def OnAddReceiver(self, event):
|
def OnAddReceiver(self, event=None, hide_it=False):
|
||||||
index = len(self.receiver_list)
|
index = len(self.receiver_list)
|
||||||
if index >= 7:
|
if index >= 7:
|
||||||
return
|
return
|
||||||
if index == 0:
|
if index == 0:
|
||||||
pane2 = self.rx_zero
|
|
||||||
splitter = pane2.GetParent()
|
|
||||||
pane1 = MultiRxGraph(self, self.data_width, self.graph_width, index)
|
pane1 = MultiRxGraph(self, self.data_width, self.graph_width, index)
|
||||||
self.receiver_list.append(pane1)
|
self.receiver_list.append(pane1)
|
||||||
|
if hide_it:
|
||||||
|
pane1.Show(False)
|
||||||
|
pane1.graph_display.Show(False)
|
||||||
|
else:
|
||||||
|
pane2 = self.rx_zero
|
||||||
|
splitter = pane2.GetParent()
|
||||||
|
splitter.SplitHorizontally(pane1, self.rx_zero)
|
||||||
|
elif index == 1 and not self.receiver_list[0].IsShown():
|
||||||
|
pane1 = self.receiver_list[0]
|
||||||
|
pane2 = self.rx_zero
|
||||||
|
splitter = pane2.GetParent()
|
||||||
|
pane1.Show(True)
|
||||||
|
pane1.graph_display.Show(True)
|
||||||
splitter.SplitHorizontally(pane1, self.rx_zero)
|
splitter.SplitHorizontally(pane1, self.rx_zero)
|
||||||
else:
|
else:
|
||||||
pane2 = self.receiver_list[-1]
|
pane2 = self.receiver_list[-1]
|
||||||
@@ -3466,6 +3801,7 @@ class App(wx.App):
|
|||||||
if not os.path.isdir(self.QuiskFilesDir):
|
if not os.path.isdir(self.QuiskFilesDir):
|
||||||
self.QuiskFilesDir = DefaultConfigDir
|
self.QuiskFilesDir = DefaultConfigDir
|
||||||
self.std_out_err = StdOutput(self)
|
self.std_out_err = StdOutput(self)
|
||||||
|
self.std_out_err.Logfile("WxPython " + wx.version())
|
||||||
QS.set_params(quisk_is_vna=0) # We are not the VNA program
|
QS.set_params(quisk_is_vna=0) # We are not the VNA program
|
||||||
# Read in configuration from the selected radio
|
# Read in configuration from the selected radio
|
||||||
self.BandPlan = []
|
self.BandPlan = []
|
||||||
@@ -3556,6 +3892,7 @@ class App(wx.App):
|
|||||||
setattr(conf, 'widgets_file_name', '')
|
setattr(conf, 'widgets_file_name', '')
|
||||||
Hardware = self.Hardware
|
Hardware = self.Hardware
|
||||||
self.use_fast_heart_beat = hasattr(Hardware, "FastHeartBeat")
|
self.use_fast_heart_beat = hasattr(Hardware, "FastHeartBeat")
|
||||||
|
self.poll_gui_control = hasattr(Hardware, "PollGuiControl")
|
||||||
# Initialization - may be over-written by persistent state
|
# Initialization - may be over-written by persistent state
|
||||||
self.local_conf.Initialize()
|
self.local_conf.Initialize()
|
||||||
self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow
|
self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow
|
||||||
@@ -3565,12 +3902,13 @@ class App(wx.App):
|
|||||||
self.smeter_avg_seconds = 1.0 # seconds for S-meter average
|
self.smeter_avg_seconds = 1.0 # seconds for S-meter average
|
||||||
self.smeter_sunits = -87.0
|
self.smeter_sunits = -87.0
|
||||||
self.smeter_usage = "smeter" # specify use of s-meter display
|
self.smeter_usage = "smeter" # specify use of s-meter display
|
||||||
|
self.hamlib_strength = 0.0;
|
||||||
self.timer = time.time() # A seconds clock
|
self.timer = time.time() # A seconds clock
|
||||||
self.heart_time0 = self.timer # timer to call HeartBeat at intervals
|
self.heart_time0 = self.timer # timer to call HeartBeat at intervals
|
||||||
self.save_time0 = self.timer
|
self.save_time0 = self.timer
|
||||||
self.smeter_db_time0 = self.timer
|
self.smeter_db_time0 = self.timer
|
||||||
self.smeter_sunits_time0 = self.timer
|
self.smeter_sunits_time0 = self.timer
|
||||||
self.fewsec_time0 = self.timer
|
self.slowheart_time0 = self.timer
|
||||||
self.multi_rx_index = 0
|
self.multi_rx_index = 0
|
||||||
self.multi_rx_timer = self.timer
|
self.multi_rx_timer = self.timer
|
||||||
self.band_up_down = 0 # Are band Up/Down buttons in use?
|
self.band_up_down = 0 # Are band Up/Down buttons in use?
|
||||||
@@ -3641,6 +3979,19 @@ class App(wx.App):
|
|||||||
# traceback.print_exc()
|
# traceback.print_exc()
|
||||||
else:
|
else:
|
||||||
self.hamlib_socket = None
|
self.hamlib_socket = None
|
||||||
|
# Quisk control by K4 commands through a TCP port
|
||||||
|
self.k4_tcp_clients = [] # list of TCP connections to handle
|
||||||
|
if conf.k4_tcp_port:
|
||||||
|
try:
|
||||||
|
self.k4_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.k4_tcp_socket.bind((conf.k4_tcp_ip, conf.k4_tcp_port))
|
||||||
|
self.k4_tcp_socket.settimeout(0.0)
|
||||||
|
self.k4_tcp_socket.listen(5) # listen for TCP connections from multiple clients
|
||||||
|
except:
|
||||||
|
self.k4_tcp_socket = None
|
||||||
|
# traceback.print_exc()
|
||||||
|
else:
|
||||||
|
self.k4_tcp_socket = None
|
||||||
# Quisk control by fldigi
|
# Quisk control by fldigi
|
||||||
self.fldigi_new_freq = None
|
self.fldigi_new_freq = None
|
||||||
self.fldigi_freq = None
|
self.fldigi_freq = None
|
||||||
@@ -3726,6 +4077,7 @@ class App(wx.App):
|
|||||||
pass #traceback.print_exc()
|
pass #traceback.print_exc()
|
||||||
if "Version" not in self.bandAmplPhase:
|
if "Version" not in self.bandAmplPhase:
|
||||||
self.FixAmplPhase() # Convert to new format Oct 2020
|
self.FixAmplPhase() # Convert to new format Oct 2020
|
||||||
|
self.FixAmplPhase2() # New logic June 2024
|
||||||
if Hardware.VarDecimGetChoices(): # Hardware can change the decimation.
|
if Hardware.VarDecimGetChoices(): # Hardware can change the decimation.
|
||||||
self.sample_rate = Hardware.VarDecimSet() # Get the sample rate.
|
self.sample_rate = Hardware.VarDecimSet() # Get the sample rate.
|
||||||
self.vardecim_set = self.sample_rate
|
self.vardecim_set = self.sample_rate
|
||||||
@@ -3764,16 +4116,16 @@ class App(wx.App):
|
|||||||
self.std_out_err.Show(False)
|
self.std_out_err.Show(False)
|
||||||
else:
|
else:
|
||||||
self.std_out_err.Show(True)
|
self.std_out_err.Show(True)
|
||||||
#w, h = frame.GetSize().Get()
|
wClient, hClient = self.main_frame.GetClientSize()
|
||||||
#ww, hh = frame.GetClientSizeTuple()
|
wFrame, hFrame = self.main_frame.GetSize()
|
||||||
#print ('Main frame: size', w, h, 'client', ww, hh)
|
main_border_w = wFrame - wClient
|
||||||
|
#print ('Main frame: size', wFrame, hFrame, 'client', wClient, hClient, 'border', main_border_w)
|
||||||
# Find the data width from a list of preferred sizes; it is the width of returned graph data.
|
# Find the data width from a list of preferred sizes; it is the width of returned graph data.
|
||||||
# The graph_width is the width of data_width that is displayed.
|
# The graph_width is the width of data_width that is displayed.
|
||||||
|
# The total width of the graph is graph_width + self.graph_borders
|
||||||
if conf.window_width > 0:
|
if conf.window_width > 0:
|
||||||
#wFrame, h = frame.GetClientSize().Get() # client window width
|
|
||||||
wFrame = conf.window_width - 15 # Thanks to Nick Abramenko, RA3PKJ
|
|
||||||
graph = GraphScreen(frame, self.width//2, self.width//2, None) # make a GraphScreen to calculate borders
|
graph = GraphScreen(frame, self.width//2, self.width//2, None) # make a GraphScreen to calculate borders
|
||||||
self.graph_width = wFrame - (graph.width - graph.graph_width) # less graph borders equals actual graph_width
|
self.graph_width = wClient - (graph.width - graph.graph_width) # less graph borders equals actual graph_width
|
||||||
graph.Destroy()
|
graph.Destroy()
|
||||||
del graph
|
del graph
|
||||||
if self.graph_width % 2 == 1: # Both data_width and graph_width are even numbers
|
if self.graph_width % 2 == 1: # Both data_width and graph_width are even numbers
|
||||||
@@ -3867,6 +4219,8 @@ class App(wx.App):
|
|||||||
# Start wdsp
|
# Start wdsp
|
||||||
self.wdsp = quisk_wdsp.Cwdsp(self)
|
self.wdsp = quisk_wdsp.Cwdsp(self)
|
||||||
self.wdsp_channel = 1
|
self.wdsp_channel = 1
|
||||||
|
self.wdsp_SNB = 0
|
||||||
|
self.wdsp_NR2 = 0
|
||||||
self.wdsp.open(self.wdsp_channel)
|
self.wdsp.open(self.wdsp_channel)
|
||||||
#print ('data_width %d, FFT size %d, FFT mult %d, average_count %d, rate %d, Refresh %.2f Hz' % (
|
#print ('data_width %d, FFT size %d, FFT mult %d, average_count %d, rate %d, Refresh %.2f Hz' % (
|
||||||
# self.data_width, self.fft_size, self.fft_size / self.data_width, average_count, self.sample_rate,
|
# self.data_width, self.fft_size, self.fft_size / self.data_width, average_count, self.sample_rate,
|
||||||
@@ -3898,14 +4252,14 @@ class App(wx.App):
|
|||||||
frame.SetSizer(vertBox)
|
frame.SetSizer(vertBox)
|
||||||
# Add the screens
|
# Add the screens
|
||||||
vertBox.Add(self.config_screen, 1, wx.EXPAND)
|
vertBox.Add(self.config_screen, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.multi_rx_screen, 1)
|
vertBox.Add(self.multi_rx_screen, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.scope, 1)
|
vertBox.Add(self.scope, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.bandscope_screen, 1)
|
vertBox.Add(self.bandscope_screen, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.filter_screen, 1)
|
vertBox.Add(self.filter_screen, 1, wx.EXPAND)
|
||||||
if self.rate_audio_fft:
|
if self.rate_audio_fft:
|
||||||
vertBox.Add(self.audio_fft_screen, 1)
|
vertBox.Add(self.audio_fft_screen, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.help_screen, 1)
|
vertBox.Add(self.help_screen, 1, wx.EXPAND)
|
||||||
vertBox.Add(self.station_screen)
|
vertBox.Add(self.station_screen, 0, wx.EXPAND)
|
||||||
# Add the spacer
|
# Add the spacer
|
||||||
vertBox.Add(Spacer(frame), 0, wx.EXPAND)
|
vertBox.Add(Spacer(frame), 0, wx.EXPAND)
|
||||||
# Add the sizer for the controls
|
# Add the sizer for the controls
|
||||||
@@ -3918,13 +4272,16 @@ class App(wx.App):
|
|||||||
vertBox.AddSpacer(5) # Thanks to Christof, DJ4CM
|
vertBox.AddSpacer(5) # Thanks to Christof, DJ4CM
|
||||||
# End of vertical box.
|
# End of vertical box.
|
||||||
self.MakeButtons(frame, gbs)
|
self.MakeButtons(frame, gbs)
|
||||||
minw = width = self.graph.width
|
|
||||||
maxw = maxh = -1
|
|
||||||
minh = 100
|
|
||||||
if conf.window_width > 0:
|
if conf.window_width > 0:
|
||||||
minw = width = maxw = conf.window_width
|
minw = maxw = conf.window_width
|
||||||
|
else:
|
||||||
|
minw = self.graph.width + main_border_w
|
||||||
|
maxw = -1
|
||||||
if conf.window_height > 0:
|
if conf.window_height > 0:
|
||||||
minh = maxh = self.height = conf.window_height
|
minh = maxh = self.height = conf.window_height
|
||||||
|
else:
|
||||||
|
minh = 100
|
||||||
|
maxh = -1
|
||||||
self.main_frame.SetSizeHints(minw, minh, maxw, maxh)
|
self.main_frame.SetSizeHints(minw, minh, maxw, maxh)
|
||||||
self.main_frame.SetClientSize(wx.Size(width, self.height))
|
self.main_frame.SetClientSize(wx.Size(width, self.height))
|
||||||
if hasattr(Hardware, 'pre_open'): # pre_open() is called before open()
|
if hasattr(Hardware, 'pre_open'): # pre_open() is called before open()
|
||||||
@@ -3966,7 +4323,6 @@ class App(wx.App):
|
|||||||
if conf.dxClHost:
|
if conf.dxClHost:
|
||||||
# create DX Cluster and register listener for change notification
|
# create DX Cluster and register listener for change notification
|
||||||
self.dxCluster = dxcluster.DxCluster()
|
self.dxCluster = dxcluster.DxCluster()
|
||||||
self.dxCluster.setListener(self.OnDxClChange)
|
|
||||||
self.dxCluster.start()
|
self.dxCluster.start()
|
||||||
# Create shortcut keys for buttons
|
# Create shortcut keys for buttons
|
||||||
if conf.button_layout == 'Large screen':
|
if conf.button_layout == 'Large screen':
|
||||||
@@ -4317,8 +4673,6 @@ class App(wx.App):
|
|||||||
conf.tx_ip, conf.tx_audio_port,
|
conf.tx_ip, conf.tx_audio_port,
|
||||||
conf.mic_sample_rate, conf.mic_channel_I, conf.mic_channel_Q,
|
conf.mic_sample_rate, conf.mic_channel_I, conf.mic_channel_Q,
|
||||||
0.7, conf.mic_playback_rate)
|
0.7, conf.mic_playback_rate)
|
||||||
def OnDxClChange(self):
|
|
||||||
self.station_screen.Refresh()
|
|
||||||
def OnIdle(self, event):
|
def OnIdle(self, event):
|
||||||
if self.screen:
|
if self.screen:
|
||||||
self.screen.OnIdle(event)
|
self.screen.OnIdle(event)
|
||||||
@@ -4348,6 +4702,9 @@ class App(wx.App):
|
|||||||
if self.hamlib_socket:
|
if self.hamlib_socket:
|
||||||
self.hamlib_socket.close()
|
self.hamlib_socket.close()
|
||||||
self.hamlib_socket = None
|
self.hamlib_socket = None
|
||||||
|
if self.k4_tcp_socket:
|
||||||
|
self.k4_tcp_socket.close()
|
||||||
|
self.k4_tcp_socket = None
|
||||||
if self.dxCluster:
|
if self.dxCluster:
|
||||||
self.dxCluster.stop()
|
self.dxCluster.stop()
|
||||||
if self.hamlib_com1_handler:
|
if self.hamlib_com1_handler:
|
||||||
@@ -4392,6 +4749,25 @@ class App(wx.App):
|
|||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.bandAmplPhase[band] = {}
|
self.bandAmplPhase[band] = {}
|
||||||
|
def FixAmplPhase2(self): # New definition of phase
|
||||||
|
if self.bandAmplPhase["Version"]["rx"] == [1]:
|
||||||
|
return
|
||||||
|
degrad = 360.0 / 2 / math.pi
|
||||||
|
for band in self.bandAmplPhase:
|
||||||
|
if band == "Version":
|
||||||
|
continue
|
||||||
|
for rx_tx in self.bandAmplPhase[band]:
|
||||||
|
if rx_tx in ('rx', 'tx'):
|
||||||
|
data = self.bandAmplPhase[band][rx_tx]
|
||||||
|
for item in data:
|
||||||
|
vfo = item[0]
|
||||||
|
lst_framph = item[1]
|
||||||
|
for framph in lst_framph:
|
||||||
|
freq, am, ph = framph
|
||||||
|
p = math.atan(math.tan(ph / degrad) / (1.0 + am))
|
||||||
|
#print ("%5s %3s %8d %8d %8.4f %8.3f %8.3f" % (band, rx_tx, vfo, freq, am, ph, p * degrad))
|
||||||
|
framph[2] = p * degrad
|
||||||
|
self.bandAmplPhase["Version"]["rx"] = [1]
|
||||||
def ImmediateChange(self, name):
|
def ImmediateChange(self, name):
|
||||||
if name == "pulse_audio_verbose_output":
|
if name == "pulse_audio_verbose_output":
|
||||||
value = getattr(conf, name)
|
value = getattr(conf, name)
|
||||||
@@ -4534,7 +4910,7 @@ class App(wx.App):
|
|||||||
b.char_shortcut = 'u'
|
b.char_shortcut = 'u'
|
||||||
self.MakeAccel(b)
|
self.MakeAccel(b)
|
||||||
left_row2.append(b)
|
left_row2.append(b)
|
||||||
b = QuiskCheckbutton(frame, self.OnBtnNR2, text='NR2')
|
b = QuiskCycleCheckbutton(frame, self.OnBtnNR2, ['NR2', 'NR2', 'NR2t'])
|
||||||
if not self.wdsp.version:
|
if not self.wdsp.version:
|
||||||
b.Enable(False)
|
b.Enable(False)
|
||||||
left_row2.append(b)
|
left_row2.append(b)
|
||||||
@@ -4630,7 +5006,7 @@ class App(wx.App):
|
|||||||
b.char_shortcut = 'l'
|
b.char_shortcut = 'l'
|
||||||
self.MakeAccel(b)
|
self.MakeAccel(b)
|
||||||
self.splitButton = WrapMenu(b, self.split_menu)
|
self.splitButton = WrapMenu(b, self.split_menu)
|
||||||
if conf.mouse_tune_method: # Mouse motion changes the VFO frequency
|
if False: #conf.mouse_tune_method: # Mouse motion changes the VFO frequency
|
||||||
self.splitButton.Enable(False)
|
self.splitButton.Enable(False)
|
||||||
left_row3.append(self.splitButton)
|
left_row3.append(self.splitButton)
|
||||||
b = QuiskCheckbutton(frame, self.OnBtnFDX, 'FDX', color=conf.color_test)
|
b = QuiskCheckbutton(frame, self.OnBtnFDX, 'FDX', color=conf.color_test)
|
||||||
@@ -4742,7 +5118,7 @@ class App(wx.App):
|
|||||||
else:
|
else:
|
||||||
self.modeButns.Enable('FDV-U', False)
|
self.modeButns.Enable('FDV-U', False)
|
||||||
if conf.add_imd_button:
|
if conf.add_imd_button:
|
||||||
val = 500
|
val = 1000
|
||||||
QS.set_imd_level(val)
|
QS.set_imd_level(val)
|
||||||
if conf.button_layout == 'Large screen':
|
if conf.button_layout == 'Large screen':
|
||||||
b = QuiskCheckbutton(frame, None, 'IMD', color=conf.color_test)
|
b = QuiskCheckbutton(frame, None, 'IMD', color=conf.color_test)
|
||||||
@@ -4840,7 +5216,8 @@ class App(wx.App):
|
|||||||
self.freqDisplay.Display(self.txFreq + self.VFO)
|
self.freqDisplay.Display(self.txFreq + self.VFO)
|
||||||
# On/Off button
|
# On/Off button
|
||||||
if conf.button_layout == 'Large screen':
|
if conf.button_layout == 'Large screen':
|
||||||
b_onoff = QuiskCheckbutton(frame, self.OnBtnOnOff, "On", color='#77DD77')
|
b_onoff = QuiskCheckbutton(frame, self.OnBtnOnOff, "On", color=conf.color_onoff)
|
||||||
|
b_onoff.text_color = conf.color_onoff_text
|
||||||
b_onoff.SetValue(True, do_cmd=False)
|
b_onoff.SetValue(True, do_cmd=False)
|
||||||
h = b_freqdisp.height
|
h = b_freqdisp.height
|
||||||
b_onoff.SetSizeHints(h, h, h, h)
|
b_onoff.SetSizeHints(h, h, h, h)
|
||||||
@@ -5043,6 +5420,7 @@ class App(wx.App):
|
|||||||
self.smeter_sunits_time0 = self.timer
|
self.smeter_sunits_time0 = self.timer
|
||||||
s = self.smeter_sunits / 6.0 # change to S units; 6db per S unit
|
s = self.smeter_sunits / 6.0 # change to S units; 6db per S unit
|
||||||
s += Hardware.correct_smeter # S-meter correction for the gain, band, etc.
|
s += Hardware.correct_smeter # S-meter correction for the gain, band, etc.
|
||||||
|
self.hamlib_strength = (s - 9.0) * 6.0 # convert to dB; 0 dB is S9
|
||||||
if s < 0:
|
if s < 0:
|
||||||
s = 0
|
s = 0
|
||||||
if s >= 9.5:
|
if s >= 9.5:
|
||||||
@@ -5738,11 +6116,18 @@ class App(wx.App):
|
|||||||
QS.set_auto_notch(0)
|
QS.set_auto_notch(0)
|
||||||
def OnBtnNR2(self, event):
|
def OnBtnNR2(self, event):
|
||||||
btn = event.GetEventObject()
|
btn = event.GetEventObject()
|
||||||
if btn.GetValue():
|
if btn.index == 1:
|
||||||
|
self.wdsp.put(self.wdsp.SetRXAEMNRgainMethod, self.wdsp_channel, 2)
|
||||||
self.wdsp.put(self.wdsp.SetRXAEMNRRun, self.wdsp_channel, 1)
|
self.wdsp.put(self.wdsp.SetRXAEMNRRun, self.wdsp_channel, 1)
|
||||||
QS.wdsp_set_parameter(self.wdsp_channel, in_use=1)
|
self.wdsp_NR2 = 1
|
||||||
|
elif btn.index == 2:
|
||||||
|
self.wdsp.put(self.wdsp.SetRXAEMNRgainMethod, self.wdsp_channel, 3)
|
||||||
|
self.wdsp.put(self.wdsp.SetRXAEMNRRun, self.wdsp_channel, 1)
|
||||||
|
self.wdsp_NR2 = 1
|
||||||
else:
|
else:
|
||||||
self.wdsp.put(self.wdsp.SetRXAEMNRRun, self.wdsp_channel, 0)
|
self.wdsp.put(self.wdsp.SetRXAEMNRRun, self.wdsp_channel, 0)
|
||||||
|
self.wdsp_NR2 = 0
|
||||||
|
QS.wdsp_set_parameter(self.wdsp_channel, in_use=self.wdsp_NR2 + self.wdsp_SNB)
|
||||||
def OnMenuNB(self, event):
|
def OnMenuNB(self, event):
|
||||||
# menu is ("NB 1", "NB 2", "NB 3", "SNB")
|
# menu is ("NB 1", "NB 2", "NB 3", "SNB")
|
||||||
for item in self.NB_menu.GetMenuItems():
|
for item in self.NB_menu.GetMenuItems():
|
||||||
@@ -5758,14 +6143,17 @@ class App(wx.App):
|
|||||||
if text == "SNB":
|
if text == "SNB":
|
||||||
QS.set_noise_blanker(0)
|
QS.set_noise_blanker(0)
|
||||||
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 1)
|
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 1)
|
||||||
QS.wdsp_set_parameter(self.wdsp_channel, in_use=1)
|
self.wdsp_SNB = 1
|
||||||
else:
|
else:
|
||||||
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 0)
|
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 0)
|
||||||
|
self.wdsp_SNB = 0
|
||||||
index = int(text[-1])
|
index = int(text[-1])
|
||||||
QS.set_noise_blanker(index)
|
QS.set_noise_blanker(index)
|
||||||
else: # Noise blanker Off
|
else: # Noise blanker Off
|
||||||
QS.set_noise_blanker(0)
|
QS.set_noise_blanker(0)
|
||||||
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 0)
|
self.wdsp.put(self.wdsp.SetRXASNBARun, self.wdsp_channel, 0)
|
||||||
|
self.wdsp_SNB = 0
|
||||||
|
QS.wdsp_set_parameter(self.wdsp_channel, in_use=self.wdsp_NR2 + self.wdsp_SNB)
|
||||||
def FreqEntry(self, event):
|
def FreqEntry(self, event):
|
||||||
freq = event.GetString()
|
freq = event.GetString()
|
||||||
win = event.GetEventObject()
|
win = event.GetEventObject()
|
||||||
@@ -5795,16 +6183,31 @@ class App(wx.App):
|
|||||||
The hardware will reply with the updated frequencies which may be different
|
The hardware will reply with the updated frequencies which may be different
|
||||||
from those requested; use and display the returned tune and vfo.
|
from those requested; use and display the returned tune and vfo.
|
||||||
"""
|
"""
|
||||||
|
#print ("ChangeHW", source, tune, vfo, vfo + tune)
|
||||||
if not self.split_rxtx:
|
if not self.split_rxtx:
|
||||||
self.rxFreq = tune # rxFreq must be correct before the call to Hardware.ChangeFrequency()
|
self.rxFreq = tune # rxFreq must be correct before the call to Hardware.ChangeFrequency()
|
||||||
elif rx_freq is not None:
|
elif rx_freq is not None:
|
||||||
self.rxFreq = rx_freq
|
self.rxFreq = rx_freq
|
||||||
|
rx_offset = self.rxFreq - tune
|
||||||
if self.screen == self.bandscope_screen:
|
if self.screen == self.bandscope_screen:
|
||||||
freq = vfo + tune
|
freq = vfo + tune
|
||||||
tune = freq % 10000
|
tune = freq % 10000
|
||||||
vfo = freq - tune
|
vfo = freq - tune
|
||||||
tune, vfo = Hardware.ChangeFrequency(vfo + tune, vfo, source, band, event)
|
tune, vfo = Hardware.ChangeFrequency(vfo + tune, vfo, source, band, event)
|
||||||
self.ChangeDisplayFrequency(tune - vfo, vfo, rx_freq is not None)
|
self.ChangeDisplayFrequency(tune - vfo, vfo, rx_freq is not None)
|
||||||
|
elif conf.fixed_tune_offset:
|
||||||
|
# Tune with the VFO and keep a constant audio offset from the center. Tx tune is always conf.fixed_tune_offset.
|
||||||
|
tune_freq = vfo + tune
|
||||||
|
self.rxFreq = conf.fixed_tune_offset + rx_offset
|
||||||
|
if source == "BtnUpDown":
|
||||||
|
tune_freq = vfo + conf.fixed_tune_offset
|
||||||
|
else:
|
||||||
|
vfo = tune_freq - conf.fixed_tune_offset
|
||||||
|
tune_freq, vfo = Hardware.ChangeFrequency(tune_freq, vfo, source, band, event)
|
||||||
|
self.ChangeDisplayFrequency(tune_freq - vfo, vfo, True)
|
||||||
|
else:
|
||||||
|
tune, vfo = Hardware.ChangeFrequency(vfo + tune, vfo, source, band, event)
|
||||||
|
self.ChangeDisplayFrequency(tune - vfo, vfo, rx_freq is not None)
|
||||||
def ChangeDisplayFrequency(self, tune, vfo, new_rxfreq=False):
|
def ChangeDisplayFrequency(self, tune, vfo, new_rxfreq=False):
|
||||||
'Change the frequency displayed by Quisk'
|
'Change the frequency displayed by Quisk'
|
||||||
change = 0
|
change = 0
|
||||||
@@ -5824,10 +6227,8 @@ class App(wx.App):
|
|||||||
self.graph.SetVFO(vfo)
|
self.graph.SetVFO(vfo)
|
||||||
self.waterfall.SetVFO(vfo)
|
self.waterfall.SetVFO(vfo)
|
||||||
self.station_screen.Refresh()
|
self.station_screen.Refresh()
|
||||||
if self.w_phase:
|
|
||||||
self.w_phase.Redraw()
|
|
||||||
if change:
|
if change:
|
||||||
if conf.name_of_sound_capt or conf.name_of_mic_play:
|
if (conf.name_of_sound_capt or conf.name_of_mic_play) and QS.get_params("softrock_correct_active") == 0:
|
||||||
ampl, phase = self.GetAmplPhase('rx')
|
ampl, phase = self.GetAmplPhase('rx')
|
||||||
QS.set_ampl_phase(ampl, phase, 0)
|
QS.set_ampl_phase(ampl, phase, 0)
|
||||||
ampl, phase = self.GetAmplPhase('tx')
|
ampl, phase = self.GetAmplPhase('tx')
|
||||||
@@ -6291,7 +6692,7 @@ class App(wx.App):
|
|||||||
if rxtx != 'rx':
|
if rxtx != 'rx':
|
||||||
self.fldigi_server.main.rx()
|
self.fldigi_server.main.rx()
|
||||||
self.fldigi_timer = time.time()
|
self.fldigi_timer = time.time()
|
||||||
def HamlibPoll(self): # Poll for Hamlib commands
|
def HamlibPoll(self): # Poll for Hamlib and K4 TCP commands
|
||||||
if self.hamlib_socket:
|
if self.hamlib_socket:
|
||||||
try: # Poll for new client connections.
|
try: # Poll for new client connections.
|
||||||
conn, address = self.hamlib_socket.accept()
|
conn, address = self.hamlib_socket.accept()
|
||||||
@@ -6303,7 +6704,20 @@ class App(wx.App):
|
|||||||
for client in self.hamlib_clients: # Service existing clients
|
for client in self.hamlib_clients: # Service existing clients
|
||||||
if not client.Process(): # False return indicates a closed connection; remove the handler for this client
|
if not client.Process(): # False return indicates a closed connection; remove the handler for this client
|
||||||
self.hamlib_clients.remove(client)
|
self.hamlib_clients.remove(client)
|
||||||
# print 'Remove', client.address
|
# print ('Remove', client.address)
|
||||||
|
break
|
||||||
|
if self.k4_tcp_socket:
|
||||||
|
try: # Poll for new client connections.
|
||||||
|
conn, address = self.k4_tcp_socket.accept()
|
||||||
|
except socket.error:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# print ('Connection from', address)
|
||||||
|
self.k4_tcp_clients.append(ElecraftK4Handler(self, conf, conn, address))
|
||||||
|
for client in self.k4_tcp_clients: # Service existing clients
|
||||||
|
if not client.Process(): # False return indicates a closed connection; remove the handler for this client
|
||||||
|
self.k4_tcp_clients.remove(client)
|
||||||
|
# print ('Remove', client.address)
|
||||||
break
|
break
|
||||||
def OnKeyHook(self, event):
|
def OnKeyHook(self, event):
|
||||||
event.Skip()
|
event.Skip()
|
||||||
@@ -6359,6 +6773,8 @@ class App(wx.App):
|
|||||||
self.hamlib_com2_handler.Process()
|
self.hamlib_com2_handler.Process()
|
||||||
if self.use_fast_heart_beat:
|
if self.use_fast_heart_beat:
|
||||||
Hardware.FastHeartBeat()
|
Hardware.FastHeartBeat()
|
||||||
|
if self.poll_gui_control:
|
||||||
|
Hardware.PollGuiControl()
|
||||||
if conf.do_repeater_offset:
|
if conf.do_repeater_offset:
|
||||||
hold = QS.tx_hold_state(-1)
|
hold = QS.tx_hold_state(-1)
|
||||||
if hold == 2: # Tx is being held for an FM repeater TX frequency shift
|
if hold == 2: # Tx is being held for an FM repeater TX frequency shift
|
||||||
@@ -6519,6 +6935,8 @@ class App(wx.App):
|
|||||||
self.old_tx_inhibit = self.tx_inhibit
|
self.old_tx_inhibit = self.tx_inhibit
|
||||||
self.graph.display.Refresh()
|
self.graph.display.Refresh()
|
||||||
self.waterfall.pane1.display.Refresh()
|
self.waterfall.pane1.display.Refresh()
|
||||||
|
if self.tx_inhibit and self.spotButton.GetValue():
|
||||||
|
self.spotButton.SetValue(0, True)
|
||||||
msg = QS.GetQuiskPrintf()
|
msg = QS.GetQuiskPrintf()
|
||||||
if msg:
|
if msg:
|
||||||
print(msg, end='')
|
print(msg, end='')
|
||||||
@@ -6537,9 +6955,13 @@ class App(wx.App):
|
|||||||
self.ChangeDisplayFrequency(tune - vfo, vfo)
|
self.ChangeDisplayFrequency(tune - vfo, vfo)
|
||||||
self.FldigiPoll()
|
self.FldigiPoll()
|
||||||
self.HamlibPoll()
|
self.HamlibPoll()
|
||||||
#if self.timer - self.fewsec_time0 > 3.0:
|
if self.dxCluster:
|
||||||
# self.fewsec_time0 = self.timer
|
if self.dxCluster.Poll():
|
||||||
# print ('fewswc')
|
self.station_screen.Refresh()
|
||||||
|
if self.timer - self.slowheart_time0 > 0.5:
|
||||||
|
self.slowheart_time0 = self.timer
|
||||||
|
if self.w_phase:
|
||||||
|
self.w_phase.SlowHeartBeat()
|
||||||
if self.timer - self.save_time0 > 20.0:
|
if self.timer - self.save_time0 > 20.0:
|
||||||
self.save_time0 = self.timer
|
self.save_time0 = self.timer
|
||||||
if self.CheckState():
|
if self.CheckState():
|
||||||
|
|||||||
+181
-46
@@ -402,7 +402,8 @@ Hware_Hl2_EepromMACUse = 'Ignore'
|
|||||||
#Hware_Hl2_EepromMACUse = 'Set address'
|
#Hware_Hl2_EepromMACUse = 'Set address'
|
||||||
|
|
||||||
## hermes_TxLNA_dB LNA during Tx dB, integer
|
## hermes_TxLNA_dB LNA during Tx dB, integer
|
||||||
# During transmit the low noise Rx amplifier gain changes to this value (in dB) if the hardware supports it.
|
# During transmit the low noise Rx amplifier gain changes to this value (in dB).
|
||||||
|
# The LNA gain is -12 to 48 dB. Use -12 for Pure Signal.
|
||||||
# Changes are immediate (no need to restart).
|
# Changes are immediate (no need to restart).
|
||||||
hermes_TxLNA_dB = -12
|
hermes_TxLNA_dB = -12
|
||||||
|
|
||||||
@@ -1084,7 +1085,20 @@ digital_rx1_name = ""
|
|||||||
## digital_output_level Digital output level, number
|
## digital_output_level Digital output level, number
|
||||||
# This is the volume control 0.0 to 1.0 for digital playback to fldigi, etc.
|
# This is the volume control 0.0 to 1.0 for digital playback to fldigi, etc.
|
||||||
# Changes are immediate (no need to restart).
|
# Changes are immediate (no need to restart).
|
||||||
digital_output_level = 0.7
|
digital_output_level = 0.700
|
||||||
|
|
||||||
|
## file_play_level File play level, number
|
||||||
|
# Use this to reduce the volume when playing files. For example, if the volume of the CQ
|
||||||
|
# message is too loud, reduce the level relative to radio sound.
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
file_play_level = 1.000
|
||||||
|
#file_play_level = 0.500
|
||||||
|
#file_play_level = 0.100
|
||||||
|
|
||||||
|
## IQ_Server_IP Pulse server IP address, text
|
||||||
|
# IP Address for remote PulseAudio IQ server.
|
||||||
|
IQ_Server_IP = ""
|
||||||
|
#IQ_Server_IP = "192.168.230.102"
|
||||||
|
|
||||||
# Sound card names:
|
# Sound card names:
|
||||||
#
|
#
|
||||||
@@ -1279,55 +1293,31 @@ dc_remove_bw = 100
|
|||||||
#dc_remove_bw = 200
|
#dc_remove_bw = 200
|
||||||
#dc_remove_bw = 400
|
#dc_remove_bw = 400
|
||||||
|
|
||||||
|
## fixed_tune_offset Fixed tune offset, integer
|
||||||
|
# If this is zero, Quisk tunes as usual. The hardware frequency (the VFO or center frequency)
|
||||||
|
# is fixed and Quisk tunes
|
||||||
|
# within the spectrum returned by the hardware. Otherwise enter a fixed offset between the
|
||||||
|
# center frequency and the tuning frequency. Then tuning is done by the hardware.
|
||||||
|
# This is useful with Softrock hardware as
|
||||||
|
# it simplifies the corrections for amplitude and phase imbalance.
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
fixed_tune_offset = 0
|
||||||
|
#fixed_tune_offset = 5000
|
||||||
|
#fixed_tune_offset = 10000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
################ Remote
|
################ Remote
|
||||||
# DX cluster telent login data, thanks to DJ4CM. Must have station_display_lines > 0.
|
|
||||||
## dxClHost Dx cluster host name, text
|
|
||||||
# The Dx cluster options log into a Dx cluster server, and put station information
|
|
||||||
# on the station window under the graph and waterfall screens.
|
|
||||||
# dxClHost is the telnet host name.
|
|
||||||
dxClHost = ''
|
|
||||||
#dxClHost = 'example.host.net'
|
|
||||||
|
|
||||||
## dxClPort Dx cluster port number, integer
|
|
||||||
# The Dx cluster options log into a Dx cluster server, and put station information
|
|
||||||
# on the station window under the graph and waterfall screens.
|
|
||||||
# dxClPort is the telnet port number.
|
|
||||||
dxClPort = 7373
|
|
||||||
|
|
||||||
## user_call_sign Call sign for Dx cluster, text
|
|
||||||
# The Dx cluster options log into a Dx cluster server, and put station information
|
|
||||||
# on the station window under the graph and waterfall screens.
|
|
||||||
# user_call_sign is your call sign which may be needed for login.
|
|
||||||
user_call_sign = ''
|
|
||||||
|
|
||||||
## dxClPassword Password for Dx cluster, text
|
|
||||||
# The Dx cluster options log into a Dx cluster server, and put station information
|
|
||||||
# on the station window under the graph and waterfall screens.
|
|
||||||
# dxClPassword is the telnet password for the server.
|
|
||||||
dxClPassword = ''
|
|
||||||
#dxClPassword = 'getsomedx'
|
|
||||||
|
|
||||||
## dxClExpireTime Dx cluster expire minutes, integer
|
|
||||||
# The Dx cluster options log into a Dx cluster server, and put station information
|
|
||||||
# on the station window under the graph and waterfall screens.
|
|
||||||
# dxClExpireTime is the time in minutes until DX Cluster entries are removed.
|
|
||||||
dxClExpireTime = 20
|
|
||||||
|
|
||||||
## IQ_Server_IP Pulse server IP address, text
|
|
||||||
#IP Address for remote PulseAudio IQ server.
|
|
||||||
IQ_Server_IP = ""
|
|
||||||
|
|
||||||
## hamlib_ip IP address for Hamlib Rig 2, text
|
## hamlib_ip IP address for Hamlib Rig 2, text
|
||||||
# You can control Quisk from Hamlib. Set the Hamlib rig to 2 and the device for rig 2 to
|
# You can control Quisk from Hamlib. Set the Hamlib rig to 2 and the device for rig 2 to
|
||||||
# localhost:4575. Or choose a different name and port here. Set the same name and port
|
# localhost:4575. Or choose a different name and port here. Set the same name and port
|
||||||
# in the controlling program.
|
# in the controlling program.
|
||||||
# hamlib_ip is the IP name or address.
|
# hamlib_ip is the IP name or address.
|
||||||
hamlib_ip = "localhost"
|
hamlib_ip = ""
|
||||||
|
#hamlib_ip = "localhost"
|
||||||
|
|
||||||
## hamlib_port IP port for Hamlib, integer
|
## hamlib_port IP port for Hamlib Rig 2, integer
|
||||||
# You can control Quisk from Hamlib. For direct control, set the external program to rig 2
|
# You can control Quisk from Hamlib. For direct control, set the external program to rig 2
|
||||||
# "Hamlib NET rigctl", and set the Quisk hamlib port to 4532. To use the rigctld program to control
|
# "Hamlib NET rigctl", and set the Quisk hamlib port to 4532. To use the rigctld program to control
|
||||||
# Quisk, set the Quisk hamlib port to 4575. To turn off Hamlib control, set the Quisk port to zero.
|
# Quisk, set the Quisk hamlib port to 4575. To turn off Hamlib control, set the Quisk port to zero.
|
||||||
@@ -1378,19 +1368,64 @@ win_hamlib_com2_name = ""
|
|||||||
#win_hamlib_com2_name = "COM15"
|
#win_hamlib_com2_name = "COM15"
|
||||||
#win_hamlib_com2_name = "COM16"
|
#win_hamlib_com2_name = "COM16"
|
||||||
|
|
||||||
## remote_radio_ip Remote radio IP or name, text
|
## remote_radio_ip IP or name of the remote radio, text
|
||||||
# Quisk can be used as a control head to control a real radio located remotely.
|
# Quisk can be used as a control head to control a real radio located remotely.
|
||||||
# This is the IP adddress or the host name of the remote radio.
|
# This is the IP adddress or the host name of the remote radio.
|
||||||
remote_radio_ip = ""
|
remote_radio_ip = ""
|
||||||
#remote_radio_ip = "192.168.1.56"
|
#remote_radio_ip = "192.168.1.56"
|
||||||
|
|
||||||
## remote_radio_password Password for remote radio, text
|
## remote_radio_password Password for the remote radio, text
|
||||||
# Quisk can be used as a control head to control a real radio located remotely.
|
# Quisk can be used as a control head to control a real radio located remotely.
|
||||||
# For security it requires the same password to be entered on both computers.
|
# For security it requires the same password to be entered on both computers.
|
||||||
# Enter a fairly long pass phrase of 20 or more characters.
|
# Enter a fairly long pass phrase of 20 or more characters.
|
||||||
# It is only necessary to enter it once on each computer.
|
# It is only necessary to enter it once on each computer.
|
||||||
remote_radio_password = ""
|
remote_radio_password = ""
|
||||||
|
|
||||||
|
## k4_tcp_ip IP address for K4 TCP, text
|
||||||
|
# This is the Quisk IP address for the TCP server implementing K4 commands.
|
||||||
|
k4_tcp_ip = ""
|
||||||
|
#k4_tcp_ip = "localhost"
|
||||||
|
#k4_tcp_ip = "127.0.0.1"
|
||||||
|
|
||||||
|
## k4_tcp_port Port number for K4 TCP, integer
|
||||||
|
# This is the Quisk port for the TCP server implementing K4 commands.
|
||||||
|
k4_tcp_port = 0
|
||||||
|
#k4_tcp_port = 9200
|
||||||
|
#k4_tcp_port = 50004
|
||||||
|
|
||||||
|
# DX cluster telent login data, thanks to DJ4CM. Must have station_display_lines > 0.
|
||||||
|
## dxClHost Dx cluster host name, text
|
||||||
|
# The Dx cluster options log into a Dx cluster server, and put station information
|
||||||
|
# on the station window under the graph and waterfall screens.
|
||||||
|
# dxClHost is the telnet host name.
|
||||||
|
dxClHost = ''
|
||||||
|
#dxClHost = 'example.host.net'
|
||||||
|
|
||||||
|
## dxClPort Dx cluster port number, integer
|
||||||
|
# The Dx cluster options log into a Dx cluster server, and put station information
|
||||||
|
# on the station window under the graph and waterfall screens.
|
||||||
|
# dxClPort is the telnet port number.
|
||||||
|
dxClPort = 7373
|
||||||
|
|
||||||
|
## user_call_sign Call sign for Dx cluster, text
|
||||||
|
# The Dx cluster options log into a Dx cluster server, and put station information
|
||||||
|
# on the station window under the graph and waterfall screens.
|
||||||
|
# user_call_sign is your call sign which may be needed for login.
|
||||||
|
user_call_sign = ''
|
||||||
|
|
||||||
|
## dxClPassword Password for Dx cluster, text
|
||||||
|
# The Dx cluster options log into a Dx cluster server, and put station information
|
||||||
|
# on the station window under the graph and waterfall screens.
|
||||||
|
# dxClPassword is the telnet password for the server.
|
||||||
|
dxClPassword = ''
|
||||||
|
#dxClPassword = 'getsomedx'
|
||||||
|
|
||||||
|
## dxClExpireTime Dx cluster expire minutes, integer
|
||||||
|
# The Dx cluster options log into a Dx cluster server, and put station information
|
||||||
|
# on the station window under the graph and waterfall screens.
|
||||||
|
# dxClExpireTime is the time in minutes until DX Cluster entries are removed.
|
||||||
|
dxClExpireTime = 20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hamlib_com1_name = ""
|
hamlib_com1_name = ""
|
||||||
@@ -1908,6 +1943,8 @@ btn_text_switch = u"\u21C4" # Character to switch left-right
|
|||||||
color_scheme = 'A'
|
color_scheme = 'A'
|
||||||
#color_scheme = 'B'
|
#color_scheme = 'B'
|
||||||
#color_scheme = 'C'
|
#color_scheme = 'C'
|
||||||
|
#color_scheme = 'DK1MI_GR'
|
||||||
|
#color_scheme = 'DK1MI_AM'
|
||||||
|
|
||||||
## waterfall_palette Waterfall colors, text choice
|
## waterfall_palette Waterfall colors, text choice
|
||||||
# This controls the colors used in the waterfall. The default color scheme is A, and you can change this scheme
|
# This controls the colors used in the waterfall. The default color scheme is A, and you can change this scheme
|
||||||
@@ -1915,6 +1952,7 @@ color_scheme = 'A'
|
|||||||
waterfall_palette = 'A'
|
waterfall_palette = 'A'
|
||||||
#waterfall_palette = 'B'
|
#waterfall_palette = 'B'
|
||||||
#waterfall_palette = 'C'
|
#waterfall_palette = 'C'
|
||||||
|
#waterfall_palette = 'DK1MI_AM'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1949,6 +1987,8 @@ color_txline = 'red' # vertical line color for tx in graph
|
|||||||
color_rxline = 'green' # vertical line color for rx in graph
|
color_rxline = 'green' # vertical line color for rx in graph
|
||||||
color_graph_msg_fg = 'black' # text messages on the graph screen
|
color_graph_msg_fg = 'black' # text messages on the graph screen
|
||||||
color_graph_msg_bg = 'lemonchiffon2' # background of text messages on the graph screen
|
color_graph_msg_bg = 'lemonchiffon2' # background of text messages on the graph screen
|
||||||
|
color_onoff = '#77DD77' # on/off power button
|
||||||
|
color_onoff_text = 'black' # on/off power button text
|
||||||
|
|
||||||
# This color scheme B, a dark color scheme designed by Steve Murphy, KB8RWQ.
|
# This color scheme B, a dark color scheme designed by Steve Murphy, KB8RWQ.
|
||||||
# Additional colors added by N2ADR.
|
# Additional colors added by N2ADR.
|
||||||
@@ -1978,6 +2018,8 @@ color_scheme_B = {
|
|||||||
'color_rxline' : 'green',
|
'color_rxline' : 'green',
|
||||||
'color_graph_msg_fg' : 'white',
|
'color_graph_msg_fg' : 'white',
|
||||||
'color_graph_msg_bg' : '#111111',
|
'color_graph_msg_bg' : '#111111',
|
||||||
|
'color_onoff' : '#77DD77',
|
||||||
|
'color_onoff_text' : 'black',
|
||||||
}
|
}
|
||||||
|
|
||||||
# This is color scheme C:
|
# This is color scheme C:
|
||||||
@@ -2015,12 +2057,73 @@ color_scheme_C = {
|
|||||||
'color_rxline' : '#3CC918',
|
'color_rxline' : '#3CC918',
|
||||||
'color_graph_msg_fg' : '#000000',
|
'color_graph_msg_fg' : '#000000',
|
||||||
'color_graph_msg_bg' : 'lemonchiffon2',
|
'color_graph_msg_bg' : 'lemonchiffon2',
|
||||||
|
'color_onoff' : '#77DD77',
|
||||||
|
'color_onoff_text' : 'black',
|
||||||
}
|
}
|
||||||
#############################################################################################
|
#############################################################################################
|
||||||
|
# This is a green dark color scheme designed by Michael
|
||||||
|
color_scheme_DK1MI_GR = {
|
||||||
|
'color_bg' : '#0F0F0F', # Lower screen background
|
||||||
|
'color_bg_txt' : '#00CC00', # Lower screen text color
|
||||||
|
'color_graph' : '#0F0F0F', # Graph background
|
||||||
|
'color_config2' : '#008000', # color in tab row of config screen
|
||||||
|
'color_gl' : '#2F4F4F', # Lines on the graph
|
||||||
|
'color_graphticks' : '#CCCCCC', # Graph ticks
|
||||||
|
'color_graphline' : '#00FF00', # graph data line color
|
||||||
|
'color_graphlabels' : '#00FF00', # graph label color
|
||||||
|
'color_btn' : '#141414', # button color
|
||||||
|
'color_check_btn' : '#005500', # color of a check button when it is checked
|
||||||
|
'color_cycle_btn' : '#005500', # color of a cycle button when it is checked
|
||||||
|
'color_adjust_btn' : '#005500', # color of an adjustable button when it is checked
|
||||||
|
'color_test' : '#005500', # color of a button used for test (turn off for tx)
|
||||||
|
'color_freq' : '#208B57', # background color of frequency and s-meter
|
||||||
|
'color_freq_txt' : '#00FF00', # text color of frequency display
|
||||||
|
'color_entry' : '#2E2E2E', # frequency entry box
|
||||||
|
'color_entry_txt' : '#00FF00', # text color of entry box
|
||||||
|
'color_enable' : '#00CC00', # text color for an enabled button
|
||||||
|
'color_disable' : '#FF0000', # text color for a disabled button
|
||||||
|
'color_popchoice' : '#555555', # text color for button that pops up a row of buttons
|
||||||
|
'color_bandwidth' : '#003300', # color for bandwidth display; thanks to WB4JFI
|
||||||
|
'color_txline' : '#00CC00', # vertical line color for tx in graph
|
||||||
|
'color_rxline' : '#00FF00', # vertical line color for rx in graph
|
||||||
|
'color_graph_msg_fg' : '#008800', # text messages on the graph screen
|
||||||
|
'color_graph_msg_bg' : '#1E1E1E', # background of text messages on the graph screen
|
||||||
|
'color_onoff' : '#005500', # On/Off button
|
||||||
|
'color_onoff_text' : '#FF0000', # On/Off text
|
||||||
|
}
|
||||||
|
#############################################################################################
|
||||||
|
# This is an amber dark color scheme designed by Michael
|
||||||
|
color_scheme_DK1MI_AM = {
|
||||||
|
'color_bg' : '#0F0F0F', # Lower screen background
|
||||||
|
'color_bg_txt' : '#FFBF00', # Lower screen text color
|
||||||
|
'color_graph' : '#0F0F0F', # Graph background
|
||||||
|
'color_config2' : '#FF8000', # Color in tab row of config screen
|
||||||
|
'color_gl' : '#2F4F4F', # Lines on the graph
|
||||||
|
'color_graphticks' : '#CCCCCC', # Graph ticks
|
||||||
|
'color_graphline' : '#FFBF00', # Graph data line color
|
||||||
|
'color_graphlabels' : '#FFBF00', # Graph label color
|
||||||
|
'color_btn' : '#141414', # Button color
|
||||||
|
'color_check_btn' : '#865E2E', # Color of a check button when it is checked
|
||||||
|
'color_cycle_btn' : '#865E2E', # Color of a cycle button when it is checked
|
||||||
|
'color_adjust_btn' : '#865E2E', # Color of an adjustable button when it is checked
|
||||||
|
'color_test' : '#865E2E', # Color of a button used for test (turn off for tx)
|
||||||
|
'color_freq' : '#FF9933', # Background color of frequency and s-meter
|
||||||
|
'color_freq_txt' : '#000000', # Text color of frequency display
|
||||||
|
'color_entry' : '#2E2E2E', # Frequency entry box
|
||||||
|
'color_entry_txt' : '#FFBF00', # Text color of entry box
|
||||||
|
'color_enable' : '#FFBF00', # Text color for an enabled button
|
||||||
|
'color_disable' : '#FF0000', # Text color for a disabled button
|
||||||
|
'color_popchoice' : '#555555', # Text color for button that pops up a row of buttons
|
||||||
|
'color_bandwidth' : '#4B2E0F', # Color for bandwidth display
|
||||||
|
'color_txline' : '#FFBF00', # Vertical line color for tx in graph
|
||||||
|
'color_rxline' : '#FF8000', # Vertical line color for rx in graph
|
||||||
|
'color_graph_msg_fg' : '#FF8000', # Text messages on the graph screen
|
||||||
|
'color_graph_msg_bg' : '#1E1E1E', # Background of text messages on the graph screen
|
||||||
|
'color_onoff' : '#865E2E', # On/Off button
|
||||||
|
'color_onoff_text' : '#FF0000', # On/Off text
|
||||||
|
}
|
||||||
|
|
||||||
|
# These are the palettes for the waterfall.
|
||||||
# These are the palettes for the waterfall. The one used is named waterfallPallette,
|
|
||||||
# so to use a different one, overwrite this name in your configuration file.
|
|
||||||
waterfallPalette = (
|
waterfallPalette = (
|
||||||
( 0, 0, 0, 0),
|
( 0, 0, 0, 0),
|
||||||
( 36, 85, 0, 255),
|
( 36, 85, 0, 255),
|
||||||
@@ -2078,6 +2181,18 @@ waterfallPaletteC = ( # from David Fainitski
|
|||||||
(255, 245, 99, 3)
|
(255, 245, 99, 3)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
waterfallPaletteDK1MI_AM = ( # from Michael
|
||||||
|
(0, 0, 0, 0),
|
||||||
|
(32, 25, 20, 0),
|
||||||
|
(64, 58, 40, 6),
|
||||||
|
(96, 78, 50, 16),
|
||||||
|
(128, 120, 85, 29),
|
||||||
|
(160, 144, 100, 51),
|
||||||
|
(192, 195, 140, 43),
|
||||||
|
(224, 198, 150, 35),
|
||||||
|
(255, 255, 191, 0)
|
||||||
|
)
|
||||||
|
|
||||||
# This is the data used to draw colored lines on the frequency X axis to
|
# This is the data used to draw colored lines on the frequency X axis to
|
||||||
# indicate CW and Phone sub-bands. You can make it anything you want.
|
# indicate CW and Phone sub-bands. You can make it anything you want.
|
||||||
# These are the colors used for sub-bands:
|
# These are the colors used for sub-bands:
|
||||||
@@ -2103,6 +2218,26 @@ RxOnly = '#AAAAAA'
|
|||||||
# Colors start at the indicated frequency and continue until the
|
# Colors start at the indicated frequency and continue until the
|
||||||
# next frequency. The special color "None" turns off color.
|
# next frequency. The special color "None" turns off color.
|
||||||
#
|
#
|
||||||
|
BandPlanColors = [ # Display name and corresponding color
|
||||||
|
['CW, General', CW],
|
||||||
|
['CW, Extra', eCW],
|
||||||
|
['Phone, General', Phone],
|
||||||
|
['Phone, Extra', ePhone],
|
||||||
|
['AM', AM],
|
||||||
|
['Data', Data],
|
||||||
|
['DxData', DxData],
|
||||||
|
['RTTY', RTTY],
|
||||||
|
['SSTV', SSTV],
|
||||||
|
['Packet', Packet],
|
||||||
|
['Beacons', Beacons],
|
||||||
|
['Satellite', Satellite],
|
||||||
|
['Repeater out', Repeater],
|
||||||
|
['Repeater in', RepInput],
|
||||||
|
['Simplex', Simplex],
|
||||||
|
['Rx only', RxOnly],
|
||||||
|
['Special', Special],
|
||||||
|
['Other', Other]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -29,9 +29,10 @@ class Hardware(BaseHardware):
|
|||||||
# self.hamlib_rigctld_port = 4532 # Standard rigctld control port
|
# self.hamlib_rigctld_port = 4532 # Standard rigctld control port
|
||||||
# self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes
|
# self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes
|
||||||
def open(self):
|
def open(self):
|
||||||
|
# Thanks to Peter, DC6AR, Rig ID changed from 229 to 2045.
|
||||||
ret = BaseHardware.open(self)
|
ret = BaseHardware.open(self)
|
||||||
if not self.hamlib_connected: # rigctld is not started. Try to start it.
|
if not self.hamlib_connected: # rigctld is not started. Try to start it.
|
||||||
os.system("rigctld -m 229 -r /dev/ttyUSB0 -s 4800 & ") # Check the baud rate menu setting
|
os.system("rigctld -m 2045 -r /dev/ttyUSB0 -s 4800 & ") # Check the baud rate menu setting
|
||||||
# If this fails, start rigctld by hand.
|
# If this fails, start rigctld by hand.
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ class Hardware:
|
|||||||
self.application.bandscope_clock = clock
|
self.application.bandscope_clock = clock
|
||||||
#def PollCwKey(self): # Optional. Called frequently by the sound thread to check the CW key status.
|
#def PollCwKey(self): # Optional. Called frequently by the sound thread to check the CW key status.
|
||||||
# pass # Do not define if not needed.
|
# pass # Do not define if not needed.
|
||||||
|
#def PollGuiControl(self): # Optional. Called frequently by the GUI thread to change GUI settings (PTT etc.)
|
||||||
|
# pass # Do not define if not needed.
|
||||||
def StartSamples(self): # Quisk calls this from the sound thread to start sending samples.
|
def StartSamples(self): # Quisk calls this from the sound thread to start sending samples.
|
||||||
# If you return a string, it replaces the string returned from hardware open()
|
# If you return a string, it replaces the string returned from hardware open()
|
||||||
pass
|
pass
|
||||||
|
|||||||
+32
-24
@@ -2,60 +2,68 @@
|
|||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
#define CLIP32 2147483647
|
#define CLIP32 2147483647
|
||||||
#define CLIP16 32767
|
#define CLIP16 32767
|
||||||
|
|
||||||
#define MAX_CHANNELS 32
|
#define MAX_CHANNELS 32
|
||||||
#define SAMPLE_BYTES (sizeof(double) * 2)
|
|
||||||
|
|
||||||
static struct _channel {
|
static struct _channel {
|
||||||
double * cBuf; // save samples until nBuf reaches in_size
|
complex double * cBuf; // circular sample buffer; save samples until nBuf reaches in_size
|
||||||
int sizeBuf; // current size of cBuf in count of complex samples
|
int sizeBuf; // current size of cBuf in complex samples; a multiple of in_size
|
||||||
int nBuf; // current number of complex samples in cBuf
|
int nBuf; // current number of complex samples in cBuf
|
||||||
int in_size; // count of complex samples needed for wdsp_fexchange0
|
int in_size; // count of complex samples needed for wdsp_fexchange0
|
||||||
int in_use; // is this channel being used?
|
int in_use; // is this channel being used?
|
||||||
|
int Windex; // index of write
|
||||||
|
int Rindex; // index of read
|
||||||
} wdspChannel[MAX_CHANNELS];
|
} wdspChannel[MAX_CHANNELS];
|
||||||
|
|
||||||
static void (*wdsp_fexchange0) (int channel, double * in, double * out, int * error);
|
static void (*wdsp_fexchange0) (int channel, double * in, double * out, int * error);
|
||||||
|
|
||||||
int wdspFexchange0(int channel, double * cSamples, int nSamples)
|
int wdspFexchange0(int channel, complex double * cSamples, int nSamples)
|
||||||
{
|
{
|
||||||
// Call with an arbitrary number of input samples nSamples. cSamples is scaled to CLIP32.
|
// Call with an arbitrary number of input samples nSamples. cSamples is scaled to CLIP32.
|
||||||
// When we have enough samples process the samples by calling wdsp. Return the samples in the same array.
|
// When we have enough samples process the samples by calling wdsp. Return the samples in cSamples.
|
||||||
// cSamples is complex double. We treat it as interleaved Real/Imag doubles twice as long.
|
// cSamples is complex double. nSamples is the count of complex samples.
|
||||||
// nSamples is the count of complex samples.
|
|
||||||
struct _channel * ptChannel = wdspChannel + channel;
|
struct _channel * ptChannel = wdspChannel + channel;
|
||||||
int i, error;
|
int i, error, in_size;
|
||||||
double * ptD, * ptS;
|
|
||||||
|
|
||||||
if ( ! ptChannel->in_use)
|
if ( ! ptChannel->in_use) {
|
||||||
|
ptChannel->Windex = 0;
|
||||||
|
ptChannel->Rindex = 0;
|
||||||
|
ptChannel->nBuf = 0;
|
||||||
return nSamples;
|
return nSamples;
|
||||||
|
}
|
||||||
if ( ! wdsp_fexchange0)
|
if ( ! wdsp_fexchange0)
|
||||||
return nSamples;
|
return nSamples;
|
||||||
if (nSamples <= 0)
|
if (nSamples <= 0)
|
||||||
return nSamples;
|
return nSamples;
|
||||||
if (ptChannel->nBuf + nSamples >= ptChannel->sizeBuf) {
|
in_size = ptChannel->in_size;
|
||||||
ptChannel->sizeBuf = ptChannel->nBuf + nSamples * 3;
|
i = nSamples / in_size + 3; // blocks need for samples plus a partial block
|
||||||
ptChannel->cBuf = (double *)realloc(ptChannel->cBuf, ptChannel->sizeBuf * SAMPLE_BYTES);
|
if (i * in_size > ptChannel->sizeBuf) {
|
||||||
|
i *= in_size;
|
||||||
|
ptChannel->sizeBuf = i;
|
||||||
|
ptChannel->cBuf = (complex double *)realloc(ptChannel->cBuf, i * sizeof(complex double));
|
||||||
}
|
}
|
||||||
ptS = cSamples; // Copy samples from cSamples to cBuf
|
for (i = 0; i < nSamples; i++) { // Copy samples from cSamples to cBuf
|
||||||
ptD = ptChannel->cBuf + ptChannel->nBuf * 2;
|
ptChannel->cBuf[ptChannel->Windex++] = cSamples[i] / CLIP32;
|
||||||
for (i = 0; i < nSamples; i++) {
|
if (ptChannel->Windex >= ptChannel->sizeBuf)
|
||||||
*ptD++ = *ptS++ / CLIP32;
|
ptChannel->Windex = 0;
|
||||||
*ptD++ = *ptS++ / CLIP32;
|
|
||||||
}
|
}
|
||||||
ptChannel->nBuf += nSamples;
|
ptChannel->nBuf += nSamples;
|
||||||
nSamples = 0;
|
nSamples = 0;
|
||||||
while (ptChannel->nBuf >= ptChannel->in_size) {
|
while (ptChannel->nBuf >= in_size) {
|
||||||
(*wdsp_fexchange0)(channel, ptChannel->cBuf, cSamples + nSamples * 2, &error);
|
(*wdsp_fexchange0)(channel, (double *)(ptChannel->cBuf + ptChannel->Rindex), (double *)(cSamples + nSamples), &error);
|
||||||
if (error)
|
if (error)
|
||||||
printf("WDSP: wdsp_fexchange0 error %d\n", error);
|
printf("WDSP: wdsp_fexchange0 error %d\n", error);
|
||||||
nSamples += ptChannel->in_size;
|
ptChannel->Rindex += in_size;
|
||||||
ptChannel->nBuf -= ptChannel->in_size;
|
if (ptChannel->Rindex >= ptChannel->sizeBuf)
|
||||||
memmove(ptChannel->cBuf, ptChannel->cBuf + ptChannel->in_size * 2, ptChannel->nBuf * SAMPLE_BYTES);
|
ptChannel->Rindex = 0;
|
||||||
|
nSamples += in_size;
|
||||||
|
ptChannel->nBuf -= in_size;
|
||||||
}
|
}
|
||||||
for (i = 0; i < nSamples * 2; i++)
|
for (i = 0; i < nSamples; i++)
|
||||||
cSamples[i] *= CLIP32;
|
cSamples[i] *= CLIP32;
|
||||||
return nSamples;
|
return nSamples;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -24,9 +24,13 @@ class Cwdsp:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
|
self.Lib = ctypes.CDLL("./wdsp/libwdsp.so")
|
||||||
|
Log ("Found private wdsp in quisk/wdsp")
|
||||||
|
except:
|
||||||
try:
|
try:
|
||||||
self.Lib = ctypes.CDLL("./libwdsp.so")
|
self.Lib = ctypes.CDLL("./libwdsp.so")
|
||||||
Log ("Found private wdsp")
|
Log ("Found private wdsp in quisk/")
|
||||||
except:
|
except:
|
||||||
name = ctypes.util.find_library("wdsp")
|
name = ctypes.util.find_library("wdsp")
|
||||||
if name:
|
if name:
|
||||||
@@ -73,7 +77,7 @@ class Cwdsp:
|
|||||||
dsp_size = 256
|
dsp_size = 256
|
||||||
QS.wdsp_set_parameter(channel, in_size=in_size)
|
QS.wdsp_set_parameter(channel, in_size=in_size)
|
||||||
Lib.OpenChannel (channel, in_size, dsp_size, 48000, 48000, 48000, 0, 1,
|
Lib.OpenChannel (channel, in_size, dsp_size, 48000, 48000, 48000, 0, 1,
|
||||||
ctypes.c_double(0.010), ctypes.c_double(0.025), ctypes.c_double(0.0), ctypes.c_double(0.010), 0)
|
ctypes.c_double(0.010), ctypes.c_double(0.025), ctypes.c_double(0.0), ctypes.c_double(0.010), 1)
|
||||||
Lib.SetRXAShiftRun (channel, 0)
|
Lib.SetRXAShiftRun (channel, 0)
|
||||||
Lib.RXANBPSetRun (channel, 0)
|
Lib.RXANBPSetRun (channel, 0)
|
||||||
Lib.SetRXAAMSQRun (channel, 0)
|
Lib.SetRXAAMSQRun (channel, 0)
|
||||||
|
|||||||
+7
-1
@@ -582,6 +582,7 @@ class QuiskPushbutton(QuiskButtons, wx.lib.buttons.GenButton):
|
|||||||
self.Bind(wx.EVT_BUTTON, self.OnButton)
|
self.Bind(wx.EVT_BUTTON, self.OnButton)
|
||||||
self.InitButtons(text, text_color)
|
self.InitButtons(text, text_color)
|
||||||
self.direction = 1
|
self.direction = 1
|
||||||
|
self.normal_brush = self.up_brush
|
||||||
if use_right:
|
if use_right:
|
||||||
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
|
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
|
||||||
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
|
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
|
||||||
@@ -603,7 +604,12 @@ class QuiskPushbutton(QuiskButtons, wx.lib.buttons.GenButton):
|
|||||||
event = wx.PyEvent()
|
event = wx.PyEvent()
|
||||||
event.SetEventObject(self)
|
event.SetEventObject(self)
|
||||||
self.command(event)
|
self.command(event)
|
||||||
|
def SetColorNormal(self):
|
||||||
|
self.up_brush = self.normal_brush
|
||||||
|
self.Refresh()
|
||||||
|
def SetColor(self, color):
|
||||||
|
self.up_brush = wx.Brush(color)
|
||||||
|
self.Refresh()
|
||||||
|
|
||||||
class QuiskRepeatbutton(QuiskButtons, wx.lib.buttons.GenButton):
|
class QuiskRepeatbutton(QuiskButtons, wx.lib.buttons.GenButton):
|
||||||
"""A push button that repeats when held down."""
|
"""A push button that repeats when held down."""
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import os
|
|||||||
# You must define the version here. A title string including
|
# You must define the version here. A title string including
|
||||||
# the version will be written to __init__.py and read by quisk.py.
|
# the version will be written to __init__.py and read by quisk.py.
|
||||||
|
|
||||||
Version = '4.2.32'
|
Version = '4.2.44'
|
||||||
|
|
||||||
fp = open("__init__.py", "w") # write title string
|
fp = open("__init__.py", "w") # write title string
|
||||||
fp.write("#Quisk version %s\n" % Version)
|
fp.write("#Quisk version %s\n" % Version)
|
||||||
@@ -39,8 +39,10 @@ if sys.platform == "darwin": # Build for Macintosh
|
|||||||
libraries = ['portaudio', 'fftw3', 'm']
|
libraries = ['portaudio', 'fftw3', 'm']
|
||||||
if os.path.isdir('/opt/local/include'): # MacPorts
|
if os.path.isdir('/opt/local/include'): # MacPorts
|
||||||
base_dir = '/opt/local'
|
base_dir = '/opt/local'
|
||||||
elif os.path.isdir('/usr/local/include'): # HomeBrew
|
elif os.path.isdir('/usr/local/include'): # HomeBrew on macOS Intel
|
||||||
base_dir = '/usr/local'
|
base_dir = '/usr/local'
|
||||||
|
elif os.path.isdir('/opt/homebrew/include'): # HomeBrew on Apple Silicon
|
||||||
|
base_dir = '/opt/homebrew'
|
||||||
else: # Regular build?
|
else: # Regular build?
|
||||||
base_dir = '/usr'
|
base_dir = '/usr'
|
||||||
if os.path.isfile(base_dir + "/include/pulse/pulseaudio.h"):
|
if os.path.isfile(base_dir + "/include/pulse/pulseaudio.h"):
|
||||||
@@ -83,7 +85,7 @@ N1MM+ and software that uses Hamlib.
|
|||||||
url = 'http://james.ahlstrom.name/quisk/',
|
url = 'http://james.ahlstrom.name/quisk/',
|
||||||
packages = ['quisk', 'quisk.n2adr', 'quisk.softrock', 'quisk.freedvpkg',
|
packages = ['quisk', 'quisk.n2adr', 'quisk.softrock', 'quisk.freedvpkg',
|
||||||
'quisk.hermes', 'quisk.hiqsdr', 'quisk.afedrinet', 'quisk.soapypkg',
|
'quisk.hermes', 'quisk.hiqsdr', 'quisk.afedrinet', 'quisk.soapypkg',
|
||||||
'quisk.sdrmicronpkg', 'quisk.perseuspkg', 'quisk.ac2yd'],
|
'quisk.sdrmicronpkg', 'quisk.perseuspkg', 'quisk.ac2yd', 'quisk.multuspkg'],
|
||||||
package_dir = {'quisk' : '.'},
|
package_dir = {'quisk' : '.'},
|
||||||
package_data = {'' : ['*.txt', '*.html', '*.so', '*.dll']},
|
package_data = {'' : ['*.txt', '*.html', '*.so', '*.dll']},
|
||||||
entry_points = {'gui_scripts' : ['quisk = quisk.quisk:main', 'quisk_vna = quisk.quisk_vna:main']},
|
entry_points = {'gui_scripts' : ['quisk = quisk.quisk:main', 'quisk_vna = quisk.quisk_vna:main']},
|
||||||
|
|||||||
@@ -178,6 +178,8 @@ class Hardware(BaseHardware):
|
|||||||
vfo = self.vfo + int(offset * 1000) # Convert kHz to Hz
|
vfo = self.vfo + int(offset * 1000) # Convert kHz to Hz
|
||||||
self.ChangeFrequency(vfo, vfo, 'repeater')
|
self.ChangeFrequency(vfo, vfo, 'repeater')
|
||||||
return False
|
return False
|
||||||
|
def ImmediateChange(self, name):
|
||||||
|
return
|
||||||
def OnSpot(self, level):
|
def OnSpot(self, level):
|
||||||
pass
|
pass
|
||||||
def HeartBeat(self): # Called at about 10 Hz by the main
|
def HeartBeat(self): # Called at about 10 Hz by the main
|
||||||
|
|||||||
@@ -86,7 +86,9 @@ static struct wav_file file_rec_audio, file_rec_samples, file_rec_mic;
|
|||||||
static int close_file_rec;
|
static int close_file_rec;
|
||||||
|
|
||||||
double digital_output_level = 0.7;
|
double digital_output_level = 0.7;
|
||||||
|
static double file_play_level = 1.0;
|
||||||
static int dc_remove_bw=100; // bandwidth of DC removal filter
|
static int dc_remove_bw=100; // bandwidth of DC removal filter
|
||||||
|
static int multus_cw_samples = 0; // always send CW Tx samples to the Multus radio, even in Rx
|
||||||
|
|
||||||
static ty_sample_start pt_sample_start;
|
static ty_sample_start pt_sample_start;
|
||||||
static ty_sample_stop pt_sample_stop;
|
static ty_sample_stop pt_sample_stop;
|
||||||
@@ -175,9 +177,10 @@ static void correct_sample (struct sound_dev * dev, complex double * cSamples, i
|
|||||||
for (i = 0; i < nSamples; i++) {
|
for (i = 0; i < nSamples; i++) {
|
||||||
re = creal(cSamples[i]);
|
re = creal(cSamples[i]);
|
||||||
im = cimag(cSamples[i]);
|
im = cimag(cSamples[i]);
|
||||||
re = re * dev->AmPhAAAA;
|
cSamples[i] = re * dev->AmPhAAAA + I * (re * dev->AmPhCCCC + im * dev->AmPhDDDD);
|
||||||
im = re * dev->AmPhCCCC + im * dev->AmPhDDDD;
|
//re = re * dev->AmPhAAAA;
|
||||||
cSamples[i] = re + I * im;
|
//im = re * dev->AmPhCCCC + im * dev->AmPhDDDD;
|
||||||
|
//cSamples[i] = re + I * im;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -730,8 +733,11 @@ void * quisk_make_txIQ(struct sound_dev * dev, int rewind)
|
|||||||
}
|
}
|
||||||
// amplitude and phase corrections
|
// amplitude and phase corrections
|
||||||
if (dev->doAmplPhase) {
|
if (dev->doAmplPhase) {
|
||||||
dSamp0 = dSamp0 * dev->AmPhAAAA;
|
//dSamp0 = dSamp0 * dev->AmPhAAAA;
|
||||||
dSamp1 = dSamp0 * dev->AmPhCCCC + dSamp1 * dev->AmPhDDDD;
|
//dSamp1 = dSamp0 * dev->AmPhCCCC + dSamp1 * dev->AmPhDDDD;
|
||||||
|
d = dSamp0;
|
||||||
|
dSamp0 = d * dev->AmPhAAAA;
|
||||||
|
dSamp1 = d * dev->AmPhCCCC + dSamp1 * dev->AmPhDDDD;
|
||||||
}
|
}
|
||||||
switch (dev->sound_format) {
|
switch (dev->sound_format) {
|
||||||
case Int16:
|
case Int16:
|
||||||
@@ -836,6 +842,34 @@ int quisk_play_sidetone(struct sound_dev * dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void testing(double complex * cSamples, int nSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static double AvgR=0, AvgQ=0, AvgRQ=0;
|
||||||
|
double d, p, Gain, Phase;
|
||||||
|
time_t tim;
|
||||||
|
static time_t time0;
|
||||||
|
|
||||||
|
for (i = 0; i < nSamples; i++) {
|
||||||
|
d = creal(cSamples[i]);
|
||||||
|
AvgR += d * d;
|
||||||
|
p = cimag(cSamples[i]);
|
||||||
|
AvgQ += p * p;
|
||||||
|
AvgRQ += d * p;
|
||||||
|
}
|
||||||
|
tim = time(NULL);
|
||||||
|
if (tim - time0 >= 2) {
|
||||||
|
time0 = tim;
|
||||||
|
Gain = sqrt(AvgR / AvgQ);
|
||||||
|
Phase = AvgRQ / AvgQ / Gain;
|
||||||
|
Phase = asin(Phase);
|
||||||
|
printf("Time domain Gain %10.7lf, Phase %10.7lf, %10.7lf degrees\n", Gain, Phase, Phase * 57.29578);
|
||||||
|
AvgR = AvgQ = AvgRQ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int quisk_read_sound(void) // Called from sound thread
|
int quisk_read_sound(void) // Called from sound thread
|
||||||
{ // called in an infinite loop by the main program
|
{ // called in an infinite loop by the main program
|
||||||
int i, nSamples, mic_count, mic_interp, retval, is_cw, mic_sample_rate;
|
int i, nSamples, mic_count, mic_interp, retval, is_cw, mic_sample_rate;
|
||||||
@@ -913,9 +947,10 @@ int quisk_read_sound(void) // Called from sound thread
|
|||||||
//QuiskPrintTime("quisk_read_sound end", 0);
|
//QuiskPrintTime("quisk_read_sound end", 0);
|
||||||
if (Capture.channel_Delay >= 0) // delay the I or Q channel by one sample
|
if (Capture.channel_Delay >= 0) // delay the I or Q channel by one sample
|
||||||
delay_sample(&Capture, (double *)cSamples, nSamples);
|
delay_sample(&Capture, (double *)cSamples, nSamples);
|
||||||
|
DCremove(cSamples, nSamples, quisk_sound_state.sample_rate, key_state);
|
||||||
|
//testing(cSamples, nSamples);
|
||||||
if (Capture.doAmplPhase) // amplitude and phase corrections
|
if (Capture.doAmplPhase) // amplitude and phase corrections
|
||||||
correct_sample(&Capture, cSamples, nSamples);
|
correct_sample(&Capture, cSamples, nSamples);
|
||||||
DCremove(cSamples, nSamples, quisk_sound_state.sample_rate, key_state);
|
|
||||||
if (nSamples <= 0)
|
if (nSamples <= 0)
|
||||||
QuiskSleepMicrosec(2000);
|
QuiskSleepMicrosec(2000);
|
||||||
#if DEBUG_IO > 1
|
#if DEBUG_IO > 1
|
||||||
@@ -969,7 +1004,7 @@ int quisk_read_sound(void) // Called from sound thread
|
|||||||
if (quisk_record_state == TMP_PLAY_SPKR_MIC)
|
if (quisk_record_state == TMP_PLAY_SPKR_MIC)
|
||||||
quisk_tmp_playback(cSamples, nSamples, 1.0); // replace radio sound
|
quisk_tmp_playback(cSamples, nSamples, 1.0); // replace radio sound
|
||||||
else if (quisk_record_state == FILE_PLAY_SPKR_MIC)
|
else if (quisk_record_state == FILE_PLAY_SPKR_MIC)
|
||||||
quisk_file_playback(cSamples, nSamples, 1.0); // replace radio sound
|
quisk_file_playback(cSamples, nSamples, file_play_level); // replace radio sound
|
||||||
// Play the demodulated audio
|
// Play the demodulated audio
|
||||||
#if DEBUG_MIC != 2
|
#if DEBUG_MIC != 2
|
||||||
if ( ! quisk_play_sidetone(&quisk_Playback)) // play sidetone
|
if ( ! quisk_play_sidetone(&quisk_Playback)) // play sidetone
|
||||||
@@ -1075,7 +1110,7 @@ int quisk_read_sound(void) // Called from sound thread
|
|||||||
if (is_cw) { // Transmit CW; use capture device for timing, not microphone
|
if (is_cw) { // Transmit CW; use capture device for timing, not microphone
|
||||||
cwCount += (double)retval * quisk_MicPlayback.sample_rate / quisk_sound_state.sample_rate;
|
cwCount += (double)retval * quisk_MicPlayback.sample_rate / quisk_sound_state.sample_rate;
|
||||||
mic_count = 0;
|
mic_count = 0;
|
||||||
if (QUISK_CWKEY_DOWN || quiskSpotLevel >= 0) {
|
if (QUISK_CWKEY_DOWN || quiskSpotLevel >= 0 || multus_cw_samples) {
|
||||||
while (cwCount >= 1.0) {
|
while (cwCount >= 1.0) {
|
||||||
if (cwEnvelope < 1.0) {
|
if (cwEnvelope < 1.0) {
|
||||||
cwEnvelope += 1. / (quisk_MicPlayback.sample_rate * 5e-3); // 5 milliseconds
|
cwEnvelope += 1. / (quisk_MicPlayback.sample_rate * 5e-3); // 5 milliseconds
|
||||||
@@ -1401,6 +1436,8 @@ void quisk_open_sound(void) // Called from GUI thread
|
|||||||
RawSamplePlayback.channel_I = 0;
|
RawSamplePlayback.channel_I = 0;
|
||||||
RawSamplePlayback.channel_Q = 1;
|
RawSamplePlayback.channel_Q = 1;
|
||||||
|
|
||||||
|
file_play_level = QuiskGetConfigDouble("file_play_level", 1.0);
|
||||||
|
|
||||||
set_num_channels (&Capture);
|
set_num_channels (&Capture);
|
||||||
set_num_channels (&quisk_Playback);
|
set_num_channels (&quisk_Playback);
|
||||||
set_num_channels (&MicCapture);
|
set_num_channels (&MicCapture);
|
||||||
@@ -1565,10 +1602,9 @@ PyObject * quisk_micplay_channels(PyObject * self, PyObject * args) // Called fr
|
|||||||
PyObject * quisk_set_sparams(PyObject * self, PyObject * args, PyObject * keywds)
|
PyObject * quisk_set_sparams(PyObject * self, PyObject * args, PyObject * keywds)
|
||||||
{ /* Call with keyword arguments ONLY; change local parameters */
|
{ /* Call with keyword arguments ONLY; change local parameters */
|
||||||
static char * kwlist[] = {"dc_remove_bw", "digital_output_level", "remote_control_slave", "remote_control_head",
|
static char * kwlist[] = {"dc_remove_bw", "digital_output_level", "remote_control_slave", "remote_control_head",
|
||||||
NULL} ;
|
"file_play_level", "multus_cw_samples", NULL} ;
|
||||||
|
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|idiidi", kwlist, &dc_remove_bw, &digital_output_level,
|
||||||
if (!PyArg_ParseTupleAndKeywords (args, keywds, "|idii", kwlist, &dc_remove_bw, &digital_output_level,
|
&remote_control_slave, &remote_control_head, &file_play_level, &multus_cw_samples))
|
||||||
&remote_control_slave, &remote_control_head))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF (Py_None);
|
Py_INCREF (Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
|
|||||||
+340
@@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
||||||
+640
@@ -0,0 +1,640 @@
|
|||||||
|
#
|
||||||
|
# Makefile for WDSP library
|
||||||
|
# This one creates libwdsp.so, the shared library.
|
||||||
|
#
|
||||||
|
|
||||||
|
LIBS=-lfftw3 -lpthread
|
||||||
|
|
||||||
|
#CFLAGS?= -pthread -O3 -D_GNU_SOURCE -Wno-parentheses
|
||||||
|
CFLAGS=-g -fPIC -O3 -D _GNU_SOURCE
|
||||||
|
|
||||||
|
FFTWINCLUDE=`pkg-config --cflags fftw3`
|
||||||
|
|
||||||
|
COMPILE=$(CC) $(CFLAGS) $(FFTWINCLUDE)
|
||||||
|
|
||||||
|
SOURCES= amd.c\
|
||||||
|
ammod.c\
|
||||||
|
amsq.c\
|
||||||
|
analyzer.c\
|
||||||
|
anf.c\
|
||||||
|
anr.c\
|
||||||
|
bandpass.c\
|
||||||
|
calcc.c\
|
||||||
|
calculus.c\
|
||||||
|
cblock.c\
|
||||||
|
cfcomp.c\
|
||||||
|
cfir.c\
|
||||||
|
channel.c\
|
||||||
|
compress.c\
|
||||||
|
delay.c\
|
||||||
|
dexp.c\
|
||||||
|
div.c\
|
||||||
|
eer.c\
|
||||||
|
emnr.c\
|
||||||
|
emph.c\
|
||||||
|
eq.c\
|
||||||
|
fcurve.c\
|
||||||
|
fir.c\
|
||||||
|
firmin.c\
|
||||||
|
fmd.c\
|
||||||
|
fmmod.c\
|
||||||
|
fmsq.c\
|
||||||
|
gain.c\
|
||||||
|
gen.c\
|
||||||
|
icfir.c\
|
||||||
|
iir.c\
|
||||||
|
iobuffs.c\
|
||||||
|
iqc.c\
|
||||||
|
linux_port.c\
|
||||||
|
lmath.c\
|
||||||
|
main.c\
|
||||||
|
meter.c\
|
||||||
|
meterlog10.c\
|
||||||
|
nbp.c\
|
||||||
|
nob.c\
|
||||||
|
nobII.c\
|
||||||
|
osctrl.c\
|
||||||
|
patchpanel.c\
|
||||||
|
resample.c\
|
||||||
|
rmatch.c\
|
||||||
|
RXA.c\
|
||||||
|
sender.c\
|
||||||
|
shift.c\
|
||||||
|
siphon.c\
|
||||||
|
slew.c\
|
||||||
|
snb.c\
|
||||||
|
ssql.c \
|
||||||
|
syncbuffs.c\
|
||||||
|
TXA.c\
|
||||||
|
utilities.c\
|
||||||
|
varsamp.c\
|
||||||
|
version.c\
|
||||||
|
wcpAGC.c\
|
||||||
|
wisdom.c\
|
||||||
|
zetahat.c
|
||||||
|
|
||||||
|
HEADERS=amd.h\
|
||||||
|
ammod.h\
|
||||||
|
amsq.h\
|
||||||
|
analyzer.h\
|
||||||
|
anf.h\
|
||||||
|
anr.h\
|
||||||
|
bandpass.h\
|
||||||
|
calcc.h\
|
||||||
|
calculus.h\
|
||||||
|
cblock.h\
|
||||||
|
cfcomp.h\
|
||||||
|
cfir.h\
|
||||||
|
channel.h\
|
||||||
|
comm.h\
|
||||||
|
compress.h\
|
||||||
|
delay.h\
|
||||||
|
dexp.h\
|
||||||
|
div.h\
|
||||||
|
eer.h\
|
||||||
|
emnr.h\
|
||||||
|
emph.h\
|
||||||
|
eq.h\
|
||||||
|
fastmath.h\
|
||||||
|
fcurve.h\
|
||||||
|
fir.h\
|
||||||
|
firmin.h \
|
||||||
|
fmd.h\
|
||||||
|
fmmod.h\
|
||||||
|
fmsq.h\
|
||||||
|
gain.h\
|
||||||
|
gen.h\
|
||||||
|
icfir.h\
|
||||||
|
iir.h\
|
||||||
|
iobuffs.h\
|
||||||
|
iqc.h\
|
||||||
|
linux_port.h\
|
||||||
|
lmath.h\
|
||||||
|
main.h\
|
||||||
|
meter.h\
|
||||||
|
meterlog10.h\
|
||||||
|
nbp.h\
|
||||||
|
nob.h\
|
||||||
|
nobII.h\
|
||||||
|
osctrl.h\
|
||||||
|
patchpanel.h\
|
||||||
|
resample.h\
|
||||||
|
resource.h\
|
||||||
|
rmatch.h\
|
||||||
|
RXA.h\
|
||||||
|
sender.h\
|
||||||
|
shift.h\
|
||||||
|
siphon.h\
|
||||||
|
slew.h\
|
||||||
|
snb.h\
|
||||||
|
ssql.h \
|
||||||
|
syncbuffs.h\
|
||||||
|
TXA.h\
|
||||||
|
utilities.h\
|
||||||
|
wcpAGC.h \
|
||||||
|
zetahat.h
|
||||||
|
|
||||||
|
OBJS=linux_port.o\
|
||||||
|
amd.o\
|
||||||
|
ammod.o\
|
||||||
|
amsq.o\
|
||||||
|
analyzer.o\
|
||||||
|
anf.o\
|
||||||
|
anr.o\
|
||||||
|
bandpass.o\
|
||||||
|
calcc.o\
|
||||||
|
calculus.o\
|
||||||
|
cblock.o\
|
||||||
|
cfcomp.o\
|
||||||
|
cfir.o\
|
||||||
|
channel.o\
|
||||||
|
compress.o\
|
||||||
|
delay.o\
|
||||||
|
dexp.o\
|
||||||
|
div.o\
|
||||||
|
eer.o\
|
||||||
|
emnr.o\
|
||||||
|
emph.o\
|
||||||
|
eq.o\
|
||||||
|
fcurve.o\
|
||||||
|
fir.o\
|
||||||
|
firmin.o\
|
||||||
|
fmd.o\
|
||||||
|
fmmod.o\
|
||||||
|
fmsq.o\
|
||||||
|
gain.o\
|
||||||
|
gen.o\
|
||||||
|
icfir.o\
|
||||||
|
iir.o\
|
||||||
|
iobuffs.o\
|
||||||
|
iqc.o\
|
||||||
|
lmath.o\
|
||||||
|
main.o\
|
||||||
|
meter.o\
|
||||||
|
meterlog10.o\
|
||||||
|
nbp.o\
|
||||||
|
nob.o\
|
||||||
|
nobII.o\
|
||||||
|
osctrl.o\
|
||||||
|
patchpanel.o\
|
||||||
|
resample.o\
|
||||||
|
rmatch.o\
|
||||||
|
RXA.o\
|
||||||
|
sender.o\
|
||||||
|
shift.o\
|
||||||
|
siphon.o\
|
||||||
|
slew.o\
|
||||||
|
snb.o\
|
||||||
|
ssql.o \
|
||||||
|
syncbuffs.o\
|
||||||
|
TXA.o\
|
||||||
|
utilities.o\
|
||||||
|
version.o\
|
||||||
|
varsamp.o\
|
||||||
|
wcpAGC.o\
|
||||||
|
wisdom.o\
|
||||||
|
zetahat.o
|
||||||
|
|
||||||
|
libwdsp.so: $(OBJS)
|
||||||
|
$(CC) -shared -o libwdsp.so $(OBJS) $(LIBS)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(COMPILE) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f libwdsp.so *.o
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
#
|
||||||
|
# What follows is automatically generated by the "makedepend" program
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
RXA.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
RXA.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
RXA.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
RXA.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
RXA.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
RXA.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
RXA.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
TXA.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
TXA.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
TXA.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
TXA.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
TXA.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
TXA.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
TXA.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
amd.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
amd.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
amd.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
amd.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
amd.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
amd.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
amd.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
ammod.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
ammod.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
ammod.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
ammod.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
ammod.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
ammod.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
ammod.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
amsq.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
amsq.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
amsq.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
amsq.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
amsq.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
amsq.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
amsq.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
analyzer.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
analyzer.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
analyzer.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
analyzer.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
analyzer.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
analyzer.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
analyzer.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
analyzer.o: utilities.h
|
||||||
|
anf.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
anf.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
anf.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
anf.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
anf.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
anf.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
anf.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
anr.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
anr.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
anr.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
anr.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
anr.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
anr.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
anr.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
bandpass.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
bandpass.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
bandpass.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
bandpass.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
bandpass.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
bandpass.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
bandpass.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
bandpass.o: utilities.h
|
||||||
|
calcc.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
calcc.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
calcc.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
calcc.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
calcc.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
calcc.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
calcc.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
cblock.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
cblock.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
cblock.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
cblock.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
cblock.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
cblock.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
cblock.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
cfcomp.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
cfcomp.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
cfcomp.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
cfcomp.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
cfcomp.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
cfcomp.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
cfcomp.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
cfir.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
cfir.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
cfir.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
cfir.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
cfir.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
cfir.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
cfir.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
channel.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
channel.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
channel.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
channel.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
channel.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
channel.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
channel.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
channel.o: utilities.h
|
||||||
|
comm.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
comm.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
comm.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
comm.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
comm.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
comm.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
comm.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
compress.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
compress.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
compress.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
compress.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
compress.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
compress.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
compress.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
compress.o: utilities.h
|
||||||
|
delay.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
delay.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
delay.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
delay.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
delay.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
delay.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
delay.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
dexp.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
dexp.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
dexp.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
dexp.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
dexp.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
dexp.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
dexp.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
div.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
div.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
div.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
div.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
div.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
div.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
div.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
eer.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
eer.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
eer.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
eer.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
eer.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
eer.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
eer.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
emnr.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
emnr.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
emnr.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
emnr.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
emnr.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
emnr.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
emnr.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h calculus.h
|
||||||
|
emph.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
emph.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
emph.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
emph.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
emph.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
emph.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
emph.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
eq.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
eq.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
eq.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
eq.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
eq.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
eq.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
eq.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
fcurve.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
fcurve.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
fcurve.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
fcurve.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
fcurve.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
fcurve.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
fcurve.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
fir.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
fir.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
fir.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
fir.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
fir.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
fir.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
fir.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
firmin.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
firmin.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
firmin.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
firmin.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
firmin.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
firmin.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
firmin.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
fmd.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
fmd.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
fmd.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
fmd.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
fmd.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
fmd.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
fmd.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
fmmod.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
fmmod.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
fmmod.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
fmmod.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
fmmod.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
fmmod.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
fmmod.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
fmsq.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
fmsq.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
fmsq.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
fmsq.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
fmsq.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
fmsq.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
fmsq.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
gain.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
gain.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
gain.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
gain.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
gain.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
gain.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
gain.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
gen.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
gen.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
gen.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
gen.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
gen.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
gen.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
gen.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
icfir.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
icfir.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
icfir.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
icfir.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
icfir.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
icfir.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
icfir.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
iir.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
iir.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
iir.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
iir.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
iir.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
iir.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
iir.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
iobuffs.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
iobuffs.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
iobuffs.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
iobuffs.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
iobuffs.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
iobuffs.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
iobuffs.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
iobuffs.o: utilities.h
|
||||||
|
iqc.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
iqc.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
iqc.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
iqc.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
iqc.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
iqc.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
iqc.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
linux_port.o: linux_port.h comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h
|
||||||
|
linux_port.o: bandpass.h firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h
|
||||||
|
linux_port.o: cfir.h channel.h compress.h dexp.h div.h eer.h emnr.h emph.h
|
||||||
|
linux_port.o: eq.h fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h
|
||||||
|
linux_port.o: gen.h icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h
|
||||||
|
linux_port.o: nob.h nobII.h osctrl.h patchpanel.h resample.h rmatch.h
|
||||||
|
linux_port.o: varsamp.h RXA.h sender.h shift.h siphon.h slew.h snb.h ssql.h
|
||||||
|
linux_port.o: syncbuffs.h TXA.h utilities.h
|
||||||
|
lmath.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
lmath.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
lmath.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
lmath.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
lmath.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
lmath.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
lmath.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
main.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
main.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
main.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
main.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
main.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
main.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
main.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
meter.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
meter.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
meter.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
meter.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
meter.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
meter.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
meter.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
meterlog10.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
meterlog10.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
meterlog10.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
meterlog10.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
meterlog10.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
meterlog10.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h
|
||||||
|
meterlog10.o: RXA.h sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h
|
||||||
|
meterlog10.o: TXA.h utilities.h
|
||||||
|
nbp.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
nbp.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
nbp.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
nbp.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
nbp.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
nbp.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
nbp.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
nob.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
nob.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
nob.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
nob.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
nob.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
nob.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
nob.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
nobII.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
nobII.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
nobII.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
nobII.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
nobII.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
nobII.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
nobII.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
osctrl.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
osctrl.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
osctrl.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
osctrl.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
osctrl.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
osctrl.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
osctrl.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
patchpanel.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
patchpanel.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
patchpanel.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
patchpanel.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
patchpanel.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
patchpanel.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h
|
||||||
|
patchpanel.o: RXA.h sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h
|
||||||
|
patchpanel.o: TXA.h utilities.h
|
||||||
|
resample.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
resample.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
resample.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
resample.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
resample.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
resample.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
resample.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
resample.o: utilities.h
|
||||||
|
rmatch.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
rmatch.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
rmatch.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
rmatch.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
rmatch.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
rmatch.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
rmatch.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
sender.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
sender.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
sender.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
sender.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
sender.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
sender.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
sender.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
shift.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
shift.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
shift.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
shift.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
shift.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
shift.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
shift.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
siphon.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
siphon.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
siphon.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
siphon.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
siphon.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
siphon.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
siphon.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
slew.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
slew.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
slew.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
slew.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
slew.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
slew.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
slew.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
snb.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h firmin.h
|
||||||
|
snb.o: calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h compress.h
|
||||||
|
snb.o: dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h iir.h
|
||||||
|
snb.o: wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h main.h
|
||||||
|
snb.o: meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
snb.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
snb.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
ssql.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
ssql.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
ssql.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h fmd.h
|
||||||
|
ssql.o: iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h iqc.h
|
||||||
|
ssql.o: main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h patchpanel.h
|
||||||
|
ssql.o: resample.h rmatch.h varsamp.h RXA.h sender.h shift.h siphon.h slew.h
|
||||||
|
ssql.o: snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
syncbuffs.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
syncbuffs.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
syncbuffs.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
syncbuffs.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
syncbuffs.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
syncbuffs.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h
|
||||||
|
syncbuffs.o: RXA.h sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h
|
||||||
|
syncbuffs.o: TXA.h utilities.h
|
||||||
|
utilities.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
utilities.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
utilities.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
utilities.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
utilities.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
utilities.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h
|
||||||
|
utilities.o: RXA.h sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h
|
||||||
|
utilities.o: TXA.h utilities.h
|
||||||
|
varsamp.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
varsamp.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
varsamp.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
varsamp.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
varsamp.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
varsamp.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
varsamp.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
varsamp.o: utilities.h
|
||||||
|
version.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
version.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h
|
||||||
|
version.o: channel.h compress.h dexp.h div.h eer.h emnr.h emph.h eq.h
|
||||||
|
version.o: fcurve.h fir.h fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h
|
||||||
|
version.o: icfir.h iobuffs.h iqc.h main.h meter.h meterlog10.h nbp.h nob.h
|
||||||
|
version.o: nobII.h osctrl.h patchpanel.h resample.h rmatch.h varsamp.h RXA.h
|
||||||
|
version.o: sender.h shift.h siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h
|
||||||
|
version.o: utilities.h
|
||||||
|
wcpAGC.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
wcpAGC.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
wcpAGC.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
wcpAGC.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
wcpAGC.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
wcpAGC.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
wcpAGC.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
|
wisdom.o: comm.h amd.h ammod.h amsq.h analyzer.h anf.h anr.h bandpass.h
|
||||||
|
wisdom.o: firmin.h calcc.h delay.h lmath.h cblock.h cfcomp.h cfir.h channel.h
|
||||||
|
wisdom.o: compress.h dexp.h div.h eer.h emnr.h emph.h eq.h fcurve.h fir.h
|
||||||
|
wisdom.o: fmd.h iir.h wcpAGC.h fmmod.h fmsq.h gain.h gen.h icfir.h iobuffs.h
|
||||||
|
wisdom.o: iqc.h main.h meter.h meterlog10.h nbp.h nob.h nobII.h osctrl.h
|
||||||
|
wisdom.o: patchpanel.h resample.h rmatch.h varsamp.h RXA.h sender.h shift.h
|
||||||
|
wisdom.o: siphon.h slew.h snb.h ssql.h syncbuffs.h TXA.h utilities.h
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# wdsp
|
||||||
|
WDSP by Warren Pratt, NR0V
|
||||||
|
DSP Library originally written for Windows
|
||||||
|
Ported to Linux and Android by John Melton g0orx/n6lyt
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
To use this Linux library with Quisk, enter "make". It supports the NR2 and SNB features.
|
||||||
|
The resulting libwdsp.so file is used in-place. No installation is necessary.
|
||||||
|
For Windows, the libwdsp.dll file is included in the quisk directory.
|
||||||
|
|
||||||
|
The WDSP library was originally written for Windows by Warren Pratt, NR0V.
|
||||||
|
John Melton, g0orx/n6lyt, contributed a Linux port.
|
||||||
|
Christian, DL1YCF, contributed further improvements.
|
||||||
+958
@@ -0,0 +1,958 @@
|
|||||||
|
/* RXA.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2014, 2015, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
struct _rxa rxa[MAX_CHANNELS];
|
||||||
|
|
||||||
|
void create_rxa (int channel)
|
||||||
|
{
|
||||||
|
rxa[channel].mode = RXA_LSB;
|
||||||
|
rxa[channel].inbuff = (double *) malloc0 (1 * ch[channel].dsp_insize * sizeof (complex));
|
||||||
|
rxa[channel].outbuff = (double *) malloc0 (1 * ch[channel].dsp_outsize * sizeof (complex));
|
||||||
|
rxa[channel].midbuff = (double *) malloc0 (2 * ch[channel].dsp_size * sizeof (complex));
|
||||||
|
|
||||||
|
// shift to select a slice of spectrum
|
||||||
|
rxa[channel].shift.p = create_shift (
|
||||||
|
1, // run
|
||||||
|
ch[channel].dsp_insize, // input buffer size
|
||||||
|
rxa[channel].inbuff, // pointer to input buffer
|
||||||
|
rxa[channel].inbuff, // pointer to output buffer
|
||||||
|
ch[channel].in_rate, // samplerate
|
||||||
|
0.0); // amount to shift (Hz)
|
||||||
|
|
||||||
|
// resample to dsp rate for main processing
|
||||||
|
rxa[channel].rsmpin.p = create_resample (
|
||||||
|
0, // run - will be turned ON below if needed
|
||||||
|
ch[channel].dsp_insize, // input buffer size
|
||||||
|
rxa[channel].inbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].in_rate, // input samplerate
|
||||||
|
ch[channel].dsp_rate, // output samplerate
|
||||||
|
0.0, // select cutoff automatically
|
||||||
|
0, // select ncoef automatically
|
||||||
|
1.0); // gain
|
||||||
|
|
||||||
|
// signal generator
|
||||||
|
rxa[channel].gen0.p = create_gen (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // input buffer
|
||||||
|
rxa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
2); // mode
|
||||||
|
|
||||||
|
// adc (input) meter
|
||||||
|
rxa[channel].adcmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to another 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
rxa[channel].meter, // result vector
|
||||||
|
rxa[channel].pmtupdate, // locks for meter access
|
||||||
|
RXA_ADC_AV, // index for average value
|
||||||
|
RXA_ADC_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
// notch database
|
||||||
|
rxa[channel].ndb.p = create_notchdb (
|
||||||
|
0, // master run for all nbp's
|
||||||
|
1024); // max number of notches
|
||||||
|
|
||||||
|
// notched bandpass
|
||||||
|
rxa[channel].nbp0.p = create_nbp (
|
||||||
|
1, // run, always runs
|
||||||
|
0, // run the notches
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
-4150.0, // lower filter frequency
|
||||||
|
-150.0, // upper filter frequency
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0, // wintype
|
||||||
|
1.0, // gain
|
||||||
|
1, // auto-increase notch width
|
||||||
|
1025, // max number of passbands
|
||||||
|
&rxa[channel].ndb.p); // addr of database pointer
|
||||||
|
|
||||||
|
// bandpass for snba
|
||||||
|
rxa[channel].bpsnba.p = create_bpsnba (
|
||||||
|
0, // bpsnba run flag
|
||||||
|
0, // run the notches
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
rxa[channel].midbuff, // input buffer
|
||||||
|
rxa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
+ 250.0, // abs value of cutoff nearest zero
|
||||||
|
+ 5700.0, // abs value of cutoff farthest zero
|
||||||
|
- 5700.0, // current low frequency
|
||||||
|
- 250.0, // current high frequency
|
||||||
|
0, // wintype
|
||||||
|
1.0, // gain
|
||||||
|
1, // auto-increase notch width
|
||||||
|
1025, // max number of passbands
|
||||||
|
&rxa[channel].ndb.p); // addr of database pointer
|
||||||
|
|
||||||
|
// send spectrum display
|
||||||
|
rxa[channel].sender.p = create_sender (
|
||||||
|
channel == 0, // run
|
||||||
|
0, // flag
|
||||||
|
0, // mode
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
0, // arg0 <- disp
|
||||||
|
1, // arg1 <- ss
|
||||||
|
0, // arg2 <- LO
|
||||||
|
0); // arg3 <- NOT USED
|
||||||
|
|
||||||
|
// S-meter
|
||||||
|
rxa[channel].smeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to another 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
rxa[channel].meter, // result vector
|
||||||
|
rxa[channel].pmtupdate, // locks for meter access
|
||||||
|
RXA_S_AV, // index for average value
|
||||||
|
RXA_S_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
// AM squelch
|
||||||
|
rxa[channel].amsq.p = create_amsq (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to signal input buffer used by xamsq
|
||||||
|
rxa[channel].midbuff, // pointer to signal output buffer used by xamsq
|
||||||
|
rxa[channel].midbuff, // pointer to trigger buffer that xamsqcap will capture
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.010, // time constant for averaging signal level
|
||||||
|
0.070, // signal up transition time
|
||||||
|
0.070, // signal down transition time
|
||||||
|
0.009, // signal level to initiate tail
|
||||||
|
0.010, // signal level to initiate unmute
|
||||||
|
0.000, // minimum tail length
|
||||||
|
1.500, // maximum tail length
|
||||||
|
0.0); // muted gain
|
||||||
|
|
||||||
|
// AM demod
|
||||||
|
rxa[channel].amd.p = create_amd (
|
||||||
|
0, // run - OFF by default
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
0, // mode: 0->AM, 1->SAM
|
||||||
|
1, // levelfade: 0->OFF, 1->ON
|
||||||
|
0, // sideband mode: 0->OFF
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
-2000.0, // minimum lock frequency
|
||||||
|
+2000.0, // maximum lock frequency
|
||||||
|
1.0, // zeta
|
||||||
|
250.0, // omegaN
|
||||||
|
0.02, // tauR
|
||||||
|
1.4); // tauI
|
||||||
|
|
||||||
|
// FM demod
|
||||||
|
rxa[channel].fmd.p = create_fmd (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
5000.0, // deviation
|
||||||
|
300.0, // f_low
|
||||||
|
3000.0, // f_high
|
||||||
|
-8000.0, // fmin
|
||||||
|
+8000.0, // fmax
|
||||||
|
1.0, // zeta
|
||||||
|
20000.0, // omegaN
|
||||||
|
0.02, // tau - for dc removal
|
||||||
|
0.5, // audio gain
|
||||||
|
1, // run tone filter
|
||||||
|
254.1, // ctcss frequency
|
||||||
|
max(2048, ch[channel].dsp_size), // # coefs for de-emphasis filter
|
||||||
|
0, // min phase flag for de-emphasis filter
|
||||||
|
max(2048, ch[channel].dsp_size), // # coefs for audio cutoff filter
|
||||||
|
0); // min phase flag for audio cutoff filter
|
||||||
|
|
||||||
|
// FM squelch
|
||||||
|
rxa[channel].fmsq.p = create_fmsq (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input signal buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output signal buffer
|
||||||
|
rxa[channel].fmd.p->audio, // pointer to trigger buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
5000.0, // cutoff freq for noise filter (Hz)
|
||||||
|
&rxa[channel].fmd.p->pllpole, // pointer to pole frequency of the fmd pll (Hz)
|
||||||
|
0.100, // delay time after channel flush
|
||||||
|
0.001, // tau for noise averaging
|
||||||
|
0.100, // tau for long noise averaging
|
||||||
|
0.050, // signal up transition time
|
||||||
|
0.010, // signal down transition time
|
||||||
|
0.750, // noise level to initiate tail
|
||||||
|
0.562, // noise level to initiate unmute
|
||||||
|
0.000, // minimum tail time
|
||||||
|
1.200, // maximum tail time
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients for noise filter
|
||||||
|
0); // minimum phase flag
|
||||||
|
|
||||||
|
// snba
|
||||||
|
rxa[channel].snba.p = create_snba (
|
||||||
|
0, // run
|
||||||
|
rxa[channel].midbuff, // input buffer
|
||||||
|
rxa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // input / output sample rate
|
||||||
|
12000, // internal processing sample rate
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
4, // overlap factor to use
|
||||||
|
256, // frame size to use; sized for 12K rate
|
||||||
|
64, // asize
|
||||||
|
2, // npasses
|
||||||
|
8.0, // k1
|
||||||
|
20.0, // k2
|
||||||
|
10, // b
|
||||||
|
2, // pre
|
||||||
|
2, // post
|
||||||
|
0.5, // pmultmin
|
||||||
|
200.0, // output resampler low cutoff
|
||||||
|
5400.0); // output resampler high cutoff
|
||||||
|
|
||||||
|
// EQ
|
||||||
|
{
|
||||||
|
double default_F[11] = {0.0, 32.0, 63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0, 8000.0, 16000.0};
|
||||||
|
//double default_G[11] = {0.0, -12.0, -12.0, -12.0, -1.0, +1.0, +4.0, +9.0, +12.0, -10.0, -10.0};
|
||||||
|
double default_G[11] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
||||||
|
rxa[channel].eqp.p = create_eqp (
|
||||||
|
0, // run - OFF by default
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
10, // number of frequencies
|
||||||
|
default_F, // frequency vector
|
||||||
|
default_G, // gain vector
|
||||||
|
0, // cutoff mode
|
||||||
|
0, // wintype
|
||||||
|
ch[channel].dsp_rate); // sample rate
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANF
|
||||||
|
rxa[channel].anf.p = create_anf (
|
||||||
|
0, // run - OFF by default
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ANF_DLINE_SIZE, // dline_size
|
||||||
|
64, // taps
|
||||||
|
16, // delay
|
||||||
|
0.0001, // two_mu
|
||||||
|
0.1, // gamma
|
||||||
|
1.0, // lidx
|
||||||
|
0.0, // lidx_min
|
||||||
|
200.0, // lidx_max
|
||||||
|
6.25e-12, // ngamma
|
||||||
|
6.25e-10, // den_mult
|
||||||
|
1.0, // lincr
|
||||||
|
3.0); // ldecr
|
||||||
|
|
||||||
|
// ANR
|
||||||
|
rxa[channel].anr.p = create_anr (
|
||||||
|
0, // run - OFF by default
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ANR_DLINE_SIZE, // dline_size
|
||||||
|
64, // taps
|
||||||
|
16, // delay
|
||||||
|
0.0001, // two_mu
|
||||||
|
0.1, // gamma
|
||||||
|
120.0, // lidx
|
||||||
|
120.0, // lidx_min
|
||||||
|
200.0, // lidx_max
|
||||||
|
0.001, // ngamma
|
||||||
|
6.25e-10, // den_mult
|
||||||
|
1.0, // lincr
|
||||||
|
3.0); // ldecr
|
||||||
|
|
||||||
|
|
||||||
|
// EMNR
|
||||||
|
rxa[channel].emnr.p = create_emnr (
|
||||||
|
0, // run
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // input buffer
|
||||||
|
rxa[channel].midbuff, // output buffer
|
||||||
|
4096, // FFT size
|
||||||
|
4, // overlap
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0, // window type
|
||||||
|
1.0, // gain
|
||||||
|
2, // gain method
|
||||||
|
0, // npe_method
|
||||||
|
1); // ae_run
|
||||||
|
|
||||||
|
// AGC
|
||||||
|
rxa[channel].agc.p = create_wcpagc (
|
||||||
|
1, // run
|
||||||
|
3, // mode
|
||||||
|
1, // peakmode = envelope
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.001, // tau_attack
|
||||||
|
0.250, // tau_decay
|
||||||
|
4, // n_tau
|
||||||
|
10000.0, // max_gain
|
||||||
|
1.5, // var_gain
|
||||||
|
1000.0, // fixed_gain
|
||||||
|
1.0, // max_input
|
||||||
|
1.0, // out_target
|
||||||
|
0.250, // tau_fast_backaverage
|
||||||
|
0.005, // tau_fast_decay
|
||||||
|
5.0, // pop_ratio
|
||||||
|
1, // hang_enable
|
||||||
|
0.500, // tau_hang_backmult
|
||||||
|
0.250, // hangtime
|
||||||
|
0.250, // hang_thresh
|
||||||
|
0.100); // tau_hang_decay
|
||||||
|
|
||||||
|
// agc gain meter
|
||||||
|
rxa[channel].agcmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to another 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
rxa[channel].meter, // result vector
|
||||||
|
rxa[channel].pmtupdate, // locks for meter access
|
||||||
|
RXA_AGC_AV, // index for average value
|
||||||
|
RXA_AGC_PK, // index for peak value
|
||||||
|
RXA_AGC_GAIN, // index for gain value
|
||||||
|
&rxa[channel].agc.p->gain); // pointer for gain computation
|
||||||
|
|
||||||
|
// bandpass filter
|
||||||
|
rxa[channel].bp1.p = create_bandpass (
|
||||||
|
1, // run - used only with ( AM || ANF || ANR || EMNR)
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
||||||
|
0, // flag for minimum phase
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
-4150.0, // lower filter frequency
|
||||||
|
-150.0, // upper filter frequency
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
1, // wintype
|
||||||
|
1.0); // gain
|
||||||
|
|
||||||
|
// pull phase & scope display data
|
||||||
|
rxa[channel].sip1.p = create_siphon (
|
||||||
|
1, // run - needed only for phase display
|
||||||
|
0, // position
|
||||||
|
0, // mode
|
||||||
|
0, // disp
|
||||||
|
ch[channel].dsp_size, // size of input buffer
|
||||||
|
rxa[channel].midbuff, // input buffer
|
||||||
|
4096, // number of samples to store
|
||||||
|
4096, // fft size for spectrum
|
||||||
|
0); // specmode
|
||||||
|
|
||||||
|
// carrier block
|
||||||
|
rxa[channel].cbl.p = create_cbl (
|
||||||
|
0, // run - needed only if set to ON
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
0, // mode
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.02); // tau
|
||||||
|
|
||||||
|
// peaking filter
|
||||||
|
rxa[channel].speak.p = create_speak (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size,
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
600.0, // center frequency
|
||||||
|
100.0, // bandwidth
|
||||||
|
2.0, // gain
|
||||||
|
4, // number of stages
|
||||||
|
1); // design
|
||||||
|
|
||||||
|
// multiple peak filter
|
||||||
|
{
|
||||||
|
int def_enable[2] = {1, 1};
|
||||||
|
double def_freq[2] = {2125.0, 2295.0};
|
||||||
|
double def_bw[2] = {75.0, 75.0};
|
||||||
|
double def_gain[2] = {1.0, 1.0};
|
||||||
|
rxa[channel].mpeak.p = create_mpeak (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
2, // number of peaking filters
|
||||||
|
def_enable, // enable vector
|
||||||
|
def_freq, // frequency vector
|
||||||
|
def_bw, // bandwidth vector
|
||||||
|
def_gain, // gain vector
|
||||||
|
4 ); // number of stages
|
||||||
|
}
|
||||||
|
|
||||||
|
// syllabic squelch
|
||||||
|
rxa[channel].ssql.p = create_ssql(
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.070, // signal up transition time
|
||||||
|
0.070, // signal down transition time
|
||||||
|
0.0, // muted gain
|
||||||
|
0.1, // mute time-constant
|
||||||
|
0.1, // unmute time-constant
|
||||||
|
0.08, // window threshold
|
||||||
|
0.8197, // trigger threshold
|
||||||
|
2400, // ring size for f_to_v converter
|
||||||
|
2000.0); // max freq for f_to_v converter
|
||||||
|
|
||||||
|
// patchpanel
|
||||||
|
rxa[channel].panel.p = create_panel (
|
||||||
|
channel, // channel number
|
||||||
|
1, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].midbuff, // pointer to output buffer
|
||||||
|
4.0, // gain1
|
||||||
|
1.0, // gain2I
|
||||||
|
1.0, // gain2Q
|
||||||
|
3, // 3 for I and Q
|
||||||
|
0); // no copy
|
||||||
|
|
||||||
|
// resample
|
||||||
|
rxa[channel].rsmpout.p = create_resample (
|
||||||
|
0, // run - will be turned ON below if needed
|
||||||
|
ch[channel].dsp_size, // input buffer size
|
||||||
|
rxa[channel].midbuff, // pointer to input buffer
|
||||||
|
rxa[channel].outbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // input sample rate
|
||||||
|
ch[channel].out_rate, // output sample rate
|
||||||
|
0.0, // select cutoff automatically
|
||||||
|
0, // select ncoef automatically
|
||||||
|
1.0); // gain
|
||||||
|
|
||||||
|
// turn OFF / ON resamplers as needed
|
||||||
|
RXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_rxa (int channel)
|
||||||
|
{
|
||||||
|
destroy_resample (rxa[channel].rsmpout.p);
|
||||||
|
destroy_panel (rxa[channel].panel.p);
|
||||||
|
destroy_ssql (rxa[channel].ssql.p);
|
||||||
|
destroy_mpeak (rxa[channel].mpeak.p);
|
||||||
|
destroy_speak (rxa[channel].speak.p);
|
||||||
|
destroy_cbl (rxa[channel].cbl.p);
|
||||||
|
destroy_siphon (rxa[channel].sip1.p);
|
||||||
|
destroy_bandpass (rxa[channel].bp1.p);
|
||||||
|
destroy_meter (rxa[channel].agcmeter.p);
|
||||||
|
destroy_wcpagc (rxa[channel].agc.p);
|
||||||
|
destroy_emnr (rxa[channel].emnr.p);
|
||||||
|
destroy_anr (rxa[channel].anr.p);
|
||||||
|
destroy_anf (rxa[channel].anf.p);
|
||||||
|
destroy_eqp (rxa[channel].eqp.p);
|
||||||
|
destroy_snba (rxa[channel].snba.p);
|
||||||
|
destroy_fmsq (rxa[channel].fmsq.p);
|
||||||
|
destroy_fmd (rxa[channel].fmd.p);
|
||||||
|
destroy_amd (rxa[channel].amd.p);
|
||||||
|
destroy_amsq (rxa[channel].amsq.p);
|
||||||
|
destroy_meter (rxa[channel].smeter.p);
|
||||||
|
destroy_sender (rxa[channel].sender.p);
|
||||||
|
destroy_bpsnba (rxa[channel].bpsnba.p);
|
||||||
|
destroy_nbp (rxa[channel].nbp0.p);
|
||||||
|
destroy_notchdb (rxa[channel].ndb.p);
|
||||||
|
destroy_meter (rxa[channel].adcmeter.p);
|
||||||
|
destroy_gen (rxa[channel].gen0.p);
|
||||||
|
destroy_resample (rxa[channel].rsmpin.p);
|
||||||
|
destroy_shift (rxa[channel].shift.p);
|
||||||
|
_aligned_free (rxa[channel].midbuff);
|
||||||
|
_aligned_free (rxa[channel].outbuff);
|
||||||
|
_aligned_free (rxa[channel].inbuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_rxa (int channel)
|
||||||
|
{
|
||||||
|
memset (rxa[channel].inbuff, 0, 1 * ch[channel].dsp_insize * sizeof (complex));
|
||||||
|
memset (rxa[channel].outbuff, 0, 1 * ch[channel].dsp_outsize * sizeof (complex));
|
||||||
|
memset (rxa[channel].midbuff, 0, 2 * ch[channel].dsp_size * sizeof (complex));
|
||||||
|
flush_shift (rxa[channel].shift.p);
|
||||||
|
flush_resample (rxa[channel].rsmpin.p);
|
||||||
|
flush_gen (rxa[channel].gen0.p);
|
||||||
|
flush_meter (rxa[channel].adcmeter.p);
|
||||||
|
flush_nbp (rxa[channel].nbp0.p);
|
||||||
|
flush_bpsnba (rxa[channel].bpsnba.p);
|
||||||
|
flush_sender (rxa[channel].sender.p);
|
||||||
|
flush_meter (rxa[channel].smeter.p);
|
||||||
|
flush_amsq (rxa[channel].amsq.p);
|
||||||
|
flush_amd (rxa[channel].amd.p);
|
||||||
|
flush_fmd (rxa[channel].fmd.p);
|
||||||
|
flush_fmsq (rxa[channel].fmsq.p);
|
||||||
|
flush_snba (rxa[channel].snba.p);
|
||||||
|
flush_eqp (rxa[channel].eqp.p);
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
flush_emnr (rxa[channel].emnr.p);
|
||||||
|
flush_wcpagc (rxa[channel].agc.p);
|
||||||
|
flush_meter (rxa[channel].agcmeter.p);
|
||||||
|
flush_bandpass (rxa[channel].bp1.p);
|
||||||
|
flush_siphon (rxa[channel].sip1.p);
|
||||||
|
flush_cbl (rxa[channel].cbl.p);
|
||||||
|
flush_speak (rxa[channel].speak.p);
|
||||||
|
flush_mpeak (rxa[channel].mpeak.p);
|
||||||
|
flush_ssql (rxa[channel].ssql.p);
|
||||||
|
flush_panel (rxa[channel].panel.p);
|
||||||
|
flush_resample (rxa[channel].rsmpout.p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xrxa (int channel)
|
||||||
|
{
|
||||||
|
xshift (rxa[channel].shift.p);
|
||||||
|
xresample (rxa[channel].rsmpin.p);
|
||||||
|
xgen (rxa[channel].gen0.p);
|
||||||
|
xmeter (rxa[channel].adcmeter.p);
|
||||||
|
xbpsnbain (rxa[channel].bpsnba.p, 0);
|
||||||
|
xnbp (rxa[channel].nbp0.p, 0);
|
||||||
|
xmeter (rxa[channel].smeter.p);
|
||||||
|
xsender (rxa[channel].sender.p);
|
||||||
|
xamsqcap (rxa[channel].amsq.p);
|
||||||
|
xbpsnbaout (rxa[channel].bpsnba.p, 0);
|
||||||
|
xamd (rxa[channel].amd.p);
|
||||||
|
xfmd (rxa[channel].fmd.p);
|
||||||
|
xfmsq (rxa[channel].fmsq.p);
|
||||||
|
xbpsnbain (rxa[channel].bpsnba.p, 1);
|
||||||
|
xbpsnbaout (rxa[channel].bpsnba.p, 1);
|
||||||
|
xsnba (rxa[channel].snba.p);
|
||||||
|
xeqp (rxa[channel].eqp.p);
|
||||||
|
xanf (rxa[channel].anf.p, 0);
|
||||||
|
xanr (rxa[channel].anr.p, 0);
|
||||||
|
xemnr (rxa[channel].emnr.p, 0);
|
||||||
|
xbandpass (rxa[channel].bp1.p, 0);
|
||||||
|
xwcpagc (rxa[channel].agc.p);
|
||||||
|
xanf (rxa[channel].anf.p, 1);
|
||||||
|
xanr (rxa[channel].anr.p, 1);
|
||||||
|
xemnr (rxa[channel].emnr.p, 1);
|
||||||
|
xbandpass (rxa[channel].bp1.p, 1);
|
||||||
|
xmeter (rxa[channel].agcmeter.p);
|
||||||
|
xsiphon (rxa[channel].sip1.p, 0);
|
||||||
|
xcbl (rxa[channel].cbl.p);
|
||||||
|
xspeak (rxa[channel].speak.p);
|
||||||
|
xmpeak (rxa[channel].mpeak.p);
|
||||||
|
xssql (rxa[channel].ssql.p);
|
||||||
|
xpanel (rxa[channel].panel.p);
|
||||||
|
xamsq (rxa[channel].amsq.p);
|
||||||
|
xresample (rxa[channel].rsmpout.p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInputSamplerate_rxa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (rxa[channel].inbuff);
|
||||||
|
rxa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
// shift
|
||||||
|
setBuffers_shift (rxa[channel].shift.p, rxa[channel].inbuff, rxa[channel].inbuff);
|
||||||
|
setSize_shift (rxa[channel].shift.p, ch[channel].dsp_insize);
|
||||||
|
setSamplerate_shift (rxa[channel].shift.p, ch[channel].in_rate);
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpin.p, rxa[channel].inbuff, rxa[channel].midbuff);
|
||||||
|
setSize_resample (rxa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
setInRate_resample (rxa[channel].rsmpin.p, ch[channel].in_rate);
|
||||||
|
RXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOutputSamplerate_rxa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (rxa[channel].outbuff);
|
||||||
|
rxa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpout.p, rxa[channel].midbuff, rxa[channel].outbuff);
|
||||||
|
setOutRate_resample (rxa[channel].rsmpout.p, ch[channel].out_rate);
|
||||||
|
RXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDSPSamplerate_rxa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (rxa[channel].inbuff);
|
||||||
|
rxa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
_aligned_free (rxa[channel].outbuff);
|
||||||
|
rxa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// shift
|
||||||
|
setBuffers_shift (rxa[channel].shift.p, rxa[channel].inbuff, rxa[channel].inbuff);
|
||||||
|
setSize_shift (rxa[channel].shift.p, ch[channel].dsp_insize);
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpin.p, rxa[channel].inbuff, rxa[channel].midbuff);
|
||||||
|
setSize_resample (rxa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
setOutRate_resample (rxa[channel].rsmpin.p, ch[channel].dsp_rate);
|
||||||
|
// dsp_rate blocks
|
||||||
|
setSamplerate_gen (rxa[channel].gen0.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (rxa[channel].adcmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_nbp (rxa[channel].nbp0.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_bpsnba (rxa[channel].bpsnba.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (rxa[channel].smeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_sender (rxa[channel].sender.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_amsq (rxa[channel].amsq.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_amd (rxa[channel].amd.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_fmd (rxa[channel].fmd.p, ch[channel].dsp_rate);
|
||||||
|
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
||||||
|
setSamplerate_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_snba (rxa[channel].snba.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_eqp (rxa[channel].eqp.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_anf (rxa[channel].anf.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_anr (rxa[channel].anr.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_emnr (rxa[channel].emnr.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_bandpass (rxa[channel].bp1.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_wcpagc (rxa[channel].agc.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (rxa[channel].agcmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_siphon (rxa[channel].sip1.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_cbl (rxa[channel].cbl.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_speak (rxa[channel].speak.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_mpeak (rxa[channel].mpeak.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_ssql (rxa[channel].ssql.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_panel (rxa[channel].panel.p, ch[channel].dsp_rate);
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpout.p, rxa[channel].midbuff, rxa[channel].outbuff);
|
||||||
|
setInRate_resample (rxa[channel].rsmpout.p, ch[channel].dsp_rate);
|
||||||
|
RXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDSPBuffsize_rxa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free(rxa[channel].inbuff);
|
||||||
|
rxa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
_aligned_free (rxa[channel].midbuff);
|
||||||
|
rxa[channel].midbuff = (double *)malloc0(2 * ch[channel].dsp_size * sizeof(complex));
|
||||||
|
_aligned_free (rxa[channel].outbuff);
|
||||||
|
rxa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// shift
|
||||||
|
setBuffers_shift (rxa[channel].shift.p, rxa[channel].inbuff, rxa[channel].inbuff);
|
||||||
|
setSize_shift (rxa[channel].shift.p, ch[channel].dsp_insize);
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpin.p, rxa[channel].inbuff, rxa[channel].midbuff);
|
||||||
|
setSize_resample (rxa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
// dsp_size blocks
|
||||||
|
setBuffers_gen (rxa[channel].gen0.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_gen (rxa[channel].gen0.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (rxa[channel].adcmeter.p, rxa[channel].midbuff);
|
||||||
|
setSize_meter (rxa[channel].adcmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_nbp (rxa[channel].nbp0.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_nbp (rxa[channel].nbp0.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_bpsnba (rxa[channel].bpsnba.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_bpsnba (rxa[channel].bpsnba.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (rxa[channel].smeter.p, rxa[channel].midbuff);
|
||||||
|
setSize_meter (rxa[channel].smeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_sender (rxa[channel].sender.p, rxa[channel].midbuff);
|
||||||
|
setSize_sender (rxa[channel].sender.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_amsq (rxa[channel].amsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_amsq (rxa[channel].amsq.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_amd (rxa[channel].amd.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_amd (rxa[channel].amd.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_fmd (rxa[channel].fmd.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_fmd (rxa[channel].fmd.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_fmsq (rxa[channel].fmsq.p, rxa[channel].midbuff, rxa[channel].midbuff, rxa[channel].fmd.p->audio);
|
||||||
|
setSize_fmsq (rxa[channel].fmsq.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_snba (rxa[channel].snba.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_snba (rxa[channel].snba.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_eqp (rxa[channel].eqp.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_eqp (rxa[channel].eqp.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_anf (rxa[channel].anf.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_anf (rxa[channel].anf.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_anr (rxa[channel].anr.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_anr (rxa[channel].anr.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_emnr (rxa[channel].emnr.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_emnr (rxa[channel].emnr.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_bandpass (rxa[channel].bp1.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_bandpass (rxa[channel].bp1.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_wcpagc (rxa[channel].agc.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_wcpagc (rxa[channel].agc.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (rxa[channel].agcmeter.p, rxa[channel].midbuff);
|
||||||
|
setSize_meter (rxa[channel].agcmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_siphon (rxa[channel].sip1.p, rxa[channel].midbuff);
|
||||||
|
setSize_siphon (rxa[channel].sip1.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_cbl (rxa[channel].cbl.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_cbl (rxa[channel].cbl.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_speak (rxa[channel].speak.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_speak (rxa[channel].speak.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_mpeak (rxa[channel].mpeak.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_mpeak (rxa[channel].mpeak.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_ssql (rxa[channel].ssql.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_ssql (rxa[channel].ssql.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_panel (rxa[channel].panel.p, rxa[channel].midbuff, rxa[channel].midbuff);
|
||||||
|
setSize_panel (rxa[channel].panel.p, ch[channel].dsp_size);
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (rxa[channel].rsmpout.p, rxa[channel].midbuff, rxa[channel].outbuff);
|
||||||
|
setSize_resample (rxa[channel].rsmpout.p, ch[channel].dsp_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Mode & Filter Controls *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAMode (int channel, int mode)
|
||||||
|
{
|
||||||
|
if (rxa[channel].mode != mode)
|
||||||
|
{
|
||||||
|
int amd_run = (mode == RXA_AM) || (mode == RXA_SAM);
|
||||||
|
RXAbpsnbaCheck (channel, mode, rxa[channel].ndb.p->master_run);
|
||||||
|
RXAbp1Check (channel, amd_run, rxa[channel].snba.p->run, rxa[channel].emnr.p->run,
|
||||||
|
rxa[channel].anf.p->run, rxa[channel].anr.p->run);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].mode = mode;
|
||||||
|
rxa[channel].amd.p->run = 0;
|
||||||
|
rxa[channel].fmd.p->run = 0;
|
||||||
|
rxa[channel].agc.p->run = 1;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RXA_AM:
|
||||||
|
rxa[channel].amd.p->run = 1;
|
||||||
|
rxa[channel].amd.p->mode = 0;
|
||||||
|
break;
|
||||||
|
case RXA_SAM:
|
||||||
|
rxa[channel].amd.p->run = 1;
|
||||||
|
rxa[channel].amd.p->mode = 1;
|
||||||
|
break;
|
||||||
|
case RXA_DSB:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case RXA_FM:
|
||||||
|
rxa[channel].fmd.p->run = 1;
|
||||||
|
rxa[channel].agc.p->run = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RXAbp1Set (channel);
|
||||||
|
RXAbpsnbaSet (channel); // update variables
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RXAResCheck (int channel)
|
||||||
|
{
|
||||||
|
// turn OFF/ON resamplers depending upon whether they're needed
|
||||||
|
RESAMPLE a = rxa[channel].rsmpin.p;
|
||||||
|
if (ch[channel].in_rate != ch[channel].dsp_rate) a->run = 1;
|
||||||
|
else a->run = 0;
|
||||||
|
a = rxa[channel].rsmpout.p;
|
||||||
|
if (ch[channel].dsp_rate != ch[channel].out_rate) a->run = 1;
|
||||||
|
else a->run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RXAbp1Check (int channel, int amd_run, int snba_run,
|
||||||
|
int emnr_run, int anf_run, int anr_run)
|
||||||
|
{
|
||||||
|
BANDPASS a = rxa[channel].bp1.p;
|
||||||
|
double gain;
|
||||||
|
if (amd_run ||
|
||||||
|
snba_run ||
|
||||||
|
emnr_run ||
|
||||||
|
anf_run ||
|
||||||
|
anr_run) gain = 2.0;
|
||||||
|
else gain = 1.0;
|
||||||
|
if (a->gain != gain)
|
||||||
|
setGain_bandpass (a, gain, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RXAbp1Set (int channel)
|
||||||
|
{
|
||||||
|
BANDPASS a = rxa[channel].bp1.p;
|
||||||
|
int old = a->run;
|
||||||
|
if ((rxa[channel].amd.p->run == 1) ||
|
||||||
|
(rxa[channel].snba.p->run == 1) ||
|
||||||
|
(rxa[channel].emnr.p->run == 1) ||
|
||||||
|
(rxa[channel].anf.p->run == 1) ||
|
||||||
|
(rxa[channel].anr.p->run == 1)) a->run = 1;
|
||||||
|
else a->run = 0;
|
||||||
|
if (!old && a->run) flush_bandpass (a);
|
||||||
|
setUpdate_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RXAbpsnbaCheck (int channel, int mode, int notch_run)
|
||||||
|
{
|
||||||
|
// for BPSNBA: set run, position, freqs, run_notches
|
||||||
|
// call this upon change in RXA_mode, snba_run, notch_master_run
|
||||||
|
BPSNBA a = rxa[channel].bpsnba.p;
|
||||||
|
double f_low = 0.0, f_high = 0.0;
|
||||||
|
int run_notches = 0;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case RXA_LSB:
|
||||||
|
case RXA_CWL:
|
||||||
|
case RXA_DIGL:
|
||||||
|
f_low = -a->abs_high_freq;
|
||||||
|
f_high = -a->abs_low_freq;
|
||||||
|
run_notches = notch_run;
|
||||||
|
break;
|
||||||
|
case RXA_USB:
|
||||||
|
case RXA_CWU:
|
||||||
|
case RXA_DIGU:
|
||||||
|
f_low = +a->abs_low_freq;
|
||||||
|
f_high = +a->abs_high_freq;
|
||||||
|
run_notches = notch_run;
|
||||||
|
break;
|
||||||
|
case RXA_AM:
|
||||||
|
case RXA_SAM:
|
||||||
|
case RXA_DSB:
|
||||||
|
f_low = +a->abs_low_freq;
|
||||||
|
f_high = +a->abs_high_freq;
|
||||||
|
run_notches = 0;
|
||||||
|
break;
|
||||||
|
case RXA_FM:
|
||||||
|
f_low = +a->abs_low_freq;
|
||||||
|
f_high = +a->abs_high_freq;
|
||||||
|
run_notches = 0;
|
||||||
|
break;
|
||||||
|
case RXA_DRM:
|
||||||
|
case RXA_SPEC:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 'run' and 'position' are examined at run time; no filter changes required.
|
||||||
|
// Recalculate filter if frequencies OR 'run_notches' changed.
|
||||||
|
if ((a->f_low != f_low ) ||
|
||||||
|
(a->f_high != f_high ) ||
|
||||||
|
(a->run_notches != run_notches))
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->run_notches = run_notches;
|
||||||
|
// f_low, f_high, run_notches are needed for the filter recalculation
|
||||||
|
recalc_bpsnba_filter (a, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RXAbpsnbaSet (int channel)
|
||||||
|
{
|
||||||
|
// for BPSNBA: set run, position, freqs, run_notches
|
||||||
|
// call this upon change in RXA_mode, snba_run, notch_master_run
|
||||||
|
BPSNBA a = rxa[channel].bpsnba.p;
|
||||||
|
switch (rxa[channel].mode)
|
||||||
|
{
|
||||||
|
case RXA_LSB:
|
||||||
|
case RXA_CWL:
|
||||||
|
case RXA_DIGL:
|
||||||
|
a->run = rxa[channel].snba.p->run;
|
||||||
|
a->position = 0;
|
||||||
|
break;
|
||||||
|
case RXA_USB:
|
||||||
|
case RXA_CWU:
|
||||||
|
case RXA_DIGU:
|
||||||
|
a->run = rxa[channel].snba.p->run;
|
||||||
|
a->position = 0;
|
||||||
|
break;
|
||||||
|
case RXA_AM:
|
||||||
|
case RXA_SAM:
|
||||||
|
case RXA_DSB:
|
||||||
|
a->run = rxa[channel].snba.p->run;
|
||||||
|
a->position = 1;
|
||||||
|
break;
|
||||||
|
case RXA_FM:
|
||||||
|
a->run = rxa[channel].snba.p->run;
|
||||||
|
a->position = 1;
|
||||||
|
break;
|
||||||
|
case RXA_DRM:
|
||||||
|
case RXA_SPEC:
|
||||||
|
a->run = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setUpdate_fircore (a->bpsnba->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Collectives *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void RXASetPassband (int channel, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
SetRXABandpassFreqs (channel, f_low, f_high);
|
||||||
|
SetRXASNBAOutputBandwidth (channel, f_low, f_high);
|
||||||
|
RXANBPSetFreqs (channel, f_low, f_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void RXASetNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
int oldstate = SetChannelState (channel, 0, 1);
|
||||||
|
RXANBPSetNC (channel, nc);
|
||||||
|
RXABPSNBASetNC (channel, nc);
|
||||||
|
SetRXABandpassNC (channel, nc);
|
||||||
|
SetRXAEQNC (channel, nc);
|
||||||
|
SetRXAFMSQNC (channel, nc);
|
||||||
|
SetRXAFMNCde (channel, nc);
|
||||||
|
SetRXAFMNCaud (channel, nc);
|
||||||
|
SetChannelState (channel, oldstate, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void RXASetMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
RXANBPSetMP (channel, mp);
|
||||||
|
RXABPSNBASetMP (channel, mp);
|
||||||
|
SetRXABandpassMP (channel, mp);
|
||||||
|
SetRXAEQMP (channel, mp);
|
||||||
|
SetRXAFMSQMP (channel, mp);
|
||||||
|
SetRXAFMMPde (channel, mp);
|
||||||
|
SetRXAFMMPaud (channel, mp);
|
||||||
|
}
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
/* RXA.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2014, 2015, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _rxa_h
|
||||||
|
#define _rxa_h
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
enum rxaMode
|
||||||
|
{
|
||||||
|
RXA_LSB,
|
||||||
|
RXA_USB,
|
||||||
|
RXA_DSB,
|
||||||
|
RXA_CWL,
|
||||||
|
RXA_CWU,
|
||||||
|
RXA_FM,
|
||||||
|
RXA_AM,
|
||||||
|
RXA_DIGU,
|
||||||
|
RXA_SPEC,
|
||||||
|
RXA_DIGL,
|
||||||
|
RXA_SAM,
|
||||||
|
RXA_DRM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rxaMeterType
|
||||||
|
{
|
||||||
|
RXA_S_PK,
|
||||||
|
RXA_S_AV,
|
||||||
|
RXA_ADC_PK,
|
||||||
|
RXA_ADC_AV,
|
||||||
|
RXA_AGC_GAIN,
|
||||||
|
RXA_AGC_PK,
|
||||||
|
RXA_AGC_AV,
|
||||||
|
RXA_METERTYPE_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _rxa
|
||||||
|
{
|
||||||
|
double* inbuff;
|
||||||
|
double* outbuff;
|
||||||
|
double* midbuff;
|
||||||
|
int mode;
|
||||||
|
double meter[RXA_METERTYPE_LAST];
|
||||||
|
CRITICAL_SECTION* pmtupdate[RXA_METERTYPE_LAST];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
METER p;
|
||||||
|
} smeter, adcmeter, agcmeter;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SHIFT p;
|
||||||
|
} shift;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
RESAMPLE p;
|
||||||
|
} rsmpin, rsmpout;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
GEN p;
|
||||||
|
} gen0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
BANDPASS p;
|
||||||
|
} bp1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
NOTCHDB p;
|
||||||
|
} ndb;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
NBP p;
|
||||||
|
} nbp0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
BPSNBA p;
|
||||||
|
} bpsnba;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SNBA p;
|
||||||
|
} snba;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SENDER p;
|
||||||
|
} sender;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AMSQ p;
|
||||||
|
} amsq;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AMD p;
|
||||||
|
} amd;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FMD p;
|
||||||
|
} fmd;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FMSQ p;
|
||||||
|
} fmsq;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EQP p;
|
||||||
|
} eqp;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ANF p;
|
||||||
|
} anf;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ANR p;
|
||||||
|
} anr;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EMNR p;
|
||||||
|
} emnr;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
WCPAGC p;
|
||||||
|
} agc;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SPEAK p;
|
||||||
|
} speak;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
MPEAK p;
|
||||||
|
} mpeak;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
PANEL p;
|
||||||
|
} panel;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SIPHON p;
|
||||||
|
} sip1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
CBL p;
|
||||||
|
} cbl;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SSQL p;
|
||||||
|
} ssql;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct _rxa rxa[];
|
||||||
|
|
||||||
|
extern void create_rxa (int channel);
|
||||||
|
|
||||||
|
extern void destroy_rxa (int channel);
|
||||||
|
|
||||||
|
extern void flush_rxa (int channel);
|
||||||
|
|
||||||
|
extern void xrxa (int channel);
|
||||||
|
|
||||||
|
extern void setInputSamplerate_rxa (int channel);
|
||||||
|
|
||||||
|
extern void setOutputSamplerate_rxa (int channel);
|
||||||
|
|
||||||
|
extern void setDSPSamplerate_rxa (int channel);
|
||||||
|
|
||||||
|
extern void setDSPBuffsize_rxa (int channel);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAMode (int channel, int mode);
|
||||||
|
|
||||||
|
extern void RXAResCheck (int channel);
|
||||||
|
|
||||||
|
extern void RXAbp1Check (int channel, int amd_run, int snba_run, int emnr_run, int anf_run, int anr_run);
|
||||||
|
|
||||||
|
extern void RXAbp1Set (int channel);
|
||||||
|
|
||||||
|
extern void RXAbpsnbaCheck (int channel, int mode, int notch_run);
|
||||||
|
|
||||||
|
extern void RXAbpsnbaSet (int channel);
|
||||||
|
|
||||||
|
#endif
|
||||||
+935
@@ -0,0 +1,935 @@
|
|||||||
|
/* TXA.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2014, 2016, 2017, 2021, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
struct _txa txa[MAX_CHANNELS];
|
||||||
|
|
||||||
|
void create_txa (int channel)
|
||||||
|
{
|
||||||
|
txa[channel].mode = TXA_LSB;
|
||||||
|
txa[channel].f_low = -5000.0;
|
||||||
|
txa[channel].f_high = - 100.0;
|
||||||
|
txa[channel].inbuff = (double *) malloc0 (1 * ch[channel].dsp_insize * sizeof (complex));
|
||||||
|
txa[channel].outbuff = (double *) malloc0 (1 * ch[channel].dsp_outsize * sizeof (complex));
|
||||||
|
txa[channel].midbuff = (double *) malloc0 (2 * ch[channel].dsp_size * sizeof (complex));
|
||||||
|
|
||||||
|
txa[channel].rsmpin.p = create_resample (
|
||||||
|
0, // run - will be turned on below if needed
|
||||||
|
ch[channel].dsp_insize, // input buffer size
|
||||||
|
txa[channel].inbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
ch[channel].in_rate, // input sample rate
|
||||||
|
ch[channel].dsp_rate, // output sample rate
|
||||||
|
0.0, // select cutoff automatically
|
||||||
|
0, // select ncoef automatically
|
||||||
|
1.0); // gain
|
||||||
|
|
||||||
|
txa[channel].gen0.p = create_gen (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
2); // mode
|
||||||
|
|
||||||
|
txa[channel].panel.p = create_panel (
|
||||||
|
channel, // channel number
|
||||||
|
1, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
1.0, // gain1
|
||||||
|
1.0, // gain2I
|
||||||
|
1.0, // gain2Q
|
||||||
|
2, // 1 to use Q, 2 to use I for input
|
||||||
|
0); // 0, no copy
|
||||||
|
|
||||||
|
txa[channel].phrot.p = create_phrot (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
338.0, // 1/2 of phase frequency
|
||||||
|
8); // number of stages
|
||||||
|
|
||||||
|
txa[channel].micmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to another 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_MIC_AV, // index for average value
|
||||||
|
TXA_MIC_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
txa[channel].amsq.p = create_amsq (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
txa[channel].midbuff, // trigger buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.010, // time constant for averaging signal
|
||||||
|
0.004, // up-slew time
|
||||||
|
0.004, // down-slew time
|
||||||
|
0.180, // signal level to initiate tail
|
||||||
|
0.200, // signal level to initiate unmute
|
||||||
|
0.000, // minimum tail length
|
||||||
|
0.025, // maximum tail length
|
||||||
|
0.200); // muted gain
|
||||||
|
|
||||||
|
{
|
||||||
|
double default_F[11] = {0.0, 32.0, 63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0, 8000.0, 16000.0};
|
||||||
|
double default_G[11] = {0.0, -12.0, -12.0, -12.0, -1.0, +1.0, +4.0, +9.0, +12.0, -10.0, -10.0};
|
||||||
|
//double default_G[11] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
||||||
|
txa[channel].eqp.p = create_eqp (
|
||||||
|
0, // run - OFF by default
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
10, // nfreqs
|
||||||
|
default_F, // vector of frequencies
|
||||||
|
default_G, // vector of gain values
|
||||||
|
0, // cutoff mode
|
||||||
|
0, // wintype
|
||||||
|
ch[channel].dsp_rate); // samplerate
|
||||||
|
}
|
||||||
|
|
||||||
|
txa[channel].eqmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
&(txa[channel].eqp.p->run), // pointer to eqp 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_EQ_AV, // index for average value
|
||||||
|
TXA_EQ_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
txa[channel].preemph.p = create_emphp (
|
||||||
|
0, // run
|
||||||
|
1, // position
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer,
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0, // pre-emphasis type
|
||||||
|
300.0, // f_low
|
||||||
|
3000.0); // f_high
|
||||||
|
|
||||||
|
txa[channel].leveler.p = create_wcpagc (
|
||||||
|
0, // run - OFF by default
|
||||||
|
5, // mode
|
||||||
|
0, // 0 for max(I,Q), 1 for envelope
|
||||||
|
txa[channel].midbuff, // input buff pointer
|
||||||
|
txa[channel].midbuff, // output buff pointer
|
||||||
|
ch[channel].dsp_size, // io_buffsize
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.001, // tau_attack
|
||||||
|
0.500, // tau_decay
|
||||||
|
6, // n_tau
|
||||||
|
1.778, // max_gain
|
||||||
|
1.0, // var_gain
|
||||||
|
1.0, // fixed_gain
|
||||||
|
1.0, // max_input
|
||||||
|
1.05, // out_targ
|
||||||
|
0.250, // tau_fast_backaverage
|
||||||
|
0.005, // tau_fast_decay
|
||||||
|
5.0, // pop_ratio
|
||||||
|
0, // hang_enable
|
||||||
|
0.500, // tau_hang_backmult
|
||||||
|
0.500, // hangtime
|
||||||
|
2.000, // hang_thresh
|
||||||
|
0.100); // tau_hang_decay
|
||||||
|
|
||||||
|
txa[channel].lvlrmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
&(txa[channel].leveler.p->run), // pointer to leveler 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_LVLR_AV, // index for average value
|
||||||
|
TXA_LVLR_PK, // index for peak value
|
||||||
|
TXA_LVLR_GAIN, // index for gain value
|
||||||
|
&txa[channel].leveler.p->gain); // pointer for gain computation
|
||||||
|
|
||||||
|
{
|
||||||
|
double default_F[5] = {200.0, 1000.0, 2000.0, 3000.0, 4000.0};
|
||||||
|
double default_G[5] = {0.0, 5.0, 10.0, 10.0, 5.0};
|
||||||
|
double default_E[5] = {7.0, 7.0, 7.0, 7.0, 7.0};
|
||||||
|
txa[channel].cfcomp.p = create_cfcomp(
|
||||||
|
0, // run
|
||||||
|
0, // position
|
||||||
|
0, // post-equalizer run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
2048, // fft size
|
||||||
|
4, // overlap
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
1, // window type
|
||||||
|
0, // compression method
|
||||||
|
5, // nfreqs
|
||||||
|
0.0, // pre-compression
|
||||||
|
0.0, // pre-postequalization
|
||||||
|
default_F, // frequency array
|
||||||
|
default_G, // compression array
|
||||||
|
default_E, // eq array
|
||||||
|
0.25, // metering time constant
|
||||||
|
0.50); // display time constant
|
||||||
|
}
|
||||||
|
|
||||||
|
txa[channel].cfcmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
&(txa[channel].cfcomp.p->run), // pointer to eqp 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_CFC_AV, // index for average value
|
||||||
|
TXA_CFC_PK, // index for peak value
|
||||||
|
TXA_CFC_GAIN, // index for gain value
|
||||||
|
&txa[channel].cfcomp.p->gain); // pointer for gain computation
|
||||||
|
|
||||||
|
txa[channel].bp0.p = create_bandpass (
|
||||||
|
1, // always runs
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
||||||
|
0, // flag for minimum phase
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
txa[channel].f_low, // low freq cutoff
|
||||||
|
txa[channel].f_high, // high freq cutoff
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
1, // wintype
|
||||||
|
2.0); // gain
|
||||||
|
|
||||||
|
txa[channel].compressor.p = create_compressor (
|
||||||
|
0, // run - OFF by default
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
3.0); // gain
|
||||||
|
|
||||||
|
txa[channel].bp1.p = create_bandpass (
|
||||||
|
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
||||||
|
0, // flag for minimum phase
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
txa[channel].f_low, // low freq cutoff
|
||||||
|
txa[channel].f_high, // high freq cutoff
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
1, // wintype
|
||||||
|
2.0); // gain
|
||||||
|
|
||||||
|
txa[channel].osctrl.p = create_osctrl (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
1.95); // gain for clippings
|
||||||
|
|
||||||
|
txa[channel].bp2.p = create_bandpass (
|
||||||
|
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
||||||
|
0, // position
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
||||||
|
0, // flag for minimum phase
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
txa[channel].f_low, // low freq cutoff
|
||||||
|
txa[channel].f_high, // high freq cutoff
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
1, // wintype
|
||||||
|
1.0); // gain
|
||||||
|
|
||||||
|
txa[channel].compmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
&(txa[channel].compressor.p->run), // pointer to compressor 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_COMP_AV, // index for average value
|
||||||
|
TXA_COMP_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
txa[channel].alc.p = create_wcpagc (
|
||||||
|
1, // run - always ON
|
||||||
|
5, // mode
|
||||||
|
1, // 0 for max(I,Q), 1 for envelope
|
||||||
|
txa[channel].midbuff, // input buff pointer
|
||||||
|
txa[channel].midbuff, // output buff pointer
|
||||||
|
ch[channel].dsp_size, // io_buffsize
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.001, // tau_attack
|
||||||
|
0.010, // tau_decay
|
||||||
|
6, // n_tau
|
||||||
|
1.0, // max_gain
|
||||||
|
1.0, // var_gain
|
||||||
|
1.0, // fixed_gain
|
||||||
|
1.0, // max_input
|
||||||
|
1.0, // out_targ
|
||||||
|
0.250, // tau_fast_backaverage
|
||||||
|
0.005, // tau_fast_decay
|
||||||
|
5.0, // pop_ratio
|
||||||
|
0, // hang_enable
|
||||||
|
0.500, // tau_hang_backmult
|
||||||
|
0.500, // hangtime
|
||||||
|
2.000, // hang_thresh
|
||||||
|
0.100); // tau_hang_decay
|
||||||
|
|
||||||
|
txa[channel].ammod.p = create_ammod (
|
||||||
|
0, // run - OFF by default
|
||||||
|
0, // mode: 0=>AM, 1=>DSB
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to output buffer
|
||||||
|
0.5); // carrier level
|
||||||
|
|
||||||
|
|
||||||
|
txa[channel].fmmod.p = create_fmmod (
|
||||||
|
0, // run - OFF by default
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
5000.0, // deviation
|
||||||
|
300.0, // low cutoff frequency
|
||||||
|
3000.0, // high cutoff frequency
|
||||||
|
1, // ctcss run control
|
||||||
|
0.10, // ctcss level
|
||||||
|
100.0, // ctcss frequency
|
||||||
|
1, // run bandpass filter
|
||||||
|
max(2048, ch[channel].dsp_size), // number coefficients for bandpass filter
|
||||||
|
0); // minimum phase flag
|
||||||
|
|
||||||
|
txa[channel].gen1.p = create_gen (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0); // mode
|
||||||
|
|
||||||
|
txa[channel].uslew.p = create_uslew (
|
||||||
|
channel, // channel
|
||||||
|
&ch[channel].iob.ch_upslew, // pointer to channel upslew flag
|
||||||
|
ch[channel].dsp_size, // buffer size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // sample rate
|
||||||
|
0.000, // delay time
|
||||||
|
0.005); // upslew time
|
||||||
|
|
||||||
|
txa[channel].alcmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to a 'run'
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // pointer to buffer
|
||||||
|
ch[channel].dsp_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_ALC_AV, // index for average value
|
||||||
|
TXA_ALC_PK, // index for peak value
|
||||||
|
TXA_ALC_GAIN, // index for gain value
|
||||||
|
&txa[channel].alc.p->gain); // pointer for gain computation
|
||||||
|
|
||||||
|
txa[channel].sip1.p = create_siphon (
|
||||||
|
1, // run
|
||||||
|
0, // position
|
||||||
|
0, // mode
|
||||||
|
0, // disp
|
||||||
|
ch[channel].dsp_size, // input buffer size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
16384, // number of samples to buffer
|
||||||
|
16384, // fft size for spectrum
|
||||||
|
1); // specmode
|
||||||
|
|
||||||
|
txa[channel].calcc.p = create_calcc (
|
||||||
|
channel, // channel number
|
||||||
|
1, // run calibration
|
||||||
|
1024, // input buffer size
|
||||||
|
ch[channel].in_rate, // samplerate
|
||||||
|
16, // ints
|
||||||
|
256, // spi
|
||||||
|
(1.0 / 0.4072), // hw_scale
|
||||||
|
0.1, // mox delay
|
||||||
|
0.0, // loop delay
|
||||||
|
0.8, // ptol
|
||||||
|
0, // mox
|
||||||
|
0, // solidmox
|
||||||
|
1, // pin mode
|
||||||
|
1, // map mode
|
||||||
|
0, // stbl mode
|
||||||
|
256, // pin samples
|
||||||
|
0.9); // alpha
|
||||||
|
|
||||||
|
txa[channel].iqc.p0 = txa[channel].iqc.p1 = create_iqc (
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
(double)ch[channel].dsp_rate, // sample rate
|
||||||
|
16, // ints
|
||||||
|
0.005, // changeover time
|
||||||
|
256); // spi
|
||||||
|
|
||||||
|
txa[channel].cfir.p = create_cfir(
|
||||||
|
0, // run
|
||||||
|
ch[channel].dsp_size, // size
|
||||||
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
||||||
|
0, // minimum phase flag
|
||||||
|
txa[channel].midbuff, // input buffer
|
||||||
|
txa[channel].midbuff, // output buffer
|
||||||
|
ch[channel].dsp_rate, // input sample rate
|
||||||
|
ch[channel].out_rate, // CIC input sample rate
|
||||||
|
1, // CIC differential delay
|
||||||
|
640, // CIC interpolation factor
|
||||||
|
5, // CIC integrator-comb pairs
|
||||||
|
20000.0, // cutoff frequency
|
||||||
|
2, // brick-wall windowed rolloff
|
||||||
|
0.0, // raised-cosine transition width
|
||||||
|
0); // window type
|
||||||
|
|
||||||
|
txa[channel].rsmpout.p = create_resample (
|
||||||
|
0, // run - will be turned ON below if needed
|
||||||
|
ch[channel].dsp_size, // input size
|
||||||
|
txa[channel].midbuff, // pointer to input buffer
|
||||||
|
txa[channel].outbuff, // pointer to output buffer
|
||||||
|
ch[channel].dsp_rate, // input sample rate
|
||||||
|
ch[channel].out_rate, // output sample rate
|
||||||
|
0.0, // select cutoff automatically
|
||||||
|
0, // select ncoef automatically
|
||||||
|
0.980); // gain
|
||||||
|
|
||||||
|
txa[channel].outmeter.p = create_meter (
|
||||||
|
1, // run
|
||||||
|
0, // optional pointer to another 'run'
|
||||||
|
ch[channel].dsp_outsize, // size
|
||||||
|
txa[channel].outbuff, // pointer to buffer
|
||||||
|
ch[channel].out_rate, // samplerate
|
||||||
|
0.100, // averaging time constant
|
||||||
|
0.100, // peak decay time constant
|
||||||
|
txa[channel].meter, // result vector
|
||||||
|
txa[channel].pmtupdate, // locks for meter access
|
||||||
|
TXA_OUT_AV, // index for average value
|
||||||
|
TXA_OUT_PK, // index for peak value
|
||||||
|
-1, // index for gain value
|
||||||
|
0); // pointer for gain computation
|
||||||
|
|
||||||
|
// turn OFF / ON resamplers as needed
|
||||||
|
TXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_txa (int channel)
|
||||||
|
{
|
||||||
|
// in reverse order, free each item we created
|
||||||
|
destroy_meter (txa[channel].outmeter.p);
|
||||||
|
destroy_resample (txa[channel].rsmpout.p);
|
||||||
|
destroy_cfir(txa[channel].cfir.p);
|
||||||
|
destroy_calcc (txa[channel].calcc.p);
|
||||||
|
destroy_iqc (txa[channel].iqc.p0);
|
||||||
|
destroy_siphon (txa[channel].sip1.p);
|
||||||
|
destroy_meter (txa[channel].alcmeter.p);
|
||||||
|
destroy_uslew (txa[channel].uslew.p);
|
||||||
|
destroy_gen (txa[channel].gen1.p);
|
||||||
|
destroy_fmmod (txa[channel].fmmod.p);
|
||||||
|
destroy_ammod (txa[channel].ammod.p);
|
||||||
|
destroy_wcpagc (txa[channel].alc.p);
|
||||||
|
destroy_meter (txa[channel].compmeter.p);
|
||||||
|
destroy_bandpass (txa[channel].bp2.p);
|
||||||
|
destroy_osctrl (txa[channel].osctrl.p);
|
||||||
|
destroy_bandpass (txa[channel].bp1.p);
|
||||||
|
destroy_compressor (txa[channel].compressor.p);
|
||||||
|
destroy_bandpass (txa[channel].bp0.p);
|
||||||
|
destroy_meter (txa[channel].cfcmeter.p);
|
||||||
|
destroy_cfcomp (txa[channel].cfcomp.p);
|
||||||
|
destroy_meter (txa[channel].lvlrmeter.p);
|
||||||
|
destroy_wcpagc (txa[channel].leveler.p);
|
||||||
|
destroy_emphp (txa[channel].preemph.p);
|
||||||
|
destroy_meter (txa[channel].eqmeter.p);
|
||||||
|
destroy_eqp (txa[channel].eqp.p);
|
||||||
|
destroy_amsq (txa[channel].amsq.p);
|
||||||
|
destroy_meter (txa[channel].micmeter.p);
|
||||||
|
destroy_phrot (txa[channel].phrot.p);
|
||||||
|
destroy_panel (txa[channel].panel.p);
|
||||||
|
destroy_gen (txa[channel].gen0.p);
|
||||||
|
destroy_resample (txa[channel].rsmpin.p);
|
||||||
|
_aligned_free (txa[channel].midbuff);
|
||||||
|
_aligned_free (txa[channel].outbuff);
|
||||||
|
_aligned_free (txa[channel].inbuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_txa (int channel)
|
||||||
|
{
|
||||||
|
memset (txa[channel].inbuff, 0, 1 * ch[channel].dsp_insize * sizeof (complex));
|
||||||
|
memset (txa[channel].outbuff, 0, 1 * ch[channel].dsp_outsize * sizeof (complex));
|
||||||
|
memset (txa[channel].midbuff, 0, 2 * ch[channel].dsp_size * sizeof (complex));
|
||||||
|
flush_resample (txa[channel].rsmpin.p);
|
||||||
|
flush_gen (txa[channel].gen0.p);
|
||||||
|
flush_panel (txa[channel].panel.p);
|
||||||
|
flush_phrot (txa[channel].phrot.p);
|
||||||
|
flush_meter (txa[channel].micmeter.p);
|
||||||
|
flush_amsq (txa[channel].amsq.p);
|
||||||
|
flush_eqp (txa[channel].eqp.p);
|
||||||
|
flush_meter (txa[channel].eqmeter.p);
|
||||||
|
flush_emphp (txa[channel].preemph.p);
|
||||||
|
flush_wcpagc (txa[channel].leveler.p);
|
||||||
|
flush_meter (txa[channel].lvlrmeter.p);
|
||||||
|
flush_cfcomp (txa[channel].cfcomp.p);
|
||||||
|
flush_meter (txa[channel].cfcmeter.p);
|
||||||
|
flush_bandpass (txa[channel].bp0.p);
|
||||||
|
flush_compressor (txa[channel].compressor.p);
|
||||||
|
flush_bandpass (txa[channel].bp1.p);
|
||||||
|
flush_osctrl (txa[channel].osctrl.p);
|
||||||
|
flush_bandpass (txa[channel].bp2.p);
|
||||||
|
flush_meter (txa[channel].compmeter.p);
|
||||||
|
flush_wcpagc (txa[channel].alc.p);
|
||||||
|
flush_ammod (txa[channel].ammod.p);
|
||||||
|
flush_fmmod (txa[channel].fmmod.p);
|
||||||
|
flush_gen (txa[channel].gen1.p);
|
||||||
|
flush_uslew (txa[channel].uslew.p);
|
||||||
|
flush_meter (txa[channel].alcmeter.p);
|
||||||
|
flush_siphon (txa[channel].sip1.p);
|
||||||
|
flush_iqc (txa[channel].iqc.p0);
|
||||||
|
flush_cfir(txa[channel].cfir.p);
|
||||||
|
flush_resample (txa[channel].rsmpout.p);
|
||||||
|
flush_meter (txa[channel].outmeter.p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xtxa (int channel)
|
||||||
|
{
|
||||||
|
xresample (txa[channel].rsmpin.p); // input resampler
|
||||||
|
xgen (txa[channel].gen0.p); // input signal generator
|
||||||
|
xpanel (txa[channel].panel.p); // includes MIC gain
|
||||||
|
xphrot (txa[channel].phrot.p); // phase rotator
|
||||||
|
xmeter (txa[channel].micmeter.p); // MIC meter
|
||||||
|
xamsqcap (txa[channel].amsq.p); // downward expander capture
|
||||||
|
xamsq (txa[channel].amsq.p); // downward expander action
|
||||||
|
xeqp (txa[channel].eqp.p); // pre-EQ
|
||||||
|
xmeter (txa[channel].eqmeter.p); // EQ meter
|
||||||
|
xemphp (txa[channel].preemph.p, 0); // FM pre-emphasis (first option)
|
||||||
|
xwcpagc (txa[channel].leveler.p); // Leveler
|
||||||
|
xmeter (txa[channel].lvlrmeter.p); // Leveler Meter
|
||||||
|
xcfcomp (txa[channel].cfcomp.p, 0); // Continuous Frequency Compressor with post-EQ
|
||||||
|
xmeter (txa[channel].cfcmeter.p); // CFC+PostEQ Meter
|
||||||
|
xbandpass (txa[channel].bp0.p, 0); // primary bandpass filter
|
||||||
|
xcompressor (txa[channel].compressor.p); // COMP compressor
|
||||||
|
xbandpass (txa[channel].bp1.p, 0); // aux bandpass (runs if COMP)
|
||||||
|
xosctrl (txa[channel].osctrl.p); // CESSB Overshoot Control
|
||||||
|
xbandpass (txa[channel].bp2.p, 0); // aux bandpass (runs if CESSB)
|
||||||
|
xmeter (txa[channel].compmeter.p); // COMP meter
|
||||||
|
xwcpagc (txa[channel].alc.p); // ALC
|
||||||
|
xammod (txa[channel].ammod.p); // AM Modulator
|
||||||
|
xemphp (txa[channel].preemph.p, 1); // FM pre-emphasis (second option)
|
||||||
|
xfmmod (txa[channel].fmmod.p); // FM Modulator
|
||||||
|
xgen (txa[channel].gen1.p); // output signal generator (TUN and Two-tone)
|
||||||
|
xuslew (txa[channel].uslew.p); // up-slew for AM, FM, and gens
|
||||||
|
xmeter (txa[channel].alcmeter.p); // ALC Meter
|
||||||
|
xsiphon (txa[channel].sip1.p, 0); // siphon data for display
|
||||||
|
xiqc (txa[channel].iqc.p0); // PureSignal correction
|
||||||
|
xcfir(txa[channel].cfir.p); // compensating FIR filter (used Protocol_2 only)
|
||||||
|
xresample (txa[channel].rsmpout.p); // output resampler
|
||||||
|
xmeter (txa[channel].outmeter.p); // output meter
|
||||||
|
// print_peak_env ("env_exception.txt", ch[channel].dsp_outsize, txa[channel].outbuff, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInputSamplerate_txa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (txa[channel].inbuff);
|
||||||
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
||||||
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
setInRate_resample (txa[channel].rsmpin.p, ch[channel].in_rate);
|
||||||
|
TXAResCheck (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOutputSamplerate_txa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (txa[channel].outbuff);
|
||||||
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// cfir - needs to know input rate of firmware CIC
|
||||||
|
setOutRate_cfir (txa[channel].cfir.p, ch[channel].out_rate);
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
||||||
|
setOutRate_resample (txa[channel].rsmpout.p, ch[channel].out_rate);
|
||||||
|
TXAResCheck (channel);
|
||||||
|
// output meter
|
||||||
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
||||||
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
||||||
|
setSamplerate_meter (txa[channel].outmeter.p, ch[channel].out_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDSPSamplerate_txa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (txa[channel].inbuff);
|
||||||
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
_aligned_free (txa[channel].outbuff);
|
||||||
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
||||||
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
setOutRate_resample (txa[channel].rsmpin.p, ch[channel].dsp_rate);
|
||||||
|
// dsp_rate blocks
|
||||||
|
setSamplerate_gen (txa[channel].gen0.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_panel (txa[channel].panel.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_phrot (txa[channel].phrot.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].micmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_amsq (txa[channel].amsq.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_eqp (txa[channel].eqp.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].eqmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_emphp (txa[channel].preemph.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_wcpagc (txa[channel].leveler.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].lvlrmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_cfcomp (txa[channel].cfcomp.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].cfcmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_bandpass (txa[channel].bp0.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_compressor (txa[channel].compressor.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_bandpass (txa[channel].bp1.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_osctrl (txa[channel].osctrl.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_bandpass (txa[channel].bp2.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].compmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_wcpagc (txa[channel].alc.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_ammod (txa[channel].ammod.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_fmmod (txa[channel].fmmod.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_gen (txa[channel].gen1.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_uslew (txa[channel].uslew.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_meter (txa[channel].alcmeter.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_siphon (txa[channel].sip1.p, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_iqc (txa[channel].iqc.p0, ch[channel].dsp_rate);
|
||||||
|
setSamplerate_cfir (txa[channel].cfir.p, ch[channel].dsp_rate);
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
||||||
|
setInRate_resample (txa[channel].rsmpout.p, ch[channel].dsp_rate);
|
||||||
|
TXAResCheck (channel);
|
||||||
|
// output meter
|
||||||
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
||||||
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDSPBuffsize_txa (int channel)
|
||||||
|
{
|
||||||
|
// buffers
|
||||||
|
_aligned_free (txa[channel].inbuff);
|
||||||
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
||||||
|
_aligned_free (txa[channel].midbuff);
|
||||||
|
txa[channel].midbuff = (double *)malloc0(2 * ch[channel].dsp_size * sizeof(complex));
|
||||||
|
_aligned_free (txa[channel].outbuff);
|
||||||
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
||||||
|
// input resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
||||||
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
||||||
|
// dsp_size blocks
|
||||||
|
setBuffers_gen (txa[channel].gen0.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_gen (txa[channel].gen0.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_panel (txa[channel].panel.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_panel (txa[channel].panel.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_phrot (txa[channel].phrot.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_phrot (txa[channel].phrot.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].micmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].micmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_amsq (txa[channel].amsq.p, txa[channel].midbuff, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_amsq (txa[channel].amsq.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_eqp (txa[channel].eqp.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_eqp (txa[channel].eqp.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].eqmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].eqmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_emphp (txa[channel].preemph.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_emphp (txa[channel].preemph.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_wcpagc (txa[channel].leveler.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_wcpagc (txa[channel].leveler.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].lvlrmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].lvlrmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_cfcomp (txa[channel].cfcomp.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_cfcomp (txa[channel].cfcomp.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].cfcmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].cfcmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_bandpass (txa[channel].bp0.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_bandpass (txa[channel].bp0.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_compressor (txa[channel].compressor.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_compressor (txa[channel].compressor.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_bandpass (txa[channel].bp1.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_bandpass (txa[channel].bp1.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_osctrl (txa[channel].osctrl.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_osctrl (txa[channel].osctrl.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_bandpass (txa[channel].bp2.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_bandpass (txa[channel].bp2.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].compmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].compmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_wcpagc (txa[channel].alc.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_wcpagc (txa[channel].alc.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_ammod (txa[channel].ammod.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_ammod (txa[channel].ammod.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_fmmod (txa[channel].fmmod.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_fmmod (txa[channel].fmmod.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_gen (txa[channel].gen1.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_gen (txa[channel].gen1.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_uslew (txa[channel].uslew.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_uslew (txa[channel].uslew.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_meter (txa[channel].alcmeter.p, txa[channel].midbuff);
|
||||||
|
setSize_meter (txa[channel].alcmeter.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_siphon (txa[channel].sip1.p, txa[channel].midbuff);
|
||||||
|
setSize_siphon (txa[channel].sip1.p, ch[channel].dsp_size);
|
||||||
|
setBuffers_iqc (txa[channel].iqc.p0, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_iqc (txa[channel].iqc.p0, ch[channel].dsp_size);
|
||||||
|
setBuffers_cfir (txa[channel].cfir.p, txa[channel].midbuff, txa[channel].midbuff);
|
||||||
|
setSize_cfir (txa[channel].cfir.p, ch[channel].dsp_size);
|
||||||
|
// output resampler
|
||||||
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
||||||
|
setSize_resample (txa[channel].rsmpout.p, ch[channel].dsp_size);
|
||||||
|
// output meter
|
||||||
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
||||||
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAMode (int channel, int mode)
|
||||||
|
{
|
||||||
|
if (txa[channel].mode != mode)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].mode = mode;
|
||||||
|
txa[channel].ammod.p->run = 0;
|
||||||
|
txa[channel].fmmod.p->run = 0;
|
||||||
|
txa[channel].preemph.p->run = 0;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case TXA_AM:
|
||||||
|
case TXA_SAM:
|
||||||
|
txa[channel].ammod.p->run = 1;
|
||||||
|
txa[channel].ammod.p->mode = 0;
|
||||||
|
break;
|
||||||
|
case TXA_DSB:
|
||||||
|
txa[channel].ammod.p->run = 1;
|
||||||
|
txa[channel].ammod.p->mode = 1;
|
||||||
|
break;
|
||||||
|
case TXA_AM_LSB:
|
||||||
|
case TXA_AM_USB:
|
||||||
|
txa[channel].ammod.p->run = 1;
|
||||||
|
txa[channel].ammod.p->mode = 2;
|
||||||
|
break;
|
||||||
|
case TXA_FM:
|
||||||
|
txa[channel].fmmod.p->run = 1;
|
||||||
|
txa[channel].preemph.p->run = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TXASetupBPFilters (channel);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABandpassFreqs (int channel, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
if ((txa[channel].f_low != f_low) || (txa[channel].f_high != f_high))
|
||||||
|
{
|
||||||
|
txa[channel].f_low = f_low;
|
||||||
|
txa[channel].f_high = f_high;
|
||||||
|
TXASetupBPFilters (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Internal Functions *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void TXAResCheck (int channel)
|
||||||
|
{
|
||||||
|
RESAMPLE a = txa[channel].rsmpin.p;
|
||||||
|
if (ch[channel].in_rate != ch[channel].dsp_rate) a->run = 1;
|
||||||
|
else a->run = 0;
|
||||||
|
a = txa[channel].rsmpout.p;
|
||||||
|
if (ch[channel].dsp_rate != ch[channel].out_rate) a->run = 1;
|
||||||
|
else a->run = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TXAUslewCheck (int channel)
|
||||||
|
{
|
||||||
|
return (txa[channel].ammod.p->run == 1) ||
|
||||||
|
(txa[channel].fmmod.p->run == 1) ||
|
||||||
|
(txa[channel].gen0.p->run == 1) ||
|
||||||
|
(txa[channel].gen1.p->run == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TXASetupBPFilters (int channel)
|
||||||
|
{
|
||||||
|
txa[channel].bp0.p->run = 1;
|
||||||
|
txa[channel].bp1.p->run = 0;
|
||||||
|
txa[channel].bp2.p->run = 0;
|
||||||
|
switch (txa[channel].mode)
|
||||||
|
{
|
||||||
|
case TXA_LSB:
|
||||||
|
case TXA_USB:
|
||||||
|
case TXA_CWL:
|
||||||
|
case TXA_CWU:
|
||||||
|
case TXA_DIGL:
|
||||||
|
case TXA_DIGU:
|
||||||
|
case TXA_SPEC:
|
||||||
|
case TXA_DRM:
|
||||||
|
CalcBandpassFilter (txa[channel].bp0.p, txa[channel].f_low, txa[channel].f_high, 2.0);
|
||||||
|
if (txa[channel].compressor.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp1.p, txa[channel].f_low, txa[channel].f_high, 2.0);
|
||||||
|
txa[channel].bp1.p->run = 1;
|
||||||
|
if (txa[channel].osctrl.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp2.p, txa[channel].f_low, txa[channel].f_high, 1.0);
|
||||||
|
txa[channel].bp2.p->run = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TXA_DSB:
|
||||||
|
case TXA_AM:
|
||||||
|
case TXA_SAM:
|
||||||
|
case TXA_FM:
|
||||||
|
if (txa[channel].compressor.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
||||||
|
CalcBandpassFilter (txa[channel].bp1.p, 0.0, txa[channel].f_high, 2.0);
|
||||||
|
txa[channel].bp1.p->run = 1;
|
||||||
|
if (txa[channel].osctrl.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp2.p, 0.0, txa[channel].f_high, 1.0);
|
||||||
|
txa[channel].bp2.p->run = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp0.p, txa[channel].f_low, txa[channel].f_high, 1.0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TXA_AM_LSB:
|
||||||
|
CalcBandpassFilter (txa[channel].bp0.p, -txa[channel].f_high, 0.0, 2.0);
|
||||||
|
if (txa[channel].compressor.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp1.p, -txa[channel].f_high, 0.0, 2.0);
|
||||||
|
txa[channel].bp1.p->run = 1;
|
||||||
|
if (txa[channel].osctrl.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp2.p, -txa[channel].f_high, 0.0, 1.0);
|
||||||
|
txa[channel].bp2.p->run = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TXA_AM_USB:
|
||||||
|
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
||||||
|
if (txa[channel].compressor.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp1.p, 0.0, txa[channel].f_high, 2.0);
|
||||||
|
txa[channel].bp1.p->run = 1;
|
||||||
|
if (txa[channel].osctrl.p->run)
|
||||||
|
{
|
||||||
|
CalcBandpassFilter (txa[channel].bp2.p, 0.0, txa[channel].f_high, 1.0);
|
||||||
|
txa[channel].bp2.p->run = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Collectives *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void TXASetNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
int oldstate = SetChannelState (channel, 0, 1);
|
||||||
|
SetTXABandpassNC (channel, nc);
|
||||||
|
SetTXAFMEmphNC (channel, nc);
|
||||||
|
SetTXAEQNC (channel, nc);
|
||||||
|
SetTXAFMNC (channel, nc);
|
||||||
|
SetTXACFIRNC (channel, nc);
|
||||||
|
SetChannelState (channel, oldstate, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void TXASetMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
SetTXABandpassMP (channel, mp);
|
||||||
|
SetTXAFMEmphMP (channel, mp);
|
||||||
|
SetTXAEQMP (channel, mp);
|
||||||
|
SetTXAFMMP (channel, mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMAFFilter (int channel, double low, double high)
|
||||||
|
{
|
||||||
|
SetTXAFMPreEmphFreqs (channel, low, high);
|
||||||
|
SetTXAFMAFFreqs (channel, low, high);
|
||||||
|
}
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
/* TXA.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _txa_h
|
||||||
|
#define _txa_h
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
enum txaMode
|
||||||
|
{
|
||||||
|
TXA_LSB,
|
||||||
|
TXA_USB,
|
||||||
|
TXA_DSB,
|
||||||
|
TXA_CWL,
|
||||||
|
TXA_CWU,
|
||||||
|
TXA_FM,
|
||||||
|
TXA_AM,
|
||||||
|
TXA_DIGU,
|
||||||
|
TXA_SPEC,
|
||||||
|
TXA_DIGL,
|
||||||
|
TXA_SAM,
|
||||||
|
TXA_DRM,
|
||||||
|
TXA_AM_LSB,
|
||||||
|
TXA_AM_USB
|
||||||
|
};
|
||||||
|
|
||||||
|
enum txaMeterType
|
||||||
|
{
|
||||||
|
TXA_MIC_PK,
|
||||||
|
TXA_MIC_AV,
|
||||||
|
TXA_EQ_PK,
|
||||||
|
TXA_EQ_AV,
|
||||||
|
TXA_LVLR_PK,
|
||||||
|
TXA_LVLR_AV,
|
||||||
|
TXA_LVLR_GAIN,
|
||||||
|
TXA_CFC_PK,
|
||||||
|
TXA_CFC_AV,
|
||||||
|
TXA_CFC_GAIN,
|
||||||
|
TXA_COMP_PK,
|
||||||
|
TXA_COMP_AV,
|
||||||
|
TXA_ALC_PK,
|
||||||
|
TXA_ALC_AV,
|
||||||
|
TXA_ALC_GAIN,
|
||||||
|
TXA_OUT_PK,
|
||||||
|
TXA_OUT_AV,
|
||||||
|
TXA_METERTYPE_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _txa
|
||||||
|
{
|
||||||
|
double* inbuff;
|
||||||
|
double* outbuff;
|
||||||
|
double* midbuff;
|
||||||
|
int mode;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double meter[TXA_METERTYPE_LAST];
|
||||||
|
CRITICAL_SECTION* pmtupdate[TXA_METERTYPE_LAST];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
METER p;
|
||||||
|
} micmeter, eqmeter, lvlrmeter, cfcmeter, compmeter, alcmeter, outmeter;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
RESAMPLE p;
|
||||||
|
} rsmpin, rsmpout;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
PANEL p;
|
||||||
|
} panel;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AMSQ p;
|
||||||
|
} amsq;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EQP p;
|
||||||
|
} eqp;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
PHROT p;
|
||||||
|
} phrot;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
CFCOMP p;
|
||||||
|
} cfcomp;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
COMPRESSOR p;
|
||||||
|
} compressor;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
BANDPASS p;
|
||||||
|
} bp0, bp1, bp2;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
OSCTRL p;
|
||||||
|
} osctrl;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
WCPAGC p;
|
||||||
|
} leveler, alc;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AMMOD p;
|
||||||
|
} ammod;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EMPHP p;
|
||||||
|
} preemph;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FMMOD p;
|
||||||
|
} fmmod;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SIPHON p;
|
||||||
|
} sip1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
GEN p;
|
||||||
|
} gen0, gen1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USLEW p;
|
||||||
|
} uslew;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
CALCC p;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} calcc;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
IQC p0, p1;
|
||||||
|
// p0 for dsp-synchronized reference, p1 for other
|
||||||
|
} iqc;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
CFIR p;
|
||||||
|
} cfir;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct _txa txa[];
|
||||||
|
|
||||||
|
extern void create_txa (int channel);
|
||||||
|
|
||||||
|
extern void destroy_txa (int channel);
|
||||||
|
|
||||||
|
extern void flush_txa (int channel);
|
||||||
|
|
||||||
|
extern void xtxa (int channel);
|
||||||
|
|
||||||
|
extern int TXAUslewCheck (int channel);
|
||||||
|
|
||||||
|
extern void setInputSamplerate_txa (int channel);
|
||||||
|
|
||||||
|
extern void setOutputSamplerate_txa (int channel);
|
||||||
|
|
||||||
|
extern void setDSPSamplerate_txa (int channel);
|
||||||
|
|
||||||
|
extern void setDSPBuffsize_txa (int channel);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAMode (int channel, int mode);
|
||||||
|
|
||||||
|
extern void TXAResCheck (int channel);
|
||||||
|
|
||||||
|
extern void TXASetupBPFilters (int channel);
|
||||||
|
|
||||||
|
#endif
|
||||||
+293
@@ -0,0 +1,293 @@
|
|||||||
|
/* amd.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
AMD create_amd
|
||||||
|
(
|
||||||
|
int run,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int mode,
|
||||||
|
int levelfade,
|
||||||
|
int sbmode,
|
||||||
|
int sample_rate,
|
||||||
|
double fmin,
|
||||||
|
double fmax,
|
||||||
|
double zeta,
|
||||||
|
double omegaN,
|
||||||
|
double tauR,
|
||||||
|
double tauI
|
||||||
|
)
|
||||||
|
{
|
||||||
|
AMD a = (AMD) malloc0 (sizeof(amd));
|
||||||
|
a->run = run;
|
||||||
|
a->buff_size = buff_size;
|
||||||
|
a->in_buff = in_buff;
|
||||||
|
a->out_buff = out_buff;
|
||||||
|
a->mode = mode;
|
||||||
|
a->levelfade = levelfade;
|
||||||
|
a->sbmode = sbmode;
|
||||||
|
a->sample_rate = (double)sample_rate;
|
||||||
|
a->fmin = fmin;
|
||||||
|
a->fmax = fmax;
|
||||||
|
a->zeta = zeta;
|
||||||
|
a->omegaN = omegaN;
|
||||||
|
a->tauR = tauR;
|
||||||
|
a->tauI = tauI;
|
||||||
|
|
||||||
|
init_amd(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_amd(AMD a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_amd(AMD a)
|
||||||
|
{
|
||||||
|
//pll
|
||||||
|
a->omega_min = TWOPI * a->fmin / a->sample_rate;
|
||||||
|
a->omega_max = TWOPI * a->fmax / a->sample_rate;
|
||||||
|
a->g1 = 1.0 - exp(-2.0 * a->omegaN * a->zeta / a->sample_rate);
|
||||||
|
a->g2 = -a->g1 + 2.0 * (1 - exp(-a->omegaN * a->zeta / a->sample_rate) * cos(a->omegaN / a->sample_rate * sqrt(1.0 - a->zeta * a->zeta)));
|
||||||
|
a->phs = 0.0;
|
||||||
|
a->fil_out = 0.0;
|
||||||
|
a->omega = 0.0;
|
||||||
|
|
||||||
|
//fade leveler
|
||||||
|
a->dc = 0.0;
|
||||||
|
a->dc_insert = 0.0;
|
||||||
|
a->mtauR = exp(-1.0 / (a->sample_rate * a->tauR));
|
||||||
|
a->onem_mtauR = 1.0 - a->mtauR;
|
||||||
|
a->mtauI = exp(-1.0 / (a->sample_rate * a->tauI));
|
||||||
|
a->onem_mtauI = 1.0 - a->mtauI;
|
||||||
|
|
||||||
|
//sideband separation
|
||||||
|
a->c0[0] = -0.328201924180698;
|
||||||
|
a->c0[1] = -0.744171491539427;
|
||||||
|
a->c0[2] = -0.923022915444215;
|
||||||
|
a->c0[3] = -0.978490468768238;
|
||||||
|
a->c0[4] = -0.994128272402075;
|
||||||
|
a->c0[5] = -0.998458978159551;
|
||||||
|
a->c0[6] = -0.999790306259206;
|
||||||
|
|
||||||
|
a->c1[0] = -0.0991227952747244;
|
||||||
|
a->c1[1] = -0.565619728761389;
|
||||||
|
a->c1[2] = -0.857467122550052;
|
||||||
|
a->c1[3] = -0.959123933111275;
|
||||||
|
a->c1[4] = -0.988739372718090;
|
||||||
|
a->c1[5] = -0.996959189310611;
|
||||||
|
a->c1[6] = -0.999282492800792;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_amd (AMD a)
|
||||||
|
{
|
||||||
|
a->dc = 0.0;
|
||||||
|
a->dc_insert = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xamd (AMD a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double audio;
|
||||||
|
double vco[2];
|
||||||
|
double corr[2];
|
||||||
|
double det;
|
||||||
|
double del_out;
|
||||||
|
double ai, bi, aq, bq;
|
||||||
|
double ai_ps, bi_ps, aq_ps, bq_ps;
|
||||||
|
int j, k;
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
switch (a->mode)
|
||||||
|
{
|
||||||
|
|
||||||
|
case 0: //AM Demodulator
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->buff_size; i++)
|
||||||
|
{
|
||||||
|
audio = sqrt(a->in_buff[2 * i + 0] * a->in_buff[2 * i + 0] + a->in_buff[2 * i + 1] * a->in_buff[2 * i + 1]);
|
||||||
|
if (a->levelfade)
|
||||||
|
{
|
||||||
|
a->dc = a->mtauR * a->dc + a->onem_mtauR * audio;
|
||||||
|
a->dc_insert = a->mtauI * a->dc_insert + a->onem_mtauI * audio;
|
||||||
|
audio += a->dc_insert - a->dc;
|
||||||
|
}
|
||||||
|
a->out_buff[2 * i + 0] = audio;
|
||||||
|
a->out_buff[2 * i + 1] = audio;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1: //Synchronous AM Demodulator with Sideband Separation
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->buff_size; i++)
|
||||||
|
{
|
||||||
|
vco[0] = cos(a->phs);
|
||||||
|
vco[1] = sin(a->phs);
|
||||||
|
|
||||||
|
ai = a->in_buff[2 * i + 0] * vco[0];
|
||||||
|
bi = a->in_buff[2 * i + 0] * vco[1];
|
||||||
|
aq = a->in_buff[2 * i + 1] * vco[0];
|
||||||
|
bq = a->in_buff[2 * i + 1] * vco[1];
|
||||||
|
|
||||||
|
if (a->sbmode != 0)
|
||||||
|
{
|
||||||
|
a->a[0] = a->dsI;
|
||||||
|
a->b[0] = bi;
|
||||||
|
a->c[0] = a->dsQ;
|
||||||
|
a->d[0] = aq;
|
||||||
|
a->dsI = ai;
|
||||||
|
a->dsQ = bq;
|
||||||
|
|
||||||
|
for (j = 0; j < STAGES; j++)
|
||||||
|
{
|
||||||
|
k = 3 * j;
|
||||||
|
a->a[k + 3] = a->c0[j] * (a->a[k] - a->a[k + 5]) + a->a[k + 2];
|
||||||
|
a->b[k + 3] = a->c1[j] * (a->b[k] - a->b[k + 5]) + a->b[k + 2];
|
||||||
|
a->c[k + 3] = a->c0[j] * (a->c[k] - a->c[k + 5]) + a->c[k + 2];
|
||||||
|
a->d[k + 3] = a->c1[j] * (a->d[k] - a->d[k + 5]) + a->d[k + 2];
|
||||||
|
}
|
||||||
|
ai_ps = a->a[OUT_IDX];
|
||||||
|
bi_ps = a->b[OUT_IDX];
|
||||||
|
bq_ps = a->c[OUT_IDX];
|
||||||
|
aq_ps = a->d[OUT_IDX];
|
||||||
|
|
||||||
|
for (j = OUT_IDX + 2; j > 0; j--)
|
||||||
|
{
|
||||||
|
a->a[j] = a->a[j - 1];
|
||||||
|
a->b[j] = a->b[j - 1];
|
||||||
|
a->c[j] = a->c[j - 1];
|
||||||
|
a->d[j] = a->d[j - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
corr[0] = +ai + bq;
|
||||||
|
corr[1] = -bi + aq;
|
||||||
|
|
||||||
|
switch(a->sbmode)
|
||||||
|
{
|
||||||
|
case 0: //both sidebands
|
||||||
|
{
|
||||||
|
audio = corr[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: //LSB
|
||||||
|
{
|
||||||
|
audio = (ai_ps - bi_ps) + (aq_ps + bq_ps);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: //USB
|
||||||
|
{
|
||||||
|
audio = (ai_ps + bi_ps) - (aq_ps - bq_ps);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->levelfade)
|
||||||
|
{
|
||||||
|
a->dc = a->mtauR * a->dc + a->onem_mtauR * audio;
|
||||||
|
a->dc_insert = a->mtauI * a->dc_insert + a->onem_mtauI * corr[0];
|
||||||
|
audio += a->dc_insert - a->dc;
|
||||||
|
}
|
||||||
|
a->out_buff[2 * i + 0] = audio;
|
||||||
|
a->out_buff[2 * i + 1] = audio;
|
||||||
|
|
||||||
|
if ((corr[0] == 0.0) && (corr[1] == 0.0)) corr[0] = 1.0;
|
||||||
|
det = atan2(corr[1], corr[0]);
|
||||||
|
del_out = a->fil_out;
|
||||||
|
a->omega += a->g2 * det;
|
||||||
|
if (a->omega < a->omega_min) a->omega = a->omega_min;
|
||||||
|
if (a->omega > a->omega_max) a->omega = a->omega_max;
|
||||||
|
a->fil_out = a->g1 * det + a->omega;
|
||||||
|
a->phs += del_out;
|
||||||
|
while (a->phs >= TWOPI) a->phs -= TWOPI;
|
||||||
|
while (a->phs < 0.0) a->phs += TWOPI;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in_buff != a->out_buff)
|
||||||
|
memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof(complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_amd (AMD a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in_buff = in;
|
||||||
|
a->out_buff = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_amd (AMD a, int rate)
|
||||||
|
{
|
||||||
|
a->sample_rate = rate;
|
||||||
|
init_amd(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_amd (AMD a, int size)
|
||||||
|
{
|
||||||
|
a->buff_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAAMDRun(int channel, int run)
|
||||||
|
{
|
||||||
|
AMD a = rxa[channel].amd.p;
|
||||||
|
if (a->run != run)
|
||||||
|
{
|
||||||
|
RXAbp1Check (channel, run, rxa[channel].snba.p->run, rxa[channel].emnr.p->run,
|
||||||
|
rxa[channel].anf.p->run, rxa[channel].anr.p->run);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->run = run;
|
||||||
|
RXAbp1Set (channel);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAAMDSBMode(int channel, int sbmode)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].amd.p->sbmode = sbmode;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAAMDFadeLevel(int channel, int levelfade)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].amd.p->levelfade = levelfade;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/* amd.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _amd_h
|
||||||
|
#define _amd_h
|
||||||
|
|
||||||
|
// ff defines for sbdemod
|
||||||
|
#ifndef STAGES
|
||||||
|
#define STAGES 7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OUT_IDX
|
||||||
|
#define OUT_IDX (3 * STAGES)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _amd
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int buff_size; // buffer size
|
||||||
|
double *in_buff; // pointer to input buffer
|
||||||
|
double *out_buff; // pointer to output buffer
|
||||||
|
int mode; // demodulation mode
|
||||||
|
double sample_rate; // sample rate
|
||||||
|
double dc; // dc component in demodulated output
|
||||||
|
double fmin; // pll - minimum carrier freq to lock
|
||||||
|
double fmax; // pll - maximum carrier freq to lock
|
||||||
|
double omega_min; // pll - minimum lock check parameter
|
||||||
|
double omega_max; // pll - maximum lock check parameter
|
||||||
|
double zeta; // pll - damping factor; as coded, must be <=1.0
|
||||||
|
double omegaN; // pll - natural frequency
|
||||||
|
double phs; // pll - phase accumulator
|
||||||
|
double omega; // pll - locked pll frequency
|
||||||
|
double fil_out; // pll - filter output
|
||||||
|
double g1, g2; // pll - filter gain parameters
|
||||||
|
double tauR; // carrier removal time constant
|
||||||
|
double tauI; // carrier insertion time constant
|
||||||
|
double mtauR; // carrier removal multiplier
|
||||||
|
double onem_mtauR; // 1.0 - carrier_removal_multiplier
|
||||||
|
double mtauI; // carrier insertion multiplier
|
||||||
|
double onem_mtauI; // 1.0 - carrier_insertion_multiplier
|
||||||
|
double a[3 * STAGES + 3]; // Filter a variables
|
||||||
|
double b[3 * STAGES + 3]; // Filter b variables
|
||||||
|
double c[3 * STAGES + 3]; // Filter c variables
|
||||||
|
double d[3 * STAGES + 3]; // Filter d variables
|
||||||
|
double c0[STAGES]; // Filter coefficients - path 0
|
||||||
|
double c1[STAGES]; // Filter coefficients - path 1
|
||||||
|
double dsI; // delayed sample, I path
|
||||||
|
double dsQ; // delayed sample, Q path
|
||||||
|
double dc_insert; // dc component to insert in output
|
||||||
|
int sbmode; // sideband mode
|
||||||
|
int levelfade; // Fade Leveler switch
|
||||||
|
|
||||||
|
}amd, *AMD;
|
||||||
|
|
||||||
|
extern AMD create_amd
|
||||||
|
(
|
||||||
|
int run,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int mode,
|
||||||
|
int levelfade,
|
||||||
|
int sbmode,
|
||||||
|
int sample_rate,
|
||||||
|
double fmin,
|
||||||
|
double fmax,
|
||||||
|
double zeta,
|
||||||
|
double omegaN,
|
||||||
|
double tauR,
|
||||||
|
double tauI
|
||||||
|
);
|
||||||
|
|
||||||
|
extern void init_amd (AMD a);
|
||||||
|
|
||||||
|
extern void destroy_amd (AMD a);
|
||||||
|
|
||||||
|
extern void flush_amd (AMD a);
|
||||||
|
|
||||||
|
extern void xamd (AMD a);
|
||||||
|
|
||||||
|
extern void setBuffers_amd (AMD a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_amd (AMD a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_amd (AMD a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMDRun(int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMDSBMode(int channel, int sbmode);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMDFadeLevel(int channel, int levelfade);
|
||||||
|
|
||||||
|
#endif
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
/* ammod.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
AMMOD create_ammod (int run, int mode, int size, double* in, double* out, double c_level)
|
||||||
|
{
|
||||||
|
AMMOD a = (AMMOD) malloc0 (sizeof (ammod));
|
||||||
|
a->run = run;
|
||||||
|
a->mode = mode;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->c_level = c_level;
|
||||||
|
a->a_level = 1.0 - a->c_level;
|
||||||
|
a->mult = 1.0 / sqrt (2.0);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_ammod (AMMOD a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_ammod (AMMOD a)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void xammod (AMMOD a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
switch (a->mode)
|
||||||
|
{
|
||||||
|
case 0: // AM
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
a->out[2 * i + 0] = a->out[2 * i + 1] = a->mult * (a->c_level + a->a_level * a->in[2 * i + 0]);
|
||||||
|
break;
|
||||||
|
case 1: // DSB
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
a->out[2 * i + 0] = a->out[2 * i + 1] = a->mult * a->in[2 * i + 0];
|
||||||
|
break;
|
||||||
|
case 2: // SSB w/Carrier
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = a->mult * a->c_level + a->a_level * a->in[2 * i + 0];
|
||||||
|
a->out[2 * i + 1] = a->mult * a->c_level + a->a_level * a->in[2 * i + 1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_ammod (AMMOD a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_ammod (AMMOD a, int rate)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_ammod (AMMOD a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetTXAAMCarrierLevel (int channel, double c_level)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].ammod.p->c_level = c_level;
|
||||||
|
txa[channel].ammod.p->a_level = 1.0 - c_level;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/* ammod.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ammod_h
|
||||||
|
#define _ammod_h
|
||||||
|
|
||||||
|
typedef struct _ammod
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int mode;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double c_level;
|
||||||
|
double a_level;
|
||||||
|
double mult;
|
||||||
|
}ammod, *AMMOD;
|
||||||
|
|
||||||
|
extern AMMOD create_ammod (int run, int mode, int size, double* in, double* out, double c_level);
|
||||||
|
|
||||||
|
extern void destroy_ammod (AMMOD a);
|
||||||
|
|
||||||
|
extern void flush_ammod (AMMOD a);
|
||||||
|
|
||||||
|
extern void xammod (AMMOD a);
|
||||||
|
|
||||||
|
extern void setBuffers_ammod (AMMOD a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_ammod (AMMOD a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_ammod (AMMOD a, int size);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAAMCarrierLevel (int channel, double c_level);
|
||||||
|
|
||||||
|
#endif
|
||||||
+272
@@ -0,0 +1,272 @@
|
|||||||
|
/* amsq.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void compute_slews(AMSQ a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double delta, theta;
|
||||||
|
delta = PI / (double)a->ntup;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ntup; i++)
|
||||||
|
{
|
||||||
|
a->cup[i] = a->muted_gain + (1.0 - a->muted_gain) * 0.5 * (1.0 - cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
delta = PI / (double)a->ntdown;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ntdown; i++)
|
||||||
|
{
|
||||||
|
a->cdown[i] = a->muted_gain + (1.0 - a->muted_gain) * 0.5 * (1.0 + cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_amsq(AMSQ a)
|
||||||
|
{
|
||||||
|
// signal averaging
|
||||||
|
a->trigsig = (double *)malloc0(a->size * sizeof(complex));
|
||||||
|
a->avm = exp(-1.0 / (a->rate * a->avtau));
|
||||||
|
a->onem_avm = 1.0 - a->avm;
|
||||||
|
a->avsig = 0.0;
|
||||||
|
// level change
|
||||||
|
a->ntup = (int)(a->tup * a->rate);
|
||||||
|
a->ntdown = (int)(a->tdown * a->rate);
|
||||||
|
a->cup = (double *)malloc0((a->ntup + 1) * sizeof(double));
|
||||||
|
a->cdown = (double *)malloc0((a->ntdown + 1) * sizeof(double));
|
||||||
|
compute_slews(a);
|
||||||
|
// control
|
||||||
|
a->state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_amsq (AMSQ a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->cdown);
|
||||||
|
_aligned_free (a->cup);
|
||||||
|
_aligned_free (a->trigsig);
|
||||||
|
}
|
||||||
|
|
||||||
|
AMSQ create_amsq (int run, int size, double* in, double* out, double* trigger, int rate, double avtau,
|
||||||
|
double tup, double tdown, double tail_thresh, double unmute_thresh, double min_tail, double max_tail, double muted_gain)
|
||||||
|
{
|
||||||
|
AMSQ a = (AMSQ) malloc0 (sizeof (amsq));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->muted_gain = muted_gain;
|
||||||
|
a->trigger = trigger;
|
||||||
|
a->avtau = avtau;
|
||||||
|
a->tup = tup;
|
||||||
|
a->tdown = tdown;
|
||||||
|
a->tail_thresh = tail_thresh;
|
||||||
|
a->unmute_thresh = unmute_thresh;
|
||||||
|
a->min_tail = min_tail;
|
||||||
|
a->max_tail = max_tail;
|
||||||
|
calc_amsq (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_amsq (AMSQ a)
|
||||||
|
{
|
||||||
|
decalc_amsq (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_amsq (AMSQ a)
|
||||||
|
{
|
||||||
|
memset (a->trigsig, 0, a->size * sizeof (complex));
|
||||||
|
a->avsig = 0.0;
|
||||||
|
a->state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _amsqstate
|
||||||
|
{
|
||||||
|
MUTED,
|
||||||
|
INCREASE,
|
||||||
|
UNMUTED,
|
||||||
|
TAIL,
|
||||||
|
DECREASE
|
||||||
|
};
|
||||||
|
|
||||||
|
void xamsq (AMSQ a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sig, siglimit;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
sig = sqrt (a->trigsig[2 * i + 0] * a->trigsig[2 * i + 0] + a->trigsig[2 * i + 1] * a->trigsig[2 * i + 1]);
|
||||||
|
a->avsig = a->avm * a->avsig + a->onem_avm * sig;
|
||||||
|
switch (a->state)
|
||||||
|
{
|
||||||
|
case MUTED:
|
||||||
|
if (a->avsig > a->unmute_thresh)
|
||||||
|
{
|
||||||
|
a->state = INCREASE;
|
||||||
|
a->count = a->ntup;
|
||||||
|
}
|
||||||
|
a->out[2 * i + 0] = a->muted_gain * a->in[2 * i + 0];
|
||||||
|
a->out[2 * i + 1] = a->muted_gain * a->in[2 * i + 1];
|
||||||
|
break;
|
||||||
|
case INCREASE:
|
||||||
|
a->out[2 * i + 0] = a->in[2 * i + 0] * a->cup[a->ntup - a->count];
|
||||||
|
a->out[2 * i + 1] = a->in[2 * i + 1] * a->cup[a->ntup - a->count];
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = UNMUTED;
|
||||||
|
break;
|
||||||
|
case UNMUTED:
|
||||||
|
if (a->avsig < a->tail_thresh)
|
||||||
|
{
|
||||||
|
a->state = TAIL;
|
||||||
|
if ((siglimit = a->avsig) > 1.0) siglimit = 1.0;
|
||||||
|
a->count = (int)((a->min_tail + (a->max_tail - a->min_tail) * (1.0 - siglimit)) * a->rate);
|
||||||
|
}
|
||||||
|
a->out[2 * i + 0] = a->in[2 * i + 0];
|
||||||
|
a->out[2 * i + 1] = a->in[2 * i + 1];
|
||||||
|
break;
|
||||||
|
case TAIL:
|
||||||
|
a->out[2 * i + 0] = a->in[2 * i + 0];
|
||||||
|
a->out[2 * i + 1] = a->in[2 * i + 1];
|
||||||
|
if (a->avsig > a->unmute_thresh)
|
||||||
|
a->state = UNMUTED;
|
||||||
|
else if (a->count-- == 0)
|
||||||
|
{
|
||||||
|
a->state = DECREASE;
|
||||||
|
a->count = a->ntdown;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DECREASE:
|
||||||
|
a->out[2 * i + 0] = a->in[2 * i + 0] * a->cdown[a->ntdown - a->count];
|
||||||
|
a->out[2 * i + 1] = a->in[2 * i + 1] * a->cdown[a->ntdown - a->count];
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = MUTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xamsqcap (AMSQ a)
|
||||||
|
{
|
||||||
|
memcpy (a->trigsig, a->trigger, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_amsq (AMSQ a, double* in, double* out, double* trigger)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->trigger = trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_amsq (AMSQ a, int rate)
|
||||||
|
{
|
||||||
|
decalc_amsq (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_amsq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_amsq (AMSQ a, int size)
|
||||||
|
{
|
||||||
|
decalc_amsq (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_amsq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAAMSQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].amsq.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAAMSQThreshold (int channel, double threshold)
|
||||||
|
{
|
||||||
|
double thresh = pow (10.0, threshold / 20.0);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].amsq.p->tail_thresh = 0.9 * thresh;
|
||||||
|
rxa[channel].amsq.p->unmute_thresh = thresh;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAAMSQMaxTail (int channel, double tail)
|
||||||
|
{
|
||||||
|
AMSQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].amsq.p;
|
||||||
|
if (tail < a->min_tail) tail = a->min_tail;
|
||||||
|
a->max_tail = tail;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAAMSQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].amsq.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAAMSQMutedGain (int channel, double dBlevel)
|
||||||
|
{ // dBlevel is negative
|
||||||
|
AMSQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].amsq.p;
|
||||||
|
a->muted_gain = pow (10.0, dBlevel / 20.0);
|
||||||
|
compute_slews(a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAAMSQThreshold (int channel, double threshold)
|
||||||
|
{
|
||||||
|
double thresh = pow (10.0, threshold / 20.0);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].amsq.p->tail_thresh = 0.9 * thresh;
|
||||||
|
txa[channel].amsq.p->unmute_thresh = thresh;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/* amsq.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _amsq_h
|
||||||
|
#define _amsq_h
|
||||||
|
|
||||||
|
typedef struct _amsq
|
||||||
|
{
|
||||||
|
int run; // 0 if squelch system is OFF; 1 if it's ON
|
||||||
|
int size; // size of input/output buffers
|
||||||
|
double* in; // squelch input signal buffer
|
||||||
|
double* out; // squelch output signal buffer
|
||||||
|
double* trigger; // pointer to trigger data source
|
||||||
|
double* trigsig; // buffer containing trigger signal
|
||||||
|
double rate; // sample rate
|
||||||
|
double avtau; // time constant for averaging noise
|
||||||
|
double avm;
|
||||||
|
double onem_avm;
|
||||||
|
double avsig;
|
||||||
|
int state; // state machine control
|
||||||
|
int count;
|
||||||
|
double tup;
|
||||||
|
double tdown;
|
||||||
|
int ntup;
|
||||||
|
int ntdown;
|
||||||
|
double* cup;
|
||||||
|
double* cdown;
|
||||||
|
double tail_thresh;
|
||||||
|
double unmute_thresh;
|
||||||
|
double min_tail;
|
||||||
|
double max_tail;
|
||||||
|
double muted_gain;
|
||||||
|
} amsq, *AMSQ;
|
||||||
|
|
||||||
|
extern AMSQ create_amsq (int run, int size, double* in, double* out, double* trigger, int rate, double avtau, double tup, double tdown, double tail_thresh, double unmute_thresh, double min_tail, double max_tail, double muted_gain);
|
||||||
|
|
||||||
|
extern void destroy_amsq (AMSQ a);
|
||||||
|
|
||||||
|
extern void flush_amsq (AMSQ a);
|
||||||
|
|
||||||
|
extern void xamsq (AMSQ a);
|
||||||
|
|
||||||
|
extern void xamsqcap (AMSQ a);
|
||||||
|
|
||||||
|
extern void setBuffers_amsq (AMSQ a, double* in, double* out, double* trigger);
|
||||||
|
|
||||||
|
extern void setSamplerate_amsq (AMSQ a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_amsq (AMSQ a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMSQRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMSQThreshold (int channel, double threshold);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAAMSQMaxTail (int channel, double tail);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAAMSQRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAAMSQMutedGain (int channel, double dBlevel);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAAMSQThreshold (int channel, double threshold);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1686
File diff suppressed because it is too large
Load Diff
+195
@@ -0,0 +1,195 @@
|
|||||||
|
/* analyzer.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Spectrum Analyzer
|
||||||
|
used in conjunction with software-defined-radio hardware.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013, 2014, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _analyzer_h
|
||||||
|
#define _analyzer_h
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
typedef struct _dp
|
||||||
|
{
|
||||||
|
int max_size; // maximum fft size to be used
|
||||||
|
int max_num_fft; // maximum number of LO positions per sub-span to be used
|
||||||
|
int max_stitch; // maximum number of sub-spans to be concatenated
|
||||||
|
// NOTE: max_size, max_num_fft, and max_stitch MUST BE <= THE
|
||||||
|
// CORRESPONDING VALUES IN <analyzer.h>!!
|
||||||
|
int num_fft; // current number of ffts in use
|
||||||
|
int num_pixout; // current number of detector/averages/pixel value outputs
|
||||||
|
int size; // current size of fft input sample vector
|
||||||
|
int out_size; // current size of fft output vector
|
||||||
|
int window_type; // type of the window function to be applied
|
||||||
|
int overlap; // number of samples re-used per fft, range 0 to size-1
|
||||||
|
int flip[dMAX_NUM_FFT]; // 0 for low-side LO => do NOT flip; 1 for high-side LO => FLIP
|
||||||
|
int clip; // number of bins to clip off on EACH end of the sub-span fft
|
||||||
|
// ASSUMES size/2 IS AN EVEN NUMBER!!!
|
||||||
|
double fsclipL; // number of intervals to clip off the lower end of the TOTAL SPAN
|
||||||
|
double fsclipH; // number of intervals to clip off the upper end of the TOTAL SPAN
|
||||||
|
int fscL; // fsclipL modulo (out_size - 2 * clip)
|
||||||
|
int fscH; // fsclipH modulo (out_size - 2 * clip)
|
||||||
|
int begin_ss; // number of first sub-span that is NOT completely clipped off
|
||||||
|
int end_ss; // number of last sub-span that is NOT completely clipped off
|
||||||
|
int ss_bins[dMAX_STITCH]; // number of bins delivered by eliminate()/Celiminate in each sub-span
|
||||||
|
volatile LONG input_busy[dMAX_STITCH][dMAX_NUM_FFT];
|
||||||
|
int num_pixels; // number of pixels requested
|
||||||
|
int num_stitch; // number of results to be stitched together to generate the pixel frame
|
||||||
|
unsigned long long stitch_flag;
|
||||||
|
int spec_flag[dMAX_STITCH]; // flags showing if all ffts for a sub-span are done so elimination can proceed
|
||||||
|
double pix_per_bin; // number of pixels per fft bin, note that this is fractional, not integral
|
||||||
|
double det_offset; // offset needed in detector
|
||||||
|
double bin_per_pix; // number of fft bins per pixel, this is fractional and != 1.0/pix_per_bin
|
||||||
|
double scale; // output amplitude scale factor
|
||||||
|
double PiAlpha; // parameter for Kaiser window function
|
||||||
|
|
||||||
|
int cal_set; // specifies which set of calibration data to use
|
||||||
|
double f_min; // frequency at first pixel (for calibration)
|
||||||
|
double f_max; // frequency at last pixel (for calibration)
|
||||||
|
int cal_changed; // flag to indicate that the calibration data has changed
|
||||||
|
|
||||||
|
double *window; // pointer to buffer to hold window coefficients
|
||||||
|
double *result[dMAX_STITCH]; // pointers to buffer to hold elimination results for each sub-span
|
||||||
|
dOUTREAL *pixels[dMAX_PIXOUTS][dNUM_PIXEL_BUFFS]; // pointers pixel output buffers
|
||||||
|
double *t_pixels[dMAX_PIXOUTS]; // pointer to temporary pixel buffer //pointer to temporary pixel buffer for non-averaged data
|
||||||
|
int w_pix_buff[dMAX_PIXOUTS]; // number of pixel buffer owned by writing process
|
||||||
|
int r_pix_buff[dMAX_PIXOUTS]; // number of pixel buffer owned by reading process
|
||||||
|
int last_pix_buff[dMAX_PIXOUTS]; // number of the last pixel buffer written
|
||||||
|
volatile LONG pb_ready[dMAX_PIXOUTS][dNUM_PIXEL_BUFFS]; // if value is 0, this data has already been read; 1 = fresh data to read
|
||||||
|
int num_average[dMAX_PIXOUTS]; // number of spans to average to create the pixels
|
||||||
|
int avail_frames[dMAX_PIXOUTS]; // number of pixel frames currently available to average
|
||||||
|
int av_in_idx[dMAX_PIXOUTS]; // input index in averaging pixel buffer ring
|
||||||
|
int av_out_idx[dMAX_PIXOUTS]; // output index in averaging pixel buffer ring
|
||||||
|
double *av_sum[dMAX_PIXOUTS]; // pointer to sum buffer for averaging
|
||||||
|
double *av_buff[dMAX_PIXOUTS][dMAX_AVERAGE]; // pointers to ring of buffers to hold pixel frames for averaging
|
||||||
|
double *pre_av_out;
|
||||||
|
int av_mode[dMAX_PIXOUTS];
|
||||||
|
double av_backmult[dMAX_PIXOUTS]; // back multiplier for weighted averaging
|
||||||
|
double *cd; // pointer to amplitude calibration buffer
|
||||||
|
int n_freqs[dMAX_CAL_SETS]; // number of frequencies in each calibration set
|
||||||
|
double *freqs[dMAX_CAL_SETS]; // pointers to vectors of calibration frequencies
|
||||||
|
double (*ac3[dMAX_CAL_SETS][dMAX_M]); // pointers to amplitude interpolant coefficients
|
||||||
|
double (*ac2[dMAX_CAL_SETS][dMAX_M]);
|
||||||
|
double (*ac1[dMAX_CAL_SETS][dMAX_M]);
|
||||||
|
double (*ac0[dMAX_CAL_SETS][dMAX_M]);
|
||||||
|
|
||||||
|
fftw_plan plan[dMAX_STITCH][dMAX_NUM_FFT]; // fftw plans
|
||||||
|
fftw_plan Cplan[dMAX_STITCH][dMAX_NUM_FFT];
|
||||||
|
double *fft_in[dMAX_STITCH][dMAX_NUM_FFT]; // pointers to fftw real input vectors
|
||||||
|
fftw_complex *Cfft_in[dMAX_STITCH][dMAX_NUM_FFT]; // pointers to fftw complex input vectors
|
||||||
|
fftw_complex *fft_out[dMAX_STITCH][dMAX_NUM_FFT]; // pointers to fftw complex output vectors
|
||||||
|
volatile LONG *pnum_threads; // pointer to current number of active worker threads
|
||||||
|
int stop; // when set, fft threads will be returned to the pool
|
||||||
|
int end_dispatcher; // set this flag to one to destroy the dispatcher thread
|
||||||
|
volatile int dispatcher; // one if the dispatcher thread is alive & active
|
||||||
|
int ss; // sub-span being processed
|
||||||
|
int LO; // LO (within current sub-span) being processed
|
||||||
|
int flag;
|
||||||
|
int have_samples[dMAX_STITCH][dMAX_NUM_FFT]; // number of unused samples remaining in a buffer
|
||||||
|
int type; // 0 for REAL, 1 for COMPLEX
|
||||||
|
int incr; // size - overlap
|
||||||
|
int buff_size; // amount of data to be stored each time an input buffer is opened and closed = JanusAudio/BlockSize
|
||||||
|
dINREAL* I_samples[dMAX_STITCH][dMAX_NUM_FFT]; // pointers to current input position in I/Q buffers
|
||||||
|
dINREAL* Q_samples[dMAX_STITCH][dMAX_NUM_FFT];
|
||||||
|
int bsize; // size of I_samples[][] and Q_samples[][] (number of samples they hold)
|
||||||
|
int IQout_index[dMAX_STITCH][dMAX_NUM_FFT]; // current output index for I_samples[ss][LO] and Q_samples[ss][LO]
|
||||||
|
int IQO_idx[dMAX_STITCH][dMAX_NUM_FFT];
|
||||||
|
int IQin_index[dMAX_STITCH][dMAX_NUM_FFT]; // current input index for I_samples[ss][LO] and Q_samples[ss][LO]
|
||||||
|
volatile LONG buff_ready[dMAX_STITCH][dMAX_NUM_FFT]; // 1 if buffer ready to read; 0 if needs to be filled
|
||||||
|
int max_writeahead; // max allowed input samples ahead of where reading output samples
|
||||||
|
|
||||||
|
volatile LONG snap[dMAX_STITCH][dMAX_NUM_FFT]; // set to 1 to allow a snap of raw spectrum data
|
||||||
|
HANDLE hSnapEvent[dMAX_STITCH][dMAX_NUM_FFT]; // mutex handles; mutexes will be used to signal a snap is complete
|
||||||
|
double *snap_buff[dMAX_STITCH][dMAX_NUM_FFT]; // pointers to buffers for the snap
|
||||||
|
|
||||||
|
CRITICAL_SECTION PB_ControlsSection[dMAX_PIXOUTS];
|
||||||
|
CRITICAL_SECTION SetAnalyzerSection;
|
||||||
|
CRITICAL_SECTION BufferControlSection[dMAX_STITCH][dMAX_NUM_FFT];
|
||||||
|
CRITICAL_SECTION StitchSection;
|
||||||
|
CRITICAL_SECTION EliminateSection[dMAX_STITCH];
|
||||||
|
CRITICAL_SECTION ResampleSection;
|
||||||
|
|
||||||
|
int det_type[dMAX_PIXOUTS]; // detector type
|
||||||
|
double inv_coherent_gain;
|
||||||
|
double inherent_power_gain;
|
||||||
|
double inv_enb;
|
||||||
|
double norm_oneHz; // dB factor to normalize to one Hz bandwidth
|
||||||
|
int sample_rate; // sample rate; used for normalization calculations
|
||||||
|
int normalize[dMAX_PIXOUTS];
|
||||||
|
} dp, *DP;
|
||||||
|
|
||||||
|
extern DP pdisp[];
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void CreateAnalyzer ( int disp,
|
||||||
|
int *success,
|
||||||
|
char *app_data_path);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void XCreateAnalyzer ( int disp,
|
||||||
|
int *success, //writes '0' to success if all went well, <0 if mem alloc failed
|
||||||
|
int m_size, //maximum fft size to be used
|
||||||
|
int m_LO, //maximum number of LO positions per subspan
|
||||||
|
int m_stitch, //maximum number of subspans to be concatenated
|
||||||
|
char *app_data_path
|
||||||
|
);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void DestroyAnalyzer(int disp);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void SetCalibration ( int disp,
|
||||||
|
int set_num, //identifier for this calibration data set
|
||||||
|
int n_points, //number of calibration points in the set
|
||||||
|
double (*cal)[dMAX_M+1] //pointer to the calibration table, first
|
||||||
|
);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void OpenBuffer(int disp, int ss, int LO, void **Ipointer, void **Qpointer);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void CloseBuffer(int disp, int ss, int LO);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void Spectrum(int disp, int ss, int LO, dINREAL* pI, dINREAL* pQ);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void Spectrum2(int run, int disp, int ss, int LO, dINREAL* pbuff);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void Spectrum0(int run, int disp, int ss, int LO, double* pbuff);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void SnapSpectrum( int disp,
|
||||||
|
int ss,
|
||||||
|
int LO,
|
||||||
|
double *snap_buff);
|
||||||
|
|
||||||
|
extern __declspec( dllexport )
|
||||||
|
void SnapSpectrumTimeout (int disp,
|
||||||
|
int ss,
|
||||||
|
int LO,
|
||||||
|
double* snap_buff,
|
||||||
|
DWORD timeout,
|
||||||
|
int* flag);
|
||||||
|
|
||||||
|
#endif
|
||||||
+239
@@ -0,0 +1,239 @@
|
|||||||
|
/* anf.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
ANF create_anf (
|
||||||
|
int run,
|
||||||
|
int position,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int dline_size,
|
||||||
|
int n_taps,
|
||||||
|
int delay,
|
||||||
|
double two_mu,
|
||||||
|
double gamma,
|
||||||
|
|
||||||
|
double lidx,
|
||||||
|
double lidx_min,
|
||||||
|
double lidx_max,
|
||||||
|
double ngamma,
|
||||||
|
double den_mult,
|
||||||
|
double lincr,
|
||||||
|
double ldecr
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ANF a = (ANF) malloc0 (sizeof(anf));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->buff_size = buff_size;
|
||||||
|
a->in_buff = in_buff;
|
||||||
|
a->out_buff = out_buff;
|
||||||
|
a->dline_size = dline_size;
|
||||||
|
a->mask = dline_size - 1;
|
||||||
|
a->n_taps = n_taps;
|
||||||
|
a->delay = delay;
|
||||||
|
a->two_mu = two_mu;
|
||||||
|
a->gamma = gamma;
|
||||||
|
a->in_idx = 0;
|
||||||
|
a->lidx = lidx;
|
||||||
|
a->lidx_min = lidx_min;
|
||||||
|
a->lidx_max = lidx_max;
|
||||||
|
a->ngamma = ngamma;
|
||||||
|
a->den_mult = den_mult;
|
||||||
|
a->lincr = lincr;
|
||||||
|
a->ldecr = ldecr;
|
||||||
|
|
||||||
|
memset (a->d, 0, sizeof(double) * ANF_DLINE_SIZE);
|
||||||
|
memset (a->w, 0, sizeof(double) * ANF_DLINE_SIZE);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_anf (ANF a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xanf(ANF a, int position)
|
||||||
|
{
|
||||||
|
int i, j, idx;
|
||||||
|
double c0, c1;
|
||||||
|
double y, error, sigma, inv_sigp;
|
||||||
|
double nel, nev;
|
||||||
|
if (a->run && (a->position == position))
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->buff_size; i++)
|
||||||
|
{
|
||||||
|
a->d[a->in_idx] = a->in_buff[2 * i + 0];
|
||||||
|
|
||||||
|
y = 0;
|
||||||
|
sigma = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < a->n_taps; j++)
|
||||||
|
{
|
||||||
|
idx = (a->in_idx + j + a->delay) & a->mask;
|
||||||
|
y += a->w[j] * a->d[idx];
|
||||||
|
sigma += a->d[idx] * a->d[idx];
|
||||||
|
}
|
||||||
|
inv_sigp = 1.0 / (sigma + 1e-10);
|
||||||
|
error = a->d[a->in_idx] - y;
|
||||||
|
|
||||||
|
a->out_buff[2 * i + 0] = error;
|
||||||
|
a->out_buff[2 * i + 1] = 0.0;
|
||||||
|
|
||||||
|
if((nel = error * (1.0 - a->two_mu * sigma * inv_sigp)) < 0.0) nel = -nel;
|
||||||
|
if((nev = a->d[a->in_idx] - (1.0 - a->two_mu * a->ngamma) * y - a->two_mu * error * sigma * inv_sigp) < 0.0) nev = -nev;
|
||||||
|
if (nev < nel)
|
||||||
|
{
|
||||||
|
if ((a->lidx += a->lincr) > a->lidx_max) a->lidx = a->lidx_max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((a->lidx -= a->ldecr) < a->lidx_min) a->lidx = a->lidx_min;
|
||||||
|
}
|
||||||
|
a->ngamma = a->gamma * (a->lidx * a->lidx) * (a->lidx * a->lidx) * a->den_mult;
|
||||||
|
|
||||||
|
c0 = 1.0 - a->two_mu * a->ngamma;
|
||||||
|
c1 = a->two_mu * error * inv_sigp;
|
||||||
|
|
||||||
|
for (j = 0; j < a->n_taps; j++)
|
||||||
|
{
|
||||||
|
idx = (a->in_idx + j + a->delay) & a->mask;
|
||||||
|
a->w[j] = c0 * a->w[j] + c1 * a->d[idx];
|
||||||
|
}
|
||||||
|
a->in_idx = (a->in_idx + a->mask) & a->mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in_buff != a->out_buff)
|
||||||
|
memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_anf (ANF a)
|
||||||
|
{
|
||||||
|
memset (a->d, 0, sizeof(double) * ANF_DLINE_SIZE);
|
||||||
|
memset (a->w, 0, sizeof(double) * ANF_DLINE_SIZE);
|
||||||
|
a->in_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_anf (ANF a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in_buff = in;
|
||||||
|
a->out_buff = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_anf (ANF a, int rate)
|
||||||
|
{
|
||||||
|
flush_anf (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_anf (ANF a, int size)
|
||||||
|
{
|
||||||
|
a->buff_size = size;
|
||||||
|
flush_anf (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFRun (int channel, int run)
|
||||||
|
{
|
||||||
|
ANF a = rxa[channel].anf.p;
|
||||||
|
if (a->run != run)
|
||||||
|
{
|
||||||
|
RXAbp1Check (channel, rxa[channel].amd.p->run, rxa[channel].snba.p->run,
|
||||||
|
rxa[channel].emnr.p->run, run, rxa[channel].anr.p->run);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->run = run;
|
||||||
|
RXAbp1Set (channel);
|
||||||
|
flush_anf (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFVals (int channel, int taps, int delay, double gain, double leakage)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->n_taps = taps;
|
||||||
|
rxa[channel].anf.p->delay = delay;
|
||||||
|
rxa[channel].anf.p->two_mu = gain; //try two_mu = 1e-4
|
||||||
|
rxa[channel].anf.p->gamma = leakage; //try gamma = 0.10
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFTaps (int channel, int taps)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->n_taps = taps;
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFDelay (int channel, int delay)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->delay = delay;
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFGain (int channel, double gain)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->two_mu = gain;
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFLeakage (int channel, double leakage)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->gamma = leakage;
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANFPosition (int channel, int position)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anf.p->position = position;
|
||||||
|
rxa[channel].bp1.p->position = position;
|
||||||
|
flush_anf (rxa[channel].anf.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
/* anf.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _anf_h
|
||||||
|
#define _anf_h
|
||||||
|
|
||||||
|
#define ANF_DLINE_SIZE 2048
|
||||||
|
|
||||||
|
typedef struct _anf
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int buff_size;
|
||||||
|
double *in_buff;
|
||||||
|
double *out_buff;
|
||||||
|
int dline_size;
|
||||||
|
int mask;
|
||||||
|
int n_taps;
|
||||||
|
int delay;
|
||||||
|
double two_mu;
|
||||||
|
double gamma;
|
||||||
|
double d [ANF_DLINE_SIZE];
|
||||||
|
double w [ANF_DLINE_SIZE];
|
||||||
|
int in_idx;
|
||||||
|
|
||||||
|
double lidx;
|
||||||
|
double lidx_min;
|
||||||
|
double lidx_max;
|
||||||
|
double ngamma;
|
||||||
|
double den_mult;
|
||||||
|
double lincr;
|
||||||
|
double ldecr;
|
||||||
|
} anf, *ANF;
|
||||||
|
|
||||||
|
extern ANF create_anf (
|
||||||
|
int run,
|
||||||
|
int position,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int dline_size,
|
||||||
|
int n_taps,
|
||||||
|
int delay,
|
||||||
|
double two_mu,
|
||||||
|
double gamma,
|
||||||
|
|
||||||
|
double lidx,
|
||||||
|
double lidx_min,
|
||||||
|
double lidx_max,
|
||||||
|
double ngamma,
|
||||||
|
double den_mult,
|
||||||
|
double lincr,
|
||||||
|
double ldecr
|
||||||
|
);
|
||||||
|
|
||||||
|
extern void destroy_anf (ANF a);
|
||||||
|
|
||||||
|
extern void flush_anf (ANF a);
|
||||||
|
|
||||||
|
extern void xanf (ANF a, int position);
|
||||||
|
|
||||||
|
extern void setBuffers_anf (ANF a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_anf (ANF a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_anf (ANF a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFRun (int channel, int setit);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFVals (int channel, int taps, int delay, double gain, double leakage);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFTaps (int channel, int taps);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFDelay (int channel, int delay);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFGain (int channel, double gain);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFLeakage (int channel, double leakage);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANFPosition (int channel, int position);
|
||||||
|
|
||||||
|
#endif
|
||||||
+238
@@ -0,0 +1,238 @@
|
|||||||
|
/* anr.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
ANR create_anr (
|
||||||
|
int run,
|
||||||
|
int position,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int dline_size,
|
||||||
|
int n_taps,
|
||||||
|
int delay,
|
||||||
|
double two_mu,
|
||||||
|
double gamma,
|
||||||
|
|
||||||
|
double lidx,
|
||||||
|
double lidx_min,
|
||||||
|
double lidx_max,
|
||||||
|
double ngamma,
|
||||||
|
double den_mult,
|
||||||
|
double lincr,
|
||||||
|
double ldecr
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ANR a = (ANR) malloc0 (sizeof(anr));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->buff_size = buff_size;
|
||||||
|
a->in_buff = in_buff;
|
||||||
|
a->out_buff = out_buff;
|
||||||
|
a->dline_size = dline_size;
|
||||||
|
a->mask = dline_size - 1;
|
||||||
|
a->n_taps = n_taps;
|
||||||
|
a->delay = delay;
|
||||||
|
a->two_mu = two_mu;
|
||||||
|
a->gamma = gamma;
|
||||||
|
a->in_idx = 0;
|
||||||
|
a->lidx = lidx;
|
||||||
|
a->lidx_min = lidx_min;
|
||||||
|
a->lidx_max = lidx_max;
|
||||||
|
a->ngamma = ngamma;
|
||||||
|
a->den_mult = den_mult;
|
||||||
|
a->lincr = lincr;
|
||||||
|
a->ldecr = ldecr;
|
||||||
|
|
||||||
|
memset (a->d, 0, sizeof(double) * ANR_DLINE_SIZE);
|
||||||
|
memset (a->w, 0, sizeof(double) * ANR_DLINE_SIZE);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_anr (ANR a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xanr (ANR a, int position)
|
||||||
|
{
|
||||||
|
int i, j, idx;
|
||||||
|
double c0, c1;
|
||||||
|
double y, error, sigma, inv_sigp;
|
||||||
|
double nel, nev;
|
||||||
|
if (a->run && (a->position == position))
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->buff_size; i++)
|
||||||
|
{
|
||||||
|
a->d[a->in_idx] = a->in_buff[2 * i + 0];
|
||||||
|
|
||||||
|
y = 0;
|
||||||
|
sigma = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < a->n_taps; j++)
|
||||||
|
{
|
||||||
|
idx = (a->in_idx + j + a->delay) & a->mask;
|
||||||
|
y += a->w[j] * a->d[idx];
|
||||||
|
sigma += a->d[idx] * a->d[idx];
|
||||||
|
}
|
||||||
|
inv_sigp = 1.0 / (sigma + 1e-10);
|
||||||
|
error = a->d[a->in_idx] - y;
|
||||||
|
|
||||||
|
a->out_buff[2 * i + 0] = y;
|
||||||
|
a->out_buff[2 * i + 1] = 0.0;
|
||||||
|
|
||||||
|
if((nel = error * (1.0 - a->two_mu * sigma * inv_sigp)) < 0.0) nel = -nel;
|
||||||
|
if((nev = a->d[a->in_idx] - (1.0 - a->two_mu * a->ngamma) * y - a->two_mu * error * sigma * inv_sigp) < 0.0) nev = -nev;
|
||||||
|
if (nev < nel)
|
||||||
|
{
|
||||||
|
if ((a->lidx += a->lincr) > a->lidx_max) a->lidx = a->lidx_max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((a->lidx -= a->ldecr) < a->lidx_min) a->lidx = a->lidx_min;
|
||||||
|
}
|
||||||
|
a->ngamma = a->gamma * (a->lidx * a->lidx) * (a->lidx * a->lidx) * a->den_mult;
|
||||||
|
|
||||||
|
c0 = 1.0 - a->two_mu * a->ngamma;
|
||||||
|
c1 = a->two_mu * error * inv_sigp;
|
||||||
|
|
||||||
|
for (j = 0; j < a->n_taps; j++)
|
||||||
|
{
|
||||||
|
idx = (a->in_idx + j + a->delay) & a->mask;
|
||||||
|
a->w[j] = c0 * a->w[j] + c1 * a->d[idx];
|
||||||
|
}
|
||||||
|
a->in_idx = (a->in_idx + a->mask) & a->mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in_buff != a->out_buff)
|
||||||
|
memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_anr (ANR a)
|
||||||
|
{
|
||||||
|
memset (a->d, 0, sizeof(double) * ANR_DLINE_SIZE);
|
||||||
|
memset (a->w, 0, sizeof(double) * ANR_DLINE_SIZE);
|
||||||
|
a->in_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_anr (ANR a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in_buff = in;
|
||||||
|
a->out_buff = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_anr (ANR a, int rate)
|
||||||
|
{
|
||||||
|
flush_anr(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_anr (ANR a, int size)
|
||||||
|
{
|
||||||
|
a->buff_size = size;
|
||||||
|
flush_anr(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRRun (int channel, int run)
|
||||||
|
{
|
||||||
|
ANR a = rxa[channel].anr.p;
|
||||||
|
if (a->run != run)
|
||||||
|
{
|
||||||
|
RXAbp1Check (channel, rxa[channel].amd.p->run, rxa[channel].snba.p->run,
|
||||||
|
rxa[channel].emnr.p->run, rxa[channel].anf.p->run, run);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->run = run;
|
||||||
|
RXAbp1Set (channel);
|
||||||
|
flush_anr (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRVals (int channel, int taps, int delay, double gain, double leakage)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->n_taps = taps;
|
||||||
|
rxa[channel].anr.p->delay = delay;
|
||||||
|
rxa[channel].anr.p->two_mu = gain;
|
||||||
|
rxa[channel].anr.p->gamma = leakage;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRTaps (int channel, int taps)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->n_taps = taps;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRDelay (int channel, int delay)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->delay = delay;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRGain (int channel, double gain)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->two_mu = gain;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRLeakage (int channel, double leakage)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->gamma = leakage;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXAANRPosition (int channel, int position)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].anr.p->position = position;
|
||||||
|
rxa[channel].bp1.p->position = position;
|
||||||
|
flush_anr (rxa[channel].anr.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
/* anr.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _anr_h
|
||||||
|
#define _anr_h
|
||||||
|
|
||||||
|
#define ANR_DLINE_SIZE 2048
|
||||||
|
|
||||||
|
typedef struct _anr
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int buff_size;
|
||||||
|
double *in_buff;
|
||||||
|
double *out_buff;
|
||||||
|
int dline_size;
|
||||||
|
int mask;
|
||||||
|
int n_taps;
|
||||||
|
int delay;
|
||||||
|
double two_mu;
|
||||||
|
double gamma;
|
||||||
|
double d [ANR_DLINE_SIZE];
|
||||||
|
double w [ANR_DLINE_SIZE];
|
||||||
|
int in_idx;
|
||||||
|
|
||||||
|
double lidx;
|
||||||
|
double lidx_min;
|
||||||
|
double lidx_max;
|
||||||
|
double ngamma;
|
||||||
|
double den_mult;
|
||||||
|
double lincr;
|
||||||
|
double ldecr;
|
||||||
|
} anr, *ANR;
|
||||||
|
|
||||||
|
extern ANR create_anr (
|
||||||
|
int run,
|
||||||
|
int position,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int dline_size,
|
||||||
|
int n_taps,
|
||||||
|
int delay,
|
||||||
|
double two_mu,
|
||||||
|
double gamma,
|
||||||
|
|
||||||
|
double lidx,
|
||||||
|
double lidx_min,
|
||||||
|
double lidx_max,
|
||||||
|
double ngamma,
|
||||||
|
double den_mult,
|
||||||
|
double lincr,
|
||||||
|
double ldecr
|
||||||
|
);
|
||||||
|
|
||||||
|
extern void destroy_anr (ANR a);
|
||||||
|
|
||||||
|
extern void flush_anr (ANR a);
|
||||||
|
|
||||||
|
extern void xanr (ANR a, int position);
|
||||||
|
|
||||||
|
extern void setBuffers_anr (ANR a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_anr (ANR a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_anr (ANR a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRRun (int channel, int setit);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRVals (int channel, int taps, int delay, double gain, double leakage);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRTaps (int channel, int taps);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRDelay (int channel, int delay);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRGain (int channel, double gain);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRLeakage (int channel, double leakage);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAANRPosition (int channel, int position);
|
||||||
|
|
||||||
|
#endif
|
||||||
+594
@@ -0,0 +1,594 @@
|
|||||||
|
/* bandpass.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void calc_bps (BPS a)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->infilt = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->product = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
impulse = fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults(2 * a->size, impulse);
|
||||||
|
a->CFor = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->infilt, (fftw_complex *)a->product, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->CRev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->product, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
_aligned_free(impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_bps (BPS a)
|
||||||
|
{
|
||||||
|
fftw_destroy_plan(a->CRev);
|
||||||
|
fftw_destroy_plan(a->CFor);
|
||||||
|
_aligned_free(a->mults);
|
||||||
|
_aligned_free(a->product);
|
||||||
|
_aligned_free(a->infilt);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPS create_bps (int run, int position, int size, double* in, double* out,
|
||||||
|
double f_low, double f_high, int samplerate, int wintype, double gain)
|
||||||
|
{
|
||||||
|
BPS a = (BPS) malloc0 (sizeof (bps));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->samplerate = (double)samplerate;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->gain = gain;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
calc_bps (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_bps (BPS a)
|
||||||
|
{
|
||||||
|
decalc_bps (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_bps (BPS a)
|
||||||
|
{
|
||||||
|
memset (a->infilt, 0, 2 * a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xbps (BPS a, int pos)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double I, Q;
|
||||||
|
if (a->run && pos == a->position)
|
||||||
|
{
|
||||||
|
memcpy (&(a->infilt[2 * a->size]), a->in, a->size * sizeof (complex));
|
||||||
|
fftw_execute (a->CFor);
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
{
|
||||||
|
I = a->gain * a->product[2 * i + 0];
|
||||||
|
Q = a->gain * a->product[2 * i + 1];
|
||||||
|
a->product[2 * i + 0] = I * a->mults[2 * i + 0] - Q * a->mults[2 * i + 1];
|
||||||
|
a->product[2 * i + 1] = I * a->mults[2 * i + 1] + Q * a->mults[2 * i + 0];
|
||||||
|
}
|
||||||
|
fftw_execute (a->CRev);
|
||||||
|
memcpy (a->infilt, &(a->infilt[2 * a->size]), a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_bps (BPS a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_bps (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_bps (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_bps (BPS a, int rate)
|
||||||
|
{
|
||||||
|
decalc_bps (a);
|
||||||
|
a->samplerate = rate;
|
||||||
|
calc_bps (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_bps (BPS a, int size)
|
||||||
|
{
|
||||||
|
decalc_bps (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_bps (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFreqs_bps (BPS a, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
decalc_bps (a);
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
calc_bps (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Bandpass: RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
/* // UNCOMMENT properties when a pointer is in place in rxa[channel]
|
||||||
|
PORT
|
||||||
|
void SetRXABPSRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].bp1.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABPSFreqs (int channel, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BPS a1;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a1 = rxa[channel].bp1.p;
|
||||||
|
if ((f_low != a1->f_low) || (f_high != a1->f_high))
|
||||||
|
{
|
||||||
|
a1->f_low = f_low;
|
||||||
|
a1->f_high = f_high;
|
||||||
|
_aligned_free (a1->mults);
|
||||||
|
impulse = fir_bandpass(a1->size + 1, f_low, f_high, a1->samplerate, a1->wintype, 1, 1.0 / (double)(2 * a1->size));
|
||||||
|
a1->mults = fftcv_mults (2 * a1->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABPSWindow (int channel, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BPS a1;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a1 = rxa[channel].bp1.p;
|
||||||
|
if ((a1->wintype != wintype))
|
||||||
|
{
|
||||||
|
a1->wintype = wintype;
|
||||||
|
_aligned_free (a1->mults);
|
||||||
|
impulse = fir_bandpass(a1->size + 1, a1->f_low, a1->f_high, a1->samplerate, a1->wintype, 1, 1.0 / (double)(2 * a1->size));
|
||||||
|
a1->mults = fftcv_mults (2 * a1->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
/* // UNCOMMENT properties when pointers in place in txa[channel]
|
||||||
|
PORT
|
||||||
|
void SetTXABPSRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].bp1.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABPSFreqs (int channel, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BPS a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].bp0.p;
|
||||||
|
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp1.p;
|
||||||
|
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp2.p;
|
||||||
|
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABPSWindow (int channel, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BPS a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].bp0.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp1.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp2.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
impulse = fir_bandpass (a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||||
|
a->mults = fftcv_mults (2 * a->size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
BANDPASS create_bandpass (int run, int position, int size, int nc, int mp, double* in, double* out,
|
||||||
|
double f_low, double f_high, int samplerate, int wintype, double gain)
|
||||||
|
{
|
||||||
|
// NOTE: 'nc' must be >= 'size'
|
||||||
|
BANDPASS a = (BANDPASS) malloc0 (sizeof (bandpass));
|
||||||
|
double* impulse;
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->samplerate = samplerate;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->gain = gain;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
a->p = create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_bandpass (BANDPASS a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_bandpass (BANDPASS a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xbandpass (BANDPASS a, int pos)
|
||||||
|
{
|
||||||
|
if (a->run && a->position == pos)
|
||||||
|
xfircore (a->p);
|
||||||
|
else if (a->out != a->in)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_bandpass (BANDPASS a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
setBuffers_fircore (a->p, a->in, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_bandpass (BANDPASS a, int rate)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->samplerate = rate;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_bandpass (BANDPASS a, int size)
|
||||||
|
{
|
||||||
|
// NOTE: 'size' must be <= 'nc'
|
||||||
|
double* impulse;
|
||||||
|
a->size = size;
|
||||||
|
setSize_fircore (a->p, a->size);
|
||||||
|
// recalc impulse because scale factor is a function of size
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGain_bandpass (BANDPASS a, double gain, int update)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->gain = gain;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, update);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalcBandpassFilter (BANDPASS a, double f_low, double f_high, double gain)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
if ((a->f_low != f_low) || (a->f_high != f_high) || (a->gain != gain))
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->gain = gain;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABandpassRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].bp1.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABandpassFreqs (int channel, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BANDPASS a = rxa[channel].bp1.p;
|
||||||
|
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
{
|
||||||
|
impulse = fir_bandpass (a->nc, f_low, f_high, a->samplerate,
|
||||||
|
a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 0);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
setUpdate_fircore (a->p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABandpassWindow (int channel, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BANDPASS a = rxa[channel].bp1.p;
|
||||||
|
if ((a->wintype != wintype))
|
||||||
|
{
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate,
|
||||||
|
wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 0);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->wintype = wintype;
|
||||||
|
setUpdate_fircore (a->p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABandpassNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
// NOTE: 'nc' must be >= 'size'
|
||||||
|
double* impulse;
|
||||||
|
BANDPASS a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].bp1.p;
|
||||||
|
if (nc != a->nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXABandpassMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
BANDPASS a;
|
||||||
|
a = rxa[channel].bp1.p;
|
||||||
|
if (mp != a->mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABandpassRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].bp1.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
//PORT
|
||||||
|
//void SetTXABandpassFreqs (int channel, double f_low, double f_high)
|
||||||
|
//{
|
||||||
|
// double* impulse;
|
||||||
|
// BANDPASS a;
|
||||||
|
// a = txa[channel].bp0.p;
|
||||||
|
// if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
// {
|
||||||
|
// a->f_low = f_low;
|
||||||
|
// a->f_high = f_high;
|
||||||
|
// impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
// setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
// _aligned_free (impulse);
|
||||||
|
// }
|
||||||
|
// a = txa[channel].bp1.p;
|
||||||
|
// if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
// {
|
||||||
|
// a->f_low = f_low;
|
||||||
|
// a->f_high = f_high;
|
||||||
|
// impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
// setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
// _aligned_free (impulse);
|
||||||
|
// }
|
||||||
|
// a = txa[channel].bp2.p;
|
||||||
|
// if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||||
|
// {
|
||||||
|
// a->f_low = f_low;
|
||||||
|
// a->f_high = f_high;
|
||||||
|
// impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
// setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
// _aligned_free (impulse);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABandpassWindow (int channel, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
BANDPASS a;
|
||||||
|
a = txa[channel].bp0.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp1.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp2.p;
|
||||||
|
if (a->wintype != wintype)
|
||||||
|
{
|
||||||
|
a->wintype = wintype;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABandpassNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
// NOTE: 'nc' must be >= 'size'
|
||||||
|
double* impulse;
|
||||||
|
BANDPASS a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].bp0.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp1.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp2.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXABandpassMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
BANDPASS a;
|
||||||
|
a = txa[channel].bp0.p;
|
||||||
|
if (mp != a->mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp1.p;
|
||||||
|
if (mp != a->mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
a = txa[channel].bp2.p;
|
||||||
|
if (mp != a->mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
/* bandpass.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _bps_h
|
||||||
|
#define _bps_h
|
||||||
|
|
||||||
|
typedef struct _bps
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double* infilt;
|
||||||
|
double* product;
|
||||||
|
double* mults;
|
||||||
|
double samplerate;
|
||||||
|
int wintype;
|
||||||
|
double gain;
|
||||||
|
fftw_plan CFor;
|
||||||
|
fftw_plan CRev;
|
||||||
|
}bps, *BPS;
|
||||||
|
|
||||||
|
extern BPS create_bps (int run, int position, int size, double* in, double* out,
|
||||||
|
double f_low, double f_high, int samplerate, int wintype, double gain);
|
||||||
|
|
||||||
|
extern void destroy_bps (BPS a);
|
||||||
|
|
||||||
|
extern void flush_bps (BPS a);
|
||||||
|
|
||||||
|
extern void xbps (BPS a, int pos);
|
||||||
|
|
||||||
|
extern void setBuffers_bps (BPS a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_bps (BPS a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_bps (BPS a, int size);
|
||||||
|
|
||||||
|
extern void setFreqs_bps (BPS a, double f_low, double f_high);
|
||||||
|
|
||||||
|
// RXA Prototypes
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXABPSRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXABPSFreqs (int channel, double low, double high);
|
||||||
|
|
||||||
|
// TXA Prototypes
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXABPSRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXABPSFreqs (int channel, double low, double high);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _bandpass_h
|
||||||
|
#define _bandpass_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _bandpass
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int size;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double samplerate;
|
||||||
|
int wintype;
|
||||||
|
double gain;
|
||||||
|
FIRCORE p;
|
||||||
|
}bandpass, *BANDPASS;
|
||||||
|
|
||||||
|
extern BANDPASS create_bandpass (int run, int position, int size, int nc, int mp, double* in, double* out,
|
||||||
|
double f_low, double f_high, int samplerate, int wintype, double gain);
|
||||||
|
|
||||||
|
extern void destroy_bandpass (BANDPASS a);
|
||||||
|
|
||||||
|
extern void flush_bandpass (BANDPASS a);
|
||||||
|
|
||||||
|
extern void xbandpass (BANDPASS a, int pos);
|
||||||
|
|
||||||
|
extern void setBuffers_bandpass (BANDPASS a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_bandpass (BANDPASS a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_bandpass (BANDPASS a, int size);
|
||||||
|
|
||||||
|
extern void setGain_bandpass (BANDPASS a, double gain, int update);
|
||||||
|
|
||||||
|
extern void CalcBandpassFilter (BANDPASS a, double f_low, double f_high, double gain);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXABandpassFreqs (int channel, double f_low, double f_high);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXABandpassNC (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXABandpassMP (int channel, int mp);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXABandpassNC (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXABandpassMP (int channel, int mp);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1154
File diff suppressed because it is too large
Load Diff
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/* calcc.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _calcc_h
|
||||||
|
#define _calcc_h
|
||||||
|
#include "delay.h"
|
||||||
|
#include "lmath.h"
|
||||||
|
typedef struct _calcc
|
||||||
|
{
|
||||||
|
int channel;
|
||||||
|
int runcal;
|
||||||
|
int size;
|
||||||
|
volatile long mox;
|
||||||
|
volatile long solidmox;
|
||||||
|
int rate;
|
||||||
|
int ints;
|
||||||
|
int spi;
|
||||||
|
int nsamps;
|
||||||
|
int npsamps;
|
||||||
|
int pin;
|
||||||
|
int map;
|
||||||
|
int convex;
|
||||||
|
int stbl;
|
||||||
|
int scOK;
|
||||||
|
double hw_scale;
|
||||||
|
double rx_scale;
|
||||||
|
double alpha;
|
||||||
|
|
||||||
|
int tsamps;
|
||||||
|
double* env_TX;
|
||||||
|
double* env_RX;
|
||||||
|
double* x;
|
||||||
|
double* ym;
|
||||||
|
double* yc;
|
||||||
|
double* ys;
|
||||||
|
double* cat;
|
||||||
|
|
||||||
|
double* t;
|
||||||
|
double* tmap;
|
||||||
|
double* cm;
|
||||||
|
double* cc;
|
||||||
|
double* cs;
|
||||||
|
double* cm_old;
|
||||||
|
double* rxs;
|
||||||
|
double* txs;
|
||||||
|
double ptol;
|
||||||
|
int* info;
|
||||||
|
int* binfo;
|
||||||
|
double txdel;
|
||||||
|
BLDR ccbld;
|
||||||
|
volatile long savecorr_bypass;
|
||||||
|
HANDLE Sem_SaveCorr;
|
||||||
|
volatile long restcorr_bypass;
|
||||||
|
HANDLE Sem_RestCorr;
|
||||||
|
volatile long calccorr_bypass;
|
||||||
|
HANDLE Sem_CalcCorr;
|
||||||
|
volatile long turnoff_bypass;
|
||||||
|
HANDLE Sem_TurnOff;
|
||||||
|
struct _ctrl
|
||||||
|
{
|
||||||
|
double moxdelay;
|
||||||
|
double loopdelay;
|
||||||
|
int state;
|
||||||
|
int reset;
|
||||||
|
int automode;
|
||||||
|
int mancal;
|
||||||
|
int turnon;
|
||||||
|
int moxsamps;
|
||||||
|
int moxcount;
|
||||||
|
int count;
|
||||||
|
int* cpi;
|
||||||
|
int* sindex;
|
||||||
|
int* sbase;
|
||||||
|
int full_ints;
|
||||||
|
int calcinprogress;
|
||||||
|
volatile LONG calcdone;
|
||||||
|
int waitsamps;
|
||||||
|
int waitcount;
|
||||||
|
double env_maxtx;
|
||||||
|
volatile long running;
|
||||||
|
int bs_count;
|
||||||
|
volatile long current_state;
|
||||||
|
CRITICAL_SECTION cs_SafeToEnd;
|
||||||
|
} ctrl;
|
||||||
|
struct _disp
|
||||||
|
{
|
||||||
|
double* x;
|
||||||
|
double* ym;
|
||||||
|
double* yc;
|
||||||
|
double* ys;
|
||||||
|
double* cm;
|
||||||
|
double* cc;
|
||||||
|
double* cs;
|
||||||
|
CRITICAL_SECTION cs_disp;
|
||||||
|
} disp;
|
||||||
|
DELAY rxdelay;
|
||||||
|
DELAY txdelay;
|
||||||
|
struct _util
|
||||||
|
{
|
||||||
|
char savefile[256];
|
||||||
|
char restfile[256];
|
||||||
|
int ints;
|
||||||
|
int channel;
|
||||||
|
double* pm;
|
||||||
|
double* pc;
|
||||||
|
double* ps;
|
||||||
|
} util;
|
||||||
|
double* temptx; //////////////////////////////////////////////////// temporary tx complex buffer - remove with new callback3port()
|
||||||
|
double* temprx; //////////////////////////////////////////////////// temporary rx complex buffer - remove with new callback3port()
|
||||||
|
} calcc, *CALCC;
|
||||||
|
|
||||||
|
extern CALCC create_calcc (int channel, int runcal, int size, int rate, int ints, int spi, double hw_scale,
|
||||||
|
double moxdelay, double loopdelay, double ptol, int mox, int solidmox, int pin, int map, int stbl,
|
||||||
|
int npsamps, double alpha);
|
||||||
|
|
||||||
|
extern void destroy_calcc (CALCC a);
|
||||||
|
|
||||||
|
extern void flush_calcc (CALCC a);
|
||||||
|
|
||||||
|
extern __declspec(dllexport) void pscc (int channel, int size, double* tx, double* rx);
|
||||||
|
|
||||||
|
extern void __cdecl PSSaveCorrection(void* pargs);
|
||||||
|
|
||||||
|
extern void __cdecl PSRestoreCorrection(void* pargs);
|
||||||
|
|
||||||
|
extern void __cdecl doPSCalcCorrection(void* arg);
|
||||||
|
|
||||||
|
extern void __cdecl doPSTurnoff(void* arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 'info' assignments:
|
||||||
|
// 0 - builder for rx_scale
|
||||||
|
// 1 - builder for cm
|
||||||
|
// 2 - builder for cc
|
||||||
|
// 3 - builder for cs
|
||||||
|
// 4 - feedback level warning
|
||||||
|
// 5 - count of attempted calibrations
|
||||||
|
// 6 - results from scheck()
|
||||||
|
// 7 - results from rxscheck()
|
||||||
|
//
|
||||||
|
// 13 - dogcount
|
||||||
|
// 14 - indicates iqc_Run = 1
|
||||||
|
// 15 - control state
|
||||||
Binary file not shown.
+29045
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _calculus_h
|
||||||
|
#define _calculus_h
|
||||||
|
|
||||||
|
extern double GG[];
|
||||||
|
|
||||||
|
extern double GGS[];
|
||||||
|
|
||||||
|
#endif
|
||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
/* cblock.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_cbl (CBL a)
|
||||||
|
{
|
||||||
|
a->prevIin = 0.0;
|
||||||
|
a->prevQin = 0.0;
|
||||||
|
a->prevIout = 0.0;
|
||||||
|
a->prevQout = 0.0;
|
||||||
|
a->mtau = exp(-1.0 / (a->sample_rate * a->tau));
|
||||||
|
}
|
||||||
|
|
||||||
|
CBL create_cbl
|
||||||
|
(
|
||||||
|
int run,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int mode,
|
||||||
|
int sample_rate,
|
||||||
|
double tau
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CBL a = (CBL) malloc0 (sizeof(cbl));
|
||||||
|
a->run = run;
|
||||||
|
a->buff_size = buff_size;
|
||||||
|
a->in_buff = in_buff;
|
||||||
|
a->out_buff = out_buff;
|
||||||
|
a->mode = mode;
|
||||||
|
a->sample_rate = (double)sample_rate;
|
||||||
|
a->tau = tau;
|
||||||
|
calc_cbl (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_cbl(CBL a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_cbl (CBL a)
|
||||||
|
{
|
||||||
|
a->prevIin = 0.0;
|
||||||
|
a->prevQin = 0.0;
|
||||||
|
a->prevIout = 0.0;
|
||||||
|
a->prevQout = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xcbl (CBL a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double tempI, tempQ;
|
||||||
|
for (i = 0; i < a->buff_size; i++)
|
||||||
|
{
|
||||||
|
tempI = a->in_buff[2 * i + 0];
|
||||||
|
tempQ = a->in_buff[2 * i + 1];
|
||||||
|
a->out_buff[2 * i + 0] = a->in_buff[2 * i + 0] - a->prevIin + a->mtau * a->prevIout;
|
||||||
|
a->out_buff[2 * i + 1] = a->in_buff[2 * i + 1] - a->prevQin + a->mtau * a->prevQout;
|
||||||
|
a->prevIin = tempI;
|
||||||
|
a->prevQin = tempQ;
|
||||||
|
if (fabs(a->prevIout = a->out_buff[2 * i + 0]) < 1.0e-100) a->prevIout = 0.0;
|
||||||
|
if (fabs(a->prevQout = a->out_buff[2 * i + 1]) < 1.0e-100) a->prevQout = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in_buff != a->out_buff)
|
||||||
|
memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_cbl (CBL a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in_buff = in;
|
||||||
|
a->out_buff = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_cbl (CBL a, int rate)
|
||||||
|
{
|
||||||
|
a->sample_rate = rate;
|
||||||
|
calc_cbl (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_cbl (CBL a, int size)
|
||||||
|
{
|
||||||
|
a->buff_size = size;
|
||||||
|
flush_cbl (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetRXACBLRun(int channel, int setit)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].cbl.p->run = setit;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* cblock.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _cblock_h
|
||||||
|
#define _cblock_h
|
||||||
|
|
||||||
|
typedef struct _cbl
|
||||||
|
{
|
||||||
|
int run; //run
|
||||||
|
int buff_size; //buffer size
|
||||||
|
double *in_buff; //pointer to input buffer
|
||||||
|
double *out_buff; //pointer to output buffer
|
||||||
|
int mode;
|
||||||
|
double sample_rate; //sample rate
|
||||||
|
double prevIin;
|
||||||
|
double prevQin;
|
||||||
|
double prevIout;
|
||||||
|
double prevQout;
|
||||||
|
double tau; //carrier removal time constant
|
||||||
|
double mtau; //carrier removal multiplier
|
||||||
|
} cbl, *CBL;
|
||||||
|
|
||||||
|
extern CBL create_cbl
|
||||||
|
(
|
||||||
|
int run,
|
||||||
|
int buff_size,
|
||||||
|
double *in_buff,
|
||||||
|
double *out_buff,
|
||||||
|
int mode,
|
||||||
|
int sample_rate,
|
||||||
|
double tau
|
||||||
|
);
|
||||||
|
|
||||||
|
extern void destroy_cbl (CBL a);
|
||||||
|
|
||||||
|
extern void flush_cbl (CBL a);
|
||||||
|
|
||||||
|
extern void xcbl (CBL a);
|
||||||
|
|
||||||
|
extern void setBuffers_cbl (CBL a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_cbl (CBL a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_cbl (CBL a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXACBLRun(int channel, int setit);
|
||||||
|
|
||||||
|
#endif
|
||||||
+519
@@ -0,0 +1,519 @@
|
|||||||
|
/* cfcomp.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2017, 2021 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_cfcwindow (CFCOMP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double arg0, arg1, cgsum, igsum, coherent_gain, inherent_power_gain, wmult;
|
||||||
|
switch (a->wintype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
arg0 = 2.0 * PI / (double)a->fsize;
|
||||||
|
cgsum = 0.0;
|
||||||
|
igsum = 0.0;
|
||||||
|
for (i = 0; i < a->fsize; i++)
|
||||||
|
{
|
||||||
|
a->window[i] = sqrt (0.54 - 0.46 * cos((double)i * arg0));
|
||||||
|
cgsum += a->window[i];
|
||||||
|
igsum += a->window[i] * a->window[i];
|
||||||
|
}
|
||||||
|
coherent_gain = cgsum / (double)a->fsize;
|
||||||
|
inherent_power_gain = igsum / (double)a->fsize;
|
||||||
|
wmult = 1.0 / sqrt (inherent_power_gain);
|
||||||
|
for (i = 0; i < a->fsize; i++)
|
||||||
|
a->window[i] *= wmult;
|
||||||
|
a->winfudge = sqrt (1.0 / coherent_gain);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
arg0 = 2.0 * PI / (double)a->fsize;
|
||||||
|
cgsum = 0.0;
|
||||||
|
igsum = 0.0;
|
||||||
|
for (i = 0; i < a->fsize; i++)
|
||||||
|
{
|
||||||
|
arg1 = cos(arg0 * (double)i);
|
||||||
|
a->window[i] = sqrt (+0.21747
|
||||||
|
+ arg1 * (-0.45325
|
||||||
|
+ arg1 * (+0.28256
|
||||||
|
+ arg1 * (-0.04672))));
|
||||||
|
cgsum += a->window[i];
|
||||||
|
igsum += a->window[i] * a->window[i];
|
||||||
|
}
|
||||||
|
coherent_gain = cgsum / (double)a->fsize;
|
||||||
|
inherent_power_gain = igsum / (double)a->fsize;
|
||||||
|
wmult = 1.0 / sqrt (inherent_power_gain);
|
||||||
|
for (i = 0; i < a->fsize; i++)
|
||||||
|
a->window[i] *= wmult;
|
||||||
|
a->winfudge = sqrt (1.0 / coherent_gain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fCOMPcompare (const void * a, const void * b)
|
||||||
|
{
|
||||||
|
if (*(double*)a < *(double*)b)
|
||||||
|
return -1;
|
||||||
|
else if (*(double*)a == *(double*)b)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_comp (CFCOMP a)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
double f, frac, fincr, fmax;
|
||||||
|
double* sary;
|
||||||
|
a->precomplin = pow (10.0, 0.05 * a->precomp);
|
||||||
|
a->prepeqlin = pow (10.0, 0.05 * a->prepeq);
|
||||||
|
fmax = 0.5 * a->rate;
|
||||||
|
for (i = 0; i < a->nfreqs; i++)
|
||||||
|
{
|
||||||
|
a->F[i] = max (a->F[i], 0.0);
|
||||||
|
a->F[i] = min (a->F[i], fmax);
|
||||||
|
a->G[i] = max (a->G[i], 0.0);
|
||||||
|
}
|
||||||
|
sary = (double *)malloc0 (3 * a->nfreqs * sizeof (double));
|
||||||
|
for (i = 0; i < a->nfreqs; i++)
|
||||||
|
{
|
||||||
|
sary[3 * i + 0] = a->F[i];
|
||||||
|
sary[3 * i + 1] = a->G[i];
|
||||||
|
sary[3 * i + 2] = a->E[i];
|
||||||
|
}
|
||||||
|
qsort (sary, a->nfreqs, 3 * sizeof (double), fCOMPcompare);
|
||||||
|
for (i = 0; i < a->nfreqs; i++)
|
||||||
|
{
|
||||||
|
a->F[i] = sary[3 * i + 0];
|
||||||
|
a->G[i] = sary[3 * i + 1];
|
||||||
|
a->E[i] = sary[3 * i + 2];
|
||||||
|
}
|
||||||
|
_aligned_free (sary);
|
||||||
|
a->fp[0] = 0.0;
|
||||||
|
a->fp[a->nfreqs + 1] = fmax;
|
||||||
|
a->gp[0] = a->G[0];
|
||||||
|
a->gp[a->nfreqs + 1] = a->G[a->nfreqs - 1];
|
||||||
|
a->ep[0] = a->E[0]; // cutoff?
|
||||||
|
a->ep[a->nfreqs + 1] = a->E[a->nfreqs - 1]; // cutoff?
|
||||||
|
for (i = 0, j = 1; i < a->nfreqs; i++, j++)
|
||||||
|
{
|
||||||
|
a->fp[j] = a->F[i];
|
||||||
|
a->gp[j] = a->G[i];
|
||||||
|
a->ep[j] = a->E[i];
|
||||||
|
}
|
||||||
|
fincr = a->rate / (double)a->fsize;
|
||||||
|
j = 0;
|
||||||
|
// print_impulse ("gp.txt", a->nfreqs+2, a->gp, 0, 0);
|
||||||
|
for (i = 0; i < a->msize; i++)
|
||||||
|
{
|
||||||
|
f = fincr * (double)i;
|
||||||
|
while (f >= a->fp[j + 1] && j < a->nfreqs) j++;
|
||||||
|
frac = (f - a->fp[j]) / (a->fp[j + 1] - a->fp[j]);
|
||||||
|
a->comp[i] = pow (10.0, 0.05 * (frac * a->gp[j + 1] + (1.0 - frac) * a->gp[j]));
|
||||||
|
a->peq[i] = pow (10.0, 0.05 * (frac * a->ep[j + 1] + (1.0 - frac) * a->ep[j]));
|
||||||
|
a->cfc_gain[i] = a->precomplin * a->comp[i];
|
||||||
|
}
|
||||||
|
// print_impulse ("comp.txt", a->msize, a->comp, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_cfcomp(CFCOMP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
a->incr = a->fsize / a->ovrlp;
|
||||||
|
if (a->fsize > a->bsize)
|
||||||
|
a->iasize = a->fsize;
|
||||||
|
else
|
||||||
|
a->iasize = a->bsize + a->fsize - a->incr;
|
||||||
|
a->iainidx = 0;
|
||||||
|
a->iaoutidx = 0;
|
||||||
|
if (a->fsize > a->bsize)
|
||||||
|
{
|
||||||
|
if (a->bsize > a->incr) a->oasize = a->bsize;
|
||||||
|
else a->oasize = a->incr;
|
||||||
|
a->oainidx = (a->fsize - a->bsize - a->incr) % a->oasize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a->oasize = a->bsize;
|
||||||
|
a->oainidx = a->fsize - a->incr;
|
||||||
|
}
|
||||||
|
a->init_oainidx = a->oainidx;
|
||||||
|
a->oaoutidx = 0;
|
||||||
|
a->msize = a->fsize / 2 + 1;
|
||||||
|
a->window = (double *)malloc0 (a->fsize * sizeof(double));
|
||||||
|
a->inaccum = (double *)malloc0 (a->iasize * sizeof(double));
|
||||||
|
a->forfftin = (double *)malloc0 (a->fsize * sizeof(double));
|
||||||
|
a->forfftout = (double *)malloc0 (a->msize * sizeof(complex));
|
||||||
|
a->cmask = (double *)malloc0 (a->msize * sizeof(double));
|
||||||
|
a->mask = (double *)malloc0 (a->msize * sizeof(double));
|
||||||
|
a->cfc_gain = (double *)malloc0 (a->msize * sizeof(double));
|
||||||
|
a->revfftin = (double *)malloc0 (a->msize * sizeof(complex));
|
||||||
|
a->revfftout = (double *)malloc0 (a->fsize * sizeof(double));
|
||||||
|
a->save = (double **)malloc0(a->ovrlp * sizeof(double *));
|
||||||
|
for (i = 0; i < a->ovrlp; i++)
|
||||||
|
a->save[i] = (double *)malloc0(a->fsize * sizeof(double));
|
||||||
|
a->outaccum = (double *)malloc0(a->oasize * sizeof(double));
|
||||||
|
a->nsamps = 0;
|
||||||
|
a->saveidx = 0;
|
||||||
|
a->Rfor = fftw_plan_dft_r2c_1d(a->fsize, a->forfftin, (fftw_complex *)a->forfftout, FFTW_ESTIMATE);
|
||||||
|
a->Rrev = fftw_plan_dft_c2r_1d(a->fsize, (fftw_complex *)a->revfftin, a->revfftout, FFTW_ESTIMATE);
|
||||||
|
calc_cfcwindow(a);
|
||||||
|
|
||||||
|
a->pregain = (2.0 * a->winfudge) / (double)a->fsize;
|
||||||
|
a->postgain = 0.5 / ((double)a->ovrlp * a->winfudge);
|
||||||
|
|
||||||
|
a->fp = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
a->gp = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
a->ep = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
a->comp = (double *) malloc0 (a->msize * sizeof (double));
|
||||||
|
a->peq = (double *) malloc0 (a->msize * sizeof (double));
|
||||||
|
calc_comp (a);
|
||||||
|
|
||||||
|
a->gain = 0.0;
|
||||||
|
a->mmult = exp (-1.0 / (a->rate * a->ovrlp * a->mtau));
|
||||||
|
a->dmult = exp (-(double)a->fsize / (a->rate * a->ovrlp * a->dtau));
|
||||||
|
|
||||||
|
a->delta = (double*)malloc0 (a->msize * sizeof(double));
|
||||||
|
a->delta_copy = (double*)malloc0 (a->msize * sizeof(double));
|
||||||
|
a->cfc_gain_copy = (double*)malloc0 (a->msize * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_cfcomp(CFCOMP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
_aligned_free (a->cfc_gain_copy);
|
||||||
|
_aligned_free (a->delta_copy);
|
||||||
|
_aligned_free (a->delta);
|
||||||
|
_aligned_free (a->peq);
|
||||||
|
_aligned_free (a->comp);
|
||||||
|
_aligned_free (a->ep);
|
||||||
|
_aligned_free (a->gp);
|
||||||
|
_aligned_free (a->fp);
|
||||||
|
|
||||||
|
fftw_destroy_plan(a->Rrev);
|
||||||
|
fftw_destroy_plan(a->Rfor);
|
||||||
|
_aligned_free(a->outaccum);
|
||||||
|
for (i = 0; i < a->ovrlp; i++)
|
||||||
|
_aligned_free(a->save[i]);
|
||||||
|
_aligned_free(a->save);
|
||||||
|
_aligned_free(a->revfftout);
|
||||||
|
_aligned_free(a->revfftin);
|
||||||
|
_aligned_free(a->cfc_gain);
|
||||||
|
_aligned_free(a->mask);
|
||||||
|
_aligned_free(a->cmask);
|
||||||
|
_aligned_free(a->forfftout);
|
||||||
|
_aligned_free(a->forfftin);
|
||||||
|
_aligned_free(a->inaccum);
|
||||||
|
_aligned_free(a->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFCOMP create_cfcomp (int run, int position, int peq_run, int size, double* in, double* out, int fsize, int ovrlp,
|
||||||
|
int rate, int wintype, int comp_method, int nfreqs, double precomp, double prepeq, double* F, double* G, double* E, double mtau, double dtau)
|
||||||
|
{
|
||||||
|
CFCOMP a = (CFCOMP) malloc0 (sizeof (cfcomp));
|
||||||
|
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->peq_run = peq_run;
|
||||||
|
a->bsize = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->fsize = fsize;
|
||||||
|
a->ovrlp = ovrlp;
|
||||||
|
a->rate = rate;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->comp_method = comp_method;
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->precomp = precomp;
|
||||||
|
a->prepeq = prepeq;
|
||||||
|
a->mtau = mtau; // compression metering time constant
|
||||||
|
a->dtau = dtau; // compression display time constant
|
||||||
|
a->F = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
a->G = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
a->E = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->F, F, a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->G, G, a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->E, E, a->nfreqs * sizeof (double));
|
||||||
|
calc_cfcomp (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_cfcomp (CFCOMP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memset (a->inaccum, 0, a->iasize * sizeof (double));
|
||||||
|
for (i = 0; i < a->ovrlp; i++)
|
||||||
|
memset (a->save[i], 0, a->fsize * sizeof (double));
|
||||||
|
memset (a->outaccum, 0, a->oasize * sizeof (double));
|
||||||
|
a->nsamps = 0;
|
||||||
|
a->iainidx = 0;
|
||||||
|
a->iaoutidx = 0;
|
||||||
|
a->oainidx = a->init_oainidx;
|
||||||
|
a->oaoutidx = 0;
|
||||||
|
a->saveidx = 0;
|
||||||
|
a->gain = 0.0;
|
||||||
|
memset(a->delta, 0, a->msize * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_cfcomp (CFCOMP a)
|
||||||
|
{
|
||||||
|
decalc_cfcomp (a);
|
||||||
|
_aligned_free (a->E);
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void calc_mask (CFCOMP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double comp, mask, delta;
|
||||||
|
switch (a->comp_method)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
double mag, test;
|
||||||
|
for (i = 0; i < a->msize; i++)
|
||||||
|
{
|
||||||
|
mag = sqrt (a->forfftout[2 * i + 0] * a->forfftout[2 * i + 0]
|
||||||
|
+ a->forfftout[2 * i + 1] * a->forfftout[2 * i + 1]);
|
||||||
|
comp = a->cfc_gain[i];
|
||||||
|
test = comp * mag;
|
||||||
|
if (test > 1.0)
|
||||||
|
mask = 1.0 / mag;
|
||||||
|
else
|
||||||
|
mask = comp;
|
||||||
|
a->cmask[i] = mask;
|
||||||
|
if (test > a->gain) a->gain = test;
|
||||||
|
else a->gain = a->mmult * a->gain;
|
||||||
|
|
||||||
|
delta = a->cfc_gain[i] - a->cmask[i];
|
||||||
|
if (delta > a->delta[i]) a->delta[i] = delta;
|
||||||
|
else a->delta[i] *= a->dmult;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a->peq_run)
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->msize; i++)
|
||||||
|
{
|
||||||
|
a->mask[i] = a->cmask[i] * a->prepeqlin * a->peq[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (a->mask, a->cmask, a->msize * sizeof (double));
|
||||||
|
// print_impulse ("mask.txt", a->msize, a->mask, 0, 0);
|
||||||
|
a->mask_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xcfcomp (CFCOMP a, int pos)
|
||||||
|
{
|
||||||
|
if (a->run && pos == a->position)
|
||||||
|
{
|
||||||
|
int i, j, k, sbuff, sbegin;
|
||||||
|
for (i = 0; i < 2 * a->bsize; i += 2)
|
||||||
|
{
|
||||||
|
a->inaccum[a->iainidx] = a->in[i];
|
||||||
|
a->iainidx = (a->iainidx + 1) % a->iasize;
|
||||||
|
}
|
||||||
|
a->nsamps += a->bsize;
|
||||||
|
while (a->nsamps >= a->fsize)
|
||||||
|
{
|
||||||
|
for (i = 0, j = a->iaoutidx; i < a->fsize; i++, j = (j + 1) % a->iasize)
|
||||||
|
a->forfftin[i] = a->pregain * a->window[i] * a->inaccum[j];
|
||||||
|
a->iaoutidx = (a->iaoutidx + a->incr) % a->iasize;
|
||||||
|
a->nsamps -= a->incr;
|
||||||
|
fftw_execute (a->Rfor);
|
||||||
|
calc_mask(a);
|
||||||
|
for (i = 0; i < a->msize; i++)
|
||||||
|
{
|
||||||
|
a->revfftin[2 * i + 0] = a->mask[i] * a->forfftout[2 * i + 0];
|
||||||
|
a->revfftin[2 * i + 1] = a->mask[i] * a->forfftout[2 * i + 1];
|
||||||
|
}
|
||||||
|
fftw_execute (a->Rrev);
|
||||||
|
for (i = 0; i < a->fsize; i++)
|
||||||
|
a->save[a->saveidx][i] = a->postgain * a->window[i] * a->revfftout[i];
|
||||||
|
for (i = a->ovrlp; i > 0; i--)
|
||||||
|
{
|
||||||
|
sbuff = (a->saveidx + i) % a->ovrlp;
|
||||||
|
sbegin = a->incr * (a->ovrlp - i);
|
||||||
|
for (j = sbegin, k = a->oainidx; j < a->incr + sbegin; j++, k = (k + 1) % a->oasize)
|
||||||
|
{
|
||||||
|
if ( i == a->ovrlp)
|
||||||
|
a->outaccum[k] = a->save[sbuff][j];
|
||||||
|
else
|
||||||
|
a->outaccum[k] += a->save[sbuff][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a->saveidx = (a->saveidx + 1) % a->ovrlp;
|
||||||
|
a->oainidx = (a->oainidx + a->incr) % a->oasize;
|
||||||
|
}
|
||||||
|
for (i = 0; i < a->bsize; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = a->outaccum[a->oaoutidx];
|
||||||
|
a->out[2 * i + 1] = 0.0;
|
||||||
|
a->oaoutidx = (a->oaoutidx + 1) % a->oasize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->out != a->in)
|
||||||
|
memcpy (a->out, a->in, a->bsize * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_cfcomp (CFCOMP a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_cfcomp (CFCOMP a, int rate)
|
||||||
|
{
|
||||||
|
decalc_cfcomp (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_cfcomp (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_cfcomp (CFCOMP a, int size)
|
||||||
|
{
|
||||||
|
decalc_cfcomp (a);
|
||||||
|
a->bsize = size;
|
||||||
|
calc_cfcomp (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPRun (int channel, int run)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
if (a->run != run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPPosition (int channel, int pos)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
if (a->position != pos)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->position = pos;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPprofile (int channel, int nfreqs, double* F, double* G, double *E)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
_aligned_free (a->E);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
_aligned_free (a->G);
|
||||||
|
a->F = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
a->G = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
a->E = (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->F, F, a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->G, G, a->nfreqs * sizeof (double));
|
||||||
|
memcpy (a->E, E, a->nfreqs * sizeof (double));
|
||||||
|
_aligned_free (a->ep);
|
||||||
|
_aligned_free (a->gp);
|
||||||
|
_aligned_free (a->fp);
|
||||||
|
a->fp = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
a->gp = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
a->ep = (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||||
|
calc_comp(a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPPrecomp (int channel, double precomp)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
if (a->precomp != precomp)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->precomp = precomp;
|
||||||
|
a->precomplin = pow (10.0, 0.05 * a->precomp);
|
||||||
|
for (int i = 0; i < a->msize; i++)
|
||||||
|
{
|
||||||
|
a->cfc_gain[i] = a->precomplin * a->comp[i];
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPPeqRun (int channel, int run)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
if (a->peq_run != run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->peq_run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFCOMPPrePeq (int channel, double prepeq)
|
||||||
|
{
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->prepeq = prepeq;
|
||||||
|
a->prepeqlin = pow (10.0, 0.05 * a->prepeq);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void GetTXACFCOMPDisplayCompression (int channel, double* comp_values, int* ready)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CFCOMP a = txa[channel].cfcomp.p;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
if (*ready = a->mask_ready)
|
||||||
|
{
|
||||||
|
memcpy(a->delta_copy, a->delta, a->msize * sizeof(double));
|
||||||
|
memcpy(a->cfc_gain_copy, a->cfc_gain, a->msize * sizeof(double));
|
||||||
|
a->mask_ready = 0;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
if (*ready)
|
||||||
|
{
|
||||||
|
for (i = 0; i < a->msize; i++)
|
||||||
|
comp_values[i] = 20.0 * mlog10 (a->cfc_gain_copy[i] / (a->cfc_gain_copy[i] - a->delta_copy[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
/* cfcomp.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2017, 2021 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _cfcomp_h
|
||||||
|
#define _cfcomp_h
|
||||||
|
|
||||||
|
typedef struct _cfcomp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int bsize;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int fsize;
|
||||||
|
int ovrlp;
|
||||||
|
int incr;
|
||||||
|
double* window;
|
||||||
|
int iasize;
|
||||||
|
double* inaccum;
|
||||||
|
double* forfftin;
|
||||||
|
double* forfftout;
|
||||||
|
int msize;
|
||||||
|
double* cmask;
|
||||||
|
double* mask;
|
||||||
|
int mask_ready;
|
||||||
|
double* cfc_gain;
|
||||||
|
double* revfftin;
|
||||||
|
double* revfftout;
|
||||||
|
double** save;
|
||||||
|
int oasize;
|
||||||
|
double* outaccum;
|
||||||
|
double rate;
|
||||||
|
int wintype;
|
||||||
|
double pregain;
|
||||||
|
double postgain;
|
||||||
|
int nsamps;
|
||||||
|
int iainidx;
|
||||||
|
int iaoutidx;
|
||||||
|
int init_oainidx;
|
||||||
|
int oainidx;
|
||||||
|
int oaoutidx;
|
||||||
|
int saveidx;
|
||||||
|
fftw_plan Rfor;
|
||||||
|
fftw_plan Rrev;
|
||||||
|
|
||||||
|
int comp_method;
|
||||||
|
int nfreqs;
|
||||||
|
double* F;
|
||||||
|
double* G;
|
||||||
|
double* E;
|
||||||
|
double* fp;
|
||||||
|
double* gp;
|
||||||
|
double* ep;
|
||||||
|
double* comp;
|
||||||
|
double precomp;
|
||||||
|
double precomplin;
|
||||||
|
double* peq;
|
||||||
|
int peq_run;
|
||||||
|
double prepeq;
|
||||||
|
double prepeqlin;
|
||||||
|
double winfudge;
|
||||||
|
|
||||||
|
double gain;
|
||||||
|
double mtau;
|
||||||
|
double mmult;
|
||||||
|
// display stuff
|
||||||
|
double dtau;
|
||||||
|
double dmult;
|
||||||
|
double* delta;
|
||||||
|
double* delta_copy;
|
||||||
|
double* cfc_gain_copy;
|
||||||
|
}cfcomp, *CFCOMP;
|
||||||
|
|
||||||
|
extern CFCOMP create_cfcomp (int run, int position, int peq_run, int size, double* in, double* out, int fsize, int ovrlp,
|
||||||
|
int rate, int wintype, int comp_method, int nfreqs, double precomp, double prepeq, double* F, double* G, double* E, double mtau, double dtau);
|
||||||
|
|
||||||
|
extern void destroy_cfcomp (CFCOMP a);
|
||||||
|
|
||||||
|
extern void flush_cfcomp (CFCOMP a);
|
||||||
|
|
||||||
|
extern void xcfcomp (CFCOMP a, int pos);
|
||||||
|
|
||||||
|
extern void setBuffers_cfcomp (CFCOMP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_cfcomp (CFCOMP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_cfcomp (CFCOMP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+254
@@ -0,0 +1,254 @@
|
|||||||
|
/* cfir.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014, 2016, 2021 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_cfir (CFIR a)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->scale = 1.0 / (double)(2 * a->size);
|
||||||
|
impulse = cfir_impulse (a->nc, a->DD, a->R, a->Pairs, a->runrate, a->cicrate, a->cutoff, a->xtype, a->xbw, 1, a->scale, a->wintype);
|
||||||
|
a->p = create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_cfir (CFIR a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFIR create_cfir (int run, int size, int nc, int mp, double* in, double* out, int runrate, int cicrate,
|
||||||
|
int DD, int R, int Pairs, double cutoff, int xtype, double xbw, int wintype)
|
||||||
|
// run: 0 - no action; 1 - operate
|
||||||
|
// size: number of complex samples in an input buffer to the CFIR filter
|
||||||
|
// nc: number of filter coefficients
|
||||||
|
// mp: minimum phase flag
|
||||||
|
// in: pointer to the input buffer
|
||||||
|
// out: pointer to the output buffer
|
||||||
|
// rate: samplerate
|
||||||
|
// DD: differential delay of the CIC to be compensated (usually 1 or 2)
|
||||||
|
// R: interpolation factor of CIC
|
||||||
|
// Pairs: number of comb-integrator pairs in the CIC
|
||||||
|
// cutoff: cutoff frequency
|
||||||
|
// xtype: 0 - fourth power transition; 1 - raised cosine transition; 2 - brick wall
|
||||||
|
// xbw: width of raised cosine transition
|
||||||
|
{
|
||||||
|
CFIR a = (CFIR) malloc0 (sizeof (cfir));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->runrate = runrate;
|
||||||
|
a->cicrate = cicrate;
|
||||||
|
a->DD = DD;
|
||||||
|
a->R = R;
|
||||||
|
a->Pairs = Pairs;
|
||||||
|
a->cutoff = cutoff;
|
||||||
|
a->xtype = xtype;
|
||||||
|
a->xbw = xbw;
|
||||||
|
a->wintype = wintype;
|
||||||
|
calc_cfir (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_cfir (CFIR a)
|
||||||
|
{
|
||||||
|
decalc_cfir (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_cfir (CFIR a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xcfir (CFIR a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
xfircore (a->p);
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_cfir (CFIR a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_cfir (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_cfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_cfir (CFIR a, int rate)
|
||||||
|
{
|
||||||
|
decalc_cfir (a);
|
||||||
|
a->runrate = rate;
|
||||||
|
calc_cfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_cfir (CFIR a, int size)
|
||||||
|
{
|
||||||
|
decalc_cfir (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_cfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOutRate_cfir (CFIR a, int rate)
|
||||||
|
{
|
||||||
|
decalc_cfir (a);
|
||||||
|
a->cicrate = rate;
|
||||||
|
calc_cfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
double* cfir_impulse (int N, int DD, int R, int Pairs, double runrate, double cicrate, double cutoff, int xtype, double xbw, int rtype, double scale, int wintype)
|
||||||
|
{
|
||||||
|
// N: number of impulse response samples
|
||||||
|
// DD: differential delay used in the CIC filter
|
||||||
|
// R: interpolation / decimation factor of the CIC
|
||||||
|
// Pairs: number of comb-integrator pairs in the CIC
|
||||||
|
// runrate: sample rate at which this filter is to run (assumes there may be flat interp. between this filter and the CIC)
|
||||||
|
// cicrate: sample rate at interface to CIC
|
||||||
|
// cutoff: cutoff frequency
|
||||||
|
// xtype: transition type, 0 for 4th-power rolloff, 1 for raised cosine, 2 for brick wall
|
||||||
|
// xbw: transition bandwidth for raised cosine
|
||||||
|
// rtype: 0 for real output, 1 for complex output
|
||||||
|
// scale: scale factor to be applied to the output
|
||||||
|
int i, j;
|
||||||
|
double tmp, local_scale, ri, mag, fn;
|
||||||
|
double* impulse;
|
||||||
|
double* A = (double *) malloc0 (N * sizeof (double));
|
||||||
|
double ft = cutoff / cicrate; // normalized cutoff frequency
|
||||||
|
int u_samps = (N + 1) / 2; // number of unique samples, OK for odd or even N
|
||||||
|
int c_samps = (int)(cutoff / runrate * N) + (N + 1) / 2 - N / 2; // number of unique samples within bandpass, OK for odd or even N
|
||||||
|
int x_samps = (int)(xbw / runrate * N); // number of unique samples in transition region, OK for odd or even N
|
||||||
|
double offset = 0.5 - 0.5 * (double)((N + 1) / 2 - N / 2); // sample offset from center, OK for odd or even N
|
||||||
|
double* xistion = (double *) malloc0 ((x_samps + 1) * sizeof (double));
|
||||||
|
double delta = PI / (double)x_samps;
|
||||||
|
double L = cicrate / runrate;
|
||||||
|
double phs = 0.0;
|
||||||
|
for (i = 0; i <= x_samps; i++)
|
||||||
|
{
|
||||||
|
xistion[i] = 0.5 * (cos (phs) + 1.0);
|
||||||
|
phs += delta;
|
||||||
|
}
|
||||||
|
if ((tmp = DD * R * sin (PI * ft / R) / sin (PI * DD * ft)) < 0.0) //normalize by peak gain
|
||||||
|
tmp = -tmp;
|
||||||
|
local_scale = scale / pow (tmp, Pairs);
|
||||||
|
if (xtype == 0)
|
||||||
|
{
|
||||||
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
||||||
|
{
|
||||||
|
fn = ri / (L * (double)N);
|
||||||
|
if (fn <= ft)
|
||||||
|
{
|
||||||
|
if (fn == 0.0) tmp = 1.0;
|
||||||
|
else if ((tmp = DD * R * sin (PI * fn / R) / sin (PI * DD * fn)) < 0.0)
|
||||||
|
tmp = -tmp;
|
||||||
|
mag = pow (tmp, Pairs) * local_scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mag *= (ft * ft * ft * ft) / (fn * fn * fn * fn);
|
||||||
|
A[i] = mag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xtype == 1)
|
||||||
|
{
|
||||||
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
||||||
|
{
|
||||||
|
fn = ri / (L *(double)N);
|
||||||
|
if (i < c_samps)
|
||||||
|
{
|
||||||
|
if (fn == 0.0) tmp = 1.0;
|
||||||
|
else if ((tmp = DD * R * sin (PI * fn / R) / sin (PI * DD * fn)) < 0.0)
|
||||||
|
tmp = -tmp;
|
||||||
|
mag = pow (tmp, Pairs) * local_scale;
|
||||||
|
A[i] = mag;
|
||||||
|
}
|
||||||
|
else if ( i >= c_samps && i <= c_samps + x_samps)
|
||||||
|
A[i] = mag * xistion[i - c_samps];
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xtype == 2)
|
||||||
|
{
|
||||||
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
||||||
|
{
|
||||||
|
fn = ri / (L * (double)N);
|
||||||
|
if (fn <= ft)
|
||||||
|
{
|
||||||
|
if (fn == 0.0) tmp = 1.0;
|
||||||
|
else if ((tmp = DD * R * sin(PI * fn / R) / sin(PI * DD * fn)) < 0.0)
|
||||||
|
tmp = -tmp;
|
||||||
|
mag = pow (tmp, Pairs) * local_scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mag = 0.0;
|
||||||
|
A[i] = mag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (N & 1)
|
||||||
|
for (i = u_samps, j = 2; i < N; i++, j++)
|
||||||
|
A[i] = A[u_samps - j];
|
||||||
|
else
|
||||||
|
for (i = u_samps, j = 1; i < N; i++, j++)
|
||||||
|
A[i] = A[u_samps - j];
|
||||||
|
impulse = fir_fsamp (N, A, rtype, 1.0, wintype);
|
||||||
|
// print_impulse ("cfirImpulse.txt", N, impulse, 1, 0);
|
||||||
|
_aligned_free (A);
|
||||||
|
return impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFIRRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
txa[channel].cfir.p->run = run;
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACFIRNC(int channel, int nc)
|
||||||
|
{
|
||||||
|
// NOTE: 'nc' must be >= 'size'
|
||||||
|
CFIR a;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
a = txa[channel].cfir.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
decalc_cfir(a);
|
||||||
|
calc_cfir(a);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/* cfir.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _cfir_h
|
||||||
|
#define _cfir_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _cfir
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int runrate;
|
||||||
|
int cicrate;
|
||||||
|
int DD;
|
||||||
|
int R;
|
||||||
|
int Pairs;
|
||||||
|
double cutoff;
|
||||||
|
double scale;
|
||||||
|
int xtype;
|
||||||
|
double xbw;
|
||||||
|
int wintype;
|
||||||
|
FIRCORE p;
|
||||||
|
} cfir, *CFIR;
|
||||||
|
|
||||||
|
extern CFIR create_cfir (int run, int size, int nc, int mp, double* in, double* out, int runrate, int cicrate,
|
||||||
|
int DD, int R, int Pairs, double cutoff, int xtype, double xbw, int wintype);
|
||||||
|
|
||||||
|
extern void destroy_cfir (CFIR a);
|
||||||
|
|
||||||
|
extern void flush_cfir (CFIR a);
|
||||||
|
|
||||||
|
extern void xcfir (CFIR a);
|
||||||
|
|
||||||
|
extern void setBuffers_cfir (CFIR a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_cfir (CFIR a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_cfir (CFIR a, int size);
|
||||||
|
|
||||||
|
extern void setOutRate_cfir (CFIR a, int rate);
|
||||||
|
|
||||||
|
extern double* cfir_impulse (int N, int DD, int R, int Pairs, double runrate, double cicrate,
|
||||||
|
double cutoff, int xtype, double xbw, int rtype, double scale, int wintype);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACFIRRun(int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACFIRNC(int channel, int nc);
|
||||||
|
|
||||||
|
#endif
|
||||||
+347
@@ -0,0 +1,347 @@
|
|||||||
|
/* channel.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
struct _ch ch[MAX_CHANNELS];
|
||||||
|
|
||||||
|
void start_thread (int channel)
|
||||||
|
{
|
||||||
|
HANDLE handle = (HANDLE) _beginthread(wdspmain, 0, (void *)(uintptr_t)channel);
|
||||||
|
//SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_main_build (int channel)
|
||||||
|
{
|
||||||
|
if (ch[channel].in_rate >= ch[channel].dsp_rate)
|
||||||
|
ch[channel].dsp_insize = ch[channel].dsp_size * (ch[channel].in_rate / ch[channel].dsp_rate);
|
||||||
|
else
|
||||||
|
ch[channel].dsp_insize = ch[channel].dsp_size / (ch[channel].dsp_rate / ch[channel].in_rate);
|
||||||
|
|
||||||
|
if (ch[channel].out_rate >= ch[channel].dsp_rate)
|
||||||
|
ch[channel].dsp_outsize = ch[channel].dsp_size * (ch[channel].out_rate / ch[channel].dsp_rate);
|
||||||
|
else
|
||||||
|
ch[channel].dsp_outsize = ch[channel].dsp_size / (ch[channel].dsp_rate / ch[channel].out_rate);
|
||||||
|
|
||||||
|
if (ch[channel].in_rate >= ch[channel].out_rate)
|
||||||
|
ch[channel].out_size = ch[channel].in_size / (ch[channel].in_rate / ch[channel].out_rate);
|
||||||
|
else
|
||||||
|
ch[channel].out_size = ch[channel].in_size * (ch[channel].out_rate / ch[channel].in_rate);
|
||||||
|
|
||||||
|
InitializeCriticalSectionAndSpinCount ( &ch[channel].csDSP, 2500 );
|
||||||
|
InitializeCriticalSectionAndSpinCount ( &ch[channel].csEXCH, 2500 );
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].flushflag, 0);
|
||||||
|
create_iobuffs (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_main_build (int channel)
|
||||||
|
{
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].run, 0);
|
||||||
|
start_thread (channel);
|
||||||
|
if (ch[channel].state == 1)
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].exchange, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_channel (int channel)
|
||||||
|
{
|
||||||
|
pre_main_build (channel);
|
||||||
|
create_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void OpenChannel (int channel, int in_size, int dsp_size, int input_samplerate, int dsp_rate, int output_samplerate,
|
||||||
|
int type, int state, double tdelayup, double tslewup, double tdelaydown, double tslewdown, int bfo)
|
||||||
|
{
|
||||||
|
ch[channel].in_size = in_size;
|
||||||
|
ch[channel].dsp_size = dsp_size;
|
||||||
|
ch[channel].in_rate = input_samplerate;
|
||||||
|
ch[channel].dsp_rate = dsp_rate;
|
||||||
|
ch[channel].out_rate = output_samplerate;
|
||||||
|
ch[channel].type = type;
|
||||||
|
ch[channel].state = state;
|
||||||
|
ch[channel].tdelayup = tdelayup;
|
||||||
|
ch[channel].tslewup = tslewup;
|
||||||
|
ch[channel].tdelaydown = tdelaydown;
|
||||||
|
ch[channel].tslewdown = tslewdown;
|
||||||
|
ch[channel].bfo = bfo;
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
||||||
|
build_channel (channel);
|
||||||
|
if (ch[channel].state)
|
||||||
|
{
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].iob.pc->slew.upflag, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].iob.ch_upslew, 0);
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].iob.pc->exec_bypass, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].exchange, 0);
|
||||||
|
}
|
||||||
|
#if !defined(linux) && !defined(__APPLE__)
|
||||||
|
_MM_SET_FLUSH_ZERO_MODE (_MM_FLUSH_ZERO_ON);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_main_destroy (int channel)
|
||||||
|
{
|
||||||
|
IOB a = ch[channel].iob.pc;
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].run, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].iob.pc->exec_bypass, 0);
|
||||||
|
ReleaseSemaphore (a->Sem_BuffReady, 1, 0);
|
||||||
|
Sleep (25);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post_main_destroy (int channel)
|
||||||
|
{
|
||||||
|
destroy_iobuffs (channel);
|
||||||
|
DeleteCriticalSection ( &ch[channel].csEXCH );
|
||||||
|
DeleteCriticalSection ( &ch[channel].csDSP );
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void CloseChannel (int channel)
|
||||||
|
{
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
destroy_main (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushChannel (void* p)
|
||||||
|
{
|
||||||
|
int channel = (int)(uintptr_t)p;
|
||||||
|
IOB a = ch[channel].iob.pc;
|
||||||
|
while (!InterlockedAnd(&a->flush_bypass, 0xffffffff))
|
||||||
|
{
|
||||||
|
WaitForSingleObject(a->Sem_Flush, INFINITE);
|
||||||
|
if (!InterlockedAnd(&a->flush_bypass, 0xffffffff))
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
EnterCriticalSection(&ch[channel].csEXCH);
|
||||||
|
flush_iobuffs(channel);
|
||||||
|
InterlockedBitTestAndSet(&a->exec_bypass, 0);
|
||||||
|
flush_main(channel);
|
||||||
|
LeaveCriticalSection(&ch[channel].csEXCH);
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
InterlockedBitTestAndReset(&ch[channel].flushflag, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InterlockedBitTestAndReset(&a->flush_bypass, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Channel Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetType (int channel, int type)
|
||||||
|
{ // no need to rebuild buffers; but we did anyway
|
||||||
|
if (type != ch[channel].type)
|
||||||
|
{
|
||||||
|
CloseChannel (channel);
|
||||||
|
ch[channel].type = type;
|
||||||
|
build_channel (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetInputBuffsize (int channel, int in_size)
|
||||||
|
{ // we do not rebuild main here since it didn't change
|
||||||
|
if (in_size != ch[channel].in_size)
|
||||||
|
{
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].in_size = in_size;
|
||||||
|
pre_main_build (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDSPBuffsize (int channel, int dsp_size)
|
||||||
|
{
|
||||||
|
if (dsp_size != ch[channel].dsp_size)
|
||||||
|
{
|
||||||
|
int oldstate = SetChannelState (channel, 0, 1);
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].dsp_size = dsp_size;
|
||||||
|
pre_main_build (channel);
|
||||||
|
setDSPBuffsize_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
SetChannelState (channel, oldstate, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetInputSamplerate (int channel, int in_rate)
|
||||||
|
{ // no re-build of main required
|
||||||
|
if (in_rate != ch[channel].in_rate)
|
||||||
|
{
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].in_rate = in_rate;
|
||||||
|
pre_main_build (channel);
|
||||||
|
setInputSamplerate_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDSPSamplerate (int channel, int dsp_rate)
|
||||||
|
{
|
||||||
|
if (dsp_rate != ch[channel].dsp_rate)
|
||||||
|
{
|
||||||
|
int oldstate = SetChannelState (channel, 0, 1);
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].dsp_rate = dsp_rate;
|
||||||
|
pre_main_build (channel);
|
||||||
|
setDSPSamplerate_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
SetChannelState (channel, oldstate, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetOutputSamplerate (int channel, int out_rate)
|
||||||
|
{ // no re-build of main required
|
||||||
|
if (out_rate != ch[channel].out_rate)
|
||||||
|
{
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].out_rate = out_rate;
|
||||||
|
pre_main_build (channel);
|
||||||
|
setOutputSamplerate_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAllRates (int channel, int in_rate, int dsp_rate, int out_rate)
|
||||||
|
{
|
||||||
|
if ((in_rate != ch[channel].in_rate) || (dsp_rate != ch[channel].dsp_rate) || (out_rate != ch[channel].out_rate))
|
||||||
|
{
|
||||||
|
pre_main_destroy (channel);
|
||||||
|
post_main_destroy (channel);
|
||||||
|
ch[channel].in_rate = in_rate;
|
||||||
|
ch[channel].dsp_rate = dsp_rate;
|
||||||
|
ch[channel].out_rate = out_rate;
|
||||||
|
pre_main_build (channel);
|
||||||
|
setInputSamplerate_main (channel);
|
||||||
|
setDSPSamplerate_main (channel);
|
||||||
|
setOutputSamplerate_main (channel);
|
||||||
|
post_main_build (channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
int SetChannelState (int channel, int state, int dmode)
|
||||||
|
{
|
||||||
|
IOB a = ch[channel].iob.pc;
|
||||||
|
int prior_state = ch[channel].state;
|
||||||
|
int count = 0;
|
||||||
|
const int timeout = 100;
|
||||||
|
if (ch[channel].state != state)
|
||||||
|
{
|
||||||
|
ch[channel].state = state;
|
||||||
|
switch (ch[channel].state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
InterlockedBitTestAndSet (&a->slew.downflag, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].flushflag, 0);
|
||||||
|
if (dmode)
|
||||||
|
{
|
||||||
|
while (_InterlockedAnd (&ch[channel].flushflag, 1) && count < timeout)
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count >= timeout)
|
||||||
|
{
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].flushflag, 0);
|
||||||
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
InterlockedBitTestAndSet (&a->slew.upflag, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].iob.ch_upslew, 0);
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].iob.pc->exec_bypass, 0);
|
||||||
|
InterlockedBitTestAndSet (&ch[channel].exchange, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prior_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetChannelTDelayUp (int channel, double time)
|
||||||
|
{
|
||||||
|
IOB a;
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pc;
|
||||||
|
ch[channel].tdelayup = time;
|
||||||
|
a->slew.ndelup = (int)(ch[a->channel].tdelayup * ch[a->channel].in_rate);
|
||||||
|
flush_slews (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetChannelTSlewUp (int channel, double time)
|
||||||
|
{
|
||||||
|
IOB a;
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pc;
|
||||||
|
ch[channel].tslewup = time;
|
||||||
|
destroy_slews (a);
|
||||||
|
create_slews (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetChannelTDelayDown (int channel, double time)
|
||||||
|
{
|
||||||
|
IOB a;
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pc;
|
||||||
|
ch[channel].tdelaydown = time;
|
||||||
|
a->slew.ndeldown = (int)(ch[a->channel].tdelaydown * ch[a->channel].out_rate);
|
||||||
|
flush_slews (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetChannelTSlewDown (int channel, double time)
|
||||||
|
{
|
||||||
|
IOB a;
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pc;
|
||||||
|
ch[channel].tslewdown = time;
|
||||||
|
destroy_slews (a);
|
||||||
|
create_slews (a);
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/* channel.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _setupchannel_h
|
||||||
|
#define _setupchannel_h
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
struct _ch
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
volatile long run; // when 1, thread loops; when 0, thread terminates
|
||||||
|
volatile long exchange; // when 1, fexchange() operates; when 0, it just returns
|
||||||
|
int in_rate; // input samplerate
|
||||||
|
int out_rate; // output samplerate
|
||||||
|
int in_size; // input buffsize (complex samples) in a fexchange() operation
|
||||||
|
int dsp_rate; // sample rate for mainstream dsp processing
|
||||||
|
int dsp_size; // number complex samples processed per buffer in mainstream dsp processing
|
||||||
|
int dsp_insize; // size (complex samples) of the output of the r1 (input) buffer
|
||||||
|
int dsp_outsize; // size (complex samples) of the input of the r2 (output) buffer
|
||||||
|
int out_size; // output buffsize (complex samples) in a fexchange() operation
|
||||||
|
CRITICAL_SECTION csDSP; // used to block dsp while parameters are updated or buffers flushed
|
||||||
|
CRITICAL_SECTION csEXCH; // used to block fexchange() while parameters are updated or buffers flushed
|
||||||
|
int state; // 0 for channel OFF; 1 for channel ON
|
||||||
|
double tdelayup;
|
||||||
|
double tslewup;
|
||||||
|
double tdelaydown;
|
||||||
|
double tslewdown;
|
||||||
|
int bfo; // 'block_for_output', block fexchange until output is available
|
||||||
|
volatile long flushflag;
|
||||||
|
struct //io buffers
|
||||||
|
{
|
||||||
|
IOB pc, pd, pe, pf; // copies for console calls, dsp, exchange, and flush thread
|
||||||
|
volatile long ch_upslew;
|
||||||
|
} iob;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct _ch ch[];
|
||||||
|
|
||||||
|
PORT void OpenChannel (int channel, int in_size, int dsp_size, int input_samplerate, int dsp_rate, int output_samplerate, int type, int state, double tdelayup, double tslewup, double tdelaydown, double tslewdown, int bfo);
|
||||||
|
|
||||||
|
PORT void CloseChannel (int channel);
|
||||||
|
|
||||||
|
extern void flushChannel (void* p);
|
||||||
|
|
||||||
|
PORT void SetType (int channel, int type);
|
||||||
|
|
||||||
|
PORT void SetInputBuffsize (int channel, int in_size);
|
||||||
|
|
||||||
|
PORT void SetDSPBuffsize (int channel, int dsp_size);
|
||||||
|
|
||||||
|
PORT void SetInputSamplerate (int channel, int samplerate);
|
||||||
|
|
||||||
|
PORT void SetDSPSamplerate (int channel, int samplerate);
|
||||||
|
|
||||||
|
PORT void SetOutputSamplerate (int channel, int samplerate);
|
||||||
|
|
||||||
|
PORT void SetAllRates (int channel, int in_rate, int dsp_rate, int out_rate);
|
||||||
|
|
||||||
|
PORT int SetChannelState (int channel, int state, int dmode);
|
||||||
|
|
||||||
|
#endif
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
/* comm.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(linux) || defined(__APPLE__)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "linux_port.h"
|
||||||
|
#ifdef ANDROID
|
||||||
|
#include <android/log.h>
|
||||||
|
#define APPNAME "WDSP"
|
||||||
|
#define LOGD(LOG_TAG, ...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGI(LOG_TAG, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG,__VA_ARGS__)
|
||||||
|
#define LOGV(LOG_TAG, ...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGW(LOG_TAG, ...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||||
|
#define LOGE(LOG_TAG, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <avrt.h>
|
||||||
|
#endif
|
||||||
|
#include "fftw3.h"
|
||||||
|
|
||||||
|
#include "amd.h"
|
||||||
|
#include "ammod.h"
|
||||||
|
#include "amsq.h"
|
||||||
|
#include "analyzer.h"
|
||||||
|
#include "anf.h"
|
||||||
|
#include "anr.h"
|
||||||
|
#include "bandpass.h"
|
||||||
|
#include "calcc.h"
|
||||||
|
#include "cblock.h"
|
||||||
|
#include "cfcomp.h"
|
||||||
|
#include "cfir.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "compress.h"
|
||||||
|
#include "delay.h"
|
||||||
|
#include "dexp.h"
|
||||||
|
#include "div.h"
|
||||||
|
#include "eer.h"
|
||||||
|
#include "emnr.h"
|
||||||
|
#include "emph.h"
|
||||||
|
#include "eq.h"
|
||||||
|
#include "fcurve.h"
|
||||||
|
#include "fir.h"
|
||||||
|
#include "firmin.h"
|
||||||
|
#include "fmd.h"
|
||||||
|
#include "fmmod.h"
|
||||||
|
#include "fmsq.h"
|
||||||
|
#include "gain.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "icfir.h"
|
||||||
|
#include "iir.h"
|
||||||
|
#include "iobuffs.h"
|
||||||
|
#include "iqc.h"
|
||||||
|
#include "lmath.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "meter.h"
|
||||||
|
#include "meterlog10.h"
|
||||||
|
#include "nbp.h"
|
||||||
|
#include "nob.h"
|
||||||
|
#include "nobII.h"
|
||||||
|
#include "osctrl.h"
|
||||||
|
#include "patchpanel.h"
|
||||||
|
#include "resample.h"
|
||||||
|
#include "rmatch.h"
|
||||||
|
#include "RXA.h"
|
||||||
|
#include "sender.h"
|
||||||
|
#include "shift.h"
|
||||||
|
#include "siphon.h"
|
||||||
|
#include "slew.h"
|
||||||
|
#include "snb.h"
|
||||||
|
#include "ssql.h"
|
||||||
|
#include "syncbuffs.h"
|
||||||
|
#include "TXA.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "varsamp.h"
|
||||||
|
#include "wcpAGC.h"
|
||||||
|
|
||||||
|
// manage differences among consoles
|
||||||
|
#define _Thetis
|
||||||
|
|
||||||
|
// channel definitions
|
||||||
|
#define MAX_CHANNELS 32 // maximum number of supported channels
|
||||||
|
#define DSP_MULT 2 // number of dsp_buffsizes that are held in an iobuff pseudo-ring
|
||||||
|
#define INREAL float // data type for channel input buffer
|
||||||
|
#define OUTREAL float // data type for channel output buffer
|
||||||
|
|
||||||
|
// display definitions
|
||||||
|
#define dMAX_DISPLAYS 64 // maximum number of displays = max instances
|
||||||
|
#define dMAX_STITCH 4 // maximum number of sub-spans to stitch together
|
||||||
|
#define dMAX_NUM_FFT 1 // maximum number of ffts for an elimination
|
||||||
|
#define dMAX_PIXELS 16384 // maximum number of pixels that can be requested
|
||||||
|
#define dMAX_AVERAGE 60 // maximum number of pixel frames that will be window-averaged
|
||||||
|
#ifdef _Thetis
|
||||||
|
#define dINREAL double
|
||||||
|
#else
|
||||||
|
#define dINREAL float
|
||||||
|
#endif
|
||||||
|
#define dOUTREAL float
|
||||||
|
#define dSAMP_BUFF_MULT 2 // ratio of input sample buffer size to fft size (for overlap)
|
||||||
|
#define dNUM_PIXEL_BUFFS 3 // number of pixel output buffers
|
||||||
|
#define dMAX_M 1 // number of variables to calibrate
|
||||||
|
#define dMAX_N 100 // maximum number of frequencies at which to calibrate
|
||||||
|
#define dMAX_CAL_SETS 2 // maximum number of calibration data sets
|
||||||
|
#define dMAX_PIXOUTS 4 // maximum number of det/avg/outputs per display instance
|
||||||
|
|
||||||
|
// wisdom definitions
|
||||||
|
#define MAX_WISDOM_SIZE_DISPLAY 262144
|
||||||
|
#define MAX_WISDOM_SIZE_FILTER 262144 // was 32769
|
||||||
|
|
||||||
|
// math definitions
|
||||||
|
#define PI 3.1415926535897932
|
||||||
|
#define TWOPI 6.2831853071795864
|
||||||
|
|
||||||
|
// miscellaneous
|
||||||
|
typedef double complex[2];
|
||||||
|
#define PORT __declspec( dllexport )
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
/* compress.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2011, 2013, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
This software is based upon the algorithm described by Peter Martinez, G3PLX,
|
||||||
|
in the January 2010 issue of RadCom magazine.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
COMPRESSOR create_compressor (
|
||||||
|
int run,
|
||||||
|
int buffsize,
|
||||||
|
double* inbuff,
|
||||||
|
double* outbuff,
|
||||||
|
double gain )
|
||||||
|
{
|
||||||
|
COMPRESSOR a;
|
||||||
|
a = (COMPRESSOR) malloc0 (sizeof (compressor));
|
||||||
|
a->run = run;
|
||||||
|
a->inbuff = inbuff;
|
||||||
|
a->outbuff = outbuff;
|
||||||
|
a->buffsize = buffsize;
|
||||||
|
a->gain = gain;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_compressor (COMPRESSOR a)
|
||||||
|
{
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_compressor (COMPRESSOR a)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void xcompressor (COMPRESSOR a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double mag;
|
||||||
|
if (a->run)
|
||||||
|
for (i = 0; i < a->buffsize; i++)
|
||||||
|
{
|
||||||
|
mag = sqrt(a->inbuff[2 * i + 0] * a->inbuff[2 * i + 0] + a->inbuff[2 * i + 1] * a->inbuff[2 * i + 1]);
|
||||||
|
if (a->gain * mag > 1.0)
|
||||||
|
a->outbuff[2 * i + 0] = a->inbuff[2 * i + 0] / mag;
|
||||||
|
else
|
||||||
|
a->outbuff[2 * i + 0] = a->inbuff[2 * i + 0] * a->gain;
|
||||||
|
a->outbuff[2 * i + 1] = 0.0;
|
||||||
|
}
|
||||||
|
else if (a->inbuff != a->outbuff)
|
||||||
|
memcpy(a->outbuff, a->inbuff, a->buffsize * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_compressor (COMPRESSOR a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->inbuff = in;
|
||||||
|
a->outbuff = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_compressor (COMPRESSOR a, int rate)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_compressor (COMPRESSOR a, int size)
|
||||||
|
{
|
||||||
|
a->buffsize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetTXACompressorRun (int channel, int run)
|
||||||
|
{
|
||||||
|
if (txa[channel].compressor.p->run != run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].compressor.p->run = run;
|
||||||
|
TXASetupBPFilters (channel);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT void
|
||||||
|
SetTXACompressorGain (int channel, double gain)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].compressor.p->gain = pow (10.0, gain / 20.0);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/* compress.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2011, 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _compressor_h
|
||||||
|
#define _compressor_h
|
||||||
|
|
||||||
|
typedef struct _compressor
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int buffsize;
|
||||||
|
double *inbuff;
|
||||||
|
double *outbuff;
|
||||||
|
double gain;
|
||||||
|
} compressor, *COMPRESSOR;
|
||||||
|
|
||||||
|
extern void xcompressor (COMPRESSOR a);
|
||||||
|
|
||||||
|
extern COMPRESSOR create_compressor (
|
||||||
|
int run,
|
||||||
|
int buffsize,
|
||||||
|
double* inbuff,
|
||||||
|
double* outbuff,
|
||||||
|
double gain );
|
||||||
|
|
||||||
|
extern void destroy_compressor (COMPRESSOR a);
|
||||||
|
|
||||||
|
extern void flush_compressor (COMPRESSOR a);
|
||||||
|
|
||||||
|
extern void setBuffers_compressor (COMPRESSOR a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_compressor (COMPRESSOR a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_compressor (COMPRESSOR a, int size);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACompressorRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACompressorGain (int channel, double gain);
|
||||||
|
|
||||||
|
#endif
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/* delay.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2019 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
DELAY create_delay (int run, int size, double* in, double* out, int rate, double tdelta, double tdelay)
|
||||||
|
{
|
||||||
|
DELAY a = (DELAY) malloc0 (sizeof (delay));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = rate;
|
||||||
|
a->tdelta = tdelta;
|
||||||
|
a->tdelay = tdelay;
|
||||||
|
a->L = (int)(0.5 + 1.0 / (a->tdelta * (double)a->rate));
|
||||||
|
a->adelta = 1.0 / (a->rate * a->L);
|
||||||
|
a->ft = 0.45 / (double)a->L;
|
||||||
|
a->ncoef = (int)(60.0 / a->ft);
|
||||||
|
a->ncoef = (a->ncoef / a->L + 1) * a->L;
|
||||||
|
a->cpp = a->ncoef / a->L;
|
||||||
|
a->phnum = (int)(0.5 + a->tdelay / a->adelta);
|
||||||
|
a->snum = a->phnum / a->L;
|
||||||
|
a->phnum %= a->L;
|
||||||
|
a->idx_in = 0;
|
||||||
|
a->adelay = a->adelta * (a->snum * a->L + a->phnum);
|
||||||
|
a->h = fir_bandpass (a->ncoef,-a->ft, +a->ft, 1.0, 1, 0, (double)a->L);
|
||||||
|
a->rsize = a->cpp + (WSDEL - 1);
|
||||||
|
a->ring = (double *) malloc0 (a->rsize * sizeof (complex));
|
||||||
|
InitializeCriticalSectionAndSpinCount ( &a->cs_update, 2500 );
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_delay (DELAY a)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection (&a->cs_update);
|
||||||
|
_aligned_free (a->ring);
|
||||||
|
_aligned_free (a->h);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_delay (DELAY a)
|
||||||
|
{
|
||||||
|
memset (a->ring, 0, a->cpp * sizeof (complex));
|
||||||
|
a->idx_in = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdelay (DELAY a)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i, j, k, idx, n;
|
||||||
|
double Itmp, Qtmp;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->ring[2 * a->idx_in + 0] = a->in[2 * i + 0];
|
||||||
|
a->ring[2 * a->idx_in + 1] = a->in[2 * i + 1];
|
||||||
|
Itmp = 0.0;
|
||||||
|
Qtmp = 0.0;
|
||||||
|
if ((n = a->idx_in + a->snum) >= a->rsize) n -= a->rsize;
|
||||||
|
for (j = 0, k = a->L - 1 - a->phnum; j < a->cpp; j++, k+= a->L)
|
||||||
|
{
|
||||||
|
if ((idx = n + j) >= a->rsize) idx -= a->rsize;
|
||||||
|
Itmp += a->ring[2 * idx + 0] * a->h[k];
|
||||||
|
Qtmp += a->ring[2 * idx + 1] * a->h[k];
|
||||||
|
}
|
||||||
|
a->out[2 * i + 0] = Itmp;
|
||||||
|
a->out[2 * i + 1] = Qtmp;
|
||||||
|
if (--a->idx_in < 0) a->idx_in = a->rsize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->out != a->in)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void SetDelayRun (DELAY a, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
double SetDelayValue (DELAY a, double tdelay)
|
||||||
|
{
|
||||||
|
double adelay;
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->tdelay = tdelay;
|
||||||
|
a->phnum = (int)(0.5 + a->tdelay / a->adelta);
|
||||||
|
a->snum = a->phnum / a->L;
|
||||||
|
a->phnum %= a->L;
|
||||||
|
a->adelay = a->adelta * (a->snum * a->L + a->phnum);
|
||||||
|
adelay = a->adelay;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
return adelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDelayBuffs (DELAY a, int size, double* in, double* out)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* delay.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2019 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _delay_h
|
||||||
|
#define _delay_h
|
||||||
|
|
||||||
|
#define WSDEL 1025 // number of supported whole sample delays
|
||||||
|
|
||||||
|
typedef struct _delay
|
||||||
|
{
|
||||||
|
int run; // run
|
||||||
|
int size; // number of input samples per buffer
|
||||||
|
double* in; // input buffer
|
||||||
|
double* out; // output buffer
|
||||||
|
int rate; // samplerate
|
||||||
|
double tdelta; // delay increment required (seconds)
|
||||||
|
double tdelay; // delay requested (seconds)
|
||||||
|
|
||||||
|
int L; // interpolation factor
|
||||||
|
int ncoef; // number of coefficients
|
||||||
|
int cpp; // coefficients per phase
|
||||||
|
double ft; // normalized cutoff frequency
|
||||||
|
double* h; // coefficients
|
||||||
|
int snum; // starting sample number (0 for sub-sample delay)
|
||||||
|
int phnum; // phase number
|
||||||
|
|
||||||
|
int idx_in; // index for input into ring
|
||||||
|
int rsize; // ring size in complex samples
|
||||||
|
double* ring; // ring buffer
|
||||||
|
|
||||||
|
double adelta; // actual delay increment
|
||||||
|
double adelay; // actual delay
|
||||||
|
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
|
||||||
|
} delay, *DELAY;
|
||||||
|
|
||||||
|
extern DELAY create_delay (int run, int size, double* in, double* out, int rate, double tdelta, double tdelay);
|
||||||
|
|
||||||
|
extern void destroy_delay (DELAY a);
|
||||||
|
|
||||||
|
extern void flush_delay (DELAY a);
|
||||||
|
|
||||||
|
extern void xdelay (DELAY a);
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
|
||||||
|
extern void SetDelayRun (DELAY a, int run);
|
||||||
|
|
||||||
|
extern double SetDelayValue (DELAY a, double delay); // returns actual delay in seconds
|
||||||
|
|
||||||
|
extern void SetDelayBuffs (DELAY a, int size, double* in, double* out);
|
||||||
|
|
||||||
|
#endif
|
||||||
+716
@@ -0,0 +1,716 @@
|
|||||||
|
/* dexp.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
DEXP pdexp[4];
|
||||||
|
|
||||||
|
DELRING calc_delring (int rsize, int size, int delay, double* in, double* out)
|
||||||
|
{
|
||||||
|
DELRING a = (DELRING) malloc0 (sizeof (delring));
|
||||||
|
a->rsize = rsize;
|
||||||
|
a->size = size;
|
||||||
|
a->rdelay = delay;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->ring = (double *) malloc0 (a->rsize * sizeof (complex));
|
||||||
|
a->inptr = a->rdelay;
|
||||||
|
a->outptr = 0;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_delring (DELRING a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->ring);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_delring (DELRING a)
|
||||||
|
{
|
||||||
|
memset (a->ring, 0, a->rsize * sizeof (complex));
|
||||||
|
a->inptr = a->rdelay;
|
||||||
|
a->outptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdelring (DELRING a)
|
||||||
|
{
|
||||||
|
int first, second;
|
||||||
|
// copy in
|
||||||
|
if (a->size > (a->rsize - a->inptr))
|
||||||
|
{
|
||||||
|
first = a->rsize - a->inptr;
|
||||||
|
second = a->size - first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = a->size;
|
||||||
|
second = 0;
|
||||||
|
}
|
||||||
|
memcpy (a->ring + 2 * a->inptr, a->in, first * sizeof (complex));
|
||||||
|
memcpy (a->ring, a->in + 2 * first, second * sizeof (complex));
|
||||||
|
a->inptr = (a->inptr + a->size) % a->rsize;
|
||||||
|
// copy out
|
||||||
|
if (a->size > (a->rsize - a->outptr))
|
||||||
|
{
|
||||||
|
first = a->rsize - a->outptr;
|
||||||
|
second = a->size - first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = a->size;
|
||||||
|
second = 0;
|
||||||
|
}
|
||||||
|
memcpy (a->out, a->ring + 2 * a->outptr, first * sizeof (complex));
|
||||||
|
memcpy (a->out + 2 * first, a->ring, second * sizeof (complex));
|
||||||
|
a->outptr = (a->outptr + a->size) % a->rsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_slews (DEXP a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double delta, theta;
|
||||||
|
delta = PI / (double)a->nattack;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->nattack; i++)
|
||||||
|
{
|
||||||
|
a->cattack[i] = a->low_gain + (1.0 - a->low_gain) * 0.5 * (1.0 - cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
delta = PI / (double)a->ndecay;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ndecay; i++)
|
||||||
|
{
|
||||||
|
a->cdecay[i] = a->low_gain + (1.0 - a->low_gain) * 0.5 * (1.0 + cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_buffs (DEXP a)
|
||||||
|
{
|
||||||
|
a->trigsig = (double *)malloc0 (2 * a->size * sizeof(complex)); // allow for double-sized output of filter
|
||||||
|
a->delsig = (double *)malloc0 ( a->size * sizeof(complex));
|
||||||
|
a->audbuffer = (double *)malloc0 ( a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_buffs (DEXP a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->audbuffer);
|
||||||
|
_aligned_free (a->delsig);
|
||||||
|
_aligned_free (a->trigsig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_dexp (DEXP a)
|
||||||
|
{
|
||||||
|
// trigger signal preparation
|
||||||
|
a->avm = exp(-1.0 / (a->rate * a->dettau));
|
||||||
|
a->onem_avm = 1.0 - a->avm;
|
||||||
|
a->avsig = 0.0;
|
||||||
|
// level change
|
||||||
|
a->nattack = (int)(a->tattack * a->rate);
|
||||||
|
a->ndecay = (int)(a->tdecay * a->rate);
|
||||||
|
a->cattack = (double *)malloc0((a->nattack + 1) * sizeof(double));
|
||||||
|
a->cdecay = (double *)malloc0((a->ndecay + 1) * sizeof(double));
|
||||||
|
a->low_gain = 1.0 / a->exp_ratio;
|
||||||
|
calc_slews(a);
|
||||||
|
// control
|
||||||
|
a->state = 0;
|
||||||
|
a->count = 0;
|
||||||
|
a->hold_thresh = a->hysteresis_ratio * a->attack_thresh; // hysteresis ratio < 1.0
|
||||||
|
a->nhold = (int)(a->thold * a->rate);
|
||||||
|
// vox
|
||||||
|
a->vox_count = (int)(a->audelay * a->rate);
|
||||||
|
// audio delay
|
||||||
|
a->audring = calc_delring ((int)a->rate, a->size, (int)(a->audelay * a->rate), a->audbuffer, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_dexp (DEXP a)
|
||||||
|
{
|
||||||
|
decalc_delring (a->audring);
|
||||||
|
_aligned_free (a->cdecay);
|
||||||
|
_aligned_free (a->cattack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_filter (DEXP a)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
// 2.0 gain on filter is somewhat arbitrarily chosen to get trigger input similar to that without the filter, knowing
|
||||||
|
// that for any reasonable use of the filter there will be a reduction in trigger signal.
|
||||||
|
impulse = fir_bandpass (a->nc, a->low_cut, a->high_cut, a->rate, a->wintype, 1, 2.0/(double)(2 * a->size));
|
||||||
|
// print_impulse ("scf.txt", a->nc, impulse, 1, 0);
|
||||||
|
a->p = create_fircore (a->size, a->in, a->trigsig, a->nc, 1, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
a->scdring = calc_delring (a->size + a->nc / 2, a->size, a->nc / 64, a->in, a->delsig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_filter (DEXP a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
decalc_delring (a->scdring);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_antivox(DEXP a)
|
||||||
|
{
|
||||||
|
a->antivox_mult = exp(-1.0 / (a->antivox_rate * a->antivox_tau));
|
||||||
|
a->antivox_onemmult = 1.0 - a->antivox_mult;
|
||||||
|
a->antivox_data = (double *) malloc0 (a->antivox_size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_antivox(DEXP a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->antivox_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void create_dexp (int id, int run_dexp, int size, double* in, double* out, int rate, double dettau, double tattack, double tdecay,
|
||||||
|
double thold, double exp_ratio, double hyst_ratio, double attack_thresh, int nc, int wtype, double lowcut, double highcut,
|
||||||
|
int run_filt, int run_vox, int run_audelay, double audelay, void (__stdcall *pushvox)(int id, int active),
|
||||||
|
int antivox_run, int antivox_size, int antivox_rate, double antivox_gain, double antivox_tau)
|
||||||
|
{
|
||||||
|
DEXP a = (DEXP) malloc0 (sizeof (dexp));
|
||||||
|
a->id = id;
|
||||||
|
a->run_dexp = run_dexp;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->dettau = dettau;
|
||||||
|
a->tattack = tattack;
|
||||||
|
a->tdecay = tdecay;
|
||||||
|
a->thold = thold;
|
||||||
|
a->exp_ratio = exp_ratio;
|
||||||
|
a->hysteresis_ratio = hyst_ratio;
|
||||||
|
a->attack_thresh = attack_thresh;
|
||||||
|
a->nc = nc;
|
||||||
|
a->wintype = wtype;
|
||||||
|
a->low_cut = lowcut;
|
||||||
|
a->high_cut = highcut;
|
||||||
|
a->run_filt = run_filt;
|
||||||
|
a->run_vox = run_vox;
|
||||||
|
a->run_audelay = run_audelay;
|
||||||
|
a->audelay = audelay;
|
||||||
|
a->pushvox = pushvox;
|
||||||
|
a->antivox_run = antivox_run;
|
||||||
|
a->antivox_size = antivox_size;
|
||||||
|
a->antivox_rate = (double)antivox_rate;
|
||||||
|
a->antivox_gain = antivox_gain;
|
||||||
|
a->antivox_tau = antivox_tau;
|
||||||
|
calc_buffs (a);
|
||||||
|
calc_dexp (a);
|
||||||
|
calc_filter (a);
|
||||||
|
calc_antivox (a);
|
||||||
|
InitializeCriticalSectionAndSpinCount(&a->cs_update, 2500);
|
||||||
|
pdexp[id] = a;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void destroy_dexp (int id)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
DeleteCriticalSection (&a->cs_update);
|
||||||
|
decalc_antivox (a);
|
||||||
|
decalc_filter (a);
|
||||||
|
decalc_dexp (a);
|
||||||
|
decalc_buffs (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void flush_dexp (int id)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
memset (a->audbuffer, 0, a->size * sizeof (complex));
|
||||||
|
memset (a->trigsig, 0, a->size * sizeof (complex));
|
||||||
|
memset (a->delsig, 0, a->size * sizeof (complex));
|
||||||
|
a->avsig = 0.0;
|
||||||
|
a->state = 0;
|
||||||
|
a->count = 0;
|
||||||
|
flush_fircore (a->p);
|
||||||
|
flush_delring (a->scdring);
|
||||||
|
flush_delring (a->audring);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _dexpstate
|
||||||
|
{
|
||||||
|
DEXP_LOW,
|
||||||
|
DEXP_ATTACK,
|
||||||
|
DEXP_HIGH,
|
||||||
|
DEXP_HOLD,
|
||||||
|
DEXP_DECAY
|
||||||
|
};
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void xdexp (int id)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
int i;
|
||||||
|
double sig, gain, asig;
|
||||||
|
double max = 0.0;
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
|
||||||
|
// ******* BEGIN SIDE-CHANNEL FILTER *******
|
||||||
|
if (a->run_filt)
|
||||||
|
{
|
||||||
|
xdelring (a->scdring); // input is 'a->in'; output is 'a->delsig'
|
||||||
|
xfircore (a->p); // input is 'a->in'; output is 'a->trigsig'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (a->delsig, a->in, a->size * sizeof (complex));
|
||||||
|
memcpy (a->trigsig, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
// ******* END SIDE-CHANNEL FILTER *******
|
||||||
|
|
||||||
|
// ******* CALCULATE ANTIVOX LEVEL *******
|
||||||
|
if (a->state == DEXP_LOW && a->antivox_new != 0)
|
||||||
|
{
|
||||||
|
// if VOX is currently NOT triggered, and, if we have new antivox data to process
|
||||||
|
for (i = 0; i < a->antivox_size; i++)
|
||||||
|
{
|
||||||
|
sig = sqrt (a->antivox_data[2 * i + 0] * a->antivox_data[2 * i + 0] + a->antivox_data[2 * i + 1] * a->antivox_data[2 * i + 1]);
|
||||||
|
a->antivox_level = a->antivox_mult * a->antivox_level + a->antivox_onemmult * sig;
|
||||||
|
}
|
||||||
|
// set the new_data flag to zero
|
||||||
|
a->antivox_new = 0;
|
||||||
|
}
|
||||||
|
// ******* END CALCULATE ANTIVOX LEVEL *******
|
||||||
|
|
||||||
|
// ******* BEGIN DEXP *******
|
||||||
|
// uses 'a->trigsig' as trigger signal; uses 'a->delsig' as audio input
|
||||||
|
// 'a->audbuffer' is audio output
|
||||||
|
// DEXP code runs continuously so it can be used to trigger VOX also.
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
sig = sqrt (a->trigsig[2 * i + 0] * a->trigsig[2 * i + 0] + a->trigsig[2 * i + 1] * a->trigsig[2 * i + 1]);
|
||||||
|
a->avsig = a->avm * a->avsig + a->onem_avm * sig;
|
||||||
|
if (a->avsig > max) max = a->avsig;
|
||||||
|
switch (a->state)
|
||||||
|
{
|
||||||
|
case DEXP_LOW:
|
||||||
|
if (a->antivox_run)
|
||||||
|
asig = a->avsig - a->antivox_gain * a->antivox_level;
|
||||||
|
else
|
||||||
|
asig = a->avsig;
|
||||||
|
if (asig > a->attack_thresh)
|
||||||
|
{
|
||||||
|
a->state = DEXP_ATTACK;
|
||||||
|
a->count = a->nattack;
|
||||||
|
}
|
||||||
|
a->audbuffer[2 * i + 0] = a->low_gain * a->delsig[2 * i + 0];
|
||||||
|
a->audbuffer[2 * i + 1] = a->low_gain * a->delsig[2 * i + 1];
|
||||||
|
|
||||||
|
// ******* BEGIN VOX *******
|
||||||
|
// If we're going to attack, turn on VOX immediately.
|
||||||
|
// Prepare 'vox_count' for the next turnoff too.
|
||||||
|
if (a->run_vox && a->state == DEXP_ATTACK)
|
||||||
|
{
|
||||||
|
(a->pushvox)(a->id, 1);
|
||||||
|
// Set vox_count for delay IF the audio delay is also enabled.
|
||||||
|
if (a->run_audelay)
|
||||||
|
a->vox_count = (int)(a->audelay * a->rate);
|
||||||
|
else
|
||||||
|
a->vox_count = 1;
|
||||||
|
}
|
||||||
|
// If we're sitting in this state and the delayed vox count expires, turn OFF VOX.
|
||||||
|
else if (a->run_vox && --(a->vox_count) == 0)
|
||||||
|
(a->pushvox)(a->id, 0);
|
||||||
|
// Don't let 'vox_count' keep counting down.
|
||||||
|
else if (a->vox_count < 0)
|
||||||
|
a->vox_count = 0;
|
||||||
|
// ******* END VOX *******
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DEXP_ATTACK:
|
||||||
|
gain = a->cattack[a->nattack - a->count];
|
||||||
|
a->audbuffer[2 * i + 0] = a->delsig[2 * i + 0] * gain;
|
||||||
|
a->audbuffer[2 * i + 1] = a->delsig[2 * i + 1] * gain;
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = DEXP_HIGH;
|
||||||
|
break;
|
||||||
|
case DEXP_HIGH:
|
||||||
|
if (a->avsig < a->hold_thresh)
|
||||||
|
{
|
||||||
|
a->state = DEXP_HOLD;
|
||||||
|
a->count = a->nhold;
|
||||||
|
}
|
||||||
|
a->audbuffer[2 * i + 0] = a->delsig[2 * i + 0];
|
||||||
|
a->audbuffer[2 * i + 1] = a->delsig[2 * i + 1];
|
||||||
|
break;
|
||||||
|
case DEXP_HOLD:
|
||||||
|
a->audbuffer[2 * i + 0] = a->delsig[2 * i + 0];
|
||||||
|
a->audbuffer[2 * i + 1] = a->delsig[2 * i + 1];
|
||||||
|
if (a->avsig > a->attack_thresh)
|
||||||
|
a->state = DEXP_HIGH;
|
||||||
|
else if (a->count-- == 0)
|
||||||
|
{
|
||||||
|
a->state = DEXP_DECAY;
|
||||||
|
a->count = a->ndecay;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DEXP_DECAY:
|
||||||
|
gain = a->cdecay[a->ndecay - a->count];
|
||||||
|
a->audbuffer[2 * i + 0] = a->delsig[2 * i + 0] * gain;
|
||||||
|
a->audbuffer[2 * i + 1] = a->delsig[2 * i + 1] * gain;
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = DEXP_LOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a->peak = max;
|
||||||
|
// If DEXP functionality is set to OFF, copy its input to overwrite its output.
|
||||||
|
if (!a->run_dexp)
|
||||||
|
memcpy (a->audbuffer, a->delsig, a->size * sizeof (complex));
|
||||||
|
// ******* END DEXP *******
|
||||||
|
|
||||||
|
// ******* BEGIN AUDIO DELAY *******
|
||||||
|
if (a->run_audelay)
|
||||||
|
xdelring (a->audring); // uses 'a->audbuffer' as audio input; uses 'a->out' as audio output
|
||||||
|
else
|
||||||
|
memcpy (a->out, a->audbuffer, a->size * sizeof (complex));
|
||||||
|
// ******* END AUDIO DELAY *******
|
||||||
|
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SendCBPushDexpVox (int id, void (__stdcall *pushvox)(int id, int active))
|
||||||
|
{
|
||||||
|
// Call to set the address of the callback to operate VOX.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
a->pushvox = pushvox;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPRun (int id, int run)
|
||||||
|
{
|
||||||
|
// run != 0, puts dexp in the audio processing path; otherwise, it's only used to trigger VOX
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run_dexp = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPSize (int id, int size)
|
||||||
|
{
|
||||||
|
// There are some constraints on the input/output buffer sizes.
|
||||||
|
// * must be a power-of-two
|
||||||
|
// * must be less than or equal to 'nc', the number of filter coefficients, which is also a power-of-two
|
||||||
|
// * must be less than 'rate' samples because of the sizing of 'audring'
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
decalc_dexp (a);
|
||||||
|
decalc_buffs (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_buffs (a);
|
||||||
|
calc_dexp (a);
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPIOBuffers (int id, double* in, double* out)
|
||||||
|
{
|
||||||
|
// Sets the input/output buffers. They can be the same.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_dexp (a);
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPRate (int id, double rate)
|
||||||
|
{
|
||||||
|
// Sets the sample rate.
|
||||||
|
// This is used for timing and filter calculations as well as sizing 'audring'.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_dexp (a);
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPDetectorTau (int id, double tau)
|
||||||
|
{
|
||||||
|
// Time-constant for smoothing the signal for detection (seconds).
|
||||||
|
// 0.01 seconds is a good starting point to try.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->dettau = tau;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPAttackTime (int id, double time)
|
||||||
|
{
|
||||||
|
// Set attack time, seconds.
|
||||||
|
// 0.002 - 0.100 should be a good range.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->tattack = time;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPReleaseTime (int id, double time)
|
||||||
|
{
|
||||||
|
// Set release time, seconds.
|
||||||
|
// 0.002 - 0.999 should be a good range.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->tdecay = time;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPHoldTime (int id, double time)
|
||||||
|
{
|
||||||
|
// Set hold time, seconds.
|
||||||
|
// 0.000 - 2.000 should be a good range.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->thold = time;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPExpansionRatio (int id, double ratio)
|
||||||
|
{
|
||||||
|
// Set expansion ratio. High_gain = 1.0; Low_gain = 1.0/exp_ratio.
|
||||||
|
// Range of 1.0 - 30.0 should be good. Could use dB: 0.0 - 30.0dB.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->exp_ratio = ratio;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPHysteresisRatio (int id, double ratio)
|
||||||
|
{
|
||||||
|
// Set Hysteresis Ratio. Hold_thresh = hysteresis_ratio * Attack_thresh.
|
||||||
|
// Expose to operator in dB: 0.0dB - 9.9dB should be good (1.000 - 0.320).
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->hysteresis_ratio = ratio;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPAttackThreshold (int id, double thresh)
|
||||||
|
{
|
||||||
|
// Set attack threshold.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->attack_thresh = thresh;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPFilterTaps (int id, int taps)
|
||||||
|
{
|
||||||
|
// Set number of taps. Must be a power of two and an even multiple of 'size'.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
a->nc = taps;
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPWindowType (int id, int type)
|
||||||
|
{
|
||||||
|
// Set filter window type.
|
||||||
|
// * 0 - 4-term Blackman-Harris.
|
||||||
|
// * 1 - 7-term Blackman-Harris.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
a->wintype = type;
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPLowCut (int id, double lowcut)
|
||||||
|
{
|
||||||
|
// Set side-channel filter low_cut (Hertz).
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
a->low_cut = lowcut;
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPHighCut (int id, double highcut)
|
||||||
|
{
|
||||||
|
// Set side-channel filter high_cut (Hertz).
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_filter (a);
|
||||||
|
a->high_cut = highcut;
|
||||||
|
calc_filter (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPRunSideChannelFilter (int id, int run)
|
||||||
|
{
|
||||||
|
// Turn OFF/ON the side-channel filter and its compensating delay.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run_filt = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPRunVox (int id, int run)
|
||||||
|
{
|
||||||
|
// Turn OFF/ON calls to 'pushvox(...)'.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run_vox = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPRunAudioDelay (int id, int run)
|
||||||
|
{
|
||||||
|
// Turn OFF/ON audio delay line.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run_audelay = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetDEXPAudioDelay (int id, double delay)
|
||||||
|
{
|
||||||
|
// Set the audio delay, seconds.
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_dexp (a);
|
||||||
|
a->audelay = delay;
|
||||||
|
calc_dexp (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void GetDEXPPeakSignal (int id, double* peak)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
*peak = a->peak;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAntiVOXRun (int id, int run)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->antivox_run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAntiVOXSize (int id, int size)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_antivox(a);
|
||||||
|
a->antivox_size = size;
|
||||||
|
calc_antivox(a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAntiVOXRate (int id, double rate)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_antivox(a);
|
||||||
|
a->antivox_rate = rate;
|
||||||
|
calc_antivox(a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAntiVOXGain (int id, double gain)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->antivox_gain = gain;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetAntiVOXDetectorTau (int id, double tau)
|
||||||
|
{
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
decalc_antivox (a);
|
||||||
|
a->antivox_tau = tau;
|
||||||
|
calc_antivox (a);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SendAntiVOXData (int id, int nsamples, double* data)
|
||||||
|
{
|
||||||
|
// note: 'nsamples' is not used as it has been previously specified
|
||||||
|
DEXP a = pdexp[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
memcpy (a->antivox_data, data, a->antivox_size * sizeof (complex));
|
||||||
|
a->antivox_new = 1;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
/* dexp.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2018, 2019 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _dexp_h
|
||||||
|
#define _dexp_h
|
||||||
|
|
||||||
|
typedef struct _delring
|
||||||
|
{
|
||||||
|
int rsize; // ringsize (measured in complex samples)
|
||||||
|
double* ring; // ring buffer
|
||||||
|
int inptr; // ring input pointer (counts in complex samples)
|
||||||
|
int outptr; // ring output pointer (counts in complex samples)
|
||||||
|
int rdelay; // ring delay (measured in complex samples)
|
||||||
|
int size; // input/output size in complex samples
|
||||||
|
double* in; // source buffer
|
||||||
|
double* out; // destination buffer
|
||||||
|
} delring, *DELRING;
|
||||||
|
|
||||||
|
typedef struct _dexp
|
||||||
|
{
|
||||||
|
int id; // 'id' for this dexp
|
||||||
|
int run_dexp; // 0 if dexp is OFF; 1 if it's ON
|
||||||
|
int size; // size of input/output buffers
|
||||||
|
double* in; // audio input buffer
|
||||||
|
double* out; // audio output buffer; can be same as 'in'
|
||||||
|
double rate; // sample rate
|
||||||
|
double dettau; // detection averaging time constant
|
||||||
|
double avm; // averaging multiplier
|
||||||
|
double onem_avm; // one minus averaging multiplier
|
||||||
|
double avsig; // averaged detection signal
|
||||||
|
int state; // state machine control
|
||||||
|
int count; // count variable used within a state
|
||||||
|
double tattack; // attack time
|
||||||
|
double tdecay; // decay time
|
||||||
|
int nattack; // one less than total number of attack multipliers
|
||||||
|
int ndecay; // one less than total number of decay multipliers
|
||||||
|
double* cattack; // attack curve multipliers
|
||||||
|
double* cdecay; // decay curve multipliers
|
||||||
|
double attack_thresh; // attack threshold
|
||||||
|
double hold_thresh; // hold & decay threshold
|
||||||
|
double thold; // hold time
|
||||||
|
int nhold; // hold count
|
||||||
|
double exp_ratio; // expander ratio (high-gain to low-gain)
|
||||||
|
double hysteresis_ratio; // ratio hold_thresh/attack_thresh. 0.0 < ratio < 1.0
|
||||||
|
double low_gain; // gain when gate is closed
|
||||||
|
double* trigsig; // buffer for trigger signal (signal after side-channel filter)
|
||||||
|
double* delsig; // buffer for signal delayed to match trigger signal
|
||||||
|
double peak; // peak signal value to return to console
|
||||||
|
// side-channel bandpass filter & and buffer for compensating delay
|
||||||
|
int run_filt; // 1 = side-channel filter and compensating delay are ON, 0 = OFF
|
||||||
|
int nc; // number of coefficients
|
||||||
|
int wintype; // window type
|
||||||
|
double low_cut; // low cutoff frequency
|
||||||
|
double high_cut; // high cutoff frequency
|
||||||
|
FIRCORE p; // filter structure
|
||||||
|
DELRING scdring; // delay ring for side channel
|
||||||
|
// output audio delay to cover RF_Delay + Xmtr_delay_and_upslew
|
||||||
|
double* audbuffer; // buffer to serve as input to audring
|
||||||
|
int run_audelay; // 'run' variable for audio delay ring
|
||||||
|
double audelay; // audio output delay in seconds
|
||||||
|
DELRING audring; // audio delay ring
|
||||||
|
// vox
|
||||||
|
int run_vox;
|
||||||
|
void (__stdcall *pushvox)(int channel, int active);
|
||||||
|
int vox_count;
|
||||||
|
// update critical section
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
// anti-vox
|
||||||
|
int antivox_run; // 'run' for anti-vox
|
||||||
|
int antivox_new; // internal variable indicating new anti-vox data is available
|
||||||
|
int antivox_size; // size of anti-vox data buffer
|
||||||
|
double antivox_rate; // sample-rate of anti-vox data
|
||||||
|
double antivox_tau; // time-constant of anti-vox smoothing
|
||||||
|
double antivox_gain; // anti-vox gain factor
|
||||||
|
double antivox_mult; // multiplier for anti-vox smoothing
|
||||||
|
double antivox_onemmult; // one minus antivox_mult
|
||||||
|
double antivox_level; // current anti-vox smoothed signal level
|
||||||
|
double* antivox_data; // buffer to hold new anti-vox data
|
||||||
|
} dexp, *DEXP;
|
||||||
|
|
||||||
|
extern DEXP pdexp[];
|
||||||
|
|
||||||
|
__declspec (dllexport) void create_dexp (int id, int run_dexp, int size, double* in, double* out, int rate, double dettau, double tattack, double tdecay,
|
||||||
|
double thold, double exp_ratio, double hyst_ratio, double attack_thresh, int nc, int wtype, double lowcut, double highcut,
|
||||||
|
int run_filt, int run_vox, int run_audelay, double audelay, void (__stdcall *pushvox)(int id, int active),
|
||||||
|
int antivox_run, int antivox_size, int antivox_rate, double antivox_gain, double antivox_tau);
|
||||||
|
|
||||||
|
__declspec (dllexport) void destroy_dexp (int id);
|
||||||
|
|
||||||
|
__declspec (dllexport) void flush_dexp (int id);
|
||||||
|
|
||||||
|
__declspec (dllexport) void xdexp (int id);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetDEXPSize (int id, int size);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetDEXPRate (int id, double rate);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SendAntiVOXData (int id, int nsamples, double* data);
|
||||||
|
|
||||||
|
#endif
|
||||||
+219
@@ -0,0 +1,219 @@
|
|||||||
|
/* div.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
#define MAX_NR (8) // maximum number of receivers to mix
|
||||||
|
|
||||||
|
MDIV create_div (int run, int nr, int size, double **in, double *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
MDIV a = (MDIV) malloc0 (sizeof (mdiv));
|
||||||
|
a->run = run;
|
||||||
|
a->nr = nr;
|
||||||
|
a->size = size;
|
||||||
|
a->out = out;
|
||||||
|
a->in = (double **) malloc0 ( MAX_NR * sizeof (double *));
|
||||||
|
if (in != 0)
|
||||||
|
for (i = 0; i < nr; i++) a->in[i] = in[i];
|
||||||
|
a->Irotate = (double *) malloc0 (MAX_NR * sizeof (double));
|
||||||
|
a->Qrotate = (double *) malloc0 (MAX_NR * sizeof (double));
|
||||||
|
InitializeCriticalSectionAndSpinCount (&a->cs_update, 2500);
|
||||||
|
for (i = 0; i < 4; i++) ///////////// legacy interface - remove
|
||||||
|
a->legacy[i] = (double *) malloc0 (2048 * sizeof (complex)); ///////////// legacy interface - remove
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_div (MDIV a)
|
||||||
|
{
|
||||||
|
int i; ///////////// legacy interface - remove
|
||||||
|
DeleteCriticalSection (&a->cs_update);
|
||||||
|
for (i = 0; i < 4; i++) ///////////// legacy interface - remove
|
||||||
|
_aligned_free (a->legacy[i]); ///////////// legacy interface - remove
|
||||||
|
_aligned_free (a->Qrotate);
|
||||||
|
_aligned_free (a->Irotate);
|
||||||
|
_aligned_free (a->in);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_div (MDIV a)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void xdiv (MDIV a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
if (a->output != a->nr)
|
||||||
|
{
|
||||||
|
if (a->out != a->in[a->output])
|
||||||
|
memcpy (a->out, a->in[a->output], a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
double I, Q;
|
||||||
|
memset (a->out, 0, a->size * sizeof (complex));
|
||||||
|
for (i = 0; i < a->nr; i++)
|
||||||
|
for (j = 0; j < a->size; j++)
|
||||||
|
{
|
||||||
|
I = a->in[i][2 * j + 0];
|
||||||
|
Q = a->in[i][2 * j + 1];
|
||||||
|
a->out[2 * j + 0] += a->Irotate[i] * I - a->Qrotate[i] * Q;
|
||||||
|
a->out[2 * j + 1] += a->Irotate[i] * Q + a->Qrotate[i] * I;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (a->out, a->in[0], a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* CALLS FOR EXTERNAL USE *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#define MAX_EXT_DIVS (2) // maximum number of DIVs called from outside wdsp
|
||||||
|
__declspec (align (16)) MDIV pdiv[MAX_EXT_DIVS]; // array of pointers for DIVs used EXTERNAL to wdsp
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void create_divEXT (int id, int run, int nr, int size)
|
||||||
|
{
|
||||||
|
pdiv[id] = create_div (run, nr, size, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void destroy_divEXT (int id)
|
||||||
|
{
|
||||||
|
destroy_div (pdiv[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void flush_divEXT (int id)
|
||||||
|
{
|
||||||
|
flush_div (pdiv[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void xdivEXT (int id, int nsamples, double **in, double *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
a->size = nsamples;
|
||||||
|
a->out = out;
|
||||||
|
for (i = 0; i < a->nr; i++) a->in[i] = in[i];
|
||||||
|
xdiv (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 - does nothing; 1 - operates
|
||||||
|
PORT
|
||||||
|
void SetEXTDIVRun (int id, int run)
|
||||||
|
{
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// size of data buffer in complex samples
|
||||||
|
PORT
|
||||||
|
void SetEXTDIVBuffsize (int id, int size)
|
||||||
|
{
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->size = size;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of receivers being used for diversity
|
||||||
|
PORT
|
||||||
|
void SetEXTDIVNr (int id, int nr)
|
||||||
|
{
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->nr = nr;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of which receiver to output
|
||||||
|
// if output==nr, mixing occurs
|
||||||
|
PORT
|
||||||
|
void SetEXTDIVOutput (int id, int output)
|
||||||
|
{
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->output = output;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// I and Q "rotate" multipliers for each receiver
|
||||||
|
// can be set to 1.0 and 0.0 for "reference receiver"
|
||||||
|
PORT
|
||||||
|
void SetEXTDIVRotate (int id, int nr, double *Irotate, double *Qrotate)
|
||||||
|
{
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
memcpy (a->Irotate, Irotate, nr * sizeof (double));
|
||||||
|
memcpy (a->Qrotate, Qrotate, nr * sizeof (double));
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* LEGACY INTERFACE - REMOVE *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
PORT
|
||||||
|
void xdivEXTF (int id, int size, float **input, float *Iout, float *Qout)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
MDIV a = pdiv[id];
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
for (i = 0; i < a->nr; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < a->size; j++)
|
||||||
|
{
|
||||||
|
a->legacy[i][2 * j + 0] = (double)input[2 * i + 0][j];
|
||||||
|
a->legacy[i][2 * j + 1] = (double)input[2 * i + 1][j];
|
||||||
|
}
|
||||||
|
a->in[i] = a->legacy[i];
|
||||||
|
}
|
||||||
|
a->out = a->legacy[3];
|
||||||
|
xdiv (a);
|
||||||
|
for (j = 0; j < a->size; j++)
|
||||||
|
{
|
||||||
|
Iout[j] = (float)a->legacy[3][2 * j + 0];
|
||||||
|
Qout[j] = (float)a->legacy[3][2 * j + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/* div.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _div_h
|
||||||
|
#define _div_h
|
||||||
|
|
||||||
|
typedef struct _div
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int nr; // number of receivers to mix
|
||||||
|
int size; // size of input/output buffers
|
||||||
|
double **in; // input buffers
|
||||||
|
double *out; // output buffer
|
||||||
|
int output; // which rcvr to output; ==nr for mix
|
||||||
|
double *Irotate;
|
||||||
|
double *Qrotate;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
double *legacy[4]; ///////////// legacy interface - remove
|
||||||
|
} mdiv, *MDIV;
|
||||||
|
|
||||||
|
extern MDIV create_div (int run, int nr, int size, double **in, double *out);
|
||||||
|
|
||||||
|
extern void destroy_div (MDIV pdiv);
|
||||||
|
|
||||||
|
extern void xdiv (MDIV pdiv);
|
||||||
|
|
||||||
|
extern __declspec(dllexport) void xdivEXT (int id, int nsamples, double **in, double *out);
|
||||||
|
|
||||||
|
extern __declspec(dllexport) void create_divEXT (int id, int run, int nr, int size);
|
||||||
|
|
||||||
|
extern __declspec(dllexport) void destroy_divEXT (int id);
|
||||||
|
|
||||||
|
#endif
|
||||||
+393
@@ -0,0 +1,393 @@
|
|||||||
|
/* eer.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
PORT
|
||||||
|
EER create_eer (int run, int size, double* in, double* out, double* outM, int rate, double mgain, double pgain, int rundelays, double mdelay, double pdelay, int amiq)
|
||||||
|
{
|
||||||
|
EER a = (EER) malloc0 (sizeof (eer));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->outM = outM;
|
||||||
|
a->rate = rate;
|
||||||
|
a->mgain = mgain;
|
||||||
|
a->pgain = pgain;
|
||||||
|
a->rundelays = rundelays;
|
||||||
|
a->mdelay = mdelay;
|
||||||
|
a->pdelay = pdelay;
|
||||||
|
a->amiq = amiq;
|
||||||
|
a->mdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->outM, // input buffer
|
||||||
|
a->outM, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->mdelay); // delay
|
||||||
|
a->pdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->out, // input buffer
|
||||||
|
a->out, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->pdelay); // delay
|
||||||
|
InitializeCriticalSectionAndSpinCount(&a->cs_update, 2500);
|
||||||
|
|
||||||
|
a->legacy = (double *) malloc0 (2048 * sizeof (complex)); /////////////// legacy interface - remove
|
||||||
|
a->legacyM = (double *) malloc0 (2048 * sizeof (complex)); /////////////// legacy interface - remove
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void destroy_eer (EER a)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection (&a->cs_update);
|
||||||
|
destroy_delay (a->pdel);
|
||||||
|
destroy_delay (a->mdel);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void flush_eer (EER a)
|
||||||
|
{
|
||||||
|
flush_delay (a->mdel);
|
||||||
|
flush_delay (a->pdel);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void xeer (EER a)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double I, Q, mag;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
I = a->in[2 * i + 0];
|
||||||
|
Q = a->in[2 * i + 1];
|
||||||
|
a->outM[2 * i + 0] = I * a->mgain;
|
||||||
|
a->outM[2 * i + 1] = Q * a->mgain;
|
||||||
|
switch (a->amiq)
|
||||||
|
{
|
||||||
|
case 0: // send phase info only, magnitude is constant
|
||||||
|
mag = sqrt (I * I + Q * Q);
|
||||||
|
a->out [2 * i + 0] = a->pgain * I / mag;
|
||||||
|
a->out [2 * i + 1] = a->pgain * Q / mag;
|
||||||
|
break;
|
||||||
|
case 1: // send magnitude and phase information, I and Q
|
||||||
|
a->out [2 * i + 0] = a->pgain * I;
|
||||||
|
a->out [2 * i + 1] = a->pgain * Q;
|
||||||
|
break;
|
||||||
|
case 2: // send envelope
|
||||||
|
mag = sqrt (I * I + Q * Q);
|
||||||
|
a->out [2 * i + 0] = a->out[2 * i + 1] = a->pgain * mag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xdelay (a->mdel); // delay for outM
|
||||||
|
xdelay (a->pdel); // delay for out
|
||||||
|
}
|
||||||
|
else if (a->out != a->in)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* CALLS FOR EXTERNAL USE *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#define MAX_EXT_EERS (2) // maximum number of EERs called from outside wdsp
|
||||||
|
__declspec (align (16)) EER peer[MAX_EXT_EERS]; // array of pointers for EERs used EXTERNAL to wdsp
|
||||||
|
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void create_eerEXT (int id, int run, int size, int rate, double mgain, double pgain, int rundelays, double mdelay, double pdelay, int amiq)
|
||||||
|
{
|
||||||
|
peer[id] = create_eer (run, size, 0, 0, 0, rate, mgain, pgain, rundelays, mdelay, pdelay, amiq);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void destroy_eerEXT (int id)
|
||||||
|
{
|
||||||
|
destroy_eer (peer[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void flush_eerEXT (int id)
|
||||||
|
{
|
||||||
|
flush_eer (peer[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERRun (int id, int run)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERAMIQ (int id, int amiq)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->amiq = amiq;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERMgain (int id, double gain)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->mgain = gain;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERPgain (int id, double gain)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->pgain = gain;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERRunDelays (int id, int run)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->rundelays = run;
|
||||||
|
SetDelayRun (a->mdel, a->rundelays);
|
||||||
|
SetDelayRun (a->pdel, a->rundelays);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERMdelay (int id, double delay)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->mdelay = delay;
|
||||||
|
SetDelayValue (a->mdel, a->mdelay);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERPdelay (int id, double delay)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->pdelay = delay;
|
||||||
|
SetDelayValue (a->pdel, a->pdelay);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERSize (int id, int size)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->size = size;
|
||||||
|
SetDelayBuffs (a->mdel, a->size, a->outM, a->outM);
|
||||||
|
SetDelayBuffs (a->pdel, a->size, a->out, a->out);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetEERSamplerate (int id, int rate)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->rate = rate;
|
||||||
|
destroy_delay (a->mdel);
|
||||||
|
destroy_delay (a->pdel);
|
||||||
|
a->mdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->outM, // input buffer
|
||||||
|
a->outM, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->mdelay); // delay
|
||||||
|
a->pdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->out, // input buffer
|
||||||
|
a->out, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->pdelay); // delay
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* POINTER-BASED PROPERTIES *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERRun (EER a, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERAMIQ (EER a, int amiq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->amiq = amiq;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERMgain (EER a, double gain)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->mgain = gain;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERPgain (EER a, double gain)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->pgain = gain;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERRunDelays (EER a, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->rundelays = run;
|
||||||
|
SetDelayRun (a->mdel, a->rundelays);
|
||||||
|
SetDelayRun (a->pdel, a->rundelays);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERMdelay (EER a, double delay)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->mdelay = delay;
|
||||||
|
SetDelayValue (a->mdel, a->mdelay);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERPdelay (EER a, double delay)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->pdelay = delay;
|
||||||
|
SetDelayValue (a->pdel, a->pdelay);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERSize (EER a, int size)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->size = size;
|
||||||
|
SetDelayBuffs (a->mdel, a->size, a->outM, a->outM);
|
||||||
|
SetDelayBuffs (a->pdel, a->size, a->out, a->out);
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetEERSamplerate (EER a, int rate)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->rate = rate;
|
||||||
|
destroy_delay (a->mdel);
|
||||||
|
destroy_delay (a->pdel);
|
||||||
|
a->mdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->outM, // input buffer
|
||||||
|
a->outM, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->mdelay); // delay
|
||||||
|
a->pdel = create_delay (
|
||||||
|
a->rundelays, // run
|
||||||
|
a->size, // size
|
||||||
|
a->out, // input buffer
|
||||||
|
a->out, // output buffer
|
||||||
|
a->rate, // sample rate
|
||||||
|
20.0e-09, // delta (delay stepsize)
|
||||||
|
a->pdelay); // delay
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Legacy Interface *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void xeerEXTF (int id, float* inI, float* inQ, float* outI, float* outQ, float* outMI, float* outMQ, int mox, int size)
|
||||||
|
{
|
||||||
|
EER a = peer[id];
|
||||||
|
if (mox && a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
a->in = a->legacy;
|
||||||
|
a->out = a->legacy;
|
||||||
|
a->outM = a->legacyM;
|
||||||
|
a->size = size;
|
||||||
|
SetDelayBuffs (a->mdel, a->size, a->outM, a->outM);
|
||||||
|
SetDelayBuffs (a->pdel, a->size, a->out, a->out);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->legacy[2 * i + 0] = (double)inI[i];
|
||||||
|
a->legacy[2 * i + 1] = (double)inQ[i];
|
||||||
|
}
|
||||||
|
xeer (a);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
outI[i] = (float)a->legacy [2 * i + 0];
|
||||||
|
outQ[i] = (float)a->legacy [2 * i + 1];
|
||||||
|
outMI[i] = (float)a->legacyM[2 * i + 0];
|
||||||
|
outMQ[i] = (float)a->legacyM[2 * i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/* eer.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _eer_h
|
||||||
|
#define _eer_h
|
||||||
|
|
||||||
|
typedef struct _eer
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int amiq;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double* outM;
|
||||||
|
int rate;
|
||||||
|
double mgain;
|
||||||
|
double pgain;
|
||||||
|
int rundelays;
|
||||||
|
double mdelay;
|
||||||
|
double pdelay;
|
||||||
|
DELAY mdel;
|
||||||
|
DELAY pdel;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
double *legacy; //////////// legacy interface - remove
|
||||||
|
double *legacyM; //////////// legacy interface - remove
|
||||||
|
} eer, *EER;
|
||||||
|
|
||||||
|
__declspec (dllexport) EER create_eer (int run, int size, double* in, double* out, double* outM, int rate, double mgain, double pgain, int rundelays, double mdelay, double pdelay, int amiq);
|
||||||
|
|
||||||
|
__declspec (dllexport) void destroy_eer (EER a);
|
||||||
|
|
||||||
|
__declspec (dllexport) void flush_eer (EER a);
|
||||||
|
|
||||||
|
__declspec (dllexport) void xeer (EER a);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERRun (EER a, int run);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERAMIQ (EER a, int amiq);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERMgain (EER a, double gain);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERPgain (EER a, double gain);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERRunDelays (EER a, int run);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERMdelay (EER a, double delay);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERPdelay (EER a, double delay);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERSize (EER a, int size);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetEERSamplerate (EER a, int rate);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1174
File diff suppressed because it is too large
Load Diff
+207
@@ -0,0 +1,207 @@
|
|||||||
|
/* emnr.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2015 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _emnr_h
|
||||||
|
#define _emnr_h
|
||||||
|
|
||||||
|
typedef struct _emnr
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int bsize;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int fsize;
|
||||||
|
int ovrlp;
|
||||||
|
int incr;
|
||||||
|
double* window;
|
||||||
|
int iasize;
|
||||||
|
double* inaccum;
|
||||||
|
double* forfftin;
|
||||||
|
double* forfftout;
|
||||||
|
int msize;
|
||||||
|
double* mask;
|
||||||
|
double* revfftin;
|
||||||
|
double* revfftout;
|
||||||
|
double** save;
|
||||||
|
int oasize;
|
||||||
|
double* outaccum;
|
||||||
|
double rate;
|
||||||
|
int wintype;
|
||||||
|
double ogain;
|
||||||
|
double gain;
|
||||||
|
int nsamps;
|
||||||
|
int iainidx;
|
||||||
|
int iaoutidx;
|
||||||
|
int init_oainidx;
|
||||||
|
int oainidx;
|
||||||
|
int oaoutidx;
|
||||||
|
int saveidx;
|
||||||
|
fftw_plan Rfor;
|
||||||
|
fftw_plan Rrev;
|
||||||
|
struct _g
|
||||||
|
{
|
||||||
|
int gain_method;
|
||||||
|
int npe_method;
|
||||||
|
int ae_run;
|
||||||
|
double msize;
|
||||||
|
double* mask;
|
||||||
|
double* y;
|
||||||
|
double* lambda_y;
|
||||||
|
double* lambda_d;
|
||||||
|
double* prev_mask;
|
||||||
|
double* prev_gamma;
|
||||||
|
double gf1p5;
|
||||||
|
double alpha;
|
||||||
|
double eps_floor;
|
||||||
|
double gamma_max;
|
||||||
|
double xi_min;
|
||||||
|
double q;
|
||||||
|
double gmax;
|
||||||
|
//
|
||||||
|
double* GG;
|
||||||
|
double* GGS;
|
||||||
|
FILE* fileb;
|
||||||
|
//
|
||||||
|
int dim_zeta;
|
||||||
|
double* zeta_hat;
|
||||||
|
int* zeta_true;
|
||||||
|
double z_gamma_min;
|
||||||
|
double z_gamma_max;
|
||||||
|
double z_xihat_min;
|
||||||
|
double z_xihat_max;
|
||||||
|
double zeta_thresh;
|
||||||
|
} g;
|
||||||
|
struct _npest
|
||||||
|
{
|
||||||
|
int incr;
|
||||||
|
double rate;
|
||||||
|
int msize;
|
||||||
|
double* lambda_y;
|
||||||
|
double* lambda_d;
|
||||||
|
double* p;
|
||||||
|
double* alphaOptHat;
|
||||||
|
double alphaC;
|
||||||
|
double alphaCsmooth;
|
||||||
|
double alphaCmin;
|
||||||
|
double* alphaHat;
|
||||||
|
double alphaMax;
|
||||||
|
double* sigma2N;
|
||||||
|
double alphaMin_max_value;
|
||||||
|
double snrq;
|
||||||
|
double betamax;
|
||||||
|
double* pbar;
|
||||||
|
double* p2bar;
|
||||||
|
double invQeqMax;
|
||||||
|
double av;
|
||||||
|
double* Qeq;
|
||||||
|
int U;
|
||||||
|
double Dtime;
|
||||||
|
int V;
|
||||||
|
int D;
|
||||||
|
double MofD;
|
||||||
|
double MofV;
|
||||||
|
double* bmin;
|
||||||
|
double* bmin_sub;
|
||||||
|
int* k_mod;
|
||||||
|
double* actmin;
|
||||||
|
double* actmin_sub;
|
||||||
|
int subwc;
|
||||||
|
int* lmin_flag;
|
||||||
|
double* pmin_u;
|
||||||
|
double invQbar_points[4];
|
||||||
|
double nsmax[4];
|
||||||
|
double** actminbuff;
|
||||||
|
int amb_idx;
|
||||||
|
} np;
|
||||||
|
struct _npests
|
||||||
|
{
|
||||||
|
int incr;
|
||||||
|
double rate;
|
||||||
|
int msize;
|
||||||
|
double* lambda_y;
|
||||||
|
double* lambda_d;
|
||||||
|
|
||||||
|
double alpha_pow;
|
||||||
|
double alpha_Pbar;
|
||||||
|
double epsH1;
|
||||||
|
double epsH1r;
|
||||||
|
|
||||||
|
double* sigma2N;
|
||||||
|
double* PH1y;
|
||||||
|
double* Pbar;
|
||||||
|
double* EN2y;
|
||||||
|
} nps;
|
||||||
|
struct _npestl
|
||||||
|
{
|
||||||
|
double rate;
|
||||||
|
int msize;
|
||||||
|
int incr;
|
||||||
|
double* Ysq;
|
||||||
|
double* P;
|
||||||
|
double* Pmin;
|
||||||
|
double* p;
|
||||||
|
double* D;
|
||||||
|
double* lambda_d;
|
||||||
|
|
||||||
|
double eta;
|
||||||
|
double gamma;
|
||||||
|
double beta;
|
||||||
|
double delta_LF;
|
||||||
|
double delta_MF;
|
||||||
|
double delta_0;
|
||||||
|
double delta_1;
|
||||||
|
double delta_2;
|
||||||
|
double alpha_d;
|
||||||
|
double alpha_p;
|
||||||
|
} npl;
|
||||||
|
struct _ae
|
||||||
|
{
|
||||||
|
int msize;
|
||||||
|
double* lambda_y;
|
||||||
|
double zetaThresh;
|
||||||
|
double psi;
|
||||||
|
double* nmask;
|
||||||
|
double t2;
|
||||||
|
} ae;
|
||||||
|
}emnr, *EMNR;
|
||||||
|
|
||||||
|
extern EMNR create_emnr (int run, int position, int size, double* in, double* out, int fsize, int ovrlp,
|
||||||
|
int rate, int wintype, double gain, int gain_method, int npe_method, int ae_run);
|
||||||
|
|
||||||
|
extern void destroy_emnr (EMNR a);
|
||||||
|
|
||||||
|
extern void flush_emnr (EMNR a);
|
||||||
|
|
||||||
|
extern void xemnr (EMNR a, int pos);
|
||||||
|
|
||||||
|
extern void setBuffers_emnr (EMNR a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_emnr (EMNR a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_emnr (EMNR a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+270
@@ -0,0 +1,270 @@
|
|||||||
|
/* emph.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save FM Pre-Emphasis *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
EMPHP create_emphp (int run, int position, int size, int nc, int mp, double* in, double* out, int rate, int ctype, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
EMPHP a = (EMPHP) malloc0 (sizeof (emphp));
|
||||||
|
double* impulse;
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = rate;
|
||||||
|
a->ctype = ctype;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
impulse = fc_impulse (a->nc, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
a->p = create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_emphp (EMPHP a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_emphp (EMPHP a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xemphp (EMPHP a, int position)
|
||||||
|
{
|
||||||
|
if (a->run && a->position == position)
|
||||||
|
xfircore (a->p);
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_emphp (EMPHP a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
setBuffers_fircore (a->p, a->in, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_emphp (EMPHP a, int rate)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->rate = rate;
|
||||||
|
impulse = fc_impulse (a->nc, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_emphp (EMPHP a, int size)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->size = size;
|
||||||
|
setSize_fircore (a->p, a->size);
|
||||||
|
impulse = fc_impulse (a->nc, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save FM Pre-Emphasis: TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMEmphPosition (int channel, int position)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].preemph.p->position = position;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMEmphMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
EMPHP a;
|
||||||
|
a = txa[channel].preemph.p;
|
||||||
|
if (a->mp != mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMEmphNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
EMPHP a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].preemph.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fc_impulse (a->nc, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMPreEmphFreqs (int channel, double low, double high)
|
||||||
|
{
|
||||||
|
EMPHP a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].preemph.p;
|
||||||
|
if (a->f_low != low || a->f_high != high)
|
||||||
|
{
|
||||||
|
a->f_low = low;
|
||||||
|
a->f_high = high;
|
||||||
|
impulse = fc_impulse (a->nc, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save FM Pre-Emphasis *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void calc_emph (EMPH a)
|
||||||
|
{
|
||||||
|
a->infilt = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->product = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->mults = fc_mults(a->size, a->f_low, a->f_high, -20.0 * log10(a->f_high / a->f_low), 0.0, a->ctype, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
a->CFor = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->infilt, (fftw_complex *)a->product, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->CRev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->product, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_emph (EMPH a)
|
||||||
|
{
|
||||||
|
fftw_destroy_plan(a->CRev);
|
||||||
|
fftw_destroy_plan(a->CFor);
|
||||||
|
_aligned_free(a->mults);
|
||||||
|
_aligned_free(a->product);
|
||||||
|
_aligned_free(a->infilt);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMPH create_emph (int run, int position, int size, double* in, double* out, int rate, int ctype, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
EMPH a = (EMPH) malloc0 (sizeof (emph));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->ctype = ctype;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
calc_emph (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_emph (EMPH a)
|
||||||
|
{
|
||||||
|
decalc_emph (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_emph (EMPH a)
|
||||||
|
{
|
||||||
|
memset (a->infilt, 0, 2 * a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xemph (EMPH a, int position)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double I, Q;
|
||||||
|
if (a->run && a->position == position)
|
||||||
|
{
|
||||||
|
memcpy (&(a->infilt[2 * a->size]), a->in, a->size * sizeof (complex));
|
||||||
|
fftw_execute (a->CFor);
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
{
|
||||||
|
I = a->product[2 * i + 0];
|
||||||
|
Q = a->product[2 * i + 1];
|
||||||
|
a->product[2 * i + 0] = I * a->mults[2 * i + 0] - Q * a->mults[2 * i + 1];
|
||||||
|
a->product[2 * i + 1] = I * a->mults[2 * i + 1] + Q * a->mults[2 * i + 0];
|
||||||
|
}
|
||||||
|
fftw_execute (a->CRev);
|
||||||
|
memcpy (a->infilt, &(a->infilt[2 * a->size]), a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_emph (EMPH a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_emph (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_emph (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_emph (EMPH a, int rate)
|
||||||
|
{
|
||||||
|
decalc_emph (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_emph (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_emph (EMPH a, int size)
|
||||||
|
{
|
||||||
|
decalc_emph(a);
|
||||||
|
a->size = size;
|
||||||
|
calc_emph(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save FM Pre-Emphasis: TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
/* // Uncomment when needed
|
||||||
|
PORT
|
||||||
|
void SetTXAFMEmphPosition (int channel, int position)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].preemph.p->position = position;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
*/
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
/* emph.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save FM Pre-Emphasis *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _emphp_h
|
||||||
|
#define _emphp_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _emphp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int size;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int ctype;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double rate;
|
||||||
|
FIRCORE p;
|
||||||
|
} emphp, *EMPHP;
|
||||||
|
|
||||||
|
extern EMPHP create_emphp (int run, int position, int size, int nc, int mp,
|
||||||
|
double* in, double* out, int rate, int ctype, double f_low, double f_high);
|
||||||
|
|
||||||
|
extern void destroy_emphp (EMPHP a);
|
||||||
|
|
||||||
|
extern void flush_emphp (EMPHP a);
|
||||||
|
|
||||||
|
extern void xemphp (EMPHP a, int position);
|
||||||
|
|
||||||
|
extern void setBuffers_emphp (EMPHP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_emphp (EMPHP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_emphp (EMPHP a, int size);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetTXAFMEmphMP (int channel, int mp);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetTXAFMEmphNC (int channel, int nc);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetTXAFMPreEmphFreqs(int channel, double low, double high);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save FM Pre-Emphasis *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _emph_h
|
||||||
|
#define _emph_h
|
||||||
|
|
||||||
|
typedef struct _emph
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int position;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int ctype;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double* infilt;
|
||||||
|
double* product;
|
||||||
|
double* mults;
|
||||||
|
double rate;
|
||||||
|
fftw_plan CFor;
|
||||||
|
fftw_plan CRev;
|
||||||
|
} emph, *EMPH;
|
||||||
|
|
||||||
|
extern EMPH create_emph (int run, int position, int size, double* in, double* out, int rate, int ctype, double f_low, double f_high);
|
||||||
|
|
||||||
|
extern void destroy_emph (EMPH a);
|
||||||
|
|
||||||
|
extern void flush_emph (EMPH a);
|
||||||
|
|
||||||
|
extern void xemph (EMPH a, int position);
|
||||||
|
|
||||||
|
extern void setBuffers_emph (EMPH a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_emph (EMPH a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_emph (EMPH a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,853 @@
|
|||||||
|
/* eq.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
int fEQcompare (const void * a, const void * b)
|
||||||
|
{
|
||||||
|
if (*(double*)a < *(double*)b)
|
||||||
|
return -1;
|
||||||
|
else if (*(double*)a == *(double*)b)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* eq_impulse (int N, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype)
|
||||||
|
{
|
||||||
|
double* fp = (double *) malloc0 ((nfreqs + 2) * sizeof (double));
|
||||||
|
double* gp = (double *) malloc0 ((nfreqs + 2) * sizeof (double));
|
||||||
|
double* A = (double *) malloc0 ((N / 2 + 1) * sizeof (double));
|
||||||
|
double* sary = (double *) malloc0 (2 * nfreqs * sizeof (double));
|
||||||
|
double gpreamp, f, frac;
|
||||||
|
double* impulse;
|
||||||
|
int i, j, mid;
|
||||||
|
fp[0] = 0.0;
|
||||||
|
fp[nfreqs + 1] = 1.0;
|
||||||
|
gpreamp = G[0];
|
||||||
|
for (i = 1; i <= nfreqs; i++)
|
||||||
|
{
|
||||||
|
fp[i] = 2.0 * F[i] / samplerate;
|
||||||
|
if (fp[i] < 0.0) fp[i] = 0.0;
|
||||||
|
if (fp[i] > 1.0) fp[i] = 1.0;
|
||||||
|
gp[i] = G[i];
|
||||||
|
}
|
||||||
|
for (i = 1, j = 0; i <= nfreqs; i++, j+=2)
|
||||||
|
{
|
||||||
|
sary[j + 0] = fp[i];
|
||||||
|
sary[j + 1] = gp[i];
|
||||||
|
}
|
||||||
|
qsort (sary, nfreqs, 2 * sizeof (double), fEQcompare);
|
||||||
|
for (i = 1, j = 0; i <= nfreqs; i++, j+=2)
|
||||||
|
{
|
||||||
|
fp[i] = sary[j + 0];
|
||||||
|
gp[i] = sary[j + 1];
|
||||||
|
}
|
||||||
|
gp[0] = gp[1];
|
||||||
|
gp[nfreqs + 1] = gp[nfreqs];
|
||||||
|
mid = N / 2;
|
||||||
|
j = 0;
|
||||||
|
if (N & 1)
|
||||||
|
{
|
||||||
|
for (i = 0; i <= mid; i++)
|
||||||
|
{
|
||||||
|
f = (double)i / (double)mid;
|
||||||
|
while (f > fp[j + 1]) j++;
|
||||||
|
frac = (f - fp[j]) / (fp[j + 1] - fp[j]);
|
||||||
|
A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < mid; i++)
|
||||||
|
{
|
||||||
|
f = ((double)i + 0.5) / (double)mid;
|
||||||
|
while (f > fp[j + 1]) j++;
|
||||||
|
frac = (f - fp[j]) / (fp[j + 1] - fp[j]);
|
||||||
|
A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ctfmode == 0)
|
||||||
|
{
|
||||||
|
int k, low, high;
|
||||||
|
double lowmag, highmag, flow4, fhigh4;
|
||||||
|
if (N & 1)
|
||||||
|
{
|
||||||
|
low = (int)(fp[1] * mid);
|
||||||
|
high = (int)(fp[nfreqs] * mid + 0.5);
|
||||||
|
lowmag = A[low];
|
||||||
|
highmag = A[high];
|
||||||
|
flow4 = pow((double)low / (double)mid, 4.0);
|
||||||
|
fhigh4 = pow((double)high / (double)mid, 4.0);
|
||||||
|
k = low;
|
||||||
|
while (--k >= 0)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
lowmag *= (f * f * f * f) / flow4;
|
||||||
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
||||||
|
A[k] = lowmag;
|
||||||
|
}
|
||||||
|
k = high;
|
||||||
|
while (++k <= mid)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
highmag *= fhigh4 / (f * f * f * f);
|
||||||
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
||||||
|
A[k] = highmag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
low = (int)(fp[1] * mid - 0.5);
|
||||||
|
high = (int)(fp[nfreqs] * mid - 0.5);
|
||||||
|
lowmag = A[low];
|
||||||
|
highmag = A[high];
|
||||||
|
flow4 = pow((double)low / (double)mid, 4.0);
|
||||||
|
fhigh4 = pow((double)high / (double)mid, 4.0);
|
||||||
|
k = low;
|
||||||
|
while (--k >= 0)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
lowmag *= (f * f * f * f) / flow4;
|
||||||
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
||||||
|
A[k] = lowmag;
|
||||||
|
}
|
||||||
|
k = high;
|
||||||
|
while (++k < mid)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
highmag *= fhigh4 / (f * f * f * f);
|
||||||
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
||||||
|
A[k] = highmag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (N & 1)
|
||||||
|
impulse = fir_fsamp_odd(N, A, 1, 1.0, wintype);
|
||||||
|
else
|
||||||
|
impulse = fir_fsamp(N, A, 1, 1.0, wintype);
|
||||||
|
// print_impulse("eq.txt", N, impulse, 1, 0);
|
||||||
|
_aligned_free (sary);
|
||||||
|
_aligned_free (A);
|
||||||
|
_aligned_free (gp);
|
||||||
|
_aligned_free (fp);
|
||||||
|
return impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Equalizer *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
EQP create_eqp (int run, int size, int nc, int mp, double *in, double *out, int nfreqs, double* F, double* G, int ctfmode, int wintype, int samplerate)
|
||||||
|
{
|
||||||
|
// NOTE: 'nc' must be >= 'size'
|
||||||
|
EQP a = (EQP) malloc0 (sizeof (eqp));
|
||||||
|
double* impulse;
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
a->ctfmode = ctfmode;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->samplerate = (double)samplerate;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
a->p = create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_eqp (EQP a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_eqp (EQP a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xeqp (EQP a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
xfircore (a->p);
|
||||||
|
else
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_eqp (EQP a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
setBuffers_fircore (a->p, a->in, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_eqp (EQP a, int rate)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->samplerate = rate;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_eqp (EQP a, int size)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->size = size;
|
||||||
|
setSize_fircore (a->p, a->size);
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Equalizer: RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].eqp.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
if (a->mp != mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQProfile (int channel, int nfreqs, double* F, double* G)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G,
|
||||||
|
a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQCtfmode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
a->ctfmode = mode;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQWintype (int channel, int wintype)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
a->wintype = wintype;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAGrphEQ (int channel, int *rxeq)
|
||||||
|
{ // three band equalizer (legacy compatibility)
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 4;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 150.0;
|
||||||
|
a->F[2] = 400.0;
|
||||||
|
a->F[3] = 1500.0;
|
||||||
|
a->F[4] = 6000.0;
|
||||||
|
a->G[0] = (double)rxeq[0];
|
||||||
|
a->G[1] = (double)rxeq[1];
|
||||||
|
a->G[2] = (double)rxeq[1];
|
||||||
|
a->G[3] = (double)rxeq[2];
|
||||||
|
a->G[4] = (double)rxeq[3];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAGrphEQ10 (int channel, int *rxeq)
|
||||||
|
{ // ten band equalizer (legacy compatibility)
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
int i;
|
||||||
|
a = rxa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 10;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 32.0;
|
||||||
|
a->F[2] = 63.0;
|
||||||
|
a->F[3] = 125.0;
|
||||||
|
a->F[4] = 250.0;
|
||||||
|
a->F[5] = 500.0;
|
||||||
|
a->F[6] = 1000.0;
|
||||||
|
a->F[7] = 2000.0;
|
||||||
|
a->F[8] = 4000.0;
|
||||||
|
a->F[9] = 8000.0;
|
||||||
|
a->F[10] = 16000.0;
|
||||||
|
for (i = 0; i <= a->nfreqs; i++)
|
||||||
|
a->G[i] = (double)rxeq[i];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
// print_impulse ("rxeq.txt", a->nc, impulse, 1, 0);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Equalizer: TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].eqp.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
if (a->mp != mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQProfile (int channel, int nfreqs, double* F, double* G)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQCtfmode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
a->ctfmode = mode;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQWintype (int channel, int wintype)
|
||||||
|
{
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
a->wintype = wintype;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAGrphEQ (int channel, int *txeq)
|
||||||
|
{ // three band equalizer (legacy compatibility)
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 4;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 150.0;
|
||||||
|
a->F[2] = 400.0;
|
||||||
|
a->F[3] = 1500.0;
|
||||||
|
a->F[4] = 6000.0;
|
||||||
|
a->G[0] = (double)txeq[0];
|
||||||
|
a->G[1] = (double)txeq[1];
|
||||||
|
a->G[2] = (double)txeq[1];
|
||||||
|
a->G[3] = (double)txeq[2];
|
||||||
|
a->G[4] = (double)txeq[3];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAGrphEQ10 (int channel, int *txeq)
|
||||||
|
{ // ten band equalizer (legacy compatibility)
|
||||||
|
EQP a;
|
||||||
|
double* impulse;
|
||||||
|
int i;
|
||||||
|
a = txa[channel].eqp.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 10;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 32.0;
|
||||||
|
a->F[2] = 63.0;
|
||||||
|
a->F[3] = 125.0;
|
||||||
|
a->F[4] = 250.0;
|
||||||
|
a->F[5] = 500.0;
|
||||||
|
a->F[6] = 1000.0;
|
||||||
|
a->F[7] = 2000.0;
|
||||||
|
a->F[8] = 4000.0;
|
||||||
|
a->F[9] = 8000.0;
|
||||||
|
a->F[10] = 16000.0;
|
||||||
|
for (i = 0; i <= a->nfreqs; i++)
|
||||||
|
a->G[i] = (double)txeq[i];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype);
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Equalizer *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
double* eq_mults (int size, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse = eq_impulse (size + 1, nfreqs, F, G, samplerate, scale, ctfmode, wintype);
|
||||||
|
double* mults = fftcv_mults(2 * size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return mults;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_eq (EQ a)
|
||||||
|
{
|
||||||
|
a->scale = 1.0 / (double)(2 * a->size);
|
||||||
|
a->infilt = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->product = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->CFor = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->infilt, (fftw_complex *)a->product, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->CRev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->product, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
a->mults = eq_mults(a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_eq (EQ a)
|
||||||
|
{
|
||||||
|
fftw_destroy_plan(a->CRev);
|
||||||
|
fftw_destroy_plan(a->CFor);
|
||||||
|
_aligned_free(a->mults);
|
||||||
|
_aligned_free(a->product);
|
||||||
|
_aligned_free(a->infilt);
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ create_eq (int run, int size, double *in, double *out, int nfreqs, double* F, double* G, int ctfmode, int wintype, int samplerate)
|
||||||
|
{
|
||||||
|
EQ a = (EQ) malloc0 (sizeof (eq));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
a->ctfmode = ctfmode;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->samplerate = (double)samplerate;
|
||||||
|
calc_eq (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_eq (EQ a)
|
||||||
|
{
|
||||||
|
decalc_eq (a);
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_eq (EQ a)
|
||||||
|
{
|
||||||
|
memset (a->infilt, 0, 2 * a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void xeq (EQ a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double I, Q;
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
memcpy (&(a->infilt[2 * a->size]), a->in, a->size * sizeof (complex));
|
||||||
|
fftw_execute (a->CFor);
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
{
|
||||||
|
I = a->product[2 * i + 0];
|
||||||
|
Q = a->product[2 * i + 1];
|
||||||
|
a->product[2 * i + 0] = I * a->mults[2 * i + 0] - Q * a->mults[2 * i + 1];
|
||||||
|
a->product[2 * i + 1] = I * a->mults[2 * i + 1] + Q * a->mults[2 * i + 0];
|
||||||
|
}
|
||||||
|
fftw_execute (a->CRev);
|
||||||
|
memcpy (a->infilt, &(a->infilt[2 * a->size]), a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_eq (EQ a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_eq (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_eq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_eq (EQ a, int rate)
|
||||||
|
{
|
||||||
|
decalc_eq (a);
|
||||||
|
a->samplerate = rate;
|
||||||
|
calc_eq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_eq (EQ a, int size)
|
||||||
|
{
|
||||||
|
decalc_eq (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_eq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Equalizer: RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
/* // UNCOMMENT properties when a pointer is in place in rxa[channel]
|
||||||
|
PORT
|
||||||
|
void SetRXAEQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].eq.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQProfile (int channel, int nfreqs, double* F, double* G)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQCtfmode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eq.p;
|
||||||
|
a->ctfmode = mode;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAEQWintype (int channel, int wintype)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eq.p;
|
||||||
|
a->wintype = wintype;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAGrphEQ (int channel, int *rxeq)
|
||||||
|
{ // three band equalizer (legacy compatibility)
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 4;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 150.0;
|
||||||
|
a->F[2] = 400.0;
|
||||||
|
a->F[3] = 1500.0;
|
||||||
|
a->F[4] = 6000.0;
|
||||||
|
a->G[0] = (double)rxeq[0];
|
||||||
|
a->G[1] = (double)rxeq[1];
|
||||||
|
a->G[2] = (double)rxeq[1];
|
||||||
|
a->G[3] = (double)rxeq[2];
|
||||||
|
a->G[4] = (double)rxeq[3];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAGrphEQ10 (int channel, int *rxeq)
|
||||||
|
{ // ten band equalizer (legacy compatibility)
|
||||||
|
EQ a;
|
||||||
|
int i;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 10;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 32.0;
|
||||||
|
a->F[2] = 63.0;
|
||||||
|
a->F[3] = 125.0;
|
||||||
|
a->F[4] = 250.0;
|
||||||
|
a->F[5] = 500.0;
|
||||||
|
a->F[6] = 1000.0;
|
||||||
|
a->F[7] = 2000.0;
|
||||||
|
a->F[8] = 4000.0;
|
||||||
|
a->F[9] = 8000.0;
|
||||||
|
a->F[10] = 16000.0;
|
||||||
|
for (i = 0; i <= a->nfreqs; i++)
|
||||||
|
a->G[i] = (double)rxeq[i];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Equalizer: TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
/* // UNCOMMENT properties when a pointer is in place in rxa[channel]
|
||||||
|
PORT
|
||||||
|
void SetTXAEQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].eq.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQProfile (int channel, int nfreqs, double* F, double* G)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = nfreqs;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->F, F, (nfreqs + 1) * sizeof (double));
|
||||||
|
memcpy (a->G, G, (nfreqs + 1) * sizeof (double));
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQCtfmode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eq.p;
|
||||||
|
a->ctfmode = mode;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAEQMethod (int channel, int wintype)
|
||||||
|
{
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eq.p;
|
||||||
|
a->wintype = wintype;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAGrphEQ (int channel, int *txeq)
|
||||||
|
{ // three band equalizer (legacy compatibility)
|
||||||
|
EQ a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 4;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 150.0;
|
||||||
|
a->F[2] = 400.0;
|
||||||
|
a->F[3] = 1500.0;
|
||||||
|
a->F[4] = 6000.0;
|
||||||
|
a->G[0] = (double)txeq[0];
|
||||||
|
a->G[1] = (double)txeq[1];
|
||||||
|
a->G[2] = (double)txeq[1];
|
||||||
|
a->G[3] = (double)txeq[2];
|
||||||
|
a->G[4] = (double)txeq[3];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAGrphEQ10 (int channel, int *txeq)
|
||||||
|
{ // ten band equalizer (legacy compatibility)
|
||||||
|
EQ a;
|
||||||
|
int i;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].eq.p;
|
||||||
|
_aligned_free (a->G);
|
||||||
|
_aligned_free (a->F);
|
||||||
|
a->nfreqs = 10;
|
||||||
|
a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
|
||||||
|
a->F[1] = 32.0;
|
||||||
|
a->F[2] = 63.0;
|
||||||
|
a->F[3] = 125.0;
|
||||||
|
a->F[4] = 250.0;
|
||||||
|
a->F[5] = 500.0;
|
||||||
|
a->F[6] = 1000.0;
|
||||||
|
a->F[7] = 2000.0;
|
||||||
|
a->F[8] = 4000.0;
|
||||||
|
a->F[9] = 8000.0;
|
||||||
|
a->F[10] = 16000.0;
|
||||||
|
for (i = 0; i <= a->nfreqs; i++)
|
||||||
|
a->G[i] = (double)txeq[i];
|
||||||
|
a->ctfmode = 0;
|
||||||
|
_aligned_free (a->mults);
|
||||||
|
a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/* eq.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Equalizer *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _eqp_h
|
||||||
|
#define _eqp_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _eqp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int nfreqs;
|
||||||
|
double* F;
|
||||||
|
double* G;
|
||||||
|
int ctfmode;
|
||||||
|
int wintype;
|
||||||
|
double samplerate;
|
||||||
|
FIRCORE p;
|
||||||
|
} eqp, *EQP;
|
||||||
|
|
||||||
|
extern double* eq_impulse (int N, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype);
|
||||||
|
|
||||||
|
extern EQP create_eqp (int run, int size, int nc, int mp, double *in, double *out,
|
||||||
|
int nfreqs, double* F, double* G, int ctfmode, int wintype, int samplerate);
|
||||||
|
|
||||||
|
extern void destroy_eqp (EQP a);
|
||||||
|
|
||||||
|
extern void flush_eqp (EQP a);
|
||||||
|
|
||||||
|
extern void xeqp (EQP a);
|
||||||
|
|
||||||
|
extern void setBuffers_eqp (EQP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_eqp (EQP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_eqp (EQP a, int size);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetRXAEQNC (int channel, int nc);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetRXAEQMP (int channel, int mp);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetTXAEQNC (int channel, int nc);
|
||||||
|
|
||||||
|
__declspec (dllexport) void SetTXAEQMP (int channel, int mp);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Overlap-Save Equalizer *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _eq_h
|
||||||
|
#define _eq_h
|
||||||
|
|
||||||
|
typedef struct _eq
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int nfreqs;
|
||||||
|
double* F;
|
||||||
|
double* G;
|
||||||
|
double* infilt;
|
||||||
|
double* product;
|
||||||
|
double* mults;
|
||||||
|
double scale;
|
||||||
|
int ctfmode;
|
||||||
|
int wintype;
|
||||||
|
double samplerate;
|
||||||
|
fftw_plan CFor;
|
||||||
|
fftw_plan CRev;
|
||||||
|
}eq, *EQ;
|
||||||
|
|
||||||
|
extern double* eq_mults (int size, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype);
|
||||||
|
|
||||||
|
extern EQ create_eq (int run, int size, double *in, double *out, int nfreqs, double* F, double* G, int ctfmode, int wintype, int samplerate);
|
||||||
|
|
||||||
|
extern void destroy_eq (EQ a);
|
||||||
|
|
||||||
|
extern void flush_eq (EQ a);
|
||||||
|
|
||||||
|
extern void xeq (EQ a);
|
||||||
|
|
||||||
|
extern void setBuffers_eq (EQ a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_eq (EQ a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_eq (EQ a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+154
@@ -0,0 +1,154 @@
|
|||||||
|
/* fcurve.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
double* fc_impulse (int nc, double f0, double f1, double g0, double g1, int curve, double samplerate, double scale, int ctfmode, int wintype)
|
||||||
|
{
|
||||||
|
double* A = (double *) malloc0 ((nc / 2 + 1) * sizeof (double));
|
||||||
|
int i;
|
||||||
|
double fn, f;
|
||||||
|
double* impulse;
|
||||||
|
int mid = nc / 2;
|
||||||
|
double g0_lin = pow(10.0, g0 / 20.0);
|
||||||
|
if (nc & 1)
|
||||||
|
{
|
||||||
|
for (i = 0; i <= mid; i++)
|
||||||
|
{
|
||||||
|
fn = (double)i / (double)mid;
|
||||||
|
f = fn * samplerate / 2.0;
|
||||||
|
switch (curve)
|
||||||
|
{
|
||||||
|
case 0: // fm pre-emphasis
|
||||||
|
if (f0 > 0.0)
|
||||||
|
A[i] = scale * (g0_lin * f / f0);
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
break;
|
||||||
|
case 1: // fm de-emphasis
|
||||||
|
if (f > 0.0)
|
||||||
|
A[i] = scale * (g0_lin * f0 / f);
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < mid; i++)
|
||||||
|
{
|
||||||
|
fn = ((double)i + 0.5) / (double)mid;
|
||||||
|
f = fn * samplerate / 2.0;
|
||||||
|
switch (curve)
|
||||||
|
{
|
||||||
|
case 0: // fm pre-emphasis
|
||||||
|
if (f0 > 0.0)
|
||||||
|
A[i] = scale * (g0_lin * f / f0);
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
break;
|
||||||
|
case 1: // fm de-emphasis
|
||||||
|
if (f > 0.0)
|
||||||
|
A[i] = scale * (g0_lin * f0 / f);
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ctfmode == 0)
|
||||||
|
{
|
||||||
|
int k, low, high;
|
||||||
|
double lowmag, highmag, flow4, fhigh4;
|
||||||
|
if (nc & 1)
|
||||||
|
{
|
||||||
|
low = (int)(2.0 * f0 / samplerate * mid);
|
||||||
|
high = (int)(2.0 * f1 / samplerate * mid + 0.5);
|
||||||
|
lowmag = A[low];
|
||||||
|
highmag = A[high];
|
||||||
|
flow4 = pow((double)low / (double)mid, 4.0);
|
||||||
|
fhigh4 = pow((double)high / (double)mid, 4.0);
|
||||||
|
k = low;
|
||||||
|
while (--k >= 0)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
lowmag *= (f * f * f * f) / flow4;
|
||||||
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
||||||
|
A[k] = lowmag;
|
||||||
|
}
|
||||||
|
k = high;
|
||||||
|
while (++k <= mid)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
highmag *= fhigh4 / (f * f * f * f);
|
||||||
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
||||||
|
A[k] = highmag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
low = (int)(2.0 * f0 / samplerate * mid - 0.5);
|
||||||
|
high = (int)(2.0 * f1 / samplerate * mid - 0.5);
|
||||||
|
lowmag = A[low];
|
||||||
|
highmag = A[high];
|
||||||
|
flow4 = pow((double)low / (double)mid, 4.0);
|
||||||
|
fhigh4 = pow((double)high / (double)mid, 4.0);
|
||||||
|
k = low;
|
||||||
|
while (--k >= 0)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
lowmag *= (f * f * f * f) / flow4;
|
||||||
|
if (lowmag < 1.0e-100) lowmag = 1.0e-100;
|
||||||
|
A[k] = lowmag;
|
||||||
|
}
|
||||||
|
k = high;
|
||||||
|
while (++k < mid)
|
||||||
|
{
|
||||||
|
f = (double)k / (double)mid;
|
||||||
|
highmag *= fhigh4 / (f * f * f * f);
|
||||||
|
if (highmag < 1.0e-100) highmag = 1.0e-100;
|
||||||
|
A[k] = highmag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nc & 1)
|
||||||
|
impulse = fir_fsamp_odd(nc, A, 1, 1.0, wintype);
|
||||||
|
else
|
||||||
|
impulse = fir_fsamp(nc, A, 1, 1.0, wintype);
|
||||||
|
// print_impulse ("emph.txt", size + 1, impulse, 1, 0);
|
||||||
|
_aligned_free (A);
|
||||||
|
return impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate mask for Overlap-Save Filter
|
||||||
|
double* fc_mults (int size, double f0, double f1, double g0, double g1, int curve, double samplerate, double scale, int ctfmode, int wintype)
|
||||||
|
{
|
||||||
|
double* impulse = fc_impulse (size + 1, f0, f1, g0, g1, curve, samplerate, scale, ctfmode, wintype);
|
||||||
|
double* mults = fftcv_mults(2 * size, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return mults;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/* fcurve.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _fcurve_h
|
||||||
|
#define _fcurve_h
|
||||||
|
|
||||||
|
extern double* fc_impulse (int nc, double f0, double f1, double g0, double g1, int curve, double samplerate, double scale, int ctfmode, int wintype);
|
||||||
|
|
||||||
|
extern double* fc_mults (int size, double f0, double f1, double g0, double g1, int curve, double samplerate, double scale, int ctfmode, int wintype);
|
||||||
|
|
||||||
|
#endif
|
||||||
+401
@@ -0,0 +1,401 @@
|
|||||||
|
/* fir.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2022 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@pratt.one
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
double* fftcv_mults (int NM, double* c_impulse)
|
||||||
|
{
|
||||||
|
double* mults = (double *) malloc0 (NM * sizeof (complex));
|
||||||
|
double* cfft_impulse = (double *) malloc0 (NM * sizeof (complex));
|
||||||
|
fftw_plan ptmp = fftw_plan_dft_1d(NM, (fftw_complex *) cfft_impulse,
|
||||||
|
(fftw_complex *) mults, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
memset (cfft_impulse, 0, NM * sizeof (complex));
|
||||||
|
// store complex coefs right-justified in the buffer
|
||||||
|
memcpy (&(cfft_impulse[NM - 2]), c_impulse, (NM / 2 + 1) * sizeof(complex));
|
||||||
|
fftw_execute (ptmp);
|
||||||
|
fftw_destroy_plan (ptmp);
|
||||||
|
_aligned_free (cfft_impulse);
|
||||||
|
return mults;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* get_fsamp_window(int N, int wintype)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double arg0, arg1;
|
||||||
|
double* window = (double *) malloc0 (N * sizeof(double));
|
||||||
|
switch (wintype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
arg0 = 2.0 * PI / ((double)N - 1.0);
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
arg1 = cos(arg0 * (double)i);
|
||||||
|
window[i] = +0.21747
|
||||||
|
+ arg1 * (-0.45325
|
||||||
|
+ arg1 * (+0.28256
|
||||||
|
+ arg1 * (-0.04672)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
arg0 = 2.0 * PI / ((double)N - 1.0);
|
||||||
|
for (i = 0; i < N; ++i)
|
||||||
|
{
|
||||||
|
arg1 = cos(arg0 * (double)i);
|
||||||
|
window[i] = +6.3964424114390378e-02
|
||||||
|
+ arg1 * (-2.3993864599352804e-01
|
||||||
|
+ arg1 * (+3.5015956323820469e-01
|
||||||
|
+ arg1 * (-2.4774111897080783e-01
|
||||||
|
+ arg1 * (+8.5438256055858031e-02
|
||||||
|
+ arg1 * (-1.2320203369293225e-02
|
||||||
|
+ arg1 * (+4.3778825791773474e-04))))));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
window[i] = 1.0;
|
||||||
|
}
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* fir_fsamp_odd (int N, double* A, int rtype, double scale, int wintype)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int mid = (N - 1) / 2;
|
||||||
|
double mag, phs;
|
||||||
|
double* window;
|
||||||
|
double *fcoef = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
double *c_impulse = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
fftw_plan ptmp = fftw_plan_dft_1d(N, (fftw_complex *)fcoef, (fftw_complex *)c_impulse, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
double local_scale = 1.0 / (double)N;
|
||||||
|
for (i = 0; i <= mid; i++)
|
||||||
|
{
|
||||||
|
mag = A[i] * local_scale;
|
||||||
|
phs = - (double)mid * TWOPI * (double)i / (double)N;
|
||||||
|
fcoef[2 * i + 0] = mag * cos (phs);
|
||||||
|
fcoef[2 * i + 1] = mag * sin (phs);
|
||||||
|
}
|
||||||
|
for (i = mid + 1, j = 0; i < N; i++, j++)
|
||||||
|
{
|
||||||
|
fcoef[2 * i + 0] = + fcoef[2 * (mid - j) + 0];
|
||||||
|
fcoef[2 * i + 1] = - fcoef[2 * (mid - j) + 1];
|
||||||
|
}
|
||||||
|
fftw_execute (ptmp);
|
||||||
|
fftw_destroy_plan (ptmp);
|
||||||
|
_aligned_free (fcoef);
|
||||||
|
window = get_fsamp_window(N, wintype);
|
||||||
|
switch (rtype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
c_impulse[i] = scale * c_impulse[2 * i] * window[i];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
c_impulse[2 * i + 0] *= scale * window[i];
|
||||||
|
c_impulse[2 * i + 1] = 0.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_aligned_free (window);
|
||||||
|
return c_impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* fir_fsamp (int N, double* A, int rtype, double scale, int wintype)
|
||||||
|
{
|
||||||
|
int n, i, j, k;
|
||||||
|
double sum;
|
||||||
|
double* window;
|
||||||
|
double *c_impulse = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
|
||||||
|
if (N & 1)
|
||||||
|
{
|
||||||
|
int M = (N - 1) / 2;
|
||||||
|
for (n = 0; n < M + 1; n++)
|
||||||
|
{
|
||||||
|
sum = 0.0;
|
||||||
|
for (k = 1; k < M + 1; k++)
|
||||||
|
sum += 2.0 * A[k] * cos(TWOPI * (n - M) * k / N);
|
||||||
|
c_impulse[2 * n + 0] = (1.0 / N) * (A[0] + sum);
|
||||||
|
c_impulse[2 * n + 1] = 0.0;
|
||||||
|
}
|
||||||
|
for (n = M + 1, j = 1; n < N; n++, j++)
|
||||||
|
{
|
||||||
|
c_impulse[2 * n + 0] = c_impulse[2 * (M - j) + 0];
|
||||||
|
c_impulse[2 * n + 1] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double M = (double)(N - 1) / 2.0;
|
||||||
|
for (n = 0; n < N / 2; n++)
|
||||||
|
{
|
||||||
|
sum = 0.0;
|
||||||
|
for (k = 1; k < N / 2; k++)
|
||||||
|
sum += 2.0 * A[k] * cos(TWOPI * (n - M) * k / N);
|
||||||
|
c_impulse[2 * n + 0] = (1.0 / N) * (A[0] + sum);
|
||||||
|
c_impulse[2 * n + 1] = 0.0;
|
||||||
|
}
|
||||||
|
for (n = N / 2, j = 1; n < N; n++, j++)
|
||||||
|
{
|
||||||
|
c_impulse[2 * n + 0] = c_impulse[2 * (N / 2 - j) + 0];
|
||||||
|
c_impulse[2 * n + 1] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window = get_fsamp_window (N, wintype);
|
||||||
|
switch (rtype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
c_impulse[i] = scale * c_impulse[2 * i] * window[i];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
c_impulse[2 * i + 0] *= scale * window[i];
|
||||||
|
c_impulse[2 * i + 1] = 0.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_aligned_free (window);
|
||||||
|
return c_impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
double* fir_bandpass (int N, double f_low, double f_high, double samplerate, int wintype, int rtype, double scale)
|
||||||
|
{
|
||||||
|
double *c_impulse = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
double ft = (f_high - f_low) / (2.0 * samplerate);
|
||||||
|
double ft_rad = TWOPI * ft;
|
||||||
|
double w_osc = PI * (f_high + f_low) / samplerate;
|
||||||
|
int i, j;
|
||||||
|
double m = 0.5 * (double)(N - 1);
|
||||||
|
double delta = PI / m;
|
||||||
|
double cosphi;
|
||||||
|
double posi, posj;
|
||||||
|
double sinc, window, coef;
|
||||||
|
|
||||||
|
if (N & 1)
|
||||||
|
{
|
||||||
|
switch (rtype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
c_impulse[N >> 1] = scale * 2.0 * ft;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
c_impulse[N - 1] = scale * 2.0 * ft;
|
||||||
|
c_impulse[ N ] = 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = (N + 1) / 2, j = N / 2 - 1; i < N; i++, j--)
|
||||||
|
{
|
||||||
|
posi = (double)i - m;
|
||||||
|
posj = (double)j - m;
|
||||||
|
sinc = sin (ft_rad * posi) / (PI * posi);
|
||||||
|
switch (wintype)
|
||||||
|
{
|
||||||
|
case 0: // Blackman-Harris 4-term
|
||||||
|
cosphi = cos (delta * i);
|
||||||
|
window = + 0.21747
|
||||||
|
+ cosphi * ( - 0.45325
|
||||||
|
+ cosphi * ( + 0.28256
|
||||||
|
+ cosphi * ( - 0.04672 )));
|
||||||
|
break;
|
||||||
|
case 1: // Blackman-Harris 7-term
|
||||||
|
cosphi = cos (delta * i);
|
||||||
|
window = + 6.3964424114390378e-02
|
||||||
|
+ cosphi * ( - 2.3993864599352804e-01
|
||||||
|
+ cosphi * ( + 3.5015956323820469e-01
|
||||||
|
+ cosphi * ( - 2.4774111897080783e-01
|
||||||
|
+ cosphi * ( + 8.5438256055858031e-02
|
||||||
|
+ cosphi * ( - 1.2320203369293225e-02
|
||||||
|
+ cosphi * ( + 4.3778825791773474e-04 ))))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
coef = scale * sinc * window;
|
||||||
|
switch (rtype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
c_impulse[i] = + coef * cos (posi * w_osc);
|
||||||
|
c_impulse[j] = + coef * cos (posj * w_osc);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
c_impulse[2 * i + 0] = + coef * cos (posi * w_osc);
|
||||||
|
c_impulse[2 * i + 1] = - coef * sin (posi * w_osc);
|
||||||
|
c_impulse[2 * j + 0] = + coef * cos (posj * w_osc);
|
||||||
|
c_impulse[2 * j + 1] = - coef * sin (posj * w_osc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c_impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
double *fir_read (int N, const char *filename, int rtype, double scale)
|
||||||
|
// N = number of real or complex coefficients (see rtype)
|
||||||
|
// *filename = filename
|
||||||
|
// rtype = 0: real coefficients
|
||||||
|
// rtype = 1: complex coefficients
|
||||||
|
// scale = a scale factor that will be applied to the returned coefficients;
|
||||||
|
// if this is not needed, set it to 1.0
|
||||||
|
// NOTE: The number of values in the file must NOT exceed those implied by N and rtype
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
int i;
|
||||||
|
double I, Q;
|
||||||
|
double *c_impulse = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
file = fopen (filename, "r");
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
// read in the complex impulse response
|
||||||
|
// NOTE: IF the freq response is symmetrical about 0, the imag coeffs will all be zero.
|
||||||
|
switch (rtype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
fscanf (file, "%le", &I);
|
||||||
|
c_impulse[i] = + scale * I;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fscanf (file, "%le", &I);
|
||||||
|
fscanf (file, "%le", &Q);
|
||||||
|
c_impulse[2 * i + 0] = + scale * I;
|
||||||
|
c_impulse[2 * i + 1] = - scale * Q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose (file);
|
||||||
|
return c_impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void analytic (int N, double* in, double* out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double inv_N = 1.0 / (double)N;
|
||||||
|
double two_inv_N = 2.0 * inv_N;
|
||||||
|
double* x = (double *) malloc0 (N * sizeof (complex));
|
||||||
|
fftw_plan pfor = fftw_plan_dft_1d (N, (fftw_complex *) in,
|
||||||
|
(fftw_complex *) x, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
fftw_plan prev = fftw_plan_dft_1d (N, (fftw_complex *) x,
|
||||||
|
(fftw_complex *) out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
fftw_execute (pfor);
|
||||||
|
x[0] *= inv_N;
|
||||||
|
x[1] *= inv_N;
|
||||||
|
for (i = 1; i < N / 2; i++)
|
||||||
|
{
|
||||||
|
x[2 * i + 0] *= two_inv_N;
|
||||||
|
x[2 * i + 1] *= two_inv_N;
|
||||||
|
}
|
||||||
|
x[N + 0] *= inv_N;
|
||||||
|
x[N + 1] *= inv_N;
|
||||||
|
memset (&x[N + 2], 0, (N - 2) * sizeof (double));
|
||||||
|
fftw_execute (prev);
|
||||||
|
fftw_destroy_plan (prev);
|
||||||
|
fftw_destroy_plan (pfor);
|
||||||
|
_aligned_free (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_imp (int N, double* fir, double* mpfir, int pfactor, int polarity)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int size = N * pfactor;
|
||||||
|
double inv_PN = 1.0 / (double)size;
|
||||||
|
double* firpad = (double *) malloc0 (size * sizeof (complex));
|
||||||
|
double* firfreq = (double *) malloc0 (size * sizeof (complex));
|
||||||
|
double* mag = (double *) malloc0 (size * sizeof (double));
|
||||||
|
double* ana = (double *) malloc0 (size * sizeof (complex));
|
||||||
|
double* impulse = (double *) malloc0 (size * sizeof (complex));
|
||||||
|
double* newfreq = (double *) malloc0 (size * sizeof (complex));
|
||||||
|
memcpy (firpad, fir, N * sizeof (complex));
|
||||||
|
fftw_plan pfor = fftw_plan_dft_1d (size, (fftw_complex *) firpad,
|
||||||
|
(fftw_complex *) firfreq, FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
fftw_plan prev = fftw_plan_dft_1d (size, (fftw_complex *) newfreq,
|
||||||
|
(fftw_complex *) impulse, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
// print_impulse("orig_imp.txt", N, fir, 1, 0);
|
||||||
|
fftw_execute (pfor);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
mag[i] = sqrt (firfreq[2 * i + 0] * firfreq[2 * i + 0] + firfreq[2 * i + 1] * firfreq[2 * i + 1]) * inv_PN;
|
||||||
|
if (mag[i] > 0.0)
|
||||||
|
ana[2 * i + 0] = log (mag[i]);
|
||||||
|
else
|
||||||
|
ana[2 * i + 0] = log (1.0e-300);
|
||||||
|
}
|
||||||
|
analytic (size, ana, ana);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
newfreq[2 * i + 0] = + mag[i] * cos (ana[2 * i + 1]);
|
||||||
|
if (polarity)
|
||||||
|
newfreq[2 * i + 1] = + mag[i] * sin (ana[2 * i + 1]);
|
||||||
|
else
|
||||||
|
newfreq[2 * i + 1] = - mag[i] * sin (ana[2 * i + 1]);
|
||||||
|
}
|
||||||
|
fftw_execute (prev);
|
||||||
|
if (polarity)
|
||||||
|
memcpy (mpfir, &impulse[2 * (pfactor - 1) * N], N * sizeof (complex));
|
||||||
|
else
|
||||||
|
memcpy (mpfir, impulse, N * sizeof (complex));
|
||||||
|
// print_impulse("min_imp.txt", N, mpfir, 1, 0);
|
||||||
|
fftw_destroy_plan (prev);
|
||||||
|
fftw_destroy_plan (pfor);
|
||||||
|
_aligned_free (newfreq);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
_aligned_free (ana);
|
||||||
|
_aligned_free (mag);
|
||||||
|
_aligned_free (firfreq);
|
||||||
|
_aligned_free (firpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// impulse response of a zero frequency filter comprising a cascade of two resonators,
|
||||||
|
// each followed by a detrending filter
|
||||||
|
double* zff_impulse(int nc, double scale)
|
||||||
|
{
|
||||||
|
// nc = number of coefficients (power of two)
|
||||||
|
int n_resdet = nc / 2 - 1; // size of single zero-frequency resonator with detrender
|
||||||
|
int n_dresdet = 2 * n_resdet - 1; // size of two cascaded units; when we convolve these we get 2 * n - 1 length
|
||||||
|
// allocate the single and make the values
|
||||||
|
double* resdet = (double*)malloc0 (n_resdet * sizeof(double));
|
||||||
|
for (int i = 1, j = 0, k = n_resdet - 1; i < nc / 4; i++, j++, k--)
|
||||||
|
resdet[j] = resdet[k] = (double)(i * (i + 1) / 2);
|
||||||
|
resdet[nc / 4 - 1] = (double)(nc / 4 * (nc / 4 + 1) / 2);
|
||||||
|
// print_impulse ("resdet", n_resdet, resdet, 0, 0);
|
||||||
|
// allocate the double and complex versions and make the values
|
||||||
|
double* dresdet = (double*)malloc0 (n_dresdet * sizeof(double));
|
||||||
|
double div = (double)((nc / 2 + 1) * (nc / 2 + 1)); // calculate divisor
|
||||||
|
double* c_dresdet = (double*)malloc0 (nc * sizeof(complex));
|
||||||
|
for (int n = 0; n < n_dresdet; n++) // convolve to make the cascade
|
||||||
|
{
|
||||||
|
for (int k = 0; k < n_resdet; k++)
|
||||||
|
if ((n - k) >= 0 && (n - k) < n_resdet)
|
||||||
|
dresdet[n] += resdet[k] * resdet[n - k];
|
||||||
|
dresdet[n] /= div;
|
||||||
|
c_dresdet[2 * n + 0] = dresdet[n] * scale;
|
||||||
|
c_dresdet[2 * n + 1] = 0.0;
|
||||||
|
}
|
||||||
|
// print_impulse("dresdet", n_dresdet, dresdet, 0, 0);
|
||||||
|
// print_impulse("c_dresdet", nc, c_dresdet, 1, 0);
|
||||||
|
_aligned_free(dresdet);
|
||||||
|
_aligned_free(resdet);
|
||||||
|
return c_dresdet;
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/* fir.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2022 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@pratt.one
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern double* fftcv_mults (int NM, double* c_impulse);
|
||||||
|
|
||||||
|
extern double* fir_fsamp_odd (int N, double* A, int rtype, double scale, int wintype);
|
||||||
|
|
||||||
|
extern double* fir_fsamp (int N, double* A, int rtype, double scale, int wintype);
|
||||||
|
|
||||||
|
extern double* fir_bandpass (int N, double f_low, double f_high, double samplerate, int wintype, int rtype, double scale);
|
||||||
|
|
||||||
|
extern double* get_fsamp_window(int N, int wintype);
|
||||||
|
|
||||||
|
extern double *fir_read (int N, const char *filename, int rtype, double scale);
|
||||||
|
|
||||||
|
extern void mp_imp (int N, double* fir, double* mpfir, int pfactor, int polarity);
|
||||||
|
|
||||||
|
extern double* zff_impulse(int nc, double scale);
|
||||||
+484
@@ -0,0 +1,484 @@
|
|||||||
|
/* firmin.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Time-Domain FIR *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void calc_firmin (FIRMIN a)
|
||||||
|
{
|
||||||
|
a->h = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain);
|
||||||
|
a->rsize = a->nc;
|
||||||
|
a->mask = a->rsize - 1;
|
||||||
|
a->ring = (double *) malloc0 (a->rsize * sizeof (complex));
|
||||||
|
a->idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRMIN create_firmin (int run, int position, int size, double* in, double* out,
|
||||||
|
int nc, double f_low, double f_high, int samplerate, int wintype, double gain)
|
||||||
|
{
|
||||||
|
FIRMIN a = (FIRMIN) malloc0 (sizeof (firmin));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->nc = nc;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->samplerate = samplerate;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->gain = gain;
|
||||||
|
calc_firmin (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_firmin (FIRMIN a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->ring);
|
||||||
|
_aligned_free (a->h);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_firmin (FIRMIN a)
|
||||||
|
{
|
||||||
|
memset (a->ring, 0, a->rsize * sizeof (complex));
|
||||||
|
a->idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfirmin (FIRMIN a, int pos)
|
||||||
|
{
|
||||||
|
if (a->run && a->position == pos)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->ring[2 * a->idx + 0] = a->in[2 * i + 0];
|
||||||
|
a->ring[2 * a->idx + 1] = a->in[2 * i + 1];
|
||||||
|
a->out[2 * i + 0] = 0.0;
|
||||||
|
a->out[2 * i + 1] = 0.0;
|
||||||
|
k = a->idx;
|
||||||
|
for (j = 0; j < a->nc; j++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] += a->h[2 * j + 0] * a->ring[2 * k + 0] - a->h[2 * j + 1] * a->ring[2 * k + 1];
|
||||||
|
a->out[2 * i + 1] += a->h[2 * j + 0] * a->ring[2 * k + 1] + a->h[2 * j + 1] * a->ring[2 * k + 0];
|
||||||
|
k = (k + a->mask) & a->mask;
|
||||||
|
}
|
||||||
|
a->idx = (a->idx + 1) & a->mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_firmin (FIRMIN a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_firmin (FIRMIN a, int rate)
|
||||||
|
{
|
||||||
|
a->samplerate = (double)rate;
|
||||||
|
calc_firmin (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_firmin (FIRMIN a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFreqs_firmin (FIRMIN a, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
calc_firmin (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Standalone Partitioned Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void plan_firopt (FIROPT a)
|
||||||
|
{
|
||||||
|
// must call for change in 'nc', 'size', 'out'
|
||||||
|
int i;
|
||||||
|
a->nfor = a->nc / a->size;
|
||||||
|
a->buffidx = 0;
|
||||||
|
a->idxmask = a->nfor - 1;
|
||||||
|
a->fftin = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->fftout = (double **) malloc0 (a->nfor * sizeof (double *));
|
||||||
|
a->fmask = (double **) malloc0 (a->nfor * sizeof (double *));
|
||||||
|
a->maskgen = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->pcfor = (fftw_plan *) malloc0 (a->nfor * sizeof (fftw_plan));
|
||||||
|
a->maskplan = (fftw_plan *) malloc0 (a->nfor * sizeof (fftw_plan));
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
a->fftout[i] = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->fmask[i] = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->pcfor[i] = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->fftin, (fftw_complex *)a->fftout[i], FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->maskplan[i] = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->maskgen, (fftw_complex *)a->fmask[i], FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
}
|
||||||
|
a->accum = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->crev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->accum, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_firopt (FIROPT a)
|
||||||
|
{
|
||||||
|
// call for change in frequency, rate, wintype, gain
|
||||||
|
// must also call after a call to plan_firopt()
|
||||||
|
int i;
|
||||||
|
double* impulse = fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain);
|
||||||
|
a->buffidx = 0;
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
// I right-justified the impulse response => take output from left side of output buff, discard right side
|
||||||
|
// Be careful about flipping an asymmetrical impulse response.
|
||||||
|
memcpy (&(a->maskgen[2 * a->size]), &(impulse[2 * a->size * i]), a->size * sizeof(complex));
|
||||||
|
fftw_execute (a->maskplan[i]);
|
||||||
|
}
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
FIROPT create_firopt (int run, int position, int size, double* in, double* out,
|
||||||
|
int nc, double f_low, double f_high, int samplerate, int wintype, double gain)
|
||||||
|
{
|
||||||
|
FIROPT a = (FIROPT) malloc0 (sizeof (firopt));
|
||||||
|
a->run = run;
|
||||||
|
a->position = position;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->nc = nc;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->samplerate = samplerate;
|
||||||
|
a->wintype = wintype;
|
||||||
|
a->gain = gain;
|
||||||
|
plan_firopt (a);
|
||||||
|
calc_firopt (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deplan_firopt (FIROPT a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fftw_destroy_plan (a->crev);
|
||||||
|
_aligned_free (a->accum);
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
_aligned_free (a->fftout[i]);
|
||||||
|
_aligned_free (a->fmask[i]);
|
||||||
|
fftw_destroy_plan (a->pcfor[i]);
|
||||||
|
fftw_destroy_plan (a->maskplan[i]);
|
||||||
|
}
|
||||||
|
_aligned_free (a->maskplan);
|
||||||
|
_aligned_free (a->pcfor);
|
||||||
|
_aligned_free (a->maskgen);
|
||||||
|
_aligned_free (a->fmask);
|
||||||
|
_aligned_free (a->fftout);
|
||||||
|
_aligned_free (a->fftin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_firopt (FIROPT a)
|
||||||
|
{
|
||||||
|
deplan_firopt (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_firopt (FIROPT a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memset (a->fftin, 0, 2 * a->size * sizeof (complex));
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
memset (a->fftout[i], 0, 2 * a->size * sizeof (complex));
|
||||||
|
a->buffidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfiropt (FIROPT a, int pos)
|
||||||
|
{
|
||||||
|
if (a->run && (a->position == pos))
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
memcpy (&(a->fftin[2 * a->size]), a->in, a->size * sizeof (complex));
|
||||||
|
fftw_execute (a->pcfor[a->buffidx]);
|
||||||
|
k = a->buffidx;
|
||||||
|
memset (a->accum, 0, 2 * a->size * sizeof (complex));
|
||||||
|
for (j = 0; j < a->nfor; j++)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
{
|
||||||
|
a->accum[2 * i + 0] += a->fftout[k][2 * i + 0] * a->fmask[j][2 * i + 0] - a->fftout[k][2 * i + 1] * a->fmask[j][2 * i + 1];
|
||||||
|
a->accum[2 * i + 1] += a->fftout[k][2 * i + 0] * a->fmask[j][2 * i + 1] + a->fftout[k][2 * i + 1] * a->fmask[j][2 * i + 0];
|
||||||
|
}
|
||||||
|
k = (k + a->idxmask) & a->idxmask;
|
||||||
|
}
|
||||||
|
a->buffidx = (a->buffidx + 1) & a->idxmask;
|
||||||
|
fftw_execute (a->crev);
|
||||||
|
memcpy (a->fftin, &(a->fftin[2 * a->size]), a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_firopt (FIROPT a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
deplan_firopt (a);
|
||||||
|
plan_firopt (a);
|
||||||
|
calc_firopt (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_firopt (FIROPT a, int rate)
|
||||||
|
{
|
||||||
|
a->samplerate = rate;
|
||||||
|
calc_firopt (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_firopt (FIROPT a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
deplan_firopt (a);
|
||||||
|
plan_firopt (a);
|
||||||
|
calc_firopt (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFreqs_firopt (FIROPT a, double f_low, double f_high)
|
||||||
|
{
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
calc_firopt (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Filter Kernel *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void plan_fircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
// must call for change in 'nc', 'size', 'out'
|
||||||
|
int i;
|
||||||
|
a->nfor = a->nc / a->size;
|
||||||
|
a->cset = 0;
|
||||||
|
a->buffidx = 0;
|
||||||
|
a->idxmask = a->nfor - 1;
|
||||||
|
a->fftin = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->fftout = (double **) malloc0 (a->nfor * sizeof (double *));
|
||||||
|
a->fmask = (double ***) malloc0 (2 * sizeof (double **));
|
||||||
|
a->fmask[0] = (double **) malloc0 (a->nfor * sizeof (double *));
|
||||||
|
a->fmask[1] = (double **) malloc0 (a->nfor * sizeof (double *));
|
||||||
|
a->maskgen = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->pcfor = (fftw_plan *) malloc0 (a->nfor * sizeof (fftw_plan));
|
||||||
|
a->maskplan = (fftw_plan **) malloc0 (2 * sizeof (fftw_plan *));
|
||||||
|
a->maskplan[0] = (fftw_plan *) malloc0 (a->nfor * sizeof (fftw_plan));
|
||||||
|
a->maskplan[1] = (fftw_plan *) malloc0 (a->nfor * sizeof (fftw_plan));
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
a->fftout[i] = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->fmask[0][i] = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->fmask[1][i] = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->pcfor[i] = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->fftin, (fftw_complex *)a->fftout[i], FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->maskplan[0][i] = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->maskgen, (fftw_complex *)a->fmask[0][i], FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
a->maskplan[1][i] = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->maskgen, (fftw_complex *)a->fmask[1][i], FFTW_FORWARD, FFTW_PATIENT);
|
||||||
|
}
|
||||||
|
a->accum = (double *) malloc0 (2 * a->size * sizeof (complex));
|
||||||
|
a->crev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->accum, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT);
|
||||||
|
a->masks_ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_fircore (FIRCORE a, int flip)
|
||||||
|
{
|
||||||
|
// call for change in frequency, rate, wintype, gain
|
||||||
|
// must also call after a call to plan_firopt()
|
||||||
|
int i;
|
||||||
|
if (a->mp)
|
||||||
|
mp_imp (a->nc, a->impulse, a->imp, 16, 0);
|
||||||
|
else
|
||||||
|
memcpy (a->imp, a->impulse, a->nc * sizeof (complex));
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
// I right-justified the impulse response => take output from left side of output buff, discard right side
|
||||||
|
// Be careful about flipping an asymmetrical impulse response.
|
||||||
|
memcpy (&(a->maskgen[2 * a->size]), &(a->imp[2 * a->size * i]), a->size * sizeof(complex));
|
||||||
|
fftw_execute (a->maskplan[1 - a->cset][i]);
|
||||||
|
}
|
||||||
|
a->masks_ready = 1;
|
||||||
|
if (flip)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->update);
|
||||||
|
a->cset = 1 - a->cset;
|
||||||
|
LeaveCriticalSection (&a->update);
|
||||||
|
a->masks_ready = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRCORE create_fircore (int size, double* in, double* out, int nc, int mp, double* impulse)
|
||||||
|
{
|
||||||
|
FIRCORE a = (FIRCORE) malloc0 (sizeof (fircore));
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
InitializeCriticalSectionAndSpinCount (&a->update, 2500);
|
||||||
|
plan_fircore (a);
|
||||||
|
a->impulse = (double *) malloc0 (a->nc * sizeof (complex));
|
||||||
|
a->imp = (double *) malloc0 (a->nc * sizeof (complex));
|
||||||
|
memcpy (a->impulse, impulse, a->nc * sizeof (complex));
|
||||||
|
calc_fircore (a, 1);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deplan_fircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fftw_destroy_plan (a->crev);
|
||||||
|
_aligned_free (a->accum);
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
{
|
||||||
|
_aligned_free (a->fftout[i]);
|
||||||
|
_aligned_free (a->fmask[0][i]);
|
||||||
|
_aligned_free (a->fmask[1][i]);
|
||||||
|
fftw_destroy_plan (a->pcfor[i]);
|
||||||
|
fftw_destroy_plan (a->maskplan[0][i]);
|
||||||
|
fftw_destroy_plan (a->maskplan[1][i]);
|
||||||
|
}
|
||||||
|
_aligned_free (a->maskplan[0]);
|
||||||
|
_aligned_free (a->maskplan[1]);
|
||||||
|
_aligned_free (a->maskplan);
|
||||||
|
_aligned_free (a->pcfor);
|
||||||
|
_aligned_free (a->maskgen);
|
||||||
|
_aligned_free (a->fmask[0]);
|
||||||
|
_aligned_free (a->fmask[1]);
|
||||||
|
_aligned_free (a->fmask);
|
||||||
|
_aligned_free (a->fftout);
|
||||||
|
_aligned_free (a->fftin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_fircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
deplan_fircore (a);
|
||||||
|
_aligned_free (a->imp);
|
||||||
|
_aligned_free (a->impulse);
|
||||||
|
DeleteCriticalSection (&a->update);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_fircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
memset (a->fftin, 0, 2 * a->size * sizeof (complex));
|
||||||
|
for (i = 0; i < a->nfor; i++)
|
||||||
|
memset (a->fftout[i], 0, 2 * a->size * sizeof (complex));
|
||||||
|
a->buffidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
memcpy (&(a->fftin[2 * a->size]), a->in, a->size * sizeof (complex));
|
||||||
|
fftw_execute (a->pcfor[a->buffidx]);
|
||||||
|
k = a->buffidx;
|
||||||
|
memset (a->accum, 0, 2 * a->size * sizeof (complex));
|
||||||
|
EnterCriticalSection (&a->update);
|
||||||
|
for (j = 0; j < a->nfor; j++)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
{
|
||||||
|
a->accum[2 * i + 0] += a->fftout[k][2 * i + 0] * a->fmask[a->cset][j][2 * i + 0] - a->fftout[k][2 * i + 1] * a->fmask[a->cset][j][2 * i + 1];
|
||||||
|
a->accum[2 * i + 1] += a->fftout[k][2 * i + 0] * a->fmask[a->cset][j][2 * i + 1] + a->fftout[k][2 * i + 1] * a->fmask[a->cset][j][2 * i + 0];
|
||||||
|
}
|
||||||
|
k = (k + a->idxmask) & a->idxmask;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&a->update);
|
||||||
|
a->buffidx = (a->buffidx + 1) & a->idxmask;
|
||||||
|
fftw_execute (a->crev);
|
||||||
|
memcpy (a->fftin, &(a->fftin[2 * a->size]), a->size * sizeof(complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_fircore (FIRCORE a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
deplan_fircore (a);
|
||||||
|
plan_fircore (a);
|
||||||
|
calc_fircore (a, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_fircore (FIRCORE a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
deplan_fircore (a);
|
||||||
|
plan_fircore (a);
|
||||||
|
calc_fircore (a, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setImpulse_fircore (FIRCORE a, double* impulse, int update)
|
||||||
|
{
|
||||||
|
memcpy (a->impulse, impulse, a->nc * sizeof (complex));
|
||||||
|
calc_fircore (a, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNc_fircore (FIRCORE a, int nc, double* impulse)
|
||||||
|
{
|
||||||
|
// because of FFT planning, this will probably cause a glitch in audio if done during dataflow
|
||||||
|
deplan_fircore (a);
|
||||||
|
_aligned_free (a->impulse);
|
||||||
|
_aligned_free (a->imp);
|
||||||
|
a->nc = nc;
|
||||||
|
plan_fircore (a);
|
||||||
|
a->imp = (double *) malloc0 (a->nc * sizeof (complex));
|
||||||
|
a->impulse = (double *) malloc0 (a->nc * sizeof (complex));
|
||||||
|
memcpy (a->impulse, impulse, a->nc * sizeof (complex));
|
||||||
|
calc_fircore (a, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMp_fircore (FIRCORE a, int mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
calc_fircore (a, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUpdate_fircore (FIRCORE a)
|
||||||
|
{
|
||||||
|
if (a->masks_ready)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->update);
|
||||||
|
a->cset = 1 - a->cset;
|
||||||
|
LeaveCriticalSection (&a->update);
|
||||||
|
a->masks_ready = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
/* firmin.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Time-Domain FIR *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _firmin_h
|
||||||
|
#define _firmin_h
|
||||||
|
|
||||||
|
typedef struct _firmin
|
||||||
|
{
|
||||||
|
int run; // run control
|
||||||
|
int position; // position at which to execute
|
||||||
|
int size; // input/output buffer size, power of two
|
||||||
|
double* in; // input buffer
|
||||||
|
double* out; // output buffer, can be same as input
|
||||||
|
int nc; // number of filter coefficients, power of two
|
||||||
|
double f_low; // low cutoff frequency
|
||||||
|
double f_high; // high cutoff frequency
|
||||||
|
double* ring; // internal complex ring buffer
|
||||||
|
double* h; // complex filter coefficients
|
||||||
|
int rsize; // ring size, number of complex samples, power of two
|
||||||
|
int mask; // mask to update indexes
|
||||||
|
int idx; // ring input/output index
|
||||||
|
double samplerate; // sample rate
|
||||||
|
int wintype; // filter window type
|
||||||
|
double gain; // filter gain
|
||||||
|
}firmin, *FIRMIN;
|
||||||
|
|
||||||
|
extern FIRMIN create_firmin (int run, int position, int size, double* in, double* out,
|
||||||
|
int nc, double f_low, double f_high, int samplerate, int wintype, double gain);
|
||||||
|
|
||||||
|
extern void destroy_firmin (FIRMIN a);
|
||||||
|
|
||||||
|
extern void flush_firmin (FIRMIN a);
|
||||||
|
|
||||||
|
extern void xfirmin (FIRMIN a, int pos);
|
||||||
|
|
||||||
|
extern void setBuffers_firmin (FIRMIN a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_firmin (FIRMIN a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_firmin (FIRMIN a, int size);
|
||||||
|
|
||||||
|
extern void setFreqs_firmin (FIRMIN a, double f_low, double f_high);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Standalone Partitioned Overlap-Save Bandpass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _firopt_h
|
||||||
|
#define _firopt_h
|
||||||
|
|
||||||
|
typedef struct _firopt
|
||||||
|
{
|
||||||
|
int run; // run control
|
||||||
|
int position; // position at which to execute
|
||||||
|
int size; // input/output buffer size, power of two
|
||||||
|
double* in; // input buffer
|
||||||
|
double* out; // output buffer, can be same as input
|
||||||
|
int nc; // number of filter coefficients, power of two, >= size
|
||||||
|
double f_low; // low cutoff frequency
|
||||||
|
double f_high; // high cutoff frequency
|
||||||
|
double samplerate; // sample rate
|
||||||
|
int wintype; // filter window type
|
||||||
|
double gain; // filter gain
|
||||||
|
int nfor; // number of buffers in delay line
|
||||||
|
double* fftin; // fft input buffer
|
||||||
|
double** fmask; // frequency domain masks
|
||||||
|
double** fftout; // fftout delay line
|
||||||
|
double* accum; // frequency domain accumulator
|
||||||
|
int buffidx; // fft out buffer index
|
||||||
|
int idxmask; // mask for index computations
|
||||||
|
double* maskgen; // input for mask generation FFT
|
||||||
|
fftw_plan* pcfor; // array of forward FFT plans
|
||||||
|
fftw_plan crev; // reverse fft plan
|
||||||
|
fftw_plan* maskplan; // plans for frequency domain masks
|
||||||
|
} firopt, *FIROPT;
|
||||||
|
|
||||||
|
extern FIROPT create_firopt (int run, int position, int size, double* in, double* out,
|
||||||
|
int nc, double f_low, double f_high, int samplerate, int wintype, double gain);
|
||||||
|
|
||||||
|
extern void xfiropt (FIROPT a, int pos);
|
||||||
|
|
||||||
|
extern void destroy_firopt (FIROPT a);
|
||||||
|
|
||||||
|
extern void flush_firopt (FIROPT a);
|
||||||
|
|
||||||
|
extern void setBuffers_firopt (FIROPT a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_firopt (FIROPT a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_firopt (FIROPT a, int size);
|
||||||
|
|
||||||
|
extern void setFreqs_firopt (FIROPT a, double f_low, double f_high);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Partitioned Overlap-Save Filter Kernel *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _fircore_h
|
||||||
|
#define _fircore_h
|
||||||
|
|
||||||
|
typedef struct _fircore
|
||||||
|
{
|
||||||
|
int size; // input/output buffer size, power of two
|
||||||
|
double* in; // input buffer
|
||||||
|
double* out; // output buffer, can be same as input
|
||||||
|
int nc; // number of filter coefficients, power of two, >= size
|
||||||
|
double* impulse; // impulse response of filter
|
||||||
|
double* imp;
|
||||||
|
int nfor; // number of buffers in delay line
|
||||||
|
double* fftin; // fft input buffer
|
||||||
|
double*** fmask; // frequency domain masks
|
||||||
|
double** fftout; // fftout delay line
|
||||||
|
double* accum; // frequency domain accumulator
|
||||||
|
int buffidx; // fft out buffer index
|
||||||
|
int idxmask; // mask for index computations
|
||||||
|
double* maskgen; // input for mask generation FFT
|
||||||
|
fftw_plan* pcfor; // array of forward FFT plans
|
||||||
|
fftw_plan crev; // reverse fft plan
|
||||||
|
fftw_plan** maskplan; // plans for frequency domain masks
|
||||||
|
CRITICAL_SECTION update;
|
||||||
|
int cset;
|
||||||
|
int mp;
|
||||||
|
int masks_ready;
|
||||||
|
} fircore, *FIRCORE;
|
||||||
|
|
||||||
|
extern FIRCORE create_fircore (int size, double* in, double* out,
|
||||||
|
int nc, int mp, double* impulse);
|
||||||
|
|
||||||
|
extern void xfircore (FIRCORE a);
|
||||||
|
|
||||||
|
extern void destroy_fircore (FIRCORE a);
|
||||||
|
|
||||||
|
extern void flush_fircore (FIRCORE a);
|
||||||
|
|
||||||
|
extern void setBuffers_fircore (FIRCORE a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSize_fircore (FIRCORE a, int size);
|
||||||
|
|
||||||
|
extern void setImpulse_fircore (FIRCORE a, double* impulse, int update);
|
||||||
|
|
||||||
|
extern void setNc_fircore (FIRCORE a, int nc, double* impulse);
|
||||||
|
|
||||||
|
extern void setMp_fircore (FIRCORE a, int mp);
|
||||||
|
|
||||||
|
extern void setUpdate_fircore (FIRCORE a);
|
||||||
|
|
||||||
|
#endif
|
||||||
+384
@@ -0,0 +1,384 @@
|
|||||||
|
/* fmd.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_fmd (FMD a)
|
||||||
|
{
|
||||||
|
// pll
|
||||||
|
a->omega_min = TWOPI * a->fmin / a->rate;
|
||||||
|
a->omega_max = TWOPI * a->fmax / a->rate;
|
||||||
|
a->g1 = 1.0 - exp(-2.0 * a->omegaN * a->zeta / a->rate);
|
||||||
|
a->g2 = -a->g1 + 2.0 * (1 - exp(-a->omegaN * a->zeta / a->rate) * cos(a->omegaN / a->rate * sqrt(1.0 - a->zeta * a->zeta)));
|
||||||
|
a->phs = 0.0;
|
||||||
|
a->fil_out = 0.0;
|
||||||
|
a->omega = 0.0;
|
||||||
|
a->pllpole = a->omegaN * sqrt(2.0 * a->zeta * a->zeta + 1.0 + sqrt((2.0 * a->zeta * a->zeta + 1.0) * (2.0 * a->zeta * a->zeta + 1.0) + 1)) / TWOPI;
|
||||||
|
// dc removal
|
||||||
|
a->mtau = exp(-1.0 / (a->rate * a->tau));
|
||||||
|
a->onem_mtau = 1.0 - a->mtau;
|
||||||
|
a->fmdc = 0.0;
|
||||||
|
// pll audio gain
|
||||||
|
a->again = a->rate / (a->deviation * TWOPI);
|
||||||
|
// CTCSS Removal
|
||||||
|
a->sntch = create_snotch(1, a->size, a->out, a->out, (int)a->rate, a->ctcss_freq, 0.0002);
|
||||||
|
// detector limiter
|
||||||
|
a->plim = create_wcpagc (
|
||||||
|
1, // run - always ON
|
||||||
|
5, // mode
|
||||||
|
1, // 0 for max(I,Q), 1 for envelope
|
||||||
|
a->out, // input buff pointer
|
||||||
|
a->out, // output buff pointer
|
||||||
|
a->size, // io_buffsize
|
||||||
|
(int)a->rate, // sample rate
|
||||||
|
0.001, // tau_attack
|
||||||
|
0.008, // tau_decay
|
||||||
|
4, // n_tau
|
||||||
|
a->lim_gain, // max_gain (sets threshold, initial value)
|
||||||
|
1.0, // var_gain / slope
|
||||||
|
1.0, // fixed_gain
|
||||||
|
1.0, // max_input
|
||||||
|
0.9, // out_targ
|
||||||
|
0.250, // tau_fast_backaverage
|
||||||
|
0.004, // tau_fast_decay
|
||||||
|
4.0, // pop_ratio
|
||||||
|
0, // hang_enable
|
||||||
|
0.500, // tau_hang_backmult
|
||||||
|
0.500, // hangtime
|
||||||
|
2.000, // hang_thresh
|
||||||
|
0.100); // tau_hang_decay
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_fmd (FMD a)
|
||||||
|
{
|
||||||
|
destroy_wcpagc(a->plim);
|
||||||
|
destroy_snotch(a->sntch);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMD create_fmd( int run, int size, double* in, double* out, int rate, double deviation, double f_low, double f_high,
|
||||||
|
double fmin, double fmax, double zeta, double omegaN, double tau, double afgain, int sntch_run, double ctcss_freq, int nc_de, int mp_de, int nc_aud, int mp_aud)
|
||||||
|
{
|
||||||
|
FMD a = (FMD) malloc0 (sizeof (fmd));
|
||||||
|
double* impulse;
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->deviation = deviation;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->fmin = fmin;
|
||||||
|
a->fmax = fmax;
|
||||||
|
a->zeta = zeta;
|
||||||
|
a->omegaN = omegaN;
|
||||||
|
a->tau = tau;
|
||||||
|
a->afgain = afgain;
|
||||||
|
a->sntch_run = sntch_run;
|
||||||
|
a->ctcss_freq = ctcss_freq;
|
||||||
|
a->nc_de = nc_de;
|
||||||
|
a->mp_de = mp_de;
|
||||||
|
a->nc_aud = nc_aud;
|
||||||
|
a->mp_aud = mp_aud;
|
||||||
|
a->lim_run = 0;
|
||||||
|
a->lim_pre_gain = 0.4;
|
||||||
|
a->lim_gain = 2.5;
|
||||||
|
calc_fmd (a);
|
||||||
|
// de-emphasis filter
|
||||||
|
a->audio = (double *) malloc0 (a->size * sizeof (complex));
|
||||||
|
impulse = fc_impulse (a->nc_de, a->f_low, a->f_high, +20.0 * log10(a->f_high / a->f_low), 0.0, 1, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
a->pde = create_fircore (a->size, a->audio, a->out, a->nc_de, a->mp_de, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
// audio filter
|
||||||
|
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
||||||
|
a->paud = create_fircore (a->size, a->out, a->out, a->nc_aud, a->mp_aud, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_fmd (FMD a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->paud);
|
||||||
|
destroy_fircore (a->pde);
|
||||||
|
_aligned_free (a->audio);
|
||||||
|
decalc_fmd (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_fmd (FMD a)
|
||||||
|
{
|
||||||
|
memset (a->audio, 0, a->size * sizeof (complex));
|
||||||
|
flush_fircore (a->pde);
|
||||||
|
flush_fircore (a->paud);
|
||||||
|
a->phs = 0.0;
|
||||||
|
a->fil_out = 0.0;
|
||||||
|
a->omega = 0.0;
|
||||||
|
a->fmdc = 0.0;
|
||||||
|
flush_snotch (a->sntch);
|
||||||
|
flush_wcpagc (a->plim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfmd (FMD a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double det, del_out;
|
||||||
|
double vco[2], corr[2];
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
// pll
|
||||||
|
vco[0] = cos (a->phs);
|
||||||
|
vco[1] = sin (a->phs);
|
||||||
|
corr[0] = + a->in[2 * i + 0] * vco[0] + a->in[2 * i + 1] * vco[1];
|
||||||
|
corr[1] = - a->in[2 * i + 0] * vco[1] + a->in[2 * i + 1] * vco[0];
|
||||||
|
if ((corr[0] == 0.0) && (corr[1] == 0.0)) corr[0] = 1.0;
|
||||||
|
det = atan2 (corr[1], corr[0]);
|
||||||
|
del_out = a->fil_out;
|
||||||
|
a->omega += a->g2 * det;
|
||||||
|
if (a->omega < a->omega_min) a->omega = a->omega_min;
|
||||||
|
if (a->omega > a->omega_max) a->omega = a->omega_max;
|
||||||
|
a->fil_out = a->g1 * det + a->omega;
|
||||||
|
a->phs += del_out;
|
||||||
|
while (a->phs >= TWOPI) a->phs -= TWOPI;
|
||||||
|
while (a->phs < 0.0) a->phs += TWOPI;
|
||||||
|
// dc removal, gain, & demod output
|
||||||
|
a->fmdc = a->mtau * a->fmdc + a->onem_mtau * a->fil_out;
|
||||||
|
a->audio[2 * i + 0] = a->again * (a->fil_out - a->fmdc);
|
||||||
|
a->audio[2 * i + 1] = a->audio[2 * i + 0];
|
||||||
|
}
|
||||||
|
// de-emphasis
|
||||||
|
xfircore (a->pde);
|
||||||
|
// audio filter
|
||||||
|
xfircore (a->paud);
|
||||||
|
// CTCSS Removal
|
||||||
|
xsnotch (a->sntch);
|
||||||
|
if (a->lim_run)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 2 * a->size; i++)
|
||||||
|
a->out[i] *= a->lim_pre_gain;
|
||||||
|
xwcpagc (a->plim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_fmd (FMD a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_fmd (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_fmd (a);
|
||||||
|
setBuffers_fircore (a->pde, a->audio, a->out);
|
||||||
|
setBuffers_fircore (a->paud, a->out, a->out);
|
||||||
|
setBuffers_wcpagc (a->plim, a->out, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_fmd (FMD a, int rate)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
decalc_fmd (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_fmd (a);
|
||||||
|
// de-emphasis filter
|
||||||
|
impulse = fc_impulse (a->nc_de, a->f_low, a->f_high, +20.0 * log10(a->f_high / a->f_low), 0.0, 1, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setImpulse_fircore (a->pde, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
// audio filter
|
||||||
|
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
||||||
|
setImpulse_fircore (a->paud, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
setSamplerate_wcpagc (a->plim, (int)a->rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_fmd (FMD a, int size)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
decalc_fmd (a);
|
||||||
|
_aligned_free (a->audio);
|
||||||
|
a->size = size;
|
||||||
|
calc_fmd (a);
|
||||||
|
a->audio = (double *) malloc0 (a->size * sizeof (complex));
|
||||||
|
// de-emphasis filter
|
||||||
|
destroy_fircore (a->pde);
|
||||||
|
impulse = fc_impulse (a->nc_de, a->f_low, a->f_high, +20.0 * log10(a->f_high / a->f_low), 0.0, 1, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
a->pde = create_fircore (a->size, a->audio, a->out, a->nc_de, a->mp_de, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
// audio filter
|
||||||
|
destroy_fircore (a->paud);
|
||||||
|
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
||||||
|
a->paud = create_fircore (a->size, a->out, a->out, a->nc_aud, a->mp_aud, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
setSize_wcpagc (a->plim, a->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMDeviation (int channel, double deviation)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
a->deviation = deviation;
|
||||||
|
a->again = a->rate / (a->deviation * TWOPI);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXACTCSSFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
a->ctcss_freq = freq;
|
||||||
|
SetSNCTCSSFreq (a->sntch, a->ctcss_freq);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXACTCSSRun (int channel, int run)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
a->sntch_run = run;
|
||||||
|
SetSNCTCSSRun (a->sntch, a->sntch_run);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMNCde (int channel, int nc)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
if (a->nc_de != nc)
|
||||||
|
{
|
||||||
|
a->nc_de = nc;
|
||||||
|
impulse = fc_impulse (a->nc_de, a->f_low, a->f_high, +20.0 * log10(a->f_high / a->f_low), 0.0, 1, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setNc_fircore (a->pde, a->nc_de, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMMPde (int channel, int mp)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
if (a->mp_de != mp)
|
||||||
|
{
|
||||||
|
a->mp_de = mp;
|
||||||
|
setMp_fircore (a->pde, a->mp_de);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMNCaud (int channel, int nc)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
if (a->nc_aud != nc)
|
||||||
|
{
|
||||||
|
a->nc_aud = nc;
|
||||||
|
impulse = fir_bandpass(a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
||||||
|
setNc_fircore (a->paud, a->nc_aud, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMMPaud (int channel, int mp)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
if (a->mp_aud != mp)
|
||||||
|
{
|
||||||
|
a->mp_aud = mp;
|
||||||
|
setMp_fircore (a->paud, a->mp_aud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMLimRun (int channel, int run)
|
||||||
|
{
|
||||||
|
FMD a;
|
||||||
|
a = rxa[channel].fmd.p;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
if (a->lim_run != run)
|
||||||
|
{
|
||||||
|
a->lim_run = run;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMLimGain (int channel, double gaindB)
|
||||||
|
{
|
||||||
|
double gain = pow(10.0, gaindB / 20.0);
|
||||||
|
FMD a = rxa[channel].fmd.p;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
if (a->lim_gain != gain)
|
||||||
|
{
|
||||||
|
decalc_fmd(a);
|
||||||
|
a->lim_gain = gain;
|
||||||
|
calc_fmd(a);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMAFFilter(int channel, double low, double high)
|
||||||
|
{
|
||||||
|
FMD a = rxa[channel].fmd.p;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
if (a->f_low != low || a->f_high != high)
|
||||||
|
{
|
||||||
|
a->f_low = low;
|
||||||
|
a->f_high = high;
|
||||||
|
// de-emphasis filter
|
||||||
|
impulse = fc_impulse (a->nc_de, a->f_low, a->f_high, +20.0 * log10(a->f_high / a->f_low), 0.0, 1, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setImpulse_fircore (a->pde, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
// audio filter
|
||||||
|
impulse = fir_bandpass (a->nc_aud, 0.8 * a->f_low, 1.1 * a->f_high, a->rate, 0, 1, a->afgain / (2.0 * a->size));
|
||||||
|
setImpulse_fircore (a->paud, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
/* fmd.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _fmd_h
|
||||||
|
#define _fmd_h
|
||||||
|
#include "iir.h"
|
||||||
|
#include "firmin.h"
|
||||||
|
#include "wcpAGC.h"
|
||||||
|
typedef struct _fmd
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double f_low; // audio low cutoff
|
||||||
|
double f_high; // audio high cutoff
|
||||||
|
// pll
|
||||||
|
double fmin; // pll - minimum carrier freq to lock
|
||||||
|
double fmax; // pll - maximum carrier freq to lock
|
||||||
|
double omega_min; // pll - minimum lock check parameter
|
||||||
|
double omega_max; // pll - maximum lock check parameter
|
||||||
|
double zeta; // pll - damping factor; as coded, must be <=1.0
|
||||||
|
double omegaN; // pll - natural frequency
|
||||||
|
double phs; // pll - phase accumulator
|
||||||
|
double omega; // pll - locked pll frequency
|
||||||
|
double fil_out; // pll - filter output
|
||||||
|
double g1, g2; // pll - filter gain parameters
|
||||||
|
double pllpole; // pll - pole frequency
|
||||||
|
// for dc removal
|
||||||
|
double tau;
|
||||||
|
double mtau;
|
||||||
|
double onem_mtau;
|
||||||
|
double fmdc;
|
||||||
|
// pll audio gain
|
||||||
|
double deviation;
|
||||||
|
double again;
|
||||||
|
// for de-emphasis filter
|
||||||
|
double* audio;
|
||||||
|
FIRCORE pde;
|
||||||
|
int nc_de;
|
||||||
|
int mp_de;
|
||||||
|
// for audio filter
|
||||||
|
FIRCORE paud;
|
||||||
|
int nc_aud;
|
||||||
|
int mp_aud;
|
||||||
|
double afgain;
|
||||||
|
// CTCSS removal
|
||||||
|
SNOTCH sntch;
|
||||||
|
int sntch_run;
|
||||||
|
double ctcss_freq;
|
||||||
|
// detector limiter
|
||||||
|
WCPAGC plim;
|
||||||
|
int lim_run;
|
||||||
|
double lim_gain;
|
||||||
|
double lim_pre_gain;
|
||||||
|
} fmd, *FMD;
|
||||||
|
|
||||||
|
extern FMD create_fmd ( int run, int size, double* in, double* out, int rate, double deviation,
|
||||||
|
double f_low, double f_high, double fmin, double fmax, double zeta, double omegaN, double tau,
|
||||||
|
double afgain, int sntch_run, double ctcss_freq, int nc_de, int mp_de, int nc_aud, int mp_aud);
|
||||||
|
|
||||||
|
extern void destroy_fmd (FMD a);
|
||||||
|
|
||||||
|
extern void flush_fmd (FMD a);
|
||||||
|
|
||||||
|
extern void xfmd (FMD a);
|
||||||
|
|
||||||
|
extern void setBuffers_fmd (FMD a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_fmd (FMD a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_fmd (FMD a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMDeviation (int channel, double deviation);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMNCde (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMMPde (int channel, int mp);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMNCaud (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMMPaud (int channel, int mp);
|
||||||
|
|
||||||
|
#endif
|
||||||
+232
@@ -0,0 +1,232 @@
|
|||||||
|
/* fmmod.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_fmmod (FMMOD a)
|
||||||
|
{
|
||||||
|
// ctcss gen
|
||||||
|
a->tscale = 1.0 / (1.0 + a->ctcss_level);
|
||||||
|
a->tphase = 0.0;
|
||||||
|
a->tdelta = TWOPI * a->ctcss_freq / a->samplerate;
|
||||||
|
// mod
|
||||||
|
a->sphase = 0.0;
|
||||||
|
a->sdelta = TWOPI * a->deviation / a->samplerate;
|
||||||
|
// bandpass
|
||||||
|
a->bp_fc = a->deviation + a->f_high;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMMOD create_fmmod (int run, int size, double* in, double* out, int rate, double dev, double f_low, double f_high,
|
||||||
|
int ctcss_run, double ctcss_level, double ctcss_freq, int bp_run, int nc, int mp)
|
||||||
|
{
|
||||||
|
FMMOD a = (FMMOD) malloc0 (sizeof (fmmod));
|
||||||
|
double* impulse;
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->samplerate = (double)rate;
|
||||||
|
a->deviation = dev;
|
||||||
|
a->f_low = f_low;
|
||||||
|
a->f_high = f_high;
|
||||||
|
a->ctcss_run = ctcss_run;
|
||||||
|
a->ctcss_level = ctcss_level;
|
||||||
|
a->ctcss_freq = ctcss_freq;
|
||||||
|
a->bp_run = bp_run;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
calc_fmmod (a);
|
||||||
|
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
a->p = create_fircore (a->size, a->out, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_fmmod (FMMOD a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_fmmod (FMMOD a)
|
||||||
|
{
|
||||||
|
a->tphase = 0.0;
|
||||||
|
a->sphase = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xfmmod (FMMOD a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double dp, magdp, peak;
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
peak = 0.0;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
if (a->ctcss_run)
|
||||||
|
{
|
||||||
|
a->tphase += a->tdelta;
|
||||||
|
if (a->tphase >= TWOPI) a->tphase -= TWOPI;
|
||||||
|
a->out[2 * i + 0] = a->tscale * (a->in[2 * i + 0] + a->ctcss_level * cos (a->tphase));
|
||||||
|
}
|
||||||
|
dp = a->out[2 * i + 0] * a->sdelta;
|
||||||
|
a->sphase += dp;
|
||||||
|
if (a->sphase >= TWOPI) a->sphase -= TWOPI;
|
||||||
|
if (a->sphase < 0.0 ) a->sphase += TWOPI;
|
||||||
|
a->out[2 * i + 0] = 0.7071 * cos (a->sphase);
|
||||||
|
a->out[2 * i + 1] = 0.7071 * sin (a->sphase);
|
||||||
|
if ((magdp = dp) < 0.0) magdp = - magdp;
|
||||||
|
if (magdp > peak) peak = magdp;
|
||||||
|
}
|
||||||
|
//print_deviation ("peakdev.txt", peak, a->samplerate);
|
||||||
|
if (a->bp_run)
|
||||||
|
xfircore (a->p);
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_fmmod (FMMOD a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_fmmod (a);
|
||||||
|
setBuffers_fircore (a->p, a->out, a->out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_fmmod (FMMOD a, int rate)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->samplerate = rate;
|
||||||
|
calc_fmmod (a);
|
||||||
|
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_fmmod (FMMOD a, int size)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->size = size;
|
||||||
|
calc_fmmod (a);
|
||||||
|
setSize_fircore (a->p, a->size);
|
||||||
|
impulse = fir_bandpass(a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMDeviation (int channel, double deviation)
|
||||||
|
{
|
||||||
|
FMMOD a = txa[channel].fmmod.p;
|
||||||
|
double bp_fc = a->f_high + deviation;
|
||||||
|
double* impulse = fir_bandpass (a->nc, -bp_fc, +bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 0);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->deviation = deviation;
|
||||||
|
// mod
|
||||||
|
a->sphase = 0.0;
|
||||||
|
a->sdelta = TWOPI * a->deviation / a->samplerate;
|
||||||
|
// bandpass
|
||||||
|
a->bp_fc = bp_fc;
|
||||||
|
setUpdate_fircore (a->p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACTCSSFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
FMMOD a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].fmmod.p;
|
||||||
|
a->ctcss_freq = freq;
|
||||||
|
a->tphase = 0.0;
|
||||||
|
a->tdelta = TWOPI * a->ctcss_freq / a->samplerate;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXACTCSSRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].fmmod.p->ctcss_run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
FMMOD a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].fmmod.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = fir_bandpass (a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
FMMOD a;
|
||||||
|
a = txa[channel].fmmod.p;
|
||||||
|
if (a->mp != mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAFMAFFreqs (int channel, double low, double high)
|
||||||
|
{
|
||||||
|
FMMOD a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
a = txa[channel].fmmod.p;
|
||||||
|
if (a->f_low != low || a->f_high != high)
|
||||||
|
{
|
||||||
|
a->f_low = low;
|
||||||
|
a->f_high = high;
|
||||||
|
a->bp_fc = a->deviation + a->f_high;
|
||||||
|
impulse = fir_bandpass (a->nc, -a->bp_fc, +a->bp_fc, a->samplerate, 0, 1, 1.0 / (2 * a->size));
|
||||||
|
setImpulse_fircore (a->p, impulse, 1);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/* fmmod.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _fmmod_h
|
||||||
|
#define _fmmod_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _fmmod
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double samplerate;
|
||||||
|
double deviation;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
int ctcss_run;
|
||||||
|
double ctcss_level;
|
||||||
|
double ctcss_freq;
|
||||||
|
// for ctcss gen
|
||||||
|
double tscale;
|
||||||
|
double tphase;
|
||||||
|
double tdelta;
|
||||||
|
// mod
|
||||||
|
double sphase;
|
||||||
|
double sdelta;
|
||||||
|
// bandpass
|
||||||
|
int bp_run;
|
||||||
|
double bp_fc;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
FIRCORE p;
|
||||||
|
}fmmod, *FMMOD;
|
||||||
|
|
||||||
|
extern FMMOD create_fmmod (int run, int size, double* in, double* out, int rate, double dev, double f_low, double f_high,
|
||||||
|
int ctcss_run, double ctcss_level, double ctcss_freq, int bp_run, int nc, int mp);
|
||||||
|
|
||||||
|
extern void destroy_fmmod (FMMOD a);
|
||||||
|
|
||||||
|
extern void flush_fmmod (FMMOD a);
|
||||||
|
|
||||||
|
extern void xfmmod (FMMOD a);
|
||||||
|
|
||||||
|
extern void setBuffers_fmmod (FMMOD a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_fmmod (FMMOD a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_fmmod (FMMOD a, int size);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAFMDeviation (int channel, double deviation);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACTCSSFreq (int channel, double freq);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXACTCSSRun (int channel, int run);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAFMMP (int channel, int mp);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAFMNC (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAFMAFFreqs (int channel, double low, double high);
|
||||||
|
|
||||||
|
#endif
|
||||||
+279
@@ -0,0 +1,279 @@
|
|||||||
|
/* fmsq.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_fmsq (FMSQ a)
|
||||||
|
{
|
||||||
|
double delta, theta;
|
||||||
|
double* impulse;
|
||||||
|
int i;
|
||||||
|
// noise filter
|
||||||
|
a->noise = (double *)malloc0(2 * a->size * sizeof(complex));
|
||||||
|
a->F[0] = 0.0;
|
||||||
|
a->F[1] = a->fc;
|
||||||
|
a->F[2] = *a->pllpole;
|
||||||
|
a->F[3] = 20000.0;
|
||||||
|
a->G[0] = 0.0;
|
||||||
|
a->G[1] = 0.0;
|
||||||
|
a->G[2] = 3.0;
|
||||||
|
a->G[3] = +20.0 * log10(20000.0 / *a->pllpole);
|
||||||
|
impulse = eq_impulse (a->nc, 3, a->F, a->G, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
a->p = create_fircore (a->size, a->trigger, a->noise, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
// noise averaging
|
||||||
|
a->avm = exp(-1.0 / (a->rate * a->avtau));
|
||||||
|
a->onem_avm = 1.0 - a->avm;
|
||||||
|
a->avnoise = 100.0;
|
||||||
|
a->longavm = exp(-1.0 / (a->rate * a->longtau));
|
||||||
|
a->onem_longavm = 1.0 - a->longavm;
|
||||||
|
a->longnoise = 1.0;
|
||||||
|
// level change
|
||||||
|
a->ntup = (int)(a->tup * a->rate);
|
||||||
|
a->ntdown = (int)(a->tdown * a->rate);
|
||||||
|
a->cup = (double *)malloc0 ((a->ntup + 1) * sizeof(double));
|
||||||
|
a->cdown = (double *)malloc0 ((a->ntdown + 1) * sizeof(double));
|
||||||
|
delta = PI / (double)a->ntup;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ntup; i++)
|
||||||
|
{
|
||||||
|
a->cup[i] = 0.5 * (1.0 - cos(theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
delta = PI / (double)a->ntdown;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ntdown; i++)
|
||||||
|
{
|
||||||
|
a->cdown[i] = 0.5 * (1 + cos(theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
// control
|
||||||
|
a->state = 0;
|
||||||
|
a->ready = 0;
|
||||||
|
a->ramp = 0.0;
|
||||||
|
a->rstep = 1.0 / a->rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_fmsq (FMSQ a)
|
||||||
|
{
|
||||||
|
_aligned_free(a->cdown);
|
||||||
|
_aligned_free(a->cup);
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
_aligned_free(a->noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMSQ create_fmsq (int run, int size, double* insig, double* outsig, double* trigger, int rate, double fc,
|
||||||
|
double* pllpole, double tdelay, double avtau, double longtau, double tup, double tdown, double tail_thresh,
|
||||||
|
double unmute_thresh, double min_tail, double max_tail, int nc, int mp)
|
||||||
|
{
|
||||||
|
FMSQ a = (FMSQ) malloc0 (sizeof (fmsq));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->insig = insig;
|
||||||
|
a->outsig = outsig;
|
||||||
|
a->trigger = trigger;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->fc = fc;
|
||||||
|
a->pllpole = pllpole;
|
||||||
|
a->tdelay = tdelay;
|
||||||
|
a->avtau = avtau;
|
||||||
|
a->longtau = longtau;
|
||||||
|
a->tup = tup;
|
||||||
|
a->tdown = tdown;
|
||||||
|
a->tail_thresh = tail_thresh;
|
||||||
|
a->unmute_thresh = unmute_thresh;
|
||||||
|
a->min_tail = min_tail;
|
||||||
|
a->max_tail = max_tail;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
calc_fmsq (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_fmsq (FMSQ a)
|
||||||
|
{
|
||||||
|
decalc_fmsq (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_fmsq (FMSQ a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
a->avnoise = 100.0;
|
||||||
|
a->longnoise = 1.0;
|
||||||
|
a->state = 0;
|
||||||
|
a->ready = 0;
|
||||||
|
a->ramp = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _fmsqstate
|
||||||
|
{
|
||||||
|
MUTED,
|
||||||
|
INCREASE,
|
||||||
|
UNMUTED,
|
||||||
|
TAIL,
|
||||||
|
DECREASE
|
||||||
|
};
|
||||||
|
|
||||||
|
void xfmsq (FMSQ a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double noise, lnlimit;
|
||||||
|
xfircore (a->p);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
noise = sqrt(a->noise[2 * i + 0] * a->noise[2 * i + 0] + a->noise[2 * i + 1] * a->noise[2 * i + 1]);
|
||||||
|
a->avnoise = a->avm * a->avnoise + a->onem_avm * noise;
|
||||||
|
a->longnoise = a->longavm * a->longnoise + a->onem_longavm * noise;
|
||||||
|
if (!a->ready) a->ramp += a->rstep;
|
||||||
|
if (a->ramp >= a->tdelay) a->ready = 1;
|
||||||
|
|
||||||
|
switch (a->state)
|
||||||
|
{
|
||||||
|
case MUTED:
|
||||||
|
if (a->avnoise < a->unmute_thresh && a->ready)
|
||||||
|
{
|
||||||
|
a->state = INCREASE;
|
||||||
|
a->count = a->ntup;
|
||||||
|
}
|
||||||
|
a->outsig[2 * i + 0] = 0.0;
|
||||||
|
a->outsig[2 * i + 1] = 0.0;
|
||||||
|
break;
|
||||||
|
case INCREASE:
|
||||||
|
a->outsig[2 * i + 0] = a->insig[2 * i + 0] * a->cup[a->ntup - a->count];
|
||||||
|
a->outsig[2 * i + 1] = a->insig[2 * i + 1] * a->cup[a->ntup - a->count];
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = UNMUTED;
|
||||||
|
break;
|
||||||
|
case UNMUTED:
|
||||||
|
if (a->avnoise > a->tail_thresh)
|
||||||
|
{
|
||||||
|
a->state = TAIL;
|
||||||
|
if ((lnlimit = a->longnoise) > 1.0) lnlimit = 1.0;
|
||||||
|
a->count = (int)((a->min_tail + (a->max_tail - a->min_tail) * lnlimit) * a->rate);
|
||||||
|
}
|
||||||
|
a->outsig[2 * i + 0] = a->insig[2 * i + 0];
|
||||||
|
a->outsig[2 * i + 1] = a->insig[2 * i + 1];
|
||||||
|
break;
|
||||||
|
case TAIL:
|
||||||
|
a->outsig[2 * i + 0] = a->insig[2 * i + 0];
|
||||||
|
a->outsig[2 * i + 1] = a->insig[2 * i + 1];
|
||||||
|
if (a->avnoise < a->unmute_thresh)
|
||||||
|
a->state = UNMUTED;
|
||||||
|
else if (a->count-- == 0)
|
||||||
|
{
|
||||||
|
a->state = DECREASE;
|
||||||
|
a->count = a->ntdown;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DECREASE:
|
||||||
|
a->outsig[2 * i + 0] = a->insig[2 * i + 0] * a->cdown[a->ntdown - a->count];
|
||||||
|
a->outsig[2 * i + 1] = a->insig[2 * i + 1] * a->cdown[a->ntdown - a->count];
|
||||||
|
if (a->count-- == 0)
|
||||||
|
a->state = MUTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->insig != a->outsig)
|
||||||
|
memcpy (a->outsig, a->insig, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_fmsq (FMSQ a, double* in, double* out, double* trig)
|
||||||
|
{
|
||||||
|
a->insig = in;
|
||||||
|
a->outsig = out;
|
||||||
|
a->trigger = trig;
|
||||||
|
setBuffers_fircore (a->p, a->trigger, a->noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_fmsq (FMSQ a, int rate)
|
||||||
|
{
|
||||||
|
decalc_fmsq (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_fmsq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_fmsq (FMSQ a, int size)
|
||||||
|
{
|
||||||
|
decalc_fmsq (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_fmsq (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMSQRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].fmsq.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMSQThreshold (int channel, double threshold)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].fmsq.p->tail_thresh = threshold;
|
||||||
|
rxa[channel].fmsq.p->unmute_thresh = 0.9 * threshold;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMSQNC (int channel, int nc)
|
||||||
|
{
|
||||||
|
FMSQ a;
|
||||||
|
double* impulse;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = rxa[channel].fmsq.p;
|
||||||
|
if (a->nc != nc)
|
||||||
|
{
|
||||||
|
a->nc = nc;
|
||||||
|
impulse = eq_impulse (a->nc, 3, a->F, a->G, a->rate, 1.0 / (2.0 * a->size), 0, 0);
|
||||||
|
setNc_fircore (a->p, a->nc, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAFMSQMP (int channel, int mp)
|
||||||
|
{
|
||||||
|
FMSQ a;
|
||||||
|
a = rxa[channel].fmsq.p;
|
||||||
|
if (a->mp != mp)
|
||||||
|
{
|
||||||
|
a->mp = mp;
|
||||||
|
setMp_fircore (a->p, a->mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
/* fmsq.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _fmsq_h
|
||||||
|
#define _fmsq_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _fmsq
|
||||||
|
{
|
||||||
|
int run; // 0 if squelch system is OFF; 1 if it's ON
|
||||||
|
int size; // size of input/output buffers
|
||||||
|
double* insig; // squelch input signal buffer
|
||||||
|
double* outsig; // squelch output signal buffer
|
||||||
|
double* trigger; // buffer used to trigger mute/unmute (may be same as input; matches timing of input buffer)
|
||||||
|
double rate; // sample rate
|
||||||
|
double* noise;
|
||||||
|
double fc; // corner frequency for sig / noise detection
|
||||||
|
double* pllpole; // pointer to pole frequency of the fm demodulator pll
|
||||||
|
double F[4];
|
||||||
|
double G[4];
|
||||||
|
double avtau; // time constant for averaging noise
|
||||||
|
double avm;
|
||||||
|
double onem_avm;
|
||||||
|
double avnoise;
|
||||||
|
double longtau; // time constant for long averaging
|
||||||
|
double longavm;
|
||||||
|
double onem_longavm;
|
||||||
|
double longnoise;
|
||||||
|
int state; // state machine control
|
||||||
|
int count;
|
||||||
|
double tup;
|
||||||
|
double tdown;
|
||||||
|
int ntup;
|
||||||
|
int ntdown;
|
||||||
|
double* cup;
|
||||||
|
double* cdown;
|
||||||
|
double tail_thresh;
|
||||||
|
double unmute_thresh;
|
||||||
|
double min_tail;
|
||||||
|
double max_tail;
|
||||||
|
int ready;
|
||||||
|
double ramp;
|
||||||
|
double rstep;
|
||||||
|
double tdelay;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
FIRCORE p;
|
||||||
|
} fmsq, *FMSQ;
|
||||||
|
|
||||||
|
extern FMSQ create_fmsq (int run, int size, double* insig, double* outsig, double* trigger, int rate, double fc,
|
||||||
|
double* pllpole, double tdelay, double avtau, double longtau, double tup, double tdown, double tail_thresh,
|
||||||
|
double unmute_thresh, double min_tail, double max_tail, int nc, int mp);
|
||||||
|
|
||||||
|
extern void destroy_fmsq (FMSQ a);
|
||||||
|
|
||||||
|
extern void flush_fmsq (FMSQ a);
|
||||||
|
|
||||||
|
extern void xfmsq (FMSQ a);
|
||||||
|
|
||||||
|
extern void setBuffers_fmsq (FMSQ a, double* in, double* out, double* trig);
|
||||||
|
|
||||||
|
extern void setSamplerate_fmsq (FMSQ a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_fmsq (FMSQ a, int size);
|
||||||
|
|
||||||
|
// RXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMSQThreshold (int channel, double threshold);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMSQNC (int channel, int nc);
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetRXAFMSQMP (int channel, int mp);
|
||||||
|
|
||||||
|
#endif
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
/* gain.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
PORT
|
||||||
|
GAIN create_gain (int run, int* prun, int size, double* in, double* out, double Igain, double Qgain)
|
||||||
|
{
|
||||||
|
GAIN a = (GAIN) malloc0 (sizeof (gain));
|
||||||
|
a->run = run;
|
||||||
|
a->prun = prun;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->Igain = Igain;
|
||||||
|
a->Qgain = Qgain;
|
||||||
|
InitializeCriticalSectionAndSpinCount(&a->cs_update, 2500);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void destroy_gain (GAIN a)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection (&a->cs_update);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void flush_gain (GAIN a)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void xgain (GAIN a)
|
||||||
|
{
|
||||||
|
int srun;
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
if (a->prun != 0)
|
||||||
|
srun = *(a->prun);
|
||||||
|
else
|
||||||
|
srun = 1;
|
||||||
|
if (a->run && srun)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = a->Igain * a->in[2 * i + 0];
|
||||||
|
a->out[2 * i + 1] = a->Qgain * a->in[2 * i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_gain (GAIN a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_gain (GAIN a, int rate)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_gain (GAIN a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* POINTER-BASED PROPERTIES *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetTXOutputLevel (GAIN a, double level)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->Igain = level;
|
||||||
|
a->Qgain = level;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetTXOutputLevelRun (GAIN a, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->run = run;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void pSetTXOutputLevelSize (GAIN a, int size)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->cs_update);
|
||||||
|
a->size = size;
|
||||||
|
LeaveCriticalSection (&a->cs_update);
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/* gain.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _gain_h
|
||||||
|
#define _gain_h
|
||||||
|
|
||||||
|
typedef struct _gain
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int* prun;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double Igain;
|
||||||
|
double Qgain;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
}gain, *GAIN;
|
||||||
|
|
||||||
|
__declspec (dllexport) GAIN create_gain (int run, int* prun, int size, double* in, double* out, double Igain, double Qgain);
|
||||||
|
|
||||||
|
__declspec (dllexport) void destroy_gain (GAIN a);
|
||||||
|
|
||||||
|
__declspec (dllexport) void flush_gain (GAIN a);
|
||||||
|
|
||||||
|
__declspec (dllexport) void xgain (GAIN a);
|
||||||
|
|
||||||
|
extern void setBuffers_gain (GAIN a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_gain (GAIN a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_gain (GAIN a, int size);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
// POINTER-BASED Properties
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetTXOutputLevel (GAIN a, double level);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetTXOutputLevelRun (GAIN a, int run);
|
||||||
|
|
||||||
|
__declspec (dllexport) void pSetTXOutputLevelSize (GAIN a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+686
@@ -0,0 +1,686 @@
|
|||||||
|
/* gen.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_tone (GEN a)
|
||||||
|
{
|
||||||
|
a->tone.phs = 0.0;
|
||||||
|
a->tone.delta = TWOPI * a->tone.freq / a->rate;
|
||||||
|
a->tone.cosdelta = cos (a->tone.delta);
|
||||||
|
a->tone.sindelta = sin (a->tone.delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_tt (GEN a)
|
||||||
|
{
|
||||||
|
a->tt.phs1 = 0.0;
|
||||||
|
a->tt.phs2 = 0.0;
|
||||||
|
a->tt.delta1 = TWOPI * a->tt.f1 / a->rate;
|
||||||
|
a->tt.delta2 = TWOPI * a->tt.f2 / a->rate;
|
||||||
|
a->tt.cosdelta1 = cos (a->tt.delta1);
|
||||||
|
a->tt.cosdelta2 = cos (a->tt.delta2);
|
||||||
|
a->tt.sindelta1 = sin (a->tt.delta1);
|
||||||
|
a->tt.sindelta2 = sin (a->tt.delta2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_sweep (GEN a)
|
||||||
|
{
|
||||||
|
a->sweep.phs = 0.0;
|
||||||
|
a->sweep.dphs = TWOPI * a->sweep.f1 / a->rate;
|
||||||
|
a->sweep.d2phs = TWOPI * a->sweep.sweeprate / (a->rate * a->rate);
|
||||||
|
a->sweep.dphsmax = TWOPI * a->sweep.f2 / a->rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_sawtooth (GEN a)
|
||||||
|
{
|
||||||
|
a->saw.period = 1.0 / a->saw.f;
|
||||||
|
a->saw.delta = 1.0 / a->rate;
|
||||||
|
a->saw.t = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_triangle (GEN a)
|
||||||
|
{
|
||||||
|
a->tri.period = 1.0 / a->tri.f;
|
||||||
|
a->tri.half = 0.5 * a->tri.period;
|
||||||
|
a->tri.delta = 1.0 / a->rate;
|
||||||
|
a->tri.t = 0.0;
|
||||||
|
a->tri.t1 = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_pulse (GEN a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double delta, theta;
|
||||||
|
a->pulse.pperiod = 1.0 / a->pulse.pf;
|
||||||
|
a->pulse.tphs = 0.0;
|
||||||
|
a->pulse.tdelta = TWOPI * a->pulse.tf / a->rate;
|
||||||
|
a->pulse.tcosdelta = cos (a->pulse.tdelta);
|
||||||
|
a->pulse.tsindelta = sin (a->pulse.tdelta);
|
||||||
|
a->pulse.pntrans = (int)(a->pulse.ptranstime * a->rate);
|
||||||
|
a->pulse.pnon = (int)(a->pulse.pdutycycle * a->pulse.pperiod * a->rate);
|
||||||
|
a->pulse.pnoff = (int)(a->pulse.pperiod * a->rate) - a->pulse.pnon - 2 * a->pulse.pntrans;
|
||||||
|
if (a->pulse.pnoff < 0) a->pulse.pnoff = 0;
|
||||||
|
a->pulse.pcount = a->pulse.pnoff;
|
||||||
|
a->pulse.state = 0;
|
||||||
|
a->pulse.ctrans = (double *) malloc0 ((a->pulse.pntrans + 1) * sizeof (double));
|
||||||
|
delta = PI / (double)a->pulse.pntrans;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->pulse.pntrans; i++)
|
||||||
|
{
|
||||||
|
a->pulse.ctrans[i] = 0.5 * (1.0 - cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_gen (GEN a)
|
||||||
|
{
|
||||||
|
calc_tone (a);
|
||||||
|
calc_tt (a);
|
||||||
|
calc_sweep (a);
|
||||||
|
calc_sawtooth (a);
|
||||||
|
calc_triangle (a);
|
||||||
|
calc_pulse (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_gen (GEN a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->pulse.ctrans);
|
||||||
|
}
|
||||||
|
|
||||||
|
GEN create_gen (int run, int size, double* in, double* out, int rate, int mode)
|
||||||
|
{
|
||||||
|
GEN a = (GEN) malloc0 (sizeof (gen));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = (double)rate;
|
||||||
|
a->mode = mode;
|
||||||
|
// tone
|
||||||
|
a->tone.mag = 1.0;
|
||||||
|
a->tone.freq = 1000.0;
|
||||||
|
// two-tone
|
||||||
|
a->tt.mag1 = 0.5;
|
||||||
|
a->tt.mag2 = 0.5;
|
||||||
|
a->tt.f1 = + 900.0;
|
||||||
|
a->tt.f2 = + 1700.0;
|
||||||
|
// noise
|
||||||
|
srand ((unsigned int)time (0));
|
||||||
|
a->noise.mag = 1.0;
|
||||||
|
// sweep
|
||||||
|
a->sweep.mag = 1.0;
|
||||||
|
a->sweep.f1 = -20000.0;
|
||||||
|
a->sweep.f2 = +20000.0;
|
||||||
|
a->sweep.sweeprate = +4000.0;
|
||||||
|
// sawtooth
|
||||||
|
a->saw.mag = 1.0;
|
||||||
|
a->saw.f = 500.0;
|
||||||
|
// triangle
|
||||||
|
a->tri.mag = 1.0;
|
||||||
|
a->tri.f = 500.0;
|
||||||
|
// pulse
|
||||||
|
a->pulse.mag = 1.0;
|
||||||
|
a->pulse.pf = 0.25;
|
||||||
|
a->pulse.pdutycycle = 0.25;
|
||||||
|
a->pulse.ptranstime = 0.002;
|
||||||
|
a->pulse.tf = 1000.0;
|
||||||
|
calc_gen (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_gen (GEN a)
|
||||||
|
{
|
||||||
|
decalc_gen (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_gen (GEN a)
|
||||||
|
{
|
||||||
|
a->pulse.state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum pstate
|
||||||
|
{
|
||||||
|
OFF,
|
||||||
|
UP,
|
||||||
|
ON,
|
||||||
|
DOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
void xgen (GEN a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
{
|
||||||
|
switch (a->mode)
|
||||||
|
{
|
||||||
|
case 0: // tone
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double t1, t2;
|
||||||
|
double cosphase = cos (a->tone.phs);
|
||||||
|
double sinphase = sin (a->tone.phs);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = + a->tone.mag * cosphase;
|
||||||
|
a->out[2 * i + 1] = - a->tone.mag * sinphase;
|
||||||
|
t1 = cosphase;
|
||||||
|
t2 = sinphase;
|
||||||
|
cosphase = t1 * a->tone.cosdelta - t2 * a->tone.sindelta;
|
||||||
|
sinphase = t1 * a->tone.sindelta + t2 * a->tone.cosdelta;
|
||||||
|
a->tone.phs += a->tone.delta;
|
||||||
|
if (a->tone.phs >= TWOPI) a->tone.phs -= TWOPI;
|
||||||
|
if (a->tone.phs < 0.0 ) a->tone.phs += TWOPI;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: // two-tone
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double tcos, tsin;
|
||||||
|
double cosphs1 = cos (a->tt.phs1);
|
||||||
|
double sinphs1 = sin (a->tt.phs1);
|
||||||
|
double cosphs2 = cos (a->tt.phs2);
|
||||||
|
double sinphs2 = sin (a->tt.phs2);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = + a->tt.mag1 * cosphs1 + a->tt.mag2 * cosphs2;
|
||||||
|
a->out[2 * i + 1] = - a->tt.mag1 * sinphs1 - a->tt.mag2 * sinphs2;
|
||||||
|
tcos = cosphs1;
|
||||||
|
tsin = sinphs1;
|
||||||
|
cosphs1 = tcos * a->tt.cosdelta1 - tsin * a->tt.sindelta1;
|
||||||
|
sinphs1 = tcos * a->tt.sindelta1 + tsin * a->tt.cosdelta1;
|
||||||
|
a->tt.phs1 += a->tt.delta1;
|
||||||
|
if (a->tt.phs1 >= TWOPI) a->tt.phs1 -= TWOPI;
|
||||||
|
if (a->tt.phs1 < 0.0 ) a->tt.phs1 += TWOPI;
|
||||||
|
tcos = cosphs2;
|
||||||
|
tsin = sinphs2;
|
||||||
|
cosphs2 = tcos * a->tt.cosdelta2 - tsin * a->tt.sindelta2;
|
||||||
|
sinphs2 = tcos * a->tt.sindelta2 + tsin * a->tt.cosdelta2;
|
||||||
|
a->tt.phs2 += a->tt.delta2;
|
||||||
|
if (a->tt.phs2 >= TWOPI) a->tt.phs2 -= TWOPI;
|
||||||
|
if (a->tt.phs2 < 0.0 ) a->tt.phs2 += TWOPI;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: // noise
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double r1, r2, c, rad;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r1 = 2.0 * (double)rand() / (double)RAND_MAX - 1.0;
|
||||||
|
r2 = 2.0 * (double)rand() / (double)RAND_MAX - 1.0;
|
||||||
|
c = r1 * r1 + r2 * r2;
|
||||||
|
} while (c >= 1.0);
|
||||||
|
rad = sqrt (-2.0 * log (c) / c);
|
||||||
|
a->out[2 * i + 0] = a->noise.mag * rad * r1;
|
||||||
|
a->out[2 * i + 1] = a->noise.mag * rad * r2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: // sweep
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
a->out[2 * i + 0] = + a->sweep.mag * cos(a->sweep.phs);
|
||||||
|
a->out[2 * i + 1] = - a->sweep.mag * sin(a->sweep.phs);
|
||||||
|
a->sweep.phs += a->sweep.dphs;
|
||||||
|
a->sweep.dphs += a->sweep.d2phs;
|
||||||
|
if (a->sweep.phs >= TWOPI) a->sweep.phs -= TWOPI;
|
||||||
|
if (a->sweep.phs < 0.0 ) a->sweep.phs += TWOPI;
|
||||||
|
if (a->sweep.dphs > a->sweep.dphsmax)
|
||||||
|
a->sweep.dphs = TWOPI * a->sweep.f1 / a->rate;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: // sawtooth (audio only)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
if (a->saw.t > a->saw.period) a->saw.t -= a->saw.period;
|
||||||
|
a->out[2 * i + 0] = a->saw.mag * (a->saw.t * a->saw.f - 1.0);
|
||||||
|
a->out[2 * i + 1] = 0.0;
|
||||||
|
a->saw.t += a->saw.delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // triangle (audio only)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
if (a->tri.t > a->tri.period) a->tri.t1 = a->tri.t -= a->tri.period;
|
||||||
|
if (a->tri.t > a->tri.half) a->tri.t1 -= a->tri.delta;
|
||||||
|
else a->tri.t1 += a->tri.delta;
|
||||||
|
a->out[2 * i + 0] = a->tri.mag * (4.0 * a->tri.t1 * a->tri.f - 1.0);
|
||||||
|
a->out[2 * i + 1] = 0.0;
|
||||||
|
a->tri.t += a->tri.delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6: // pulse (audio only)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double t1, t2;
|
||||||
|
double cosphase = cos (a->pulse.tphs);
|
||||||
|
double sinphase = sin (a->pulse.tphs);
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
if (a->pulse.pnoff != 0)
|
||||||
|
switch (a->pulse.state)
|
||||||
|
{
|
||||||
|
case OFF:
|
||||||
|
a->out[2 * i + 0] = 0.0;
|
||||||
|
if (--a->pulse.pcount == 0)
|
||||||
|
{
|
||||||
|
a->pulse.state = UP;
|
||||||
|
a->pulse.pcount = a->pulse.pntrans;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
a->out[2 * i + 0] = a->pulse.mag * cosphase * a->pulse.ctrans[a->pulse.pntrans - a->pulse.pcount];
|
||||||
|
if (--a->pulse.pcount == 0)
|
||||||
|
{
|
||||||
|
a->pulse.state = ON;
|
||||||
|
a->pulse.pcount = a->pulse.pnon;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ON:
|
||||||
|
a->out[2 * i + 0] = a->pulse.mag * cosphase;
|
||||||
|
if (--a->pulse.pcount == 0)
|
||||||
|
{
|
||||||
|
a->pulse.state = DOWN;
|
||||||
|
a->pulse.pcount = a->pulse.pntrans;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
a->out[2 * i + 0] = a->pulse.mag * cosphase * a->pulse.ctrans[a->pulse.pcount];
|
||||||
|
if (--a->pulse.pcount == 0)
|
||||||
|
{
|
||||||
|
a->pulse.state = OFF;
|
||||||
|
a->pulse.pcount = a->pulse.pnoff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a->out[2 * i + 0] = 0.0;
|
||||||
|
a->out[2 * i + 1] = 0.0;
|
||||||
|
t1 = cosphase;
|
||||||
|
t2 = sinphase;
|
||||||
|
cosphase = t1 * a->pulse.tcosdelta - t2 * a->pulse.tsindelta;
|
||||||
|
sinphase = t1 * a->pulse.tsindelta + t2 * a->pulse.tcosdelta;
|
||||||
|
a->pulse.tphs += a->pulse.tdelta;
|
||||||
|
if (a->pulse.tphs >= TWOPI) a->pulse.tphs -= TWOPI;
|
||||||
|
if (a->pulse.tphs < 0.0 ) a->pulse.tphs += TWOPI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // silence
|
||||||
|
{
|
||||||
|
memset (a->out, 0, a->size * sizeof (complex));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_gen (GEN a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_gen (GEN a, int rate)
|
||||||
|
{
|
||||||
|
decalc_gen (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_gen (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_gen (GEN a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
flush_gen (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* RXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
// 'PreGen', gen0
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenMode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->mode = mode;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenToneMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->tone.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenToneFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->tone.freq = freq;
|
||||||
|
calc_tone (rxa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenNoiseMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->noise.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenSweepMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->sweep.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenSweepFreq (int channel, double freq1, double freq2)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->sweep.f1 = freq1;
|
||||||
|
rxa[channel].gen0.p->sweep.f2 = freq2;
|
||||||
|
calc_sweep (rxa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetRXAPreGenSweepRate (int channel, double rate)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
rxa[channel].gen0.p->sweep.sweeprate = rate;
|
||||||
|
calc_sweep (rxa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
// 'PreGen', gen0
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenMode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->mode = mode;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenToneMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->tone.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenToneFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->tone.freq = freq;
|
||||||
|
calc_tone (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenNoiseMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->noise.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenSweepMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->sweep.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenSweepFreq (int channel, double freq1, double freq2)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->sweep.f1 = freq1;
|
||||||
|
txa[channel].gen0.p->sweep.f2 = freq2;
|
||||||
|
calc_sweep (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenSweepRate (int channel, double rate)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->sweep.sweeprate = rate;
|
||||||
|
calc_sweep (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenSawtoothMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->saw.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenSawtoothFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->saw.f = freq;
|
||||||
|
calc_sawtooth (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenTriangleMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->tri.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenTriangleFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->tri.f = freq;
|
||||||
|
calc_triangle (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenPulseMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->pulse.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenPulseFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->pulse.pf = freq;
|
||||||
|
calc_pulse (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenPulseDutyCycle (int channel, double dc)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->pulse.pdutycycle = dc;
|
||||||
|
calc_pulse (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenPulseToneFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->pulse.tf = freq;
|
||||||
|
calc_pulse (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPreGenPulseTransition (int channel, double transtime)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen0.p->pulse.ptranstime = transtime;
|
||||||
|
calc_pulse (txa[channel].gen0.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'PostGen', gen1
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenRun (int channel, int run)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->run = run;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenMode (int channel, int mode)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->mode = mode;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenToneMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->tone.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenToneFreq (int channel, double freq)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->tone.freq = freq;
|
||||||
|
calc_tone (txa[channel].gen1.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenTTMag (int channel, double mag1, double mag2)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->tt.mag1 = mag1;
|
||||||
|
txa[channel].gen1.p->tt.mag2 = mag2;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenTTFreq (int channel, double freq1, double freq2)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->tt.f1 = freq1;
|
||||||
|
txa[channel].gen1.p->tt.f2 = freq2;
|
||||||
|
calc_tt (txa[channel].gen1.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenSweepMag (int channel, double mag)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->sweep.mag = mag;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenSweepFreq (int channel, double freq1, double freq2)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->sweep.f1 = freq1;
|
||||||
|
txa[channel].gen1.p->sweep.f2 = freq2;
|
||||||
|
calc_sweep (txa[channel].gen1.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAPostGenSweepRate (int channel, double rate)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
txa[channel].gen1.p->sweep.sweeprate = rate;
|
||||||
|
calc_sweep (txa[channel].gen1.p);
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
/* gen.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _gen_h
|
||||||
|
#define _gen_h
|
||||||
|
|
||||||
|
typedef struct _gen
|
||||||
|
{
|
||||||
|
int run; // run
|
||||||
|
int size; // number of samples per buffer
|
||||||
|
double* in; // input buffer (retained in case I want to mix in a generated signal)
|
||||||
|
double* out; // output buffer
|
||||||
|
double rate; // sample rate
|
||||||
|
int mode;
|
||||||
|
struct _tone
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
double freq;
|
||||||
|
double phs;
|
||||||
|
double delta;
|
||||||
|
double cosdelta;
|
||||||
|
double sindelta;
|
||||||
|
} tone;
|
||||||
|
struct _tt
|
||||||
|
{
|
||||||
|
double mag1;
|
||||||
|
double mag2;
|
||||||
|
double f1;
|
||||||
|
double f2;
|
||||||
|
double phs1;
|
||||||
|
double phs2;
|
||||||
|
double delta1;
|
||||||
|
double delta2;
|
||||||
|
double cosdelta1;
|
||||||
|
double cosdelta2;
|
||||||
|
double sindelta1;
|
||||||
|
double sindelta2;
|
||||||
|
} tt;
|
||||||
|
struct _noise
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
} noise;
|
||||||
|
struct _sweep
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
double f1;
|
||||||
|
double f2;
|
||||||
|
double sweeprate;
|
||||||
|
double phs;
|
||||||
|
double dphs;
|
||||||
|
double d2phs;
|
||||||
|
double dphsmax;
|
||||||
|
} sweep;
|
||||||
|
struct _saw
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
double f;
|
||||||
|
double period;
|
||||||
|
double delta;
|
||||||
|
double t;
|
||||||
|
} saw;
|
||||||
|
struct _tri
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
double f;
|
||||||
|
double period;
|
||||||
|
double half;
|
||||||
|
double delta;
|
||||||
|
double t;
|
||||||
|
double t1;
|
||||||
|
} tri;
|
||||||
|
struct _pulse
|
||||||
|
{
|
||||||
|
double mag;
|
||||||
|
double pf;
|
||||||
|
double pdutycycle;
|
||||||
|
double ptranstime;
|
||||||
|
double* ctrans;
|
||||||
|
int pcount;
|
||||||
|
int pnon;
|
||||||
|
int pntrans;
|
||||||
|
int pnoff;
|
||||||
|
double pperiod;
|
||||||
|
double tf;
|
||||||
|
double tphs;
|
||||||
|
double tdelta;
|
||||||
|
double tcosdelta;
|
||||||
|
double tsindelta;
|
||||||
|
int state;
|
||||||
|
} pulse;
|
||||||
|
} gen, *GEN;
|
||||||
|
|
||||||
|
extern GEN create_gen (int run, int size, double* in, double* out, int rate, int mode);
|
||||||
|
|
||||||
|
extern void destroy_gen (GEN a);
|
||||||
|
|
||||||
|
extern void flush_gen (GEN a);
|
||||||
|
|
||||||
|
extern void xgen (GEN a);
|
||||||
|
|
||||||
|
extern void setBuffers_gen (GEN a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_gen (GEN a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_gen (GEN a, int size);
|
||||||
|
|
||||||
|
// TXA Properties
|
||||||
|
|
||||||
|
extern __declspec (dllexport) void SetTXAgenRun (int channel, int run);
|
||||||
|
|
||||||
|
#endif
|
||||||
+221
@@ -0,0 +1,221 @@
|
|||||||
|
/* icfir.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@pratt.one
|
||||||
|
|
||||||
|
*/
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void calc_icfir (ICFIR a)
|
||||||
|
{
|
||||||
|
double* impulse;
|
||||||
|
a->scale = 1.0 / (double)(2 * a->size);
|
||||||
|
impulse = icfir_impulse (a->nc, a->DD, a->R, a->Pairs, a->runrate, a->cicrate, a->cutoff, a->xtype, a->xbw, 1, a->scale, a->wintype);
|
||||||
|
a->p = create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||||
|
_aligned_free (impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_icfir (ICFIR a)
|
||||||
|
{
|
||||||
|
destroy_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
ICFIR create_icfir (int run, int size, int nc, int mp, double* in, double* out, int runrate, int cicrate,
|
||||||
|
int DD, int R, int Pairs, double cutoff, int xtype, double xbw, int wintype)
|
||||||
|
// run: 0 - no action; 1 - operate
|
||||||
|
// size: number of complex samples in an input buffer to the CFIR filter
|
||||||
|
// nc: number of filter coefficients
|
||||||
|
// mp: minimum phase flag
|
||||||
|
// in: pointer to the input buffer
|
||||||
|
// out: pointer to the output buffer
|
||||||
|
// rate: samplerate
|
||||||
|
// DD: differential delay of the CIC to be compensated (usually 1 or 2)
|
||||||
|
// R: interpolation factor of CIC
|
||||||
|
// Pairs: number of comb-integrator pairs in the CIC
|
||||||
|
// cutoff: cutoff frequency
|
||||||
|
// xtype: 0 - fourth power transition; 1 - raised cosine transition
|
||||||
|
// xbw: width of raised cosine transition
|
||||||
|
{
|
||||||
|
ICFIR a = (ICFIR) malloc0 (sizeof (icfir));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->nc = nc;
|
||||||
|
a->mp = mp;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->runrate = runrate;
|
||||||
|
a->cicrate = cicrate;
|
||||||
|
a->DD = DD;
|
||||||
|
a->R = R;
|
||||||
|
a->Pairs = Pairs;
|
||||||
|
a->cutoff = cutoff;
|
||||||
|
a->xtype = xtype;
|
||||||
|
a->xbw = xbw;
|
||||||
|
a->wintype = wintype;
|
||||||
|
calc_icfir (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_icfir (ICFIR a)
|
||||||
|
{
|
||||||
|
decalc_icfir (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_icfir (ICFIR a)
|
||||||
|
{
|
||||||
|
flush_fircore (a->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xicfir (ICFIR a)
|
||||||
|
{
|
||||||
|
if (a->run)
|
||||||
|
xfircore (a->p);
|
||||||
|
else if (a->in != a->out)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_icfir (ICFIR a, double* in, double* out)
|
||||||
|
{
|
||||||
|
decalc_icfir (a);
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
calc_icfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_icfir (ICFIR a, int rate)
|
||||||
|
{
|
||||||
|
decalc_icfir (a);
|
||||||
|
a->runrate = rate;
|
||||||
|
calc_icfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_icfir (ICFIR a, int size)
|
||||||
|
{
|
||||||
|
decalc_icfir (a);
|
||||||
|
a->size = size;
|
||||||
|
calc_icfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOutRate_icfir (ICFIR a, int rate)
|
||||||
|
{
|
||||||
|
decalc_icfir (a);
|
||||||
|
a->cicrate = rate;
|
||||||
|
calc_icfir (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
double* icfir_impulse (int N, int DD, int R, int Pairs, double runrate, double cicrate, double cutoff, int xtype, double xbw, int rtype, double scale, int wintype)
|
||||||
|
{
|
||||||
|
// N: number of impulse response samples
|
||||||
|
// DD: differential delay used in the CIC filter
|
||||||
|
// R: interpolation / decimation factor of the CIC
|
||||||
|
// Pairs: number of comb-integrator pairs in the CIC
|
||||||
|
// runrate: sample rate at which this filter is to run (assumes there may be flat interp. between this filter and the CIC)
|
||||||
|
// cicrate: sample rate at interface to CIC
|
||||||
|
// cutoff: cutoff frequency
|
||||||
|
// xtype: transition type, 0 for 4th-power rolloff, 1 for raised cosine
|
||||||
|
// xbw: transition bandwidth for raised cosine
|
||||||
|
// rtype: 0 for real output, 1 for complex output
|
||||||
|
// scale: scale factor to be applied to the output
|
||||||
|
int i, j;
|
||||||
|
double tmp, local_scale, ri, mag, fn;
|
||||||
|
double* impulse;
|
||||||
|
double* A = (double *) malloc0 (N * sizeof (double));
|
||||||
|
double ft = cutoff / cicrate; // normalized cutoff frequency
|
||||||
|
int u_samps = (N + 1) / 2; // number of unique samples, OK for odd or even N
|
||||||
|
int c_samps = (int)(cutoff / runrate * N) + (N + 1) / 2 - N / 2; // number of unique samples within bandpass, OK for odd or even N
|
||||||
|
int x_samps = (int)(xbw / runrate * N); // number of unique samples in transition region, OK for odd or even N
|
||||||
|
double offset = 0.5 - 0.5 * (double)((N + 1) / 2 - N / 2); // sample offset from center, OK for odd or even N
|
||||||
|
double* xistion = (double *) malloc0 ((x_samps + 1) * sizeof (double));
|
||||||
|
double delta = PI / (double)x_samps;
|
||||||
|
double L = cicrate / runrate;
|
||||||
|
double phs = 0.0;
|
||||||
|
for (i = 0; i <= x_samps; i++)
|
||||||
|
{
|
||||||
|
xistion[i] = 0.5 * (cos (phs) + 1.0);
|
||||||
|
phs += delta;
|
||||||
|
}
|
||||||
|
if ((tmp = DD * R * sin (PI * ft / R) / sin (PI * DD * ft)) < 0.0) //normalize by peak gain
|
||||||
|
tmp = -tmp;
|
||||||
|
local_scale = scale / pow (tmp, Pairs);
|
||||||
|
if (xtype == 0)
|
||||||
|
{
|
||||||
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
||||||
|
{
|
||||||
|
fn = ri / (L * (double)N);
|
||||||
|
if (fn <= ft)
|
||||||
|
{
|
||||||
|
if (fn == 0.0) tmp = 1.0;
|
||||||
|
else if ((tmp = sin (PI * DD * fn) / (DD * R * sin (PI * fn / R))) < 0.0)
|
||||||
|
tmp = -tmp;
|
||||||
|
mag = pow (tmp, Pairs) * local_scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mag *= (ft * ft * ft * ft) / (fn * fn * fn * fn);
|
||||||
|
A[i] = mag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xtype == 1)
|
||||||
|
{
|
||||||
|
for (i = 0, ri = offset; i < u_samps; i++, ri += 1.0)
|
||||||
|
{
|
||||||
|
fn = ri / (L *(double)N);
|
||||||
|
if (i < c_samps)
|
||||||
|
{
|
||||||
|
if (fn == 0.0) tmp = 1.0;
|
||||||
|
else if ((tmp = sin (PI * DD * fn) / (DD * R * sin (PI * fn / R))) < 0.0)
|
||||||
|
tmp = -tmp;
|
||||||
|
mag = pow (tmp, Pairs) * local_scale;
|
||||||
|
A[i] = mag;
|
||||||
|
}
|
||||||
|
else if ( i >= c_samps && i <= c_samps + x_samps)
|
||||||
|
A[i] = mag * xistion[i - c_samps];
|
||||||
|
else
|
||||||
|
A[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (N & 1)
|
||||||
|
for (i = u_samps, j = 2; i < N; i++, j++)
|
||||||
|
A[i] = A[u_samps - j];
|
||||||
|
else
|
||||||
|
for (i = u_samps, j = 1; i < N; i++, j++)
|
||||||
|
A[i] = A[u_samps - j];
|
||||||
|
impulse = fir_fsamp (N, A, rtype, 1.0, wintype);
|
||||||
|
// print_impulse ("icfirImpulse.txt", N, impulse, 1, 0);
|
||||||
|
_aligned_free (A);
|
||||||
|
return impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
//PORT void
|
||||||
|
//SetTXAICFIRRun (int channel, int run)
|
||||||
|
//{
|
||||||
|
// EnterCriticalSection(&ch[channel].csDSP);
|
||||||
|
// txa[channel].icfir.p->run = run;
|
||||||
|
// LeaveCriticalSection(&ch[channel].csDSP);
|
||||||
|
//}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/* icfir.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@pratt.one
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _icfir_h
|
||||||
|
#define _icfir_h
|
||||||
|
#include "firmin.h"
|
||||||
|
typedef struct _icfir
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
int nc;
|
||||||
|
int mp;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int runrate;
|
||||||
|
int cicrate;
|
||||||
|
int DD;
|
||||||
|
int R;
|
||||||
|
int Pairs;
|
||||||
|
double cutoff;
|
||||||
|
double scale;
|
||||||
|
int xtype;
|
||||||
|
double xbw;
|
||||||
|
int wintype;
|
||||||
|
FIRCORE p;
|
||||||
|
} icfir, *ICFIR;
|
||||||
|
|
||||||
|
extern ICFIR create_icfir (int run, int size, int nc, int mp, double* in, double* out, int runrate, int cicrate,
|
||||||
|
int DD, int R, int Pairs, double cutoff, int xtype, double xbw, int wintype);
|
||||||
|
|
||||||
|
extern void destroy_icfir (ICFIR a);
|
||||||
|
|
||||||
|
extern void flush_icfir (ICFIR a);
|
||||||
|
|
||||||
|
extern void xicfir (ICFIR a);
|
||||||
|
|
||||||
|
extern void setBuffers_icfir (ICFIR a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_icfir (ICFIR a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_icfir (ICFIR a, int size);
|
||||||
|
|
||||||
|
extern void setOutRate_icfir (ICFIR a, int rate);
|
||||||
|
|
||||||
|
extern double* icfir_impulse (int N, int DD, int R, int Pairs, double runrate, double cicrate,
|
||||||
|
double cutoff, int xtype, double xbw, int rtype, double scale, int wintype);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1380
File diff suppressed because it is too large
Load Diff
+393
@@ -0,0 +1,393 @@
|
|||||||
|
/* iir.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2014, 2022, 2023 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Bi-Quad Notch *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _snotch_h
|
||||||
|
#define _snotch_h
|
||||||
|
|
||||||
|
typedef struct _snotch
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double f;
|
||||||
|
double bw;
|
||||||
|
double a0, a1, a2, b1, b2;
|
||||||
|
double x0, x1, x2, y1, y2;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} snotch, *SNOTCH;
|
||||||
|
|
||||||
|
extern SNOTCH create_snotch (int run, int size, double* in, double* out, int rate, double f, double bw);
|
||||||
|
|
||||||
|
extern void destroy_snotch (SNOTCH a);
|
||||||
|
|
||||||
|
extern void flush_snotch (SNOTCH a);
|
||||||
|
|
||||||
|
extern void xsnotch (SNOTCH a);
|
||||||
|
|
||||||
|
extern void setBuffers_snotch (SNOTCH a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_snotch (SNOTCH a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_snotch (SNOTCH a, int size);
|
||||||
|
|
||||||
|
extern void SetSNCTCSSFreq (SNOTCH a, double freq);
|
||||||
|
|
||||||
|
extern void SetSNCTCSSRun (SNOTCH a, int run);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Complex Bi-Quad Peaking *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _speak_h
|
||||||
|
#define _speak_h
|
||||||
|
|
||||||
|
typedef struct _speak
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double f;
|
||||||
|
double bw;
|
||||||
|
double cbw;
|
||||||
|
double gain;
|
||||||
|
double fgain;
|
||||||
|
int nstages;
|
||||||
|
int design;
|
||||||
|
double a0, a1, a2, b1, b2;
|
||||||
|
double *x0, *x1, *x2, *y0, *y1, *y2;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} speak, *SPEAK;
|
||||||
|
|
||||||
|
extern SPEAK create_speak (int run, int size, double* in, double* out, int rate, double f, double bw, double gain, int nstages, int design);
|
||||||
|
|
||||||
|
extern void destroy_speak (SPEAK a);
|
||||||
|
|
||||||
|
extern void flush_speak (SPEAK a);
|
||||||
|
|
||||||
|
extern void xspeak (SPEAK a);
|
||||||
|
|
||||||
|
extern void setBuffers_speak (SPEAK a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_speak (SPEAK a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_speak (SPEAK a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Complex Multiple Peaking *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _mpeak_h
|
||||||
|
#define _mpeak_h
|
||||||
|
|
||||||
|
typedef struct _mpeak
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int rate;
|
||||||
|
int npeaks;
|
||||||
|
int* enable;
|
||||||
|
double* f;
|
||||||
|
double* bw;
|
||||||
|
double* gain;
|
||||||
|
int nstages;
|
||||||
|
SPEAK* pfil;
|
||||||
|
double* tmp;
|
||||||
|
double* mix;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} mpeak, *MPEAK;
|
||||||
|
|
||||||
|
extern MPEAK create_mpeak (int run, int size, double* in, double* out, int rate, int npeaks, int* enable, double* f, double* bw, double* gain, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_mpeak (MPEAK a);
|
||||||
|
|
||||||
|
extern void flush_mpeak (MPEAK a);
|
||||||
|
|
||||||
|
extern void xmpeak (MPEAK a);
|
||||||
|
|
||||||
|
extern void setBuffers_mpeak (MPEAK a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_mpeak (MPEAK a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_mpeak (MPEAK a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Phase Rotator *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _phrot_h
|
||||||
|
#define _phrot_h
|
||||||
|
|
||||||
|
typedef struct _phrot
|
||||||
|
{
|
||||||
|
int reverse;
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
int rate;
|
||||||
|
double fc;
|
||||||
|
int nstages;
|
||||||
|
// normalized such that a0 = 1
|
||||||
|
double a1, b0, b1;
|
||||||
|
double *x0, *x1, *y0, *y1;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} phrot, *PHROT;
|
||||||
|
|
||||||
|
extern PHROT create_phrot (int run, int size, double* in, double* out, int rate, double fc, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_phrot (PHROT a);
|
||||||
|
|
||||||
|
extern void flush_phrot (PHROT a);
|
||||||
|
|
||||||
|
extern void xphrot (PHROT a);
|
||||||
|
|
||||||
|
extern void setBuffers_phrot (PHROT a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_phrot (PHROT a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_phrot (PHROT a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Complex Bi-Quad Low-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _bqlp_h
|
||||||
|
#define _bqlp_h
|
||||||
|
|
||||||
|
typedef struct _bqlp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double fc;
|
||||||
|
double Q;
|
||||||
|
double gain;
|
||||||
|
int nstages;
|
||||||
|
double a0, a1, a2, b1, b2;
|
||||||
|
double* x0, * x1, * x2, * y0, * y1, * y2;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} bqlp, *BQLP;
|
||||||
|
|
||||||
|
extern BQLP create_bqlp(int run, int size, double* in, double* out, double rate, double fc, double Q, double gain, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_bqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void flush_bqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void xbqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void setBuffers_bqlp(BQLP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_bqlp(BQLP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_bqlp(BQLP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Double Bi-Quad Low-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _dbqlp_h
|
||||||
|
#define _dbqlp_h
|
||||||
|
|
||||||
|
extern BQLP create_dbqlp(int run, int size, double* in, double* out, double rate, double fc, double Q, double gain, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_dbqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void flush_dbqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void xdbqlp(BQLP a);
|
||||||
|
|
||||||
|
extern void setBuffers_dbqlp(BQLP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_dbqlp(BQLP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_dbqlp(BQLP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Complex Bi-Quad Band-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _bqbp_h
|
||||||
|
#define _bqbp_h
|
||||||
|
|
||||||
|
typedef struct _bqbp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double f_low;
|
||||||
|
double f_high;
|
||||||
|
double gain;
|
||||||
|
int nstages;
|
||||||
|
double a0, a1, a2, b1, b2;
|
||||||
|
double* x0, * x1, * x2, * y0, * y1, * y2;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} bqbp, * BQBP;
|
||||||
|
|
||||||
|
extern BQBP create_bqbp(int run, int size, double* in, double* out, double rate, double f_low, double f_high, double gain, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_bqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void flush_bqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void xbqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void setBuffers_bqbp(BQBP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_bqbp(BQBP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_bqbp(BQBP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Double Bi-Quad Band-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _dbqbp_h
|
||||||
|
#define _dbqbp_h
|
||||||
|
|
||||||
|
extern BQBP create_dbqbp(int run, int size, double* in, double* out, double rate, double f_low, double f_high, double gain, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_dbqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void flush_dbqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void xdbqbp(BQBP a);
|
||||||
|
|
||||||
|
extern void setBuffers_dbqbp(BQBP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_dbqbp(BQBP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_dbqbp(BQBP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Double Single-Pole High-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _dsphp_h
|
||||||
|
#define _dsphp_h
|
||||||
|
|
||||||
|
typedef struct _sphp
|
||||||
|
{
|
||||||
|
int run;
|
||||||
|
int size;
|
||||||
|
double* in;
|
||||||
|
double* out;
|
||||||
|
double rate;
|
||||||
|
double fc;
|
||||||
|
int nstages;
|
||||||
|
double a1, b0, b1;
|
||||||
|
double* x0, * x1, * y0, * y1;
|
||||||
|
CRITICAL_SECTION cs_update;
|
||||||
|
} sphp, * SPHP;
|
||||||
|
|
||||||
|
extern SPHP create_dsphp(int run, int size, double* in, double* out, double rate, double fc, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_dsphp(SPHP a);
|
||||||
|
|
||||||
|
extern void flush_dsphp(SPHP a);
|
||||||
|
|
||||||
|
extern void xdsphp(SPHP a);
|
||||||
|
|
||||||
|
extern void setBuffers_dsphp(SPHP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_dsphp(SPHP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_dsphp(SPHP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Complex Single-Pole High-Pass *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _dphp_h
|
||||||
|
#define _dphp_h
|
||||||
|
|
||||||
|
extern SPHP create_sphp(int run, int size, double* in, double* out, double rate, double fc, int nstages);
|
||||||
|
|
||||||
|
extern void destroy_sphp(SPHP a);
|
||||||
|
|
||||||
|
extern void flush_sphp(SPHP a);
|
||||||
|
|
||||||
|
extern void xsphp(SPHP a);
|
||||||
|
|
||||||
|
extern void setBuffers_sphp(SPHP a, double* in, double* out);
|
||||||
|
|
||||||
|
extern void setSamplerate_sphp(SPHP a, int rate);
|
||||||
|
|
||||||
|
extern void setSize_sphp(SPHP a, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+604
@@ -0,0 +1,604 @@
|
|||||||
|
/* iobuffs.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Begin Slew Code *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
enum _slew
|
||||||
|
{
|
||||||
|
BEGIN = 0,
|
||||||
|
DELAYUP,
|
||||||
|
UPSLEW,
|
||||||
|
ON,
|
||||||
|
DELAYDOWN,
|
||||||
|
DOWNSLEW,
|
||||||
|
ZERO,
|
||||||
|
OFF
|
||||||
|
};
|
||||||
|
|
||||||
|
void create_slews (IOB a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double delta, theta;
|
||||||
|
a->slew.ustate = BEGIN;
|
||||||
|
a->slew.dstate = BEGIN;
|
||||||
|
a->slew.ucount = 0;
|
||||||
|
a->slew.dcount = 0;
|
||||||
|
a->slew.ndelup = (int)(ch[a->channel].tdelayup * ch[a->channel].in_rate);
|
||||||
|
a->slew.ndeldown = (int)(ch[a->channel].tdelaydown * ch[a->channel].out_rate);
|
||||||
|
a->slew.ntup = (int)(ch[a->channel].tslewup * ch[a->channel].in_rate);
|
||||||
|
a->slew.ntdown = (int)(ch[a->channel].tslewdown * ch[a->channel].out_rate);
|
||||||
|
a->slew.cup = (double *) malloc0 ((a->slew.ntup + 1) * sizeof (double));
|
||||||
|
a->slew.cdown = (double *) malloc0 ((a->slew.ntdown + 1) * sizeof (double));
|
||||||
|
|
||||||
|
delta = PI / (double)a->slew.ntup;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->slew.ntup; i++)
|
||||||
|
{
|
||||||
|
a->slew.cup[i] = 0.5 * (1.0 - cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
delta = PI / (double)a->slew.ntdown;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->slew.ntdown; i++)
|
||||||
|
{
|
||||||
|
a->slew.cdown[i] = 0.5 * (1 + cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
||||||
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_slews(IOB a)
|
||||||
|
{
|
||||||
|
_aligned_free (a->slew.cdown);
|
||||||
|
_aligned_free (a->slew.cup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_slews (IOB a)
|
||||||
|
{
|
||||||
|
a->slew.ustate = BEGIN;
|
||||||
|
a->slew.dstate = BEGIN;
|
||||||
|
a->slew.ucount = 0;
|
||||||
|
a->slew.dcount = 0;
|
||||||
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
||||||
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void upslew0 (IOB a, double* pin)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double *pout;
|
||||||
|
double I, Q;
|
||||||
|
pout = a->r1_baseptr + 2 * a->r1_inidx;
|
||||||
|
for (i = 0; i < a->in_size; i++)
|
||||||
|
{
|
||||||
|
I = pin[2 * i + 0];
|
||||||
|
Q = pin[2 * i + 1];
|
||||||
|
switch (a->slew.ustate)
|
||||||
|
{
|
||||||
|
case BEGIN:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if ((I != 0.0) || (Q != 0.0))
|
||||||
|
{
|
||||||
|
if (a->slew.ndelup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = DELAYUP;
|
||||||
|
a->slew.ucount = a->slew.ndelup;
|
||||||
|
}
|
||||||
|
else if (a->slew.ntup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = UPSLEW;
|
||||||
|
a->slew.ucount = a->slew.ntup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DELAYUP:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if (a->slew.ucount-- == 0)
|
||||||
|
{
|
||||||
|
if (a->slew.ntup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = UPSLEW;
|
||||||
|
a->slew.ucount = a->slew.ntup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UPSLEW:
|
||||||
|
pout[2 * i + 0] = I * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
||||||
|
pout[2 * i + 1] = Q * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
||||||
|
if (a->slew.ucount-- == 0)
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
break;
|
||||||
|
case ON:
|
||||||
|
pout[2 * i + 0] = I;
|
||||||
|
pout[2 * i + 1] = Q;
|
||||||
|
if (i == a->in_size - 1)
|
||||||
|
{
|
||||||
|
a->slew.ustate = BEGIN;
|
||||||
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upslew2 (IOB a, INREAL* pIin, INREAL* pQin)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double *pout;
|
||||||
|
double I, Q;
|
||||||
|
pout = a->r1_baseptr + 2 * a->r1_inidx;
|
||||||
|
for (i = 0; i < a->in_size; i++)
|
||||||
|
{
|
||||||
|
I = (double)pIin[i];
|
||||||
|
Q = (double)pQin[i];
|
||||||
|
switch (a->slew.ustate)
|
||||||
|
{
|
||||||
|
case BEGIN:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if ((I != 0.0) || (Q != 0.0))
|
||||||
|
{
|
||||||
|
if (a->slew.ndelup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = DELAYUP;
|
||||||
|
a->slew.ucount = a->slew.ndelup;
|
||||||
|
}
|
||||||
|
else if (a->slew.ntup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = UPSLEW;
|
||||||
|
a->slew.ucount = a->slew.ntup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DELAYUP:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if (a->slew.ucount-- == 0)
|
||||||
|
{
|
||||||
|
if (a->slew.ntup > 0)
|
||||||
|
{
|
||||||
|
a->slew.ustate = UPSLEW;
|
||||||
|
a->slew.ucount = a->slew.ntup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UPSLEW:
|
||||||
|
pout[2 * i + 0] = I * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
||||||
|
pout[2 * i + 1] = Q * a->slew.cup[a->slew.ntup - a->slew.ucount];
|
||||||
|
if (a->slew.ucount-- == 0)
|
||||||
|
a->slew.ustate = ON;
|
||||||
|
break;
|
||||||
|
case ON:
|
||||||
|
pout[2 * i + 0] = I;
|
||||||
|
pout[2 * i + 1] = Q;
|
||||||
|
if (i == a->in_size - 1)
|
||||||
|
{
|
||||||
|
a->slew.ustate = BEGIN;
|
||||||
|
InterlockedBitTestAndReset (&a->slew.upflag, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void downslew0 (IOB a, double* pout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double *pin;
|
||||||
|
double I, Q;
|
||||||
|
pin = a->r2_baseptr + 2 * a->r2_outidx;
|
||||||
|
for (i = 0; i < a->out_size; i++)
|
||||||
|
{
|
||||||
|
I = pin[2 * i + 0];
|
||||||
|
Q = pin[2 * i + 1];
|
||||||
|
switch (a->slew.dstate)
|
||||||
|
{
|
||||||
|
case BEGIN:
|
||||||
|
pout[2 * i + 0] = I;
|
||||||
|
pout[2 * i + 1] = Q;
|
||||||
|
if (a->slew.ndeldown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DELAYDOWN;
|
||||||
|
a->slew.dcount = a->slew.ndeldown;
|
||||||
|
}
|
||||||
|
else if (a->slew.ntdown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DOWNSLEW;
|
||||||
|
a->slew.dcount = a->slew.ntdown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DELAYDOWN:
|
||||||
|
pout[2 * i + 0] = I;
|
||||||
|
pout[2 * i + 1] = Q;
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
{
|
||||||
|
if (a->slew.ntdown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DOWNSLEW;
|
||||||
|
a->slew.dcount = a->slew.ntdown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DOWNSLEW:
|
||||||
|
pout[2 * i + 0] = I * a->slew.cdown[a->slew.ntdown - a->slew.dcount];
|
||||||
|
pout[2 * i + 1] = Q * a->slew.cdown[a->slew.ntdown - a->slew.dcount];
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZERO:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
a->slew.dstate = OFF;
|
||||||
|
break;
|
||||||
|
case OFF:
|
||||||
|
pout[2 * i + 0] = 0.0;
|
||||||
|
pout[2 * i + 1] = 0.0;
|
||||||
|
if (i == a->out_size - 1)
|
||||||
|
{
|
||||||
|
a->slew.dstate = BEGIN;
|
||||||
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void downslew2 (IOB a, OUTREAL* pIout, OUTREAL* pQout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double *pin;
|
||||||
|
double I, Q;
|
||||||
|
pin = a->r2_baseptr + 2 * a->r2_outidx;
|
||||||
|
for (i = 0; i < a->out_size; i++)
|
||||||
|
{
|
||||||
|
I = pin[2 * i + 0];
|
||||||
|
Q = pin[2 * i + 1];
|
||||||
|
switch (a->slew.dstate)
|
||||||
|
{
|
||||||
|
case BEGIN:
|
||||||
|
pIout[i] = (OUTREAL)I;
|
||||||
|
pQout[i] = (OUTREAL)Q;
|
||||||
|
if (a->slew.ndeldown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DELAYDOWN;
|
||||||
|
a->slew.dcount = a->slew.ndeldown;
|
||||||
|
}
|
||||||
|
else if (a->slew.ntdown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DOWNSLEW;
|
||||||
|
a->slew.dcount = a->slew.ntdown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DELAYDOWN:
|
||||||
|
pIout[i] = (OUTREAL)I;
|
||||||
|
pQout[i] = (OUTREAL)Q;
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
{
|
||||||
|
if (a->slew.ntdown > 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = DOWNSLEW;
|
||||||
|
a->slew.dcount = a->slew.ntdown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DOWNSLEW:
|
||||||
|
pIout[i] = (OUTREAL)(I * a->slew.cdown[a->slew.ntdown - a->slew.dcount]);
|
||||||
|
pQout[i] = (OUTREAL)(Q * a->slew.cdown[a->slew.ntdown - a->slew.dcount]);
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
{
|
||||||
|
a->slew.dstate = ZERO;
|
||||||
|
a->slew.dcount = a->out_size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZERO:
|
||||||
|
pIout[i] = 0.0;
|
||||||
|
pQout[i] = 0.0;
|
||||||
|
if (a->slew.dcount-- == 0)
|
||||||
|
a->slew.dstate = OFF;
|
||||||
|
break;
|
||||||
|
case OFF:
|
||||||
|
pIout[i] = 0.0;
|
||||||
|
pQout[i] = 0.0;
|
||||||
|
if (i == a->out_size - 1)
|
||||||
|
{
|
||||||
|
a->slew.dstate = BEGIN;
|
||||||
|
InterlockedBitTestAndReset (&a->slew.downflag, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* Begin Buffer Code *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
void create_iobuffs (int channel)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
IOB a = (IOB) malloc0 (sizeof(iob));
|
||||||
|
ch[channel].iob.pc = ch[channel].iob.pd = ch[channel].iob.pe = ch[channel].iob.pf = a;
|
||||||
|
a->channel = channel;
|
||||||
|
a->in_size = ch[channel].in_size;
|
||||||
|
a->r1_outsize = ch[channel].dsp_insize;
|
||||||
|
if (a->r1_outsize > a->in_size)
|
||||||
|
a->r1_size = a->r1_outsize;
|
||||||
|
else
|
||||||
|
a->r1_size = a->in_size;
|
||||||
|
a->out_size = ch[channel].out_size;
|
||||||
|
a->r2_insize = ch[channel].dsp_outsize;
|
||||||
|
if (a->out_size > a->r2_insize)
|
||||||
|
a->r2_size = a->out_size;
|
||||||
|
else
|
||||||
|
a->r2_size = a->r2_insize;
|
||||||
|
a->r1_active_buffsize = DSP_MULT * a->r1_size;
|
||||||
|
a->r2_active_buffsize = DSP_MULT * a->r2_size;
|
||||||
|
a->r1_baseptr = (double*) malloc0 (a->r1_active_buffsize * sizeof (complex));
|
||||||
|
a->r2_baseptr = (double*) malloc0 (a->r2_active_buffsize * sizeof (complex));
|
||||||
|
a->r1_inidx = 0;
|
||||||
|
a->r1_outidx = 0;
|
||||||
|
a->r1_unqueuedsamps = 0;
|
||||||
|
a->r2_inidx = (DSP_MULT - 1) * a->r2_size;
|
||||||
|
a->r2_outidx = 0;
|
||||||
|
a->r2_havesamps = (DSP_MULT - 1) * a->r2_size;
|
||||||
|
n = a->r2_havesamps / a->out_size;
|
||||||
|
a->r2_unqueuedsamps = a->r2_havesamps - n * a->out_size;
|
||||||
|
InitializeCriticalSectionAndSpinCount(&a->r2_ControlSection, 2500);
|
||||||
|
a->Sem_BuffReady = CreateSemaphore(0, 0, 1000, 0);
|
||||||
|
a->Sem_OutReady = CreateSemaphore(0, n, 1000, 0);
|
||||||
|
a->bfo = ch[channel].bfo;
|
||||||
|
create_slews (a);
|
||||||
|
|
||||||
|
InterlockedBitTestAndReset(&a->flush_bypass, 0);
|
||||||
|
a->Sem_Flush = CreateSemaphore(0, 0, 1, 0);
|
||||||
|
_beginthread(flushChannel, 0, (void*)(uintptr_t)a->channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_iobuffs (int channel)
|
||||||
|
{
|
||||||
|
IOB a = ch[channel].iob.pc;
|
||||||
|
|
||||||
|
InterlockedBitTestAndSet(&a->flush_bypass, 0);
|
||||||
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
||||||
|
while (InterlockedAnd(&a->flush_bypass, 0xffffffff)) Sleep(1);
|
||||||
|
CloseHandle(a->Sem_Flush);
|
||||||
|
|
||||||
|
destroy_slews (a);
|
||||||
|
CloseHandle (a->Sem_OutReady);
|
||||||
|
CloseHandle (a->Sem_BuffReady);
|
||||||
|
DeleteCriticalSection(&a->r2_ControlSection);
|
||||||
|
_aligned_free (a->r2_baseptr);
|
||||||
|
_aligned_free (a->r1_baseptr);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_iobuffs (int channel)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
IOB a = ch[channel].iob.pf;
|
||||||
|
memset (a->r1_baseptr, 0, a->r1_active_buffsize * sizeof (complex));
|
||||||
|
memset (a->r2_baseptr, 0, a->r2_active_buffsize * sizeof (complex));
|
||||||
|
a->r1_inidx = 0;
|
||||||
|
a->r1_outidx = 0;
|
||||||
|
a->r1_unqueuedsamps = 0;
|
||||||
|
a->r2_inidx = (DSP_MULT - 1) * a->r2_size;
|
||||||
|
a->r2_outidx = 0;
|
||||||
|
a->r2_havesamps = (DSP_MULT - 1) * a->r2_size;
|
||||||
|
while (!WaitForSingleObject (a->Sem_BuffReady, 1));
|
||||||
|
n = a->r2_havesamps / a->out_size;
|
||||||
|
a->r2_unqueuedsamps = a->r2_havesamps - n * a->out_size;
|
||||||
|
CloseHandle (a->Sem_OutReady);
|
||||||
|
a->Sem_OutReady = CreateSemaphore(0, n, 1000, 0);
|
||||||
|
flush_slews (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PORT //double, interleaved I/Q
|
||||||
|
void fexchange0 (int channel, double* in, double* out, int* error)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
int doit = 0;
|
||||||
|
IOB a;
|
||||||
|
*error = 0;
|
||||||
|
if (_InterlockedAnd (&ch[channel].exchange, 1))
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pe;
|
||||||
|
if (_InterlockedAnd (&a->slew.upflag, 1))
|
||||||
|
upslew0 (a, in);
|
||||||
|
else
|
||||||
|
memcpy (a->r1_baseptr + 2 * a->r1_inidx, in, a->in_size * sizeof (complex));
|
||||||
|
// add check with *error += -1; for case when r1 is full and an overwrite occurs
|
||||||
|
if ((a->r1_unqueuedsamps += a->in_size) >= a->r1_outsize)
|
||||||
|
{
|
||||||
|
n = a->r1_unqueuedsamps / a->r1_outsize;
|
||||||
|
ReleaseSemaphore(a->Sem_BuffReady, n, 0);
|
||||||
|
a->r1_unqueuedsamps -= n * a->r1_outsize;
|
||||||
|
}
|
||||||
|
if ((a->r1_inidx += a->in_size) == a->r1_active_buffsize)
|
||||||
|
a->r1_inidx = 0;
|
||||||
|
|
||||||
|
EnterCriticalSection (&a->r2_ControlSection);
|
||||||
|
if (a->r2_havesamps >= a->out_size)
|
||||||
|
doit = 1;
|
||||||
|
if ((a->r2_havesamps -= a->out_size) < 0) a->r2_havesamps = 0;
|
||||||
|
LeaveCriticalSection (&a->r2_ControlSection);
|
||||||
|
if (a->bfo) WaitForSingleObject (a->Sem_OutReady, INFINITE);
|
||||||
|
if (a->bfo || doit)
|
||||||
|
if (_InterlockedAnd (&a->slew.downflag, 1))
|
||||||
|
{
|
||||||
|
downslew0 (a, out);
|
||||||
|
if (!_InterlockedAnd (&a->slew.downflag, 1))
|
||||||
|
{
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
||||||
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (out, a->r2_baseptr + 2 * a->r2_outidx, a->out_size * sizeof (complex));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset (out, 0, a->out_size * sizeof (complex));
|
||||||
|
*error += -2;
|
||||||
|
}
|
||||||
|
if ((a->r2_outidx += a->out_size) == a->r2_active_buffsize)
|
||||||
|
a->r2_outidx = 0;
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT //separate I/Q buffers
|
||||||
|
void fexchange2 (int channel, INREAL *Iin, INREAL *Qin, OUTREAL *Iout, OUTREAL *Qout, int* error)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
int doit = 0;
|
||||||
|
IOB a;
|
||||||
|
*error = 0;
|
||||||
|
if (_InterlockedAnd (&ch[channel].exchange, 1))
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&ch[channel].csEXCH);
|
||||||
|
a = ch[channel].iob.pe;
|
||||||
|
if (_InterlockedAnd (&a->slew.upflag, 1))
|
||||||
|
upslew2 (a, Iin, Qin);
|
||||||
|
else
|
||||||
|
for (i = 0; i < a->in_size; i++)
|
||||||
|
{
|
||||||
|
(a->r1_baseptr + 2 * a->r1_inidx)[2 * i + 0] = (double)(Iin[i]);
|
||||||
|
(a->r1_baseptr + 2 * a->r1_inidx)[2 * i + 1] = (double)(Qin[i]);
|
||||||
|
}
|
||||||
|
// add check with *error += -1; for case when r1 is full and an overwrite occurs
|
||||||
|
if ((a->r1_unqueuedsamps += a->in_size) >= a->r1_outsize)
|
||||||
|
{
|
||||||
|
n = a->r1_unqueuedsamps / a->r1_outsize;
|
||||||
|
ReleaseSemaphore(a->Sem_BuffReady, n, 0);
|
||||||
|
a->r1_unqueuedsamps -= n * a->r1_outsize;
|
||||||
|
}
|
||||||
|
if ((a->r1_inidx += a->in_size) == a->r1_active_buffsize)
|
||||||
|
a->r1_inidx = 0;
|
||||||
|
|
||||||
|
EnterCriticalSection (&a->r2_ControlSection);
|
||||||
|
if (a->r2_havesamps >= a->out_size)
|
||||||
|
doit = 1;
|
||||||
|
if ((a->r2_havesamps -= a->out_size) < 0) a->r2_havesamps = 0;
|
||||||
|
LeaveCriticalSection (&a->r2_ControlSection);
|
||||||
|
if (a->bfo) WaitForSingleObject (a->Sem_OutReady, INFINITE);
|
||||||
|
if (a->bfo || doit)
|
||||||
|
{
|
||||||
|
if (_InterlockedAnd (&a->slew.downflag, 1))
|
||||||
|
{
|
||||||
|
downslew2 (a, Iout, Qout);
|
||||||
|
if (!_InterlockedAnd (&a->slew.downflag, 1))
|
||||||
|
{
|
||||||
|
InterlockedBitTestAndReset (&ch[channel].exchange, 0);
|
||||||
|
ReleaseSemaphore(a->Sem_Flush, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (i = 0; i < a->out_size; i++)
|
||||||
|
{
|
||||||
|
Iout[i] = (OUTREAL)((a->r2_baseptr + 2 * a->r2_outidx)[2 * i + 0]);
|
||||||
|
Qout[i] = (OUTREAL)((a->r2_baseptr + 2 * a->r2_outidx)[2 * i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset (Iout, 0, a->out_size * sizeof (OUTREAL));
|
||||||
|
memset (Qout, 0, a->out_size * sizeof (OUTREAL));
|
||||||
|
*error += -2;
|
||||||
|
}
|
||||||
|
if ((a->r2_outidx += a->out_size) == a->r2_active_buffsize)
|
||||||
|
a->r2_outidx = 0;
|
||||||
|
LeaveCriticalSection (&ch[channel].csEXCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dexchange (int channel, double* in, double* out)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
IOB a = ch[channel].iob.pd;
|
||||||
|
if (!_InterlockedAnd (&ch[channel].run, 1)) _endthread();
|
||||||
|
|
||||||
|
EnterCriticalSection (&a->r2_ControlSection);
|
||||||
|
a->r2_havesamps += a->r2_insize;
|
||||||
|
LeaveCriticalSection (&a->r2_ControlSection);
|
||||||
|
memcpy (a->r2_baseptr + 2 * a->r2_inidx, in, a->r2_insize * sizeof (complex));
|
||||||
|
if ((a->r2_inidx += a->r2_insize) == a->r2_active_buffsize)
|
||||||
|
a->r2_inidx = 0;
|
||||||
|
if (a->bfo && (a->r2_unqueuedsamps += a->r2_insize) >= a->out_size)
|
||||||
|
{
|
||||||
|
n = a->r2_unqueuedsamps / a->out_size;
|
||||||
|
ReleaseSemaphore(a->Sem_OutReady, n, 0);
|
||||||
|
a->r2_unqueuedsamps -= n * a->out_size;
|
||||||
|
}
|
||||||
|
memcpy (out, a->r1_baseptr + 2 * a->r1_outidx, a->r1_outsize * sizeof (complex));
|
||||||
|
if ((a->r1_outidx += a->r1_outsize) == a->r1_active_buffsize)
|
||||||
|
a->r1_outidx = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/* iobuffs.h
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _iobuffs_h
|
||||||
|
#define _iobuffs_h
|
||||||
|
#include "comm.h"
|
||||||
|
typedef struct _iobf
|
||||||
|
{
|
||||||
|
int channel;
|
||||||
|
int in_size; // input number of complex samples in a fexchange call
|
||||||
|
int out_size; // output number of complex samples in a fexchange call
|
||||||
|
int r1_outsize; // number of complex samples taken out of the input-pseudo-ring for processing
|
||||||
|
int r2_insize; // number of processed complex samples returned into the output-pseudo-ring
|
||||||
|
int r1_size; // size of a single maximum sized transfer
|
||||||
|
int r2_size; // size of a single maximum sized transfer
|
||||||
|
int r1_active_buffsize; // size of input pseudo-ring (in complex samples)
|
||||||
|
int r2_active_buffsize; // size of output pseudo-ring (in complex samples)
|
||||||
|
|
||||||
|
double* r1_baseptr; // pointer to input pseudo-ring
|
||||||
|
int r1_inidx; // in 'double', actual index into the buffer is 2 times this
|
||||||
|
int r1_outidx; // in 'double', actual index into the buffer is 2 times this
|
||||||
|
int r1_unqueuedsamps; // number of input samples not yet queued/released for execution
|
||||||
|
|
||||||
|
double* r2_baseptr; // pointer to output pseudo-ring
|
||||||
|
int r2_inidx; // in 'double', actual index into the buffer is 2 times this
|
||||||
|
int r2_outidx; // in 'double', actual index into the buffer is 2 times this
|
||||||
|
int r2_havesamps; // number of processed samples in output pseudo-ring
|
||||||
|
int r2_unqueuedsamps; // number of output samples not yet queued / released for output
|
||||||
|
CRITICAL_SECTION r2_ControlSection;
|
||||||
|
|
||||||
|
int bfo; // block_for_output, wait until output is available before proceeding
|
||||||
|
HANDLE Sem_OutReady; // count = number of 'out_size' buffers processed and available for output
|
||||||
|
HANDLE Sem_BuffReady; // count = number of 'dsp_size' buffers queued for processing
|
||||||
|
volatile long exec_bypass;
|
||||||
|
volatile long flush_bypass;
|
||||||
|
HANDLE Sem_Flush;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int ustate;
|
||||||
|
int dstate;
|
||||||
|
int ucount;
|
||||||
|
int dcount;
|
||||||
|
int ndelup;
|
||||||
|
int ntup;
|
||||||
|
double* cup;
|
||||||
|
int ndeldown;
|
||||||
|
int ntdown;
|
||||||
|
double* cdown;
|
||||||
|
volatile long upflag;
|
||||||
|
volatile long downflag;
|
||||||
|
} slew;
|
||||||
|
} iob, *IOB;
|
||||||
|
|
||||||
|
extern void create_slews (IOB a);
|
||||||
|
|
||||||
|
extern void destroy_slews (IOB a);
|
||||||
|
|
||||||
|
extern void flush_slews (IOB a);
|
||||||
|
|
||||||
|
extern void create_iobuffs (int channel);
|
||||||
|
|
||||||
|
extern void destroy_iobuffs (int channel);
|
||||||
|
|
||||||
|
extern void flush_iobuffs (int channel);
|
||||||
|
|
||||||
|
PORT // double, interleaved I/Q
|
||||||
|
void fexchange0 (int channel, double* in, double* out, int* error);
|
||||||
|
|
||||||
|
PORT // separate I/Q buffers
|
||||||
|
extern void fexchange2 (int channel, INREAL *Iin, INREAL *Qin, OUTREAL *Iout, OUTREAL *Qout, int* error);
|
||||||
|
|
||||||
|
extern void dexchange (int channel, double* in, double* out);
|
||||||
|
|
||||||
|
#endif
|
||||||
+315
@@ -0,0 +1,315 @@
|
|||||||
|
/* iqc.c
|
||||||
|
|
||||||
|
This file is part of a program that implements a Software-Defined Radio.
|
||||||
|
|
||||||
|
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
The author can be reached by email at
|
||||||
|
|
||||||
|
warren@wpratt.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
void size_iqc (IQC a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
a->t = (double *) malloc0 ((a->ints + 1) * sizeof(double));
|
||||||
|
for (i = 0; i <= a->ints; i++)
|
||||||
|
a->t[i] = (double)i / (double)a->ints;
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
a->cm[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
||||||
|
a->cc[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
||||||
|
a->cs[i] = (double *) malloc0 (a->ints * 4 * sizeof(double));
|
||||||
|
}
|
||||||
|
a->dog.cpi = (int *) malloc0 (a->ints * sizeof (int));
|
||||||
|
a->dog.count = 0;
|
||||||
|
a->dog.full_ints = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void desize_iqc (IQC a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
_aligned_free (a->dog.cpi);
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
_aligned_free (a->cm[i]);
|
||||||
|
_aligned_free (a->cc[i]);
|
||||||
|
_aligned_free (a->cs[i]);
|
||||||
|
}
|
||||||
|
_aligned_free (a->t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_iqc (IQC a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double delta, theta;
|
||||||
|
a->cset = 0;
|
||||||
|
a->count = 0;
|
||||||
|
a->state = 0;
|
||||||
|
a->busy = 0;
|
||||||
|
a->ntup = (int)(a->tup * a->rate);
|
||||||
|
a->cup = (double *) malloc0 ((a->ntup + 1) * sizeof (double));
|
||||||
|
delta = PI / (double)a->ntup;
|
||||||
|
theta = 0.0;
|
||||||
|
for (i = 0; i <= a->ntup; i++)
|
||||||
|
{
|
||||||
|
a->cup[i] = 0.5 * (1.0 - cos (theta));
|
||||||
|
theta += delta;
|
||||||
|
}
|
||||||
|
InitializeCriticalSectionAndSpinCount (&a->dog.cs, 2500);
|
||||||
|
size_iqc (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decalc_iqc (IQC a)
|
||||||
|
{
|
||||||
|
desize_iqc (a);
|
||||||
|
DeleteCriticalSection (&a->dog.cs);
|
||||||
|
_aligned_free (a->cup);
|
||||||
|
}
|
||||||
|
|
||||||
|
IQC create_iqc (int run, int size, double* in, double* out, double rate, int ints, double tup, int spi)
|
||||||
|
{
|
||||||
|
IQC a = (IQC) malloc0 (sizeof (iqc));
|
||||||
|
a->run = run;
|
||||||
|
a->size = size;
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
a->rate = rate;
|
||||||
|
a->ints = ints;
|
||||||
|
a->tup = tup;
|
||||||
|
a->dog.spi = spi;
|
||||||
|
calc_iqc (a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_iqc (IQC a)
|
||||||
|
{
|
||||||
|
decalc_iqc (a);
|
||||||
|
_aligned_free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_iqc (IQC a)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _iqcstate
|
||||||
|
{
|
||||||
|
RUN = 0,
|
||||||
|
BEGIN,
|
||||||
|
SWAP,
|
||||||
|
END,
|
||||||
|
DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
void xiqc (IQC a)
|
||||||
|
{
|
||||||
|
if (_InterlockedAnd(&a->run, 1))
|
||||||
|
{
|
||||||
|
int i, k, cset, mset;
|
||||||
|
double I, Q, env, dx, ym, yc, ys, PRE0, PRE1;
|
||||||
|
for (i = 0; i < a->size; i++)
|
||||||
|
{
|
||||||
|
I = a->in[2 * i + 0];
|
||||||
|
Q = a->in[2 * i + 1];
|
||||||
|
env = sqrt (I * I + Q * Q);
|
||||||
|
if ((k = (int)(env * a->ints)) > a->ints - 1) k = a->ints - 1;
|
||||||
|
dx = env - a->t[k];
|
||||||
|
cset = a->cset;
|
||||||
|
ym = a->cm[cset][4 * k + 0] + dx * (a->cm[cset][4 * k + 1] + dx * (a->cm[cset][4 * k + 2] + dx * a->cm[cset][4 * k + 3]));
|
||||||
|
yc = a->cc[cset][4 * k + 0] + dx * (a->cc[cset][4 * k + 1] + dx * (a->cc[cset][4 * k + 2] + dx * a->cc[cset][4 * k + 3]));
|
||||||
|
ys = a->cs[cset][4 * k + 0] + dx * (a->cs[cset][4 * k + 1] + dx * (a->cs[cset][4 * k + 2] + dx * a->cs[cset][4 * k + 3]));
|
||||||
|
PRE0 = ym * (I * yc - Q * ys);
|
||||||
|
PRE1 = ym * (I * ys + Q * yc);
|
||||||
|
|
||||||
|
switch (a->state)
|
||||||
|
{
|
||||||
|
case RUN:
|
||||||
|
if (a->dog.cpi[k] != a->dog.spi)
|
||||||
|
if (++a->dog.cpi[k] == a->dog.spi)
|
||||||
|
a->dog.full_ints++;
|
||||||
|
if (a->dog.full_ints == a->ints)
|
||||||
|
{
|
||||||
|
EnterCriticalSection (&a->dog.cs);
|
||||||
|
++a->dog.count;
|
||||||
|
LeaveCriticalSection (&a->dog.cs);
|
||||||
|
a->dog.full_ints = 0;
|
||||||
|
memset (a->dog.cpi, 0, a->ints * sizeof (int));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BEGIN:
|
||||||
|
PRE0 = (1.0 - a->cup[a->count]) * I + a->cup[a->count] * PRE0;
|
||||||
|
PRE1 = (1.0 - a->cup[a->count]) * Q + a->cup[a->count] * PRE1;
|
||||||
|
if (a->count++ == a->ntup)
|
||||||
|
{
|
||||||
|
a->state = RUN;
|
||||||
|
a->count = 0;
|
||||||
|
InterlockedBitTestAndReset (&a->busy, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SWAP:
|
||||||
|
mset = 1 - cset;
|
||||||
|
ym = a->cm[mset][4 * k + 0] + dx * (a->cm[mset][4 * k + 1] + dx * (a->cm[mset][4 * k + 2] + dx * a->cm[mset][4 * k + 3]));
|
||||||
|
yc = a->cc[mset][4 * k + 0] + dx * (a->cc[mset][4 * k + 1] + dx * (a->cc[mset][4 * k + 2] + dx * a->cc[mset][4 * k + 3]));
|
||||||
|
ys = a->cs[mset][4 * k + 0] + dx * (a->cs[mset][4 * k + 1] + dx * (a->cs[mset][4 * k + 2] + dx * a->cs[mset][4 * k + 3]));
|
||||||
|
PRE0 = (1.0 - a->cup[a->count]) * ym * (I * yc - Q * ys) + a->cup[a->count] * PRE0;
|
||||||
|
PRE1 = (1.0 - a->cup[a->count]) * ym * (I * ys + Q * yc) + a->cup[a->count] * PRE1;
|
||||||
|
if (a->count++ == a->ntup)
|
||||||
|
{
|
||||||
|
a->state = RUN;
|
||||||
|
a->count = 0;
|
||||||
|
InterlockedBitTestAndReset (&a->busy, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case END:
|
||||||
|
PRE0 = (1.0 - a->cup[a->count]) * PRE0 + a->cup[a->count] * I;
|
||||||
|
PRE1 = (1.0 - a->cup[a->count]) * PRE1 + a->cup[a->count] * Q;
|
||||||
|
if (a->count++ == a->ntup)
|
||||||
|
{
|
||||||
|
a->state = DONE;
|
||||||
|
a->count = 0;
|
||||||
|
InterlockedBitTestAndReset (&a->busy, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DONE:
|
||||||
|
PRE0 = I;
|
||||||
|
PRE1 = Q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
a->out[2 * i + 0] = PRE0;
|
||||||
|
a->out[2 * i + 1] = PRE1;
|
||||||
|
// print_iqc_values("iqc.txt", a->state, env, PRE0, PRE1, ym, yc, ys, 1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a->out != a->in)
|
||||||
|
memcpy (a->out, a->in, a->size * sizeof (complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffers_iqc (IQC a, double* in, double* out)
|
||||||
|
{
|
||||||
|
a->in = in;
|
||||||
|
a->out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSamplerate_iqc (IQC a, int rate)
|
||||||
|
{
|
||||||
|
decalc_iqc (a);
|
||||||
|
a->rate = rate;
|
||||||
|
calc_iqc (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize_iqc (IQC a, int size)
|
||||||
|
{
|
||||||
|
a->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* *
|
||||||
|
* TXA Properties *
|
||||||
|
* *
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void GetTXAiqcValues (int channel, double* cm, double* cc, double* cs)
|
||||||
|
{
|
||||||
|
IQC a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].iqc.p0;
|
||||||
|
memcpy (cm, a->cm[a->cset], a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (cc, a->cc[a->cset], a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (cs, a->cs[a->cset], a->ints * 4 * sizeof (double));
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAiqcValues (int channel, double* cm, double* cc, double* cs)
|
||||||
|
{
|
||||||
|
IQC a;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a = txa[channel].iqc.p0;
|
||||||
|
a->cset = 1 - a->cset;
|
||||||
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
||||||
|
a->state = RUN;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAiqcSwap (int channel, double* cm, double* cc, double* cs)
|
||||||
|
{
|
||||||
|
IQC a = txa[channel].iqc.p1;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->cset = 1 - a->cset;
|
||||||
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
||||||
|
InterlockedBitTestAndSet (&a->busy, 0);
|
||||||
|
a->state = SWAP;
|
||||||
|
a->count = 0;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAiqcStart (int channel, double* cm, double* cc, double* cs)
|
||||||
|
{
|
||||||
|
IQC a = txa[channel].iqc.p1;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
a->cset = 0;
|
||||||
|
memcpy (a->cm[a->cset], cm, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cc[a->cset], cc, a->ints * 4 * sizeof (double));
|
||||||
|
memcpy (a->cs[a->cset], cs, a->ints * 4 * sizeof (double));
|
||||||
|
InterlockedBitTestAndSet (&a->busy, 0);
|
||||||
|
a->state = BEGIN;
|
||||||
|
a->count = 0;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
InterlockedBitTestAndSet (&txa[channel].iqc.p1->run, 0);
|
||||||
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT
|
||||||
|
void SetTXAiqcEnd (int channel)
|
||||||
|
{
|
||||||
|
IQC a = txa[channel].iqc.p1;
|
||||||
|
EnterCriticalSection (&ch[channel].csDSP);
|
||||||
|
InterlockedBitTestAndSet (&a->busy, 0);
|
||||||
|
a->state = END;
|
||||||
|
a->count = 0;
|
||||||
|
LeaveCriticalSection (&ch[channel].csDSP);
|
||||||
|
while (_InterlockedAnd (&a->busy, 1)) Sleep(1);
|
||||||
|
InterlockedBitTestAndReset (&txa[channel].iqc.p1->run, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTXAiqcDogCount (int channel, int* count)
|
||||||
|
{
|
||||||
|
IQC a = txa[channel].iqc.p1;
|
||||||
|
EnterCriticalSection (&a->dog.cs);
|
||||||
|
*count = a->dog.count;
|
||||||
|
LeaveCriticalSection (&a->dog.cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTXAiqcDogCount (int channel, int count)
|
||||||
|
{
|
||||||
|
IQC a = txa[channel].iqc.p1;
|
||||||
|
EnterCriticalSection (&a->dog.cs);
|
||||||
|
a->dog.count = count;
|
||||||
|
LeaveCriticalSection (&a->dog.cs);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user