mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-03-22 12:18:32 -04:00
Refactored WDSP initial commit
This commit is contained in:
parent
98baa03619
commit
cd4ad2cc95
8
.gitignore
vendored
8
.gitignore
vendored
@ -43,4 +43,10 @@ obj-x86_64-linux-gnu/*
|
||||
|
||||
/rescuesdriq/vendor/
|
||||
/rescuesdriq/Godeps/
|
||||
/.vs
|
||||
/.vs
|
||||
|
||||
# WDSP
|
||||
wdsp/*.o
|
||||
wdsp/*.h
|
||||
wdsp/*.c
|
||||
wdsp/Makefile
|
||||
|
@ -857,6 +857,7 @@ if (FFTW3F_FOUND)
|
||||
add_subdirectory(ft8)
|
||||
add_definitions(-DHAS_FT8)
|
||||
set(FT8_SUPPORT ON CACHE INTERNAL "")
|
||||
add_subdirectory(wdsp)
|
||||
endif()
|
||||
|
||||
add_subdirectory(sdrbench)
|
||||
|
@ -167,4 +167,16 @@
|
||||
# define FT8_API
|
||||
#endif
|
||||
|
||||
/* the 'WDSP_API' controls the import/export of 'wdsp' symbols
|
||||
*/
|
||||
#if !defined(sdrangel_STATIC)
|
||||
# ifdef wdsp_EXPORTS
|
||||
# define WDSP_API __SDR_EXPORT
|
||||
# else
|
||||
# define WDSP_API __SDR_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define WDSP_API
|
||||
#endif
|
||||
|
||||
#endif /* __SDRANGEL_EXPORT_H */
|
||||
|
135
wdsp/CMakeLists.txt
Normal file
135
wdsp/CMakeLists.txt
Normal file
@ -0,0 +1,135 @@
|
||||
project(wdsp)
|
||||
|
||||
set(wdsp_SOURCES
|
||||
../custom/apple/apple_compat.c
|
||||
amd.cpp
|
||||
ammod.cpp
|
||||
amsq.cpp
|
||||
anf.cpp
|
||||
anr.cpp
|
||||
bandpass.cpp
|
||||
bldr.cpp
|
||||
bps.cpp
|
||||
calculus.cpp
|
||||
cblock.cpp
|
||||
cfcomp.cpp
|
||||
cfir.cpp
|
||||
compress.cpp
|
||||
delay.cpp
|
||||
emnr.cpp
|
||||
emph.cpp
|
||||
eq.cpp
|
||||
fcurve.cpp
|
||||
fir.cpp
|
||||
firmin.cpp
|
||||
fmd.cpp
|
||||
fmmod.cpp
|
||||
fmsq.cpp
|
||||
gain.cpp
|
||||
gen.cpp
|
||||
icfir.cpp
|
||||
iir.cpp
|
||||
iqc.cpp
|
||||
lmath.cpp
|
||||
meter.cpp
|
||||
meterlog10.cpp
|
||||
nbp.cpp
|
||||
osctrl.cpp
|
||||
patchpanel.cpp
|
||||
resample.cpp
|
||||
rmatch.cpp
|
||||
RXA.cpp
|
||||
sender.cpp
|
||||
shift.cpp
|
||||
siphon.cpp
|
||||
slew.cpp
|
||||
snb.cpp
|
||||
ssql.cpp
|
||||
TXA.cpp
|
||||
varsamp.cpp
|
||||
wcpAGC.cpp
|
||||
)
|
||||
|
||||
set(wdsp_HEADERS
|
||||
amd.hpp
|
||||
ammod.hpp
|
||||
amsq.hpp
|
||||
anf.hpp
|
||||
anr.hpp
|
||||
bandpass.hpp
|
||||
bldr.hpp
|
||||
bps.hpp
|
||||
calculus.hpp
|
||||
cblock.hpp
|
||||
cfcomp.hpp
|
||||
cfir.hpp
|
||||
comm.hpp
|
||||
compress.hpp
|
||||
delay.hpp
|
||||
emnr.hpp
|
||||
emph.hpp
|
||||
eq.hpp
|
||||
fcurve.hpp
|
||||
fir.hpp
|
||||
firmin.hpp
|
||||
fmd.hpp
|
||||
fmmod.hpp
|
||||
fmsq.hpp
|
||||
gain.hpp
|
||||
gen.hpp
|
||||
icfir.hpp
|
||||
iir.hpp
|
||||
iqc.hpp
|
||||
lmath.hpp
|
||||
meter.hpp
|
||||
meterlog10.hpp
|
||||
nbp.hpp
|
||||
osctrl.hpp
|
||||
patchpanel.hpp
|
||||
resample.hpp
|
||||
rmatch.hpp
|
||||
RXA.hpp
|
||||
sender.hpp
|
||||
shift.hpp
|
||||
siphon.hpp
|
||||
slew.hpp
|
||||
snb.hpp
|
||||
ssql.hpp
|
||||
TXA.hpp
|
||||
varsamp.hpp
|
||||
wcpAGC.hpp
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/exports
|
||||
${CUSTOM_APPLE_INCLUDE}
|
||||
${FFTW3F_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(wdsp SHARED
|
||||
${wdsp_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(wdsp
|
||||
${FFTW3F_LIBRARIES}
|
||||
Qt::Core
|
||||
)
|
||||
|
||||
set_target_properties(wdsp PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS true)
|
||||
if (MSVC)
|
||||
set_target_properties(wdsp PROPERTIES INTERPROCEDURAL_OPTIMIZATION false)
|
||||
endif()
|
||||
|
||||
install(TARGETS wdsp DESTINATION ${INSTALL_LIB_DIR})
|
||||
|
||||
if (LINUX)
|
||||
add_executable(wdsp_make_interface
|
||||
make_interface.cpp
|
||||
)
|
||||
|
||||
add_executable(wdsp_make_calculus
|
||||
make_calculus.cpp
|
||||
)
|
||||
install(TARGETS wdsp_make_interface wdsp_make_calculus DESTINATION ${INSTALL_BIN_DIR})
|
||||
endif()
|
||||
|
340
wdsp/COPYING
Normal file
340
wdsp/COPYING
Normal file
@ -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.
|
||||
|
5
wdsp/README.md
Normal file
5
wdsp/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# wdsp
|
||||
WDSP by Warren Pratt, NR0V
|
||||
DSP Library originally written for Windows
|
||||
Ported to Linux and Android by John Melton g0orx/n6lyt
|
||||
Adapted to SDRangel by Edouard Griffiths, F4EXB
|
1045
wdsp/RXA.cpp
Normal file
1045
wdsp/RXA.cpp
Normal file
File diff suppressed because it is too large
Load Diff
243
wdsp/RXA.hpp
Normal file
243
wdsp/RXA.hpp
Normal file
@ -0,0 +1,243 @@
|
||||
/* RXA.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2014, 2015, 2016 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_rxa_h
|
||||
#define wdsp_rxa_h
|
||||
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class METER;
|
||||
class SHIFT;
|
||||
class RESAMPLE;
|
||||
class GEN;
|
||||
class BANDPASS;
|
||||
class BPS;
|
||||
class SNB;
|
||||
class NOTCHDB;
|
||||
class NBP;
|
||||
class BPSNBA;
|
||||
class SNBA;
|
||||
class SENDER;
|
||||
class AMSQ;
|
||||
class AMD;
|
||||
class FMD;
|
||||
class FMSQ;
|
||||
class EQP;
|
||||
class ANF;
|
||||
class ANR;
|
||||
class EMNR;
|
||||
class WCPAGC;
|
||||
class SPEAK;
|
||||
class MPEAK;
|
||||
class PANEL;
|
||||
class SIPHON;
|
||||
class CBL;
|
||||
class SSQL;
|
||||
|
||||
class WDSP_API RXA : public Unit
|
||||
{
|
||||
public:
|
||||
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
|
||||
};
|
||||
|
||||
double* inbuff;
|
||||
double* outbuff;
|
||||
double* midbuff;
|
||||
int mode;
|
||||
double meter[RXA_METERTYPE_LAST];
|
||||
QRecursiveMutex* 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
|
||||
{
|
||||
BPS *p;
|
||||
} bps1;
|
||||
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;
|
||||
|
||||
static RXA* create_rxa (
|
||||
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
|
||||
);
|
||||
static void destroy_rxa (RXA *rxa);
|
||||
static void flush_rxa (RXA *rxa);
|
||||
static void xrxa (RXA *rxa);
|
||||
static void setInputSamplerate (RXA *rxa, int dsp_insize, int in_rate);
|
||||
static void setOutputSamplerate (RXA *rxa, int dsp_outsize, int out_rate);
|
||||
static void setDSPSamplerate (RXA *rxa, int dsp_insize, int dsp_outsize, int dsp_rate);
|
||||
static void setDSPBuffsize (RXA *rxa, int dsp_insize, int dsp_size, int dsp_outsize);
|
||||
|
||||
// RXA Properties
|
||||
static void SetMode (RXA& rxa, int mode);
|
||||
static void ResCheck (RXA& rxa);
|
||||
static void bp1Check (RXA& rxa, int amd_run, int snba_run, int emnr_run, int anf_run, int anr_run);
|
||||
static void bp1Set (RXA& rxa);
|
||||
static void bpsnbaCheck (RXA& rxa, int mode, int notch_run);
|
||||
static void bpsnbaSet (RXA& rxa);
|
||||
|
||||
// Collectives
|
||||
static void SetPassband (RXA& rxa, double f_low, double f_high);
|
||||
static void SetNC (RXA& rxa, int nc);
|
||||
static void SetMP (RXA& rxa, int mp);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
998
wdsp/TXA.cpp
Normal file
998
wdsp/TXA.cpp
Normal file
@ -0,0 +1,998 @@
|
||||
/* 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
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
|
||||
#include "ammod.hpp"
|
||||
#include "meter.hpp"
|
||||
#include "resample.hpp"
|
||||
#include "patchpanel.hpp"
|
||||
#include "amsq.hpp"
|
||||
#include "eq.hpp"
|
||||
#include "iir.hpp"
|
||||
#include "cfcomp.hpp"
|
||||
#include "compress.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "bps.hpp"
|
||||
#include "osctrl.hpp"
|
||||
#include "wcpAGC.hpp"
|
||||
#include "emph.hpp"
|
||||
#include "fmmod.hpp"
|
||||
#include "siphon.hpp"
|
||||
#include "gen.hpp"
|
||||
#include "slew.hpp"
|
||||
#include "iqc.hpp"
|
||||
#include "cfir.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
TXA* TXA::create_txa (
|
||||
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
|
||||
)
|
||||
{
|
||||
TXA *txa = new TXA;
|
||||
|
||||
txa->in_rate = in_rate;
|
||||
txa->out_rate = out_rate;
|
||||
txa->in_size = in_size;
|
||||
txa->dsp_rate = dsp_rate;
|
||||
txa->dsp_size = dsp_size;
|
||||
txa->dsp_insize = dsp_insize;
|
||||
txa->dsp_outsize = dsp_outsize;
|
||||
txa->out_size = out_size;
|
||||
|
||||
txa->mode = TXA_LSB;
|
||||
txa->f_low = -5000.0;
|
||||
txa->f_high = - 100.0;
|
||||
txa->inbuff = new double[1 * txa->dsp_insize * 2]; // (double *) malloc0 (1 * txa->dsp_insize * sizeof (complex));
|
||||
txa->outbuff = new double[1 * txa->dsp_outsize * 2]; // (double *) malloc0 (1 * txa->dsp_outsize * sizeof (complex));
|
||||
txa->midbuff = new double[3 * txa->dsp_size * 2]; //(double *) malloc0 (2 * txa->dsp_size * sizeof (complex));
|
||||
|
||||
txa->rsmpin.p = RESAMPLE::create_resample (
|
||||
0, // run - will be turned on below if needed
|
||||
txa->dsp_insize, // input buffer size
|
||||
txa->inbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
txa->in_rate, // input sample rate
|
||||
txa->dsp_rate, // output sample rate
|
||||
0.0, // select cutoff automatically
|
||||
0, // select ncoef automatically
|
||||
1.0); // gain
|
||||
|
||||
txa->gen0.p = GEN::create_gen (
|
||||
0, // run
|
||||
txa->dsp_size, // buffer size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // sample rate
|
||||
2); // mode
|
||||
|
||||
txa->panel.p = PANEL::create_panel (
|
||||
1, // run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->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->phrot.p = PHROT::create_phrot (
|
||||
0, // run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
338.0, // 1/2 of phase frequency
|
||||
8); // number of stages
|
||||
|
||||
txa->micmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
0, // optional pointer to another 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->amsq.p = AMSQ::create_amsq (
|
||||
0, // run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->midbuff, // trigger buffer
|
||||
txa->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->eqp.p = EQP::create_eqp (
|
||||
0, // run - OFF by default
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of filter coefficients
|
||||
0, // minimum phase flag
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
10, // nfreqs
|
||||
default_F, // vector of frequencies
|
||||
default_G, // vector of gain values
|
||||
0, // cutoff mode
|
||||
0, // wintype
|
||||
txa->dsp_rate); // samplerate
|
||||
}
|
||||
|
||||
txa->eqmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
&(txa->eqp.p->run), // pointer to eqp 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->preemph.p = EMPHP::create_emphp (
|
||||
0, // run
|
||||
1, // position
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of filter coefficients
|
||||
0, // minimum phase flag
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer,
|
||||
txa->dsp_rate, // sample rate
|
||||
0, // pre-emphasis type
|
||||
300.0, // f_low
|
||||
3000.0); // f_high
|
||||
|
||||
txa->leveler.p = WCPAGC::create_wcpagc (
|
||||
0, // run - OFF by default
|
||||
5, // mode
|
||||
0, // 0 for max(I,Q), 1 for envelope
|
||||
txa->midbuff, // input buff pointer
|
||||
txa->midbuff, // output buff pointer
|
||||
txa->dsp_size, // io_buffsize
|
||||
txa->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->lvlrmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
&(txa->leveler.p->run), // pointer to leveler 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->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->cfcomp.p = CFCOMP::create_cfcomp(
|
||||
0, // run
|
||||
0, // position
|
||||
0, // post-equalizer run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
2048, // fft size
|
||||
4, // overlap
|
||||
txa->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->cfcmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
&(txa->cfcomp.p->run), // pointer to eqp 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->cfcomp.p->gain); // pointer for gain computation
|
||||
|
||||
txa->bp0.p = BANDPASS::create_bandpass (
|
||||
1, // always runs
|
||||
0, // position
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of coefficients
|
||||
0, // flag for minimum phase
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
txa->f_low, // low freq cutoff
|
||||
txa->f_high, // high freq cutoff
|
||||
txa->dsp_rate, // samplerate
|
||||
1, // wintype
|
||||
2.0); // gain
|
||||
|
||||
txa->compressor.p = COMPRESSOR::create_compressor (
|
||||
0, // run - OFF by default
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
3.0); // gain
|
||||
|
||||
txa->bp1.p = BANDPASS::create_bandpass (
|
||||
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
||||
0, // position
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of coefficients
|
||||
0, // flag for minimum phase
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
txa->f_low, // low freq cutoff
|
||||
txa->f_high, // high freq cutoff
|
||||
txa->dsp_rate, // samplerate
|
||||
1, // wintype
|
||||
2.0); // gain
|
||||
|
||||
txa->osctrl.p = OSCTRL::create_osctrl (
|
||||
0, // run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // sample rate
|
||||
1.95); // gain for clippings
|
||||
|
||||
txa->bp2.p = BANDPASS::create_bandpass (
|
||||
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
||||
0, // position
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of coefficients
|
||||
0, // flag for minimum phase
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
txa->f_low, // low freq cutoff
|
||||
txa->f_high, // high freq cutoff
|
||||
txa->dsp_rate, // samplerate
|
||||
1, // wintype
|
||||
1.0); // gain
|
||||
|
||||
txa->compmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
&(txa->compressor.p->run), // pointer to compressor 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->alc.p = WCPAGC::create_wcpagc (
|
||||
1, // run - always ON
|
||||
5, // mode
|
||||
1, // 0 for max(I,Q), 1 for envelope
|
||||
txa->midbuff, // input buff pointer
|
||||
txa->midbuff, // output buff pointer
|
||||
txa->dsp_size, // io_buffsize
|
||||
txa->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->ammod.p = AMMOD::create_ammod (
|
||||
0, // run - OFF by default
|
||||
0, // mode: 0=>AM, 1=>DSB
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to output buffer
|
||||
0.5); // carrier level
|
||||
|
||||
|
||||
txa->fmmod.p = FMMOD::create_fmmod (
|
||||
0, // run - OFF by default
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->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
|
||||
std::max(2048, txa->dsp_size), // number coefficients for bandpass filter
|
||||
0); // minimum phase flag
|
||||
|
||||
txa->gen1.p = GEN::create_gen (
|
||||
0, // run
|
||||
txa->dsp_size, // buffer size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // sample rate
|
||||
0); // mode
|
||||
|
||||
txa->uslew.p = USLEW::create_uslew (
|
||||
txa,
|
||||
&(txa->upslew), // pointer to channel upslew flag
|
||||
txa->dsp_size, // buffer size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // sample rate
|
||||
0.000, // delay time
|
||||
0.005); // upslew time
|
||||
|
||||
txa->alcmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
0, // optional pointer to a 'run'
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // pointer to buffer
|
||||
txa->dsp_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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->alc.p->gain); // pointer for gain computation
|
||||
|
||||
txa->sip1.p = SIPHON::create_siphon (
|
||||
1, // run
|
||||
0, // position
|
||||
0, // mode
|
||||
0, // disp
|
||||
txa->dsp_size, // input buffer size
|
||||
txa->midbuff, // input buffer
|
||||
16384, // number of samples to buffer
|
||||
16384, // fft size for spectrum
|
||||
1); // specmode
|
||||
|
||||
// txa->calcc.p = create_calcc (
|
||||
// channel, // channel number
|
||||
// 1, // run calibration
|
||||
// 1024, // input buffer size
|
||||
// txa->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->iqc.p0 = txa->iqc.p1 = IQC::create_iqc (
|
||||
0, // run
|
||||
txa->dsp_size, // size
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
(double)txa->dsp_rate, // sample rate
|
||||
16, // ints
|
||||
0.005, // changeover time
|
||||
256); // spi
|
||||
|
||||
txa->cfir.p = CFIR::create_cfir(
|
||||
0, // run
|
||||
txa->dsp_size, // size
|
||||
std::max(2048, txa->dsp_size), // number of filter coefficients
|
||||
0, // minimum phase flag
|
||||
txa->midbuff, // input buffer
|
||||
txa->midbuff, // output buffer
|
||||
txa->dsp_rate, // input sample rate
|
||||
txa->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->rsmpout.p = RESAMPLE::create_resample (
|
||||
0, // run - will be turned ON below if needed
|
||||
txa->dsp_size, // input size
|
||||
txa->midbuff, // pointer to input buffer
|
||||
txa->outbuff, // pointer to output buffer
|
||||
txa->dsp_rate, // input sample rate
|
||||
txa->out_rate, // output sample rate
|
||||
0.0, // select cutoff automatically
|
||||
0, // select ncoef automatically
|
||||
0.980); // gain
|
||||
|
||||
txa->outmeter.p = METER::create_meter (
|
||||
1, // run
|
||||
0, // optional pointer to another 'run'
|
||||
txa->dsp_outsize, // size
|
||||
txa->outbuff, // pointer to buffer
|
||||
txa->out_rate, // samplerate
|
||||
0.100, // averaging time constant
|
||||
0.100, // peak decay time constant
|
||||
txa->meter, // result vector
|
||||
txa->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
|
||||
ResCheck (*txa);
|
||||
return txa;
|
||||
}
|
||||
|
||||
void TXA::destroy_txa (TXA *txa)
|
||||
{
|
||||
// in reverse order, free each item we created
|
||||
METER::destroy_meter (txa->outmeter.p);
|
||||
RESAMPLE::destroy_resample (txa->rsmpout.p);
|
||||
CFIR::destroy_cfir(txa->cfir.p);
|
||||
// destroy_calcc (txa->calcc.p);
|
||||
IQC::destroy_iqc (txa->iqc.p0);
|
||||
SIPHON::destroy_siphon (txa->sip1.p);
|
||||
METER::destroy_meter (txa->alcmeter.p);
|
||||
USLEW::destroy_uslew (txa->uslew.p);
|
||||
GEN::destroy_gen (txa->gen1.p);
|
||||
FMMOD::destroy_fmmod (txa->fmmod.p);
|
||||
AMMOD::destroy_ammod (txa->ammod.p);
|
||||
WCPAGC::destroy_wcpagc (txa->alc.p);
|
||||
METER::destroy_meter (txa->compmeter.p);
|
||||
BANDPASS::destroy_bandpass (txa->bp2.p);
|
||||
OSCTRL::destroy_osctrl (txa->osctrl.p);
|
||||
BANDPASS::destroy_bandpass (txa->bp1.p);
|
||||
COMPRESSOR::destroy_compressor (txa->compressor.p);
|
||||
BANDPASS::destroy_bandpass (txa->bp0.p);
|
||||
METER::destroy_meter (txa->cfcmeter.p);
|
||||
CFCOMP::destroy_cfcomp (txa->cfcomp.p);
|
||||
METER::destroy_meter (txa->lvlrmeter.p);
|
||||
WCPAGC::destroy_wcpagc (txa->leveler.p);
|
||||
EMPHP::destroy_emphp (txa->preemph.p);
|
||||
METER::destroy_meter (txa->eqmeter.p);
|
||||
EQP::destroy_eqp (txa->eqp.p);
|
||||
AMSQ::destroy_amsq (txa->amsq.p);
|
||||
METER::destroy_meter (txa->micmeter.p);
|
||||
PHROT::destroy_phrot (txa->phrot.p);
|
||||
PANEL::destroy_panel (txa->panel.p);
|
||||
GEN::destroy_gen (txa->gen0.p);
|
||||
RESAMPLE::destroy_resample (txa->rsmpin.p);
|
||||
delete[] (txa->midbuff);
|
||||
delete[] (txa->outbuff);
|
||||
delete[] (txa->inbuff);
|
||||
delete txa;
|
||||
}
|
||||
|
||||
void flush_txa (TXA* txa)
|
||||
{
|
||||
memset (txa->inbuff, 0, 1 * txa->dsp_insize * sizeof (dcomplex));
|
||||
memset (txa->outbuff, 0, 1 * txa->dsp_outsize * sizeof (dcomplex));
|
||||
memset (txa->midbuff, 0, 2 * txa->dsp_size * sizeof (dcomplex));
|
||||
RESAMPLE::flush_resample (txa->rsmpin.p);
|
||||
GEN::flush_gen (txa->gen0.p);
|
||||
PANEL::flush_panel (txa->panel.p);
|
||||
PHROT::flush_phrot (txa->phrot.p);
|
||||
METER::flush_meter (txa->micmeter.p);
|
||||
AMSQ::flush_amsq (txa->amsq.p);
|
||||
EQP::flush_eqp (txa->eqp.p);
|
||||
METER::flush_meter (txa->eqmeter.p);
|
||||
EMPHP::flush_emphp (txa->preemph.p);
|
||||
WCPAGC::flush_wcpagc (txa->leveler.p);
|
||||
METER::flush_meter (txa->lvlrmeter.p);
|
||||
CFCOMP::flush_cfcomp (txa->cfcomp.p);
|
||||
METER::flush_meter (txa->cfcmeter.p);
|
||||
BANDPASS::flush_bandpass (txa->bp0.p);
|
||||
COMPRESSOR::flush_compressor (txa->compressor.p);
|
||||
BANDPASS::flush_bandpass (txa->bp1.p);
|
||||
OSCTRL::flush_osctrl (txa->osctrl.p);
|
||||
BANDPASS::flush_bandpass (txa->bp2.p);
|
||||
METER::flush_meter (txa->compmeter.p);
|
||||
WCPAGC::flush_wcpagc (txa->alc.p);
|
||||
AMMOD::flush_ammod (txa->ammod.p);
|
||||
FMMOD::flush_fmmod (txa->fmmod.p);
|
||||
GEN::flush_gen (txa->gen1.p);
|
||||
USLEW::flush_uslew (txa->uslew.p);
|
||||
METER::flush_meter (txa->alcmeter.p);
|
||||
SIPHON::flush_siphon (txa->sip1.p);
|
||||
IQC::flush_iqc (txa->iqc.p0);
|
||||
CFIR::flush_cfir(txa->cfir.p);
|
||||
RESAMPLE::flush_resample (txa->rsmpout.p);
|
||||
METER::flush_meter (txa->outmeter.p);
|
||||
}
|
||||
|
||||
void xtxa (TXA* txa)
|
||||
{
|
||||
RESAMPLE::xresample (txa->rsmpin.p); // input resampler
|
||||
GEN::xgen (txa->gen0.p); // input signal generator
|
||||
PANEL::xpanel (txa->panel.p); // includes MIC gain
|
||||
PHROT::xphrot (txa->phrot.p); // phase rotator
|
||||
METER::xmeter (txa->micmeter.p); // MIC meter
|
||||
AMSQ::xamsqcap (txa->amsq.p); // downward expander capture
|
||||
AMSQ::xamsq (txa->amsq.p); // downward expander action
|
||||
EQP::xeqp (txa->eqp.p); // pre-EQ
|
||||
METER::xmeter (txa->eqmeter.p); // EQ meter
|
||||
EMPHP::xemphp (txa->preemph.p, 0); // FM pre-emphasis (first option)
|
||||
WCPAGC::xwcpagc (txa->leveler.p); // Leveler
|
||||
METER::xmeter (txa->lvlrmeter.p); // Leveler Meter
|
||||
CFCOMP::xcfcomp (txa->cfcomp.p, 0); // Continuous Frequency Compressor with post-EQ
|
||||
METER::xmeter (txa->cfcmeter.p); // CFC+PostEQ Meter
|
||||
BANDPASS::xbandpass (txa->bp0.p, 0); // primary bandpass filter
|
||||
COMPRESSOR::xcompressor (txa->compressor.p); // COMP compressor
|
||||
BANDPASS::xbandpass (txa->bp1.p, 0); // aux bandpass (runs if COMP)
|
||||
OSCTRL::xosctrl (txa->osctrl.p); // CESSB Overshoot Control
|
||||
BANDPASS::xbandpass (txa->bp2.p, 0); // aux bandpass (runs if CESSB)
|
||||
METER::xmeter (txa->compmeter.p); // COMP meter
|
||||
WCPAGC::xwcpagc (txa->alc.p); // ALC
|
||||
AMMOD::xammod (txa->ammod.p); // AM Modulator
|
||||
EMPHP::xemphp (txa->preemph.p, 1); // FM pre-emphasis (second option)
|
||||
FMMOD::xfmmod (txa->fmmod.p); // FM Modulator
|
||||
GEN::xgen (txa->gen1.p); // output signal generator (TUN and Two-tone)
|
||||
USLEW::xuslew (txa->uslew.p); // up-slew for AM, FM, and gens
|
||||
METER::xmeter (txa->alcmeter.p); // ALC Meter
|
||||
SIPHON::xsiphon (txa->sip1.p, 0); // siphon data for display
|
||||
IQC::xiqc (txa->iqc.p0); // PureSignal correction
|
||||
CFIR::xcfir(txa->cfir.p); // compensating FIR filter (used Protocol_2 only)
|
||||
RESAMPLE::xresample (txa->rsmpout.p); // output resampler
|
||||
METER::xmeter (txa->outmeter.p); // output meter
|
||||
// print_peak_env ("env_exception.txt", txa->dsp_outsize, txa->outbuff, 0.7);
|
||||
}
|
||||
|
||||
void TXA::setInputSamplerate (TXA *txa, int dsp_insize, int in_rate)
|
||||
{
|
||||
txa->csDSP.lock();
|
||||
txa->dsp_insize = dsp_insize;
|
||||
txa->in_rate = in_rate;
|
||||
// buffers
|
||||
delete[] (txa->inbuff);
|
||||
txa->inbuff = new double[1 * txa->dsp_insize * 2]; //(double *)malloc0(1 * txa->dsp_insize * sizeof(complex));
|
||||
// input resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpin.p, txa->inbuff, txa->midbuff);
|
||||
RESAMPLE::setSize_resample (txa->rsmpin.p, txa->dsp_insize);
|
||||
RESAMPLE::setInRate_resample (txa->rsmpin.p, txa->in_rate);
|
||||
ResCheck (*txa);
|
||||
txa->csDSP.unlock();
|
||||
}
|
||||
|
||||
void TXA::setOutputSamplerate (TXA* txa, int dsp_outsize, int out_rate)
|
||||
{
|
||||
txa->csDSP.lock();
|
||||
txa->dsp_outsize = dsp_outsize;
|
||||
txa->out_rate = out_rate;
|
||||
// buffers
|
||||
delete[] (txa->outbuff);
|
||||
txa->outbuff = new double[1 * txa->dsp_outsize * 2]; // (double *)malloc0(1 * txa->dsp_outsize * sizeof(complex));
|
||||
// cfir - needs to know input rate of firmware CIC
|
||||
CFIR::setOutRate_cfir (txa->cfir.p, txa->out_rate);
|
||||
// output resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpout.p, txa->midbuff, txa->outbuff);
|
||||
RESAMPLE::setOutRate_resample (txa->rsmpout.p, txa->out_rate);
|
||||
ResCheck (*txa);
|
||||
// output meter
|
||||
METER::setBuffers_meter (txa->outmeter.p, txa->outbuff);
|
||||
METER::setSize_meter (txa->outmeter.p, txa->dsp_outsize);
|
||||
METER::setSamplerate_meter (txa->outmeter.p, txa->out_rate);
|
||||
txa->csDSP.unlock();
|
||||
}
|
||||
|
||||
void TXA::setDSPSamplerate (TXA *txa, int dsp_insize, int dsp_outsize, int dsp_rate)
|
||||
{
|
||||
txa->csDSP.lock();
|
||||
txa->dsp_insize = dsp_insize;
|
||||
txa->dsp_outsize = dsp_outsize;
|
||||
txa->dsp_rate = dsp_rate;
|
||||
// buffers
|
||||
delete[] (txa->inbuff);
|
||||
txa->inbuff = new double[1 * txa->dsp_insize * 2]; // (double *)malloc0(1 * txa->dsp_insize * sizeof(complex));
|
||||
delete[] (txa->outbuff);
|
||||
txa->outbuff = new double[1 * txa->dsp_outsize * 2]; // (double *)malloc0(1 * txa->dsp_outsize * sizeof(complex));
|
||||
// input resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpin.p, txa->inbuff, txa->midbuff);
|
||||
RESAMPLE::setSize_resample (txa->rsmpin.p, txa->dsp_insize);
|
||||
RESAMPLE::setOutRate_resample (txa->rsmpin.p, txa->dsp_rate);
|
||||
// dsp_rate blocks
|
||||
GEN::setSamplerate_gen (txa->gen0.p, txa->dsp_rate);
|
||||
PANEL::setSamplerate_panel (txa->panel.p, txa->dsp_rate);
|
||||
PHROT::setSamplerate_phrot (txa->phrot.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->micmeter.p, txa->dsp_rate);
|
||||
AMSQ::setSamplerate_amsq (txa->amsq.p, txa->dsp_rate);
|
||||
EQP::setSamplerate_eqp (txa->eqp.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->eqmeter.p, txa->dsp_rate);
|
||||
EMPHP::setSamplerate_emphp (txa->preemph.p, txa->dsp_rate);
|
||||
WCPAGC::setSamplerate_wcpagc (txa->leveler.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->lvlrmeter.p, txa->dsp_rate);
|
||||
CFCOMP::setSamplerate_cfcomp (txa->cfcomp.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->cfcmeter.p, txa->dsp_rate);
|
||||
BANDPASS::setSamplerate_bandpass (txa->bp0.p, txa->dsp_rate);
|
||||
COMPRESSOR::setSamplerate_compressor (txa->compressor.p, txa->dsp_rate);
|
||||
BANDPASS::setSamplerate_bandpass (txa->bp1.p, txa->dsp_rate);
|
||||
OSCTRL::setSamplerate_osctrl (txa->osctrl.p, txa->dsp_rate);
|
||||
BANDPASS::setSamplerate_bandpass (txa->bp2.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->compmeter.p, txa->dsp_rate);
|
||||
WCPAGC::setSamplerate_wcpagc (txa->alc.p, txa->dsp_rate);
|
||||
AMMOD::setSamplerate_ammod (txa->ammod.p, txa->dsp_rate);
|
||||
FMMOD::setSamplerate_fmmod (txa->fmmod.p, txa->dsp_rate);
|
||||
GEN::setSamplerate_gen (txa->gen1.p, txa->dsp_rate);
|
||||
USLEW::setSamplerate_uslew (txa->uslew.p, txa->dsp_rate);
|
||||
METER::setSamplerate_meter (txa->alcmeter.p, txa->dsp_rate);
|
||||
SIPHON::setSamplerate_siphon (txa->sip1.p, txa->dsp_rate);
|
||||
IQC::setSamplerate_iqc (txa->iqc.p0, txa->dsp_rate);
|
||||
CFIR::setSamplerate_cfir (txa->cfir.p, txa->dsp_rate);
|
||||
// output resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpout.p, txa->midbuff, txa->outbuff);
|
||||
RESAMPLE::setInRate_resample (txa->rsmpout.p, txa->dsp_rate);
|
||||
ResCheck (*txa);
|
||||
// output meter
|
||||
METER::setBuffers_meter (txa->outmeter.p, txa->outbuff);
|
||||
METER::setSize_meter (txa->outmeter.p, txa->dsp_outsize);
|
||||
txa->csDSP.unlock();
|
||||
}
|
||||
|
||||
void TXA::setDSPBuffsize (TXA *txa, int dsp_insize, int dsp_size, int dsp_outsize)
|
||||
{
|
||||
txa->csDSP.lock();
|
||||
txa->dsp_insize = dsp_insize;
|
||||
txa->dsp_size = dsp_size;
|
||||
txa->dsp_outsize = dsp_outsize;
|
||||
// buffers
|
||||
delete[] (txa->inbuff);
|
||||
txa->inbuff = new double[1 * txa->dsp_insize * 2]; // (double *)malloc0(1 * txa->dsp_insize * sizeof(complex));
|
||||
delete[] (txa->midbuff);
|
||||
txa->midbuff = new double[2 * txa->dsp_size * 2]; // (double *)malloc0(2 * txa->dsp_size * sizeof(complex));
|
||||
delete[] (txa->outbuff);
|
||||
txa->outbuff = new double[1 * txa->dsp_outsize * 2]; // (double *)malloc0(1 * txa->dsp_outsize * sizeof(complex));
|
||||
// input resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpin.p, txa->inbuff, txa->midbuff);
|
||||
RESAMPLE::setSize_resample (txa->rsmpin.p, txa->dsp_insize);
|
||||
// dsp_size blocks
|
||||
GEN::setBuffers_gen (txa->gen0.p, txa->midbuff, txa->midbuff);
|
||||
GEN::setSize_gen (txa->gen0.p, txa->dsp_size);
|
||||
PANEL::setBuffers_panel (txa->panel.p, txa->midbuff, txa->midbuff);
|
||||
PANEL::setSize_panel (txa->panel.p, txa->dsp_size);
|
||||
PHROT::setBuffers_phrot (txa->phrot.p, txa->midbuff, txa->midbuff);
|
||||
PHROT::setSize_phrot (txa->phrot.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->micmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->micmeter.p, txa->dsp_size);
|
||||
AMSQ::setBuffers_amsq (txa->amsq.p, txa->midbuff, txa->midbuff, txa->midbuff);
|
||||
AMSQ::setSize_amsq (txa->amsq.p, txa->dsp_size);
|
||||
EQP::setBuffers_eqp (txa->eqp.p, txa->midbuff, txa->midbuff);
|
||||
EQP::setSize_eqp (txa->eqp.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->eqmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->eqmeter.p, txa->dsp_size);
|
||||
EMPHP::setBuffers_emphp (txa->preemph.p, txa->midbuff, txa->midbuff);
|
||||
EMPHP::setSize_emphp (txa->preemph.p, txa->dsp_size);
|
||||
WCPAGC::setBuffers_wcpagc (txa->leveler.p, txa->midbuff, txa->midbuff);
|
||||
WCPAGC::setSize_wcpagc (txa->leveler.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->lvlrmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->lvlrmeter.p, txa->dsp_size);
|
||||
CFCOMP::setBuffers_cfcomp (txa->cfcomp.p, txa->midbuff, txa->midbuff);
|
||||
CFCOMP::setSize_cfcomp (txa->cfcomp.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->cfcmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->cfcmeter.p, txa->dsp_size);
|
||||
BANDPASS::setBuffers_bandpass (txa->bp0.p, txa->midbuff, txa->midbuff);
|
||||
BANDPASS::setSize_bandpass (txa->bp0.p, txa->dsp_size);
|
||||
COMPRESSOR::setBuffers_compressor (txa->compressor.p, txa->midbuff, txa->midbuff);
|
||||
COMPRESSOR::setSize_compressor (txa->compressor.p, txa->dsp_size);
|
||||
BANDPASS::setBuffers_bandpass (txa->bp1.p, txa->midbuff, txa->midbuff);
|
||||
BANDPASS::setSize_bandpass (txa->bp1.p, txa->dsp_size);
|
||||
OSCTRL::setBuffers_osctrl (txa->osctrl.p, txa->midbuff, txa->midbuff);
|
||||
OSCTRL::setSize_osctrl (txa->osctrl.p, txa->dsp_size);
|
||||
BANDPASS::setBuffers_bandpass (txa->bp2.p, txa->midbuff, txa->midbuff);
|
||||
BANDPASS::setSize_bandpass (txa->bp2.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->compmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->compmeter.p, txa->dsp_size);
|
||||
WCPAGC::setBuffers_wcpagc (txa->alc.p, txa->midbuff, txa->midbuff);
|
||||
WCPAGC::setSize_wcpagc (txa->alc.p, txa->dsp_size);
|
||||
AMMOD::setBuffers_ammod (txa->ammod.p, txa->midbuff, txa->midbuff);
|
||||
AMMOD::setSize_ammod (txa->ammod.p, txa->dsp_size);
|
||||
FMMOD::setBuffers_fmmod (txa->fmmod.p, txa->midbuff, txa->midbuff);
|
||||
FMMOD::setSize_fmmod (txa->fmmod.p, txa->dsp_size);
|
||||
GEN::setBuffers_gen (txa->gen1.p, txa->midbuff, txa->midbuff);
|
||||
GEN::setSize_gen (txa->gen1.p, txa->dsp_size);
|
||||
USLEW::setBuffers_uslew (txa->uslew.p, txa->midbuff, txa->midbuff);
|
||||
USLEW::setSize_uslew (txa->uslew.p, txa->dsp_size);
|
||||
METER::setBuffers_meter (txa->alcmeter.p, txa->midbuff);
|
||||
METER::setSize_meter (txa->alcmeter.p, txa->dsp_size);
|
||||
SIPHON::setBuffers_siphon (txa->sip1.p, txa->midbuff);
|
||||
SIPHON::setSize_siphon (txa->sip1.p, txa->dsp_size);
|
||||
IQC::setBuffers_iqc (txa->iqc.p0, txa->midbuff, txa->midbuff);
|
||||
IQC::setSize_iqc (txa->iqc.p0, txa->dsp_size);
|
||||
CFIR::setBuffers_cfir (txa->cfir.p, txa->midbuff, txa->midbuff);
|
||||
CFIR::setSize_cfir (txa->cfir.p, txa->dsp_size);
|
||||
// output resampler
|
||||
RESAMPLE::setBuffers_resample (txa->rsmpout.p, txa->midbuff, txa->outbuff);
|
||||
RESAMPLE::setSize_resample (txa->rsmpout.p, txa->dsp_size);
|
||||
// output meter
|
||||
METER::setBuffers_meter (txa->outmeter.p, txa->outbuff);
|
||||
METER::setSize_meter (txa->outmeter.p, txa->dsp_outsize);
|
||||
txa->csDSP.unlock();
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void TXA::SetMode (TXA& txa, int mode)
|
||||
{
|
||||
if (txa.mode != mode)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.mode = mode;
|
||||
txa.ammod.p->run = 0;
|
||||
txa.fmmod.p->run = 0;
|
||||
txa.preemph.p->run = 0;
|
||||
switch (mode)
|
||||
{
|
||||
case TXA_AM:
|
||||
case TXA_SAM:
|
||||
txa.ammod.p->run = 1;
|
||||
txa.ammod.p->mode = 0;
|
||||
break;
|
||||
case TXA_DSB:
|
||||
txa.ammod.p->run = 1;
|
||||
txa.ammod.p->mode = 1;
|
||||
break;
|
||||
case TXA_AM_LSB:
|
||||
case TXA_AM_USB:
|
||||
txa.ammod.p->run = 1;
|
||||
txa.ammod.p->mode = 2;
|
||||
break;
|
||||
case TXA_FM:
|
||||
txa.fmmod.p->run = 1;
|
||||
txa.preemph.p->run = 1;
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
SetupBPFilters (txa);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void TXA::SetBandpassFreqs (TXA& txa, double f_low, double f_high)
|
||||
{
|
||||
if ((txa.f_low != f_low) || (txa.f_high != f_high))
|
||||
{
|
||||
txa.f_low = f_low;
|
||||
txa.f_high = f_high;
|
||||
SetupBPFilters (txa);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Internal Functions *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void TXA::ResCheck (TXA& txa)
|
||||
{
|
||||
RESAMPLE *a = txa.rsmpin.p;
|
||||
if (txa.in_rate != txa.dsp_rate)
|
||||
a->run = 1;
|
||||
else
|
||||
a->run = 0;
|
||||
a = txa.rsmpout.p;
|
||||
if (txa.dsp_rate != txa.out_rate)
|
||||
a->run = 1;
|
||||
else
|
||||
a->run = 0;
|
||||
}
|
||||
|
||||
int TXA::UslewCheck (TXA& txa)
|
||||
{
|
||||
return (txa.ammod.p->run == 1) ||
|
||||
(txa.fmmod.p->run == 1) ||
|
||||
(txa.gen0.p->run == 1) ||
|
||||
(txa.gen1.p->run == 1);
|
||||
}
|
||||
|
||||
void TXA::SetupBPFilters (TXA& txa)
|
||||
{
|
||||
txa.bp0.p->run = 1;
|
||||
txa.bp1.p->run = 0;
|
||||
txa.bp2.p->run = 0;
|
||||
switch (txa.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:
|
||||
BANDPASS::CalcBandpassFilter (txa.bp0.p, txa.f_low, txa.f_high, 2.0);
|
||||
if (txa.compressor.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp1.p, txa.f_low, txa.f_high, 2.0);
|
||||
txa.bp1.p->run = 1;
|
||||
if (txa.osctrl.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp2.p, txa.f_low, txa.f_high, 1.0);
|
||||
txa.bp2.p->run = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TXA_DSB:
|
||||
case TXA_AM:
|
||||
case TXA_SAM:
|
||||
case TXA_FM:
|
||||
if (txa.compressor.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp0.p, 0.0, txa.f_high, 2.0);
|
||||
BANDPASS::CalcBandpassFilter (txa.bp1.p, 0.0, txa.f_high, 2.0);
|
||||
txa.bp1.p->run = 1;
|
||||
if (txa.osctrl.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp2.p, 0.0, txa.f_high, 1.0);
|
||||
txa.bp2.p->run = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp0.p, txa.f_low, txa.f_high, 1.0);
|
||||
}
|
||||
break;
|
||||
case TXA_AM_LSB:
|
||||
BANDPASS::CalcBandpassFilter (txa.bp0.p, -txa.f_high, 0.0, 2.0);
|
||||
if (txa.compressor.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp1.p, -txa.f_high, 0.0, 2.0);
|
||||
txa.bp1.p->run = 1;
|
||||
if (txa.osctrl.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp2.p, -txa.f_high, 0.0, 1.0);
|
||||
txa.bp2.p->run = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TXA_AM_USB:
|
||||
BANDPASS::CalcBandpassFilter (txa.bp0.p, 0.0, txa.f_high, 2.0);
|
||||
if (txa.compressor.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp1.p, 0.0, txa.f_high, 2.0);
|
||||
txa.bp1.p->run = 1;
|
||||
if (txa.osctrl.p->run)
|
||||
{
|
||||
BANDPASS::CalcBandpassFilter (txa.bp2.p, 0.0, txa.f_high, 1.0);
|
||||
txa.bp2.p->run = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Collectives *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void TXA::SetNC (TXA& txa, int nc)
|
||||
{
|
||||
int oldstate = txa.state;
|
||||
BANDPASS::SetBandpassNC (txa, nc);
|
||||
EMPHP::SetFMEmphNC (txa, nc);
|
||||
EQP::SetEQNC (txa, nc);
|
||||
FMMOD::SetFMNC (txa, nc);
|
||||
CFIR::SetCFIRNC (txa, nc);
|
||||
txa.state = oldstate;
|
||||
}
|
||||
|
||||
void TXA::SetMP (TXA& txa, int mp)
|
||||
{
|
||||
BANDPASS::SetBandpassMP (txa, mp);
|
||||
EMPHP::SetFMEmphMP (txa, mp);
|
||||
EQP::SetEQMP (txa, mp);
|
||||
FMMOD::SetFMMP (txa, mp);
|
||||
}
|
||||
|
||||
void TXA::SetFMAFFilter (TXA& txa, double low, double high)
|
||||
{
|
||||
EMPHP::SetFMPreEmphFreqs (txa, low, high);
|
||||
FMMOD::SetFMAFFreqs (txa, low, high);
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
258
wdsp/TXA.hpp
Normal file
258
wdsp/TXA.hpp
Normal file
@ -0,0 +1,258 @@
|
||||
/* TXA.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_txa_h
|
||||
#define wdsp_txa_h
|
||||
|
||||
#include <atomic>
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "unit.hpp"
|
||||
|
||||
#include "ammod.hpp"
|
||||
#include "meter.hpp"
|
||||
#include "resample.hpp"
|
||||
#include "patchpanel.hpp"
|
||||
#include "amsq.hpp"
|
||||
#include "eq.hpp"
|
||||
#include "iir.hpp"
|
||||
#include "cfcomp.hpp"
|
||||
#include "compress.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "bps.hpp"
|
||||
#include "osctrl.hpp"
|
||||
#include "wcpAGC.hpp"
|
||||
#include "emph.hpp"
|
||||
#include "fmmod.hpp"
|
||||
#include "siphon.hpp"
|
||||
#include "gen.hpp"
|
||||
#include "slew.hpp"
|
||||
// #include "calcc.h"
|
||||
#include "iqc.hpp"
|
||||
#include "cfir.hpp"
|
||||
#include "export.h"
|
||||
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class METER;
|
||||
class RESAMPLE;
|
||||
class PANEL;
|
||||
class AMSQ;
|
||||
class EQP;
|
||||
class PHROT;
|
||||
class CFCOMP;
|
||||
class COMPRESSOR;
|
||||
class BANDPASS;
|
||||
class BPS;
|
||||
class OSCTRL;
|
||||
class WCPAGC;
|
||||
class AMMOD;
|
||||
class EMPHP;
|
||||
class FMMOD;
|
||||
class SIPHON;
|
||||
class GEN;
|
||||
class USLEW;
|
||||
class IQC;
|
||||
class CFIR;
|
||||
|
||||
class WDSP_API TXA : public Unit
|
||||
{
|
||||
public:
|
||||
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
|
||||
};
|
||||
|
||||
double* inbuff;
|
||||
double* outbuff;
|
||||
double* midbuff;
|
||||
int mode;
|
||||
double f_low;
|
||||
double f_high;
|
||||
double meter[TXA_METERTYPE_LAST];
|
||||
QRecursiveMutex *pmtupdate[TXA_METERTYPE_LAST];
|
||||
std::atomic<long> upslew;
|
||||
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
|
||||
{
|
||||
BPS *p;
|
||||
} bps0, bps1, bps2;
|
||||
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;
|
||||
|
||||
static TXA* create_txa (
|
||||
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
|
||||
);
|
||||
static void destroy_txa (TXA *txa);
|
||||
static void flush_txa (TXA *txa);
|
||||
static void xtxa (TXA *txa);
|
||||
static void setInputSamplerate (TXA *txa, int dsp_insize, int in_rate);
|
||||
static void setOutputSamplerate (TXA *txa, int dsp_outsize, int out_rate);
|
||||
static void setDSPSamplerate (TXA *txa, int dsp_insize, int dsp_outsize, int dsp_rate);
|
||||
static void setDSPBuffsize (TXA *txa, int dsp_insize, int dsp_size, int dsp_outsize);
|
||||
|
||||
// TXA Properties
|
||||
static void SetMode (TXA& txa, int mode);
|
||||
static void SetBandpassFreqs (TXA& txa, double f_low, double f_high);
|
||||
|
||||
// Collectives
|
||||
static void SetNC (TXA& txa, int nc);
|
||||
static void SetMP (TXA& txa, int mp);
|
||||
static void SetFMAFFilter (TXA& txa, double low, double high);
|
||||
static void SetupBPFilters (TXA& txa);
|
||||
static int UslewCheck (TXA& txa);
|
||||
|
||||
private:
|
||||
static void ResCheck (TXA& txa);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
305
wdsp/amd.cpp
Normal file
305
wdsp/amd.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
/* amd.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 <cmath>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "amd.hpp"
|
||||
#include "anf.hpp"
|
||||
#include "emnr.hpp"
|
||||
#include "anr.hpp"
|
||||
#include "snb.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
AMD* 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 = new 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 AMD::destroy_amd(AMD *a)
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
|
||||
void AMD::init_amd(AMD *a)
|
||||
{
|
||||
//pll
|
||||
a->omega_min = 2 * M_PI * a->fmin / a->sample_rate;
|
||||
a->omega_max = 2 * M_PI * a->fmax / a->sample_rate;
|
||||
a->g1 = 1.0 - std::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 AMD::flush_amd (AMD *a)
|
||||
{
|
||||
a->dc = 0.0;
|
||||
a->dc_insert = 0.0;
|
||||
}
|
||||
|
||||
void AMD::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 >= 2 * M_PI) a->phs -= 2 * M_PI;
|
||||
while (a->phs < 0.0) a->phs += 2 * M_PI;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (a->in_buff != a->out_buff)
|
||||
{
|
||||
memcpy (a->out_buff, a->in_buff, a->buff_size * sizeof(dcomplex));
|
||||
}
|
||||
}
|
||||
|
||||
void AMD::setBuffers_amd (AMD *a, double* in, double* out)
|
||||
{
|
||||
a->in_buff = in;
|
||||
a->out_buff = out;
|
||||
}
|
||||
|
||||
void AMD::setSamplerate_amd (AMD *a, int rate)
|
||||
{
|
||||
a->sample_rate = rate;
|
||||
init_amd(a);
|
||||
}
|
||||
|
||||
void AMD::setSize_amd (AMD *a, int size)
|
||||
{
|
||||
a->buff_size = size;
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void AMD::SetAMDRun(RXA& rxa, int run)
|
||||
{
|
||||
AMD *a = rxa.amd.p;
|
||||
if (a->run != run)
|
||||
{
|
||||
RXA::bp1Check (rxa, run, rxa.snba.p->run, rxa.emnr.p->run,
|
||||
rxa.anf.p->run, rxa.anr.p->run);
|
||||
rxa.csDSP.lock();
|
||||
a->run = run;
|
||||
RXA::bp1Set (rxa);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void AMD::SetAMDSBMode(RXA& rxa, int sbmode)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.amd.p->sbmode = sbmode;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void AMD::SetAMDFadeLevel(RXA& rxa, int levelfade)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.amd.p->levelfade = levelfade;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namesoace WDSP
|
116
wdsp/amd.hpp
Normal file
116
wdsp/amd.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
/* amd.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_amd_hpp
|
||||
#define wdsp_amd_hpp
|
||||
|
||||
// ff defines for sbdemod
|
||||
#ifndef STAGES
|
||||
#define STAGES 7
|
||||
#endif
|
||||
|
||||
#ifndef OUT_IDX
|
||||
#define OUT_IDX (3 * STAGES)
|
||||
#endif
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class WDSP_API AMD {
|
||||
public:
|
||||
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
|
||||
|
||||
static 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
|
||||
);
|
||||
|
||||
static void init_amd (AMD *a);
|
||||
static void destroy_amd (AMD *a);
|
||||
static void flush_amd (AMD *a);
|
||||
static void xamd (AMD *a);
|
||||
static void setBuffers_amd (AMD *a, double* in, double* out);
|
||||
static void setSamplerate_amd (AMD *a, int rate);
|
||||
static void setSize_amd (AMD *a, int size);
|
||||
// RXA Properties
|
||||
static void SetAMDRun(RXA& rxa, int run);
|
||||
static void SetAMDSBMode(RXA& rxa, int sbmode);
|
||||
static void SetAMDFadeLevel(RXA& rxa, int levelfade);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
119
wdsp/ammod.cpp
Normal file
119
wdsp/ammod.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* ammod.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 <cmath>
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
#include "ammod.hpp"
|
||||
#include "comm.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
AMMOD* AMMOD::create_ammod (int run, int mode, int size, double* in, double* out, double c_level)
|
||||
{
|
||||
AMMOD *a = new 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 AMMOD::destroy_ammod(AMMOD *a)
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
|
||||
void AMMOD::flush_ammod(AMMOD *)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AMMOD::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 (dcomplex));
|
||||
}
|
||||
|
||||
void AMMOD::setBuffers_ammod(AMMOD *a, double* in, double* out)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
}
|
||||
|
||||
void AMMOD::setSamplerate_ammod(AMMOD *, int)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AMMOD::setSize_ammod(AMMOD *a, int size)
|
||||
{
|
||||
a->size = size;
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void AMMOD::SetAMCarrierLevel (TXA& txa, double c_level)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.ammod.p->c_level = c_level;
|
||||
txa.ammod.p->a_level = 1.0 - c_level;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
62
wdsp/ammod.hpp
Normal file
62
wdsp/ammod.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* ammod.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_ammod_h
|
||||
#define wdsp_ammod_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class TXA;
|
||||
|
||||
class WDSP_API AMMOD
|
||||
{
|
||||
public:
|
||||
int run;
|
||||
int mode;
|
||||
int size;
|
||||
double* in;
|
||||
double* out;
|
||||
double c_level;
|
||||
double a_level;
|
||||
double mult;
|
||||
|
||||
static AMMOD* create_ammod(int run, int mode, int size, double* in, double* out, double c_level);
|
||||
static void destroy_ammod (AMMOD *a);
|
||||
static void flush_ammod (AMMOD *a);
|
||||
static void xammod (AMMOD *a);
|
||||
static void setBuffers_ammod (AMMOD *a, double* in, double* out);
|
||||
static void setSamplerate_ammod (AMMOD *a, int rate);
|
||||
static void setSize_ammod (AMMOD *a, int size);
|
||||
// TXA Properties
|
||||
static void SetAMCarrierLevel (TXA& txa, double c_level);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
276
wdsp/amsq.cpp
Normal file
276
wdsp/amsq.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
/* amsq.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 <QRecursiveMutex>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "amsq.hpp"
|
||||
#include "RXA.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void AMSQ::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 AMSQ::calc_amsq(AMSQ *a)
|
||||
{
|
||||
// signal averaging
|
||||
a->trigsig = new double[a->size * 2]; // (double *)malloc0(a->size * sizeof(dcomplex));
|
||||
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 = new double[(a->ntup + 1) * 2]; // (double *)malloc0((a->ntup + 1) * sizeof(double));
|
||||
a->cdown = new double[(a->ntdown + 1) * 2]; // (double *)malloc0((a->ntdown + 1) * sizeof(double));
|
||||
compute_slews(a);
|
||||
// control
|
||||
a->state = 0;
|
||||
}
|
||||
|
||||
void AMSQ::decalc_amsq (AMSQ *a)
|
||||
{
|
||||
delete[] a->cdown;
|
||||
delete[] a->cup;
|
||||
delete[] a->trigsig;
|
||||
}
|
||||
|
||||
AMSQ* 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 = new 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 AMSQ::destroy_amsq (AMSQ *a)
|
||||
{
|
||||
decalc_amsq (a);
|
||||
delete a;
|
||||
}
|
||||
|
||||
void AMSQ::flush_amsq (AMSQ*a)
|
||||
{
|
||||
memset (a->trigsig, 0, a->size * sizeof (dcomplex));
|
||||
a->avsig = 0.0;
|
||||
a->state = 0;
|
||||
}
|
||||
|
||||
enum _amsqstate
|
||||
{
|
||||
MUTED,
|
||||
INCREASE,
|
||||
UNMUTED,
|
||||
TAIL,
|
||||
DECREASE
|
||||
};
|
||||
|
||||
void AMSQ::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 (dcomplex));
|
||||
}
|
||||
|
||||
void AMSQ::xamsqcap (AMSQ *a)
|
||||
{
|
||||
memcpy (a->trigsig, a->trigger, a->size * sizeof (dcomplex));
|
||||
}
|
||||
|
||||
void AMSQ::setBuffers_amsq (AMSQ *a, double* in, double* out, double* trigger)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
a->trigger = trigger;
|
||||
}
|
||||
|
||||
void AMSQ::setSamplerate_amsq (AMSQ *a, int rate)
|
||||
{
|
||||
decalc_amsq (a);
|
||||
a->rate = rate;
|
||||
calc_amsq (a);
|
||||
}
|
||||
|
||||
void AMSQ::setSize_amsq (AMSQ *a, int size)
|
||||
{
|
||||
decalc_amsq (a);
|
||||
a->size = size;
|
||||
calc_amsq (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void AMSQ::SetAMSQRun (RXA& rxa, int run)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.amsq.p->run = run;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void AMSQ::SetAMSQThreshold (RXA& rxa, double threshold)
|
||||
{
|
||||
double thresh = pow (10.0, threshold / 20.0);
|
||||
rxa.csDSP.lock();
|
||||
rxa.amsq.p->tail_thresh = 0.9 * thresh;
|
||||
rxa.amsq.p->unmute_thresh = thresh;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void AMSQ::SetAMSQMaxTail (RXA& rxa, double tail)
|
||||
{
|
||||
AMSQ *a;
|
||||
rxa.csDSP.lock();
|
||||
a = rxa.amsq.p;
|
||||
if (tail < a->min_tail) tail = a->min_tail;
|
||||
a->max_tail = tail;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void AMSQ::SetAMSQRun (TXA& txa, int run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.amsq.p->run = run;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void AMSQ::SetAMSQMutedGain (TXA& txa, double dBlevel)
|
||||
{ // dBlevel is negative
|
||||
AMSQ *a;
|
||||
txa.csDSP.lock();
|
||||
a = txa.amsq.p;
|
||||
a->muted_gain = pow (10.0, dBlevel / 20.0);
|
||||
compute_slews(a);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void AMSQ::SetAMSQThreshold (TXA& txa, double threshold)
|
||||
{
|
||||
double thresh = pow (10.0, threshold / 20.0);
|
||||
txa.csDSP.lock();
|
||||
txa.amsq.p->tail_thresh = 0.9 * thresh;
|
||||
txa.amsq.p->unmute_thresh = thresh;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
90
wdsp/amsq.hpp
Normal file
90
wdsp/amsq.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* amsq.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
class TXA;
|
||||
|
||||
class WDSP_API AMSQ
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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);
|
||||
static void destroy_amsq (AMSQ *a);
|
||||
static void flush_amsq (AMSQ *a);
|
||||
static void xamsq (AMSQ *a);
|
||||
static void xamsqcap (AMSQ *a);
|
||||
static void setBuffers_amsq (AMSQ *a, double* in, double* out, double* trigger);
|
||||
static void setSamplerate_amsq (AMSQ *a, int rate);
|
||||
static void setSize_amsq (AMSQ *a, int size);
|
||||
// RXA Properties
|
||||
static void SetAMSQRun (RXA& rxa, int run);
|
||||
static void SetAMSQThreshold (RXA& rxa, double threshold);
|
||||
static void SetAMSQMaxTail (RXA& rxa, double tail);
|
||||
// TXA Properties
|
||||
static void SetAMSQRun (TXA& txa, int run);
|
||||
static void SetAMSQMutedGain (TXA& txa, double dBlevel);
|
||||
static void SetAMSQThreshold (TXA& txa, double threshold);
|
||||
|
||||
private:
|
||||
static void compute_slews(AMSQ *a);
|
||||
static void calc_amsq(AMSQ *a);
|
||||
static void decalc_amsq (AMSQ *a);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
243
wdsp/anf.cpp
Normal file
243
wdsp/anf.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/* anf.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "amd.hpp"
|
||||
#include "snb.hpp"
|
||||
#include "emnr.hpp"
|
||||
#include "anr.hpp"
|
||||
#include "anf.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
ANF* 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 = new 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 ANF::destroy_anf (ANF *a)
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
|
||||
void ANF::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 (dcomplex));
|
||||
}
|
||||
|
||||
void ANF::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 ANF::setBuffers_anf (ANF *a, double* in, double* out)
|
||||
{
|
||||
a->in_buff = in;
|
||||
a->out_buff = out;
|
||||
}
|
||||
|
||||
void ANF::setSamplerate_anf (ANF *a, int)
|
||||
{
|
||||
flush_anf (a);
|
||||
}
|
||||
|
||||
void ANF::setSize_anf (ANF *a, int size)
|
||||
{
|
||||
a->buff_size = size;
|
||||
flush_anf (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void ANF::SetANFRun (RXA& rxa, int run)
|
||||
{
|
||||
ANF *a = rxa.anf.p;
|
||||
if (a->run != run)
|
||||
{
|
||||
RXA::bp1Check (rxa, rxa.amd.p->run, rxa.snba.p->run,
|
||||
rxa.emnr.p->run, run, rxa.anr.p->run);
|
||||
rxa.csDSP.lock();
|
||||
a->run = run;
|
||||
RXA::bp1Set (rxa);
|
||||
flush_anf (a);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ANF::SetANFVals (RXA& rxa, int taps, int delay, double gain, double leakage)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->n_taps = taps;
|
||||
rxa.anf.p->delay = delay;
|
||||
rxa.anf.p->two_mu = gain; //try two_mu = 1e-4
|
||||
rxa.anf.p->gamma = leakage; //try gamma = 0.10
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANF::SetANFTaps (RXA& rxa, int taps)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->n_taps = taps;
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANF::SetANFDelay (RXA& rxa, int delay)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->delay = delay;
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANF::SetANFGain (RXA& rxa, double gain)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->two_mu = gain;
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANF::SetANFLeakage (RXA& rxa, double leakage)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->gamma = leakage;
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANF::SetANFPosition (RXA& rxa, int position)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anf.p->position = position;
|
||||
rxa.bp1.p->position = position;
|
||||
flush_anf (rxa.anf.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
101
wdsp/anf.hpp
Normal file
101
wdsp/anf.hpp
Normal file
@ -0,0 +1,101 @@
|
||||
/* anf.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_anf_h
|
||||
#define wdsp_anf_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
#define ANF_DLINE_SIZE 2048
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class WDSP_API ANF
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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
|
||||
);
|
||||
static void destroy_anf (ANF *a);
|
||||
static void flush_anf (ANF *a);
|
||||
static void xanf (ANF *a, int position);
|
||||
static void setBuffers_anf (ANF *a, double* in, double* out);
|
||||
static void setSamplerate_anf (ANF *a, int rate);
|
||||
static void setSize_anf (ANF *a, int size);
|
||||
// RXA Properties
|
||||
static void SetANFRun (RXA& rxa, int setit);
|
||||
static void SetANFVals (RXA& rxa, int taps, int delay, double gain, double leakage);
|
||||
static void SetANFTaps (RXA& rxa, int taps);
|
||||
static void SetANFDelay (RXA& rxa, int delay);
|
||||
static void SetANFGain (RXA& rxa, double gain);
|
||||
static void SetANFLeakage (RXA& rxa, double leakage);
|
||||
static void SetANFPosition (RXA& rxa, int position);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
245
wdsp/anr.cpp
Normal file
245
wdsp/anr.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/* anr.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 <QRecursiveMutex>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "anr.hpp"
|
||||
#include "amd.hpp"
|
||||
#include "snb.hpp"
|
||||
#include "emnr.hpp"
|
||||
#include "anf.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
ANR* 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 = new 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 ANR::destroy_anr (ANR *a)
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
|
||||
void ANR::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 (dcomplex));
|
||||
}
|
||||
|
||||
void ANR::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 ANR::setBuffers_anr (ANR *a, double* in, double* out)
|
||||
{
|
||||
a->in_buff = in;
|
||||
a->out_buff = out;
|
||||
}
|
||||
|
||||
void ANR::setSamplerate_anr (ANR *a, int)
|
||||
{
|
||||
flush_anr(a);
|
||||
}
|
||||
|
||||
void ANR::setSize_anr (ANR *a, int size)
|
||||
{
|
||||
a->buff_size = size;
|
||||
flush_anr(a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void ANR::SetANRRun (RXA& rxa, int run)
|
||||
{
|
||||
ANR *a = rxa.anr.p;
|
||||
if (a->run != run)
|
||||
{
|
||||
RXA::bp1Check (rxa, rxa.amd.p->run, rxa.snba.p->run,
|
||||
rxa.emnr.p->run, rxa.anf.p->run, run);
|
||||
rxa.csDSP.lock();
|
||||
a->run = run;
|
||||
RXA::bp1Set (rxa);
|
||||
flush_anr (a);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ANR::SetANRVals (RXA& rxa, int taps, int delay, double gain, double leakage)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->n_taps = taps;
|
||||
rxa.anr.p->delay = delay;
|
||||
rxa.anr.p->two_mu = gain;
|
||||
rxa.anr.p->gamma = leakage;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANR::SetANRTaps (RXA& rxa, int taps)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->n_taps = taps;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANR::SetANRDelay (RXA& rxa, int delay)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->delay = delay;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANR::SetANRGain (RXA& rxa, double gain)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->two_mu = gain;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANR::SetANRLeakage (RXA& rxa, double leakage)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->gamma = leakage;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void ANR::SetANRPosition (RXA& rxa, int position)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.anr.p->position = position;
|
||||
rxa.bp1.p->position = position;
|
||||
flush_anr (rxa.anr.p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
104
wdsp/anr.hpp
Normal file
104
wdsp/anr.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* anr.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2012, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_anr_h
|
||||
#define wdsp_anr_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
#define ANR_DLINE_SIZE 2048
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class WDSP_API ANR
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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
|
||||
);
|
||||
|
||||
static void destroy_anr (ANR *a);
|
||||
static void flush_anr (ANR *a);
|
||||
static void xanr (ANR *a, int position);
|
||||
static void setBuffers_anr (ANR *a, double* in, double* out);
|
||||
static void setSamplerate_anr (ANR *a, int rate);
|
||||
static void setSize_anr (ANR *a, int size);
|
||||
// RXA Properties
|
||||
static void SetANRRun (RXA& rxa, int setit);
|
||||
static void SetANRVals (RXA& rxa, int taps, int delay, double gain, double leakage);
|
||||
static void SetANRTaps (RXA& rxa, int taps);
|
||||
static void SetANRDelay (RXA& rxa, int delay);
|
||||
static void SetANRGain (RXA& rxa, double gain);
|
||||
static void SetANRLeakage (RXA& rxa, double leakage);
|
||||
static void SetANRPosition (RXA& rxa, int position);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
285
wdsp/bandpass.cpp
Normal file
285
wdsp/bandpass.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
/* bandpass.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "fir.hpp"
|
||||
#include "firmin.hpp"
|
||||
#include "RXA.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Partitioned Overlap-Save Bandpass *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
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 = new 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::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
a->p = FIRCORE::create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||
delete[] impulse;
|
||||
return a;
|
||||
}
|
||||
|
||||
void BANDPASS::destroy_bandpass (BANDPASS *a)
|
||||
{
|
||||
FIRCORE::destroy_fircore (a->p);
|
||||
delete a;
|
||||
}
|
||||
|
||||
void BANDPASS::flush_bandpass (BANDPASS *a)
|
||||
{
|
||||
FIRCORE::flush_fircore (a->p);
|
||||
}
|
||||
|
||||
void BANDPASS::xbandpass (BANDPASS *a, int pos)
|
||||
{
|
||||
if (a->run && a->position == pos)
|
||||
FIRCORE::xfircore (a->p);
|
||||
else if (a->out != a->in)
|
||||
memcpy (a->out, a->in, a->size * sizeof (dcomplex));
|
||||
}
|
||||
|
||||
void BANDPASS::setBuffers_bandpass (BANDPASS *a, double* in, double* out)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
FIRCORE::setBuffers_fircore (a->p, a->in, a->out);
|
||||
}
|
||||
|
||||
void BANDPASS::setSamplerate_bandpass (BANDPASS *a, int rate)
|
||||
{
|
||||
double* impulse;
|
||||
a->samplerate = rate;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setImpulse_fircore (a->p, impulse, 1);
|
||||
delete[] impulse;
|
||||
}
|
||||
|
||||
void BANDPASS::setSize_bandpass (BANDPASS *a, int size)
|
||||
{
|
||||
// NOTE: 'size' must be <= 'nc'
|
||||
double* impulse;
|
||||
a->size = size;
|
||||
FIRCORE::setSize_fircore (a->p, a->size);
|
||||
// recalc impulse because scale factor is a function of size
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setImpulse_fircore (a->p, impulse, 1);
|
||||
delete[] (impulse);
|
||||
}
|
||||
|
||||
void BANDPASS::setGain_bandpass (BANDPASS *a, double gain, int update)
|
||||
{
|
||||
double* impulse;
|
||||
a->gain = gain;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setImpulse_fircore (a->p, impulse, update);
|
||||
delete[] (impulse);
|
||||
}
|
||||
|
||||
void BANDPASS::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::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setImpulse_fircore (a->p, impulse, 1);
|
||||
delete[] (impulse);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void BANDPASS::SetBandpassFreqs (RXA& rxa, double f_low, double f_high)
|
||||
{
|
||||
double* impulse;
|
||||
BANDPASS *a = rxa.bp1.p;
|
||||
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||
{
|
||||
impulse = FIR::fir_bandpass (a->nc, f_low, f_high, a->samplerate,
|
||||
a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setImpulse_fircore (a->p, impulse, 0);
|
||||
delete[] (impulse);
|
||||
rxa.csDSP.lock();
|
||||
a->f_low = f_low;
|
||||
a->f_high = f_high;
|
||||
FIRCORE::setUpdate_fircore (a->p);
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void BANDPASS::SetBandpassNC (RXA& rxa, int nc)
|
||||
{
|
||||
// NOTE: 'nc' must be >= 'size'
|
||||
double* impulse;
|
||||
BANDPASS *a;
|
||||
rxa.csDSP.lock();
|
||||
a = rxa.bp1.p;
|
||||
if (nc != a->nc)
|
||||
{
|
||||
a->nc = nc;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setNc_fircore (a->p, a->nc, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BANDPASS::SetBandpassMP (RXA& rxa, int mp)
|
||||
{
|
||||
BANDPASS *a;
|
||||
a = rxa.bp1.p;
|
||||
if (mp != a->mp)
|
||||
{
|
||||
a->mp = mp;
|
||||
FIRCORE::setMp_fircore (a->p, a->mp);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
//PORT
|
||||
//void SetTXABandpassFreqs (int channel, double f_low, double f_high)
|
||||
//{
|
||||
// double* impulse;
|
||||
// BANDPASS a;
|
||||
// a = txa.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);
|
||||
// delete[] (impulse);
|
||||
// }
|
||||
// a = txa.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);
|
||||
// delete[] (impulse);
|
||||
// }
|
||||
// a = txa.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);
|
||||
// delete[] (impulse);
|
||||
// }
|
||||
//}
|
||||
|
||||
void BANDPASS::SetBandpassNC (TXA& txa, int nc)
|
||||
{
|
||||
// NOTE: 'nc' must be >= 'size'
|
||||
double* impulse;
|
||||
BANDPASS *a;
|
||||
txa.csDSP.lock();
|
||||
a = txa.bp0.p;
|
||||
if (a->nc != nc)
|
||||
{
|
||||
a->nc = nc;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setNc_fircore (a->p, a->nc, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bp1.p;
|
||||
if (a->nc != nc)
|
||||
{
|
||||
a->nc = nc;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setNc_fircore (a->p, a->nc, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bp2.p;
|
||||
if (a->nc != nc)
|
||||
{
|
||||
a->nc = nc;
|
||||
impulse = FIR::fir_bandpass (a->nc, a->f_low, a->f_high, a->samplerate, a->wintype, 1, a->gain / (double)(2 * a->size));
|
||||
FIRCORE::setNc_fircore (a->p, a->nc, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BANDPASS::SetBandpassMP (TXA& txa, int mp)
|
||||
{
|
||||
BANDPASS *a;
|
||||
a = txa.bp0.p;
|
||||
if (mp != a->mp)
|
||||
{
|
||||
a->mp = mp;
|
||||
FIRCORE::setMp_fircore (a->p, a->mp);
|
||||
}
|
||||
a = txa.bp1.p;
|
||||
if (mp != a->mp)
|
||||
{
|
||||
a->mp = mp;
|
||||
FIRCORE::setMp_fircore (a->p, a->mp);
|
||||
}
|
||||
a = txa.bp2.p;
|
||||
if (mp != a->mp)
|
||||
{
|
||||
a->mp = mp;
|
||||
FIRCORE::setMp_fircore (a->p, a->mp);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
90
wdsp/bandpass.hpp
Normal file
90
wdsp/bandpass.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* bandpass.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_bandpass_h
|
||||
#define wdsp_bandpass_h
|
||||
|
||||
#include "fftw3.h"
|
||||
#include "export.h"
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Partitioned Overlap-Save Bandpass *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class FIRCORE;
|
||||
class RXA;
|
||||
class TXA;
|
||||
|
||||
class WDSP_API BANDPASS
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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);
|
||||
static void destroy_bandpass (BANDPASS *a);
|
||||
static void flush_bandpass (BANDPASS *a);
|
||||
static void xbandpass (BANDPASS *a, int pos);
|
||||
static void setBuffers_bandpass (BANDPASS *a, double* in, double* out);
|
||||
static void setSamplerate_bandpass (BANDPASS *a, int rate);
|
||||
static void setSize_bandpass (BANDPASS *a, int size);
|
||||
static void setGain_bandpass (BANDPASS *a, double gain, int update);
|
||||
static void CalcBandpassFilter (BANDPASS *a, double f_low, double f_high, double gain);
|
||||
// RXA Prototypes
|
||||
static void SetBandpassFreqs (RXA& rxa, double f_low, double f_high);
|
||||
static void SetBandpassNC (RXA& rxa, int nc);
|
||||
static void SetBandpassMP (RXA& rxa, int mp);
|
||||
// TXA Prototypes
|
||||
static void SetBandpassNC (TXA& txa, int nc);
|
||||
static void SetBandpassMP (TXA& txa, int mp);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
404
wdsp/bldr.cpp
Normal file
404
wdsp/bldr.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
/* lmath.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2015, 2016, 2023 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "bldr.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
BLDR* BLDR::create_builder(int points, int ints)
|
||||
{
|
||||
// for the create function, 'points' and 'ints' are the MAXIMUM values that will be encountered
|
||||
BLDR *a = new BLDR;
|
||||
a->catxy = new double[2 * points]; // (double*)malloc0(2 * points * sizeof(double));
|
||||
a->sx = new double[points]; // (double*)malloc0( points * sizeof(double));
|
||||
a->sy = new double[points]; // (double*)malloc0( points * sizeof(double));
|
||||
a->h = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->p = new int[ints]; // (int*) malloc0( ints * sizeof(int));
|
||||
a->np = new int[ints]; // (int*) malloc0( ints * sizeof(int));
|
||||
a->taa = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tab = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tag = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tad = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tbb = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tbg = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tbd = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tgg = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tgd = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
a->tdd = new double[ints]; // (double*)malloc0( ints * sizeof(double));
|
||||
int nsize = 3 * ints + 1;
|
||||
int intp1 = ints + 1;
|
||||
int intm1 = ints - 1;
|
||||
a->A = new double[intp1 * intp1]; // (double*)malloc0(intp1 * intp1 * sizeof(double));
|
||||
a->B = new double[intp1 * intp1]; // (double*)malloc0(intp1 * intp1 * sizeof(double));
|
||||
a->C = new double[intp1 * intp1]; // (double*)malloc0(intm1 * intp1 * sizeof(double));
|
||||
a->D = new double[intp1]; // (double*)malloc0(intp1 * sizeof(double));
|
||||
a->E = new double[intp1 * intp1]; // (double*)malloc0(intp1 * intp1 * sizeof(double));
|
||||
a->F = new double[intm1 * intp1]; // (double*)malloc0(intm1 * intp1 * sizeof(double));
|
||||
a->G = new double[intp1]; // (double*)malloc0(intp1 * sizeof(double));
|
||||
a->MAT = new double[nsize * nsize]; // (double*)malloc0(nsize * nsize * sizeof(double));
|
||||
a->RHS = new double[nsize]; // (double*)malloc0(nsize * sizeof(double));
|
||||
a->SLN = new double[nsize]; // (double*)malloc0(nsize * sizeof(double));
|
||||
a->z = new double[intp1]; // (double*)malloc0(intp1 * sizeof(double));
|
||||
a->zp = new double[intp1]; // (double*)malloc0(intp1 * sizeof(double));
|
||||
a->wrk = new double[nsize]; // (double*)malloc0(nsize * sizeof(double));
|
||||
a->ipiv = new int[nsize]; // (int*) malloc0(nsize * sizeof(int));
|
||||
return a;
|
||||
}
|
||||
|
||||
void BLDR::destroy_builder(BLDR *a)
|
||||
{
|
||||
delete[](a->ipiv);
|
||||
delete[](a->wrk);
|
||||
delete[](a->catxy);
|
||||
delete[](a->sx);
|
||||
delete[](a->sy);
|
||||
delete[](a->h);
|
||||
delete[](a->p);
|
||||
delete[](a->np);
|
||||
|
||||
delete[](a->taa);
|
||||
delete[](a->tab);
|
||||
delete[](a->tag);
|
||||
delete[](a->tad);
|
||||
delete[](a->tbb);
|
||||
delete[](a->tbg);
|
||||
delete[](a->tbd);
|
||||
delete[](a->tgg);
|
||||
delete[](a->tgd);
|
||||
delete[](a->tdd);
|
||||
|
||||
delete[](a->A);
|
||||
delete[](a->B);
|
||||
delete[](a->C);
|
||||
delete[](a->D);
|
||||
delete[](a->E);
|
||||
delete[](a->F);
|
||||
delete[](a->G);
|
||||
|
||||
delete[](a->MAT);
|
||||
delete[](a->RHS);
|
||||
delete[](a->SLN);
|
||||
|
||||
delete[](a->z);
|
||||
delete[](a->zp);
|
||||
|
||||
delete(a);
|
||||
}
|
||||
|
||||
void BLDRflush_builder(BLDR *a, int points, int ints)
|
||||
{
|
||||
memset(a->catxy, 0, 2 * points * sizeof(double));
|
||||
memset(a->sx, 0, points * sizeof(double));
|
||||
memset(a->sy, 0, points * sizeof(double));
|
||||
memset(a->h, 0, ints * sizeof(double));
|
||||
memset(a->p, 0, ints * sizeof(int));
|
||||
memset(a->np, 0, ints * sizeof(int));
|
||||
memset(a->taa, 0, ints * sizeof(double));
|
||||
memset(a->tab, 0, ints * sizeof(double));
|
||||
memset(a->tag, 0, ints * sizeof(double));
|
||||
memset(a->tad, 0, ints * sizeof(double));
|
||||
memset(a->tbb, 0, ints * sizeof(double));
|
||||
memset(a->tbg, 0, ints * sizeof(double));
|
||||
memset(a->tbd, 0, ints * sizeof(double));
|
||||
memset(a->tgg, 0, ints * sizeof(double));
|
||||
memset(a->tgd, 0, ints * sizeof(double));
|
||||
memset(a->tdd, 0, ints * sizeof(double));
|
||||
int nsize = 3 * ints + 1;
|
||||
int intp1 = ints + 1;
|
||||
int intm1 = ints - 1;
|
||||
memset(a->A, 0, intp1 * intp1 * sizeof(double));
|
||||
memset(a->B, 0, intp1 * intp1 * sizeof(double));
|
||||
memset(a->C, 0, intm1 * intp1 * sizeof(double));
|
||||
memset(a->D, 0, intp1 * sizeof(double));
|
||||
memset(a->E, 0, intp1 * intp1 * sizeof(double));
|
||||
memset(a->F, 0, intm1 * intp1 * sizeof(double));
|
||||
memset(a->G, 0, intp1 * sizeof(double));
|
||||
memset(a->MAT, 0, nsize * nsize * sizeof(double));
|
||||
memset(a->RHS, 0, nsize * sizeof(double));
|
||||
memset(a->SLN, 0, nsize * sizeof(double));
|
||||
memset(a->z, 0, intp1 * sizeof(double));
|
||||
memset(a->zp, 0, intp1 * sizeof(double));
|
||||
memset(a->wrk, 0, nsize * sizeof(double));
|
||||
memset(a->ipiv, 0, nsize * sizeof(int));
|
||||
}
|
||||
|
||||
int BLDR::fcompare(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 BLDR::decomp(int n, double* a, int* piv, int* info, double* wrk)
|
||||
{
|
||||
int i, j, k;
|
||||
int t_piv;
|
||||
double m_row, mt_row, m_col, mt_col;
|
||||
*info = 0;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
piv[i] = i;
|
||||
m_row = 0.0;
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
mt_row = a[n * i + j];
|
||||
if (mt_row < 0.0) mt_row = -mt_row;
|
||||
if (mt_row > m_row) m_row = mt_row;
|
||||
}
|
||||
if (m_row == 0.0)
|
||||
{
|
||||
*info = i;
|
||||
goto cleanup;
|
||||
}
|
||||
wrk[i] = m_row;
|
||||
}
|
||||
for (k = 0; k < n - 1; k++)
|
||||
{
|
||||
j = k;
|
||||
m_col = a[n * piv[k] + k] / wrk[piv[k]];
|
||||
if (m_col < 0) m_col = -m_col;
|
||||
for (i = k + 1; i < n; i++)
|
||||
{
|
||||
mt_col = a[n * piv[i] + k] / wrk[piv[k]];
|
||||
if (mt_col < 0.0) mt_col = -mt_col;
|
||||
if (mt_col > m_col)
|
||||
{
|
||||
m_col = mt_col;
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
if (m_col == 0)
|
||||
{
|
||||
*info = -k;
|
||||
goto cleanup;
|
||||
}
|
||||
t_piv = piv[k];
|
||||
piv[k] = piv[j];
|
||||
piv[j] = t_piv;
|
||||
for (i = k + 1; i < n; i++)
|
||||
{
|
||||
a[n * piv[i] + k] /= a[n * piv[k] + k];
|
||||
for (j = k + 1; j < n; j++)
|
||||
a[n * piv[i] + j] -= a[n * piv[i] + k] * a[n * piv[k] + j];
|
||||
}
|
||||
}
|
||||
if (a[n * n - 1] == 0.0)
|
||||
*info = -n;
|
||||
cleanup:
|
||||
return;
|
||||
}
|
||||
|
||||
void BLDR::dsolve(int n, double* a, int* piv, double* b, double* x)
|
||||
{
|
||||
int j, k;
|
||||
double sum;
|
||||
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
sum = 0.0;
|
||||
for (j = 0; j < k; j++)
|
||||
sum += a[n * piv[k] + j] * x[j];
|
||||
x[k] = b[piv[k]] - sum;
|
||||
}
|
||||
|
||||
for (k = n - 1; k >= 0; k--)
|
||||
{
|
||||
sum = 0.0;
|
||||
for (j = k + 1; j < n; j++)
|
||||
sum += a[n * piv[k] + j] * x[j];
|
||||
x[k] = (x[k] - sum) / a[n * piv[k] + k];
|
||||
}
|
||||
}
|
||||
|
||||
void BLDR::cull(int* n, int ints, double* x, double* t, double ptol)
|
||||
{
|
||||
int k = 0;
|
||||
int i = *n;
|
||||
int ntopint;
|
||||
int npx;
|
||||
|
||||
while (x[i - 1] > t[ints - 1])
|
||||
i--;
|
||||
ntopint = *n - i;
|
||||
npx = (int)(ntopint * (1.0 - ptol));
|
||||
i = *n;
|
||||
while ((k < npx) && (x[--i] > t[ints]))
|
||||
k++;
|
||||
*n -= k;
|
||||
}
|
||||
|
||||
void BLDR::xbuilder(BLDR *a, int points, double* x, double* y, int ints, double* t, int* info, double* c, double ptol)
|
||||
{
|
||||
double u, v, alpha, beta, gamma, delta;
|
||||
int nsize = 3 * ints + 1;
|
||||
int intp1 = ints + 1;
|
||||
int intm1 = ints - 1;
|
||||
int i, j, k, m;
|
||||
int dinfo;
|
||||
flush_builder(a, points, ints);
|
||||
for (i = 0; i < points; i++)
|
||||
{
|
||||
a->catxy[2 * i + 0] = x[i];
|
||||
a->catxy[2 * i + 1] = y[i];
|
||||
}
|
||||
qsort(a->catxy, points, 2 * sizeof(double), fcompare);
|
||||
for (i = 0; i < points; i++)
|
||||
{
|
||||
a->sx[i] = a->catxy[2 * i + 0];
|
||||
a->sy[i] = a->catxy[2 * i + 1];
|
||||
}
|
||||
cull(&points, ints, a->sx, t, ptol);
|
||||
if (points <= 0 || a->sx[points - 1] > t[ints])
|
||||
{
|
||||
*info = -1000;
|
||||
goto cleanup;
|
||||
}
|
||||
else *info = 0;
|
||||
|
||||
for (j = 0; j < ints; j++)
|
||||
a->h[j] = t[j + 1] - t[j];
|
||||
a->p[0] = 0;
|
||||
j = 0;
|
||||
for (i = 0; i < points; i++)
|
||||
{
|
||||
if (a->sx[i] <= t[j + 1])
|
||||
a->np[j]++;
|
||||
else
|
||||
{
|
||||
a->p[++j] = i;
|
||||
while (a->sx[i] > t[j + 1])
|
||||
a->p[++j] = i;
|
||||
a->np[j] = 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ints; i++)
|
||||
for (j = a->p[i]; j < a->p[i] + a->np[i]; j++)
|
||||
{
|
||||
u = (a->sx[j] - t[i]) / a->h[i];
|
||||
v = u - 1.0;
|
||||
alpha = (2.0 * u + 1.0) * v * v;
|
||||
beta = u * u * (1.0 - 2.0 * v);
|
||||
gamma = a->h[i] * u * v * v;
|
||||
delta = a->h[i] * u * u * v;
|
||||
a->taa[i] += alpha * alpha;
|
||||
a->tab[i] += alpha * beta;
|
||||
a->tag[i] += alpha * gamma;
|
||||
a->tad[i] += alpha * delta;
|
||||
a->tbb[i] += beta * beta;
|
||||
a->tbg[i] += beta * gamma;
|
||||
a->tbd[i] += beta * delta;
|
||||
a->tgg[i] += gamma * gamma;
|
||||
a->tgd[i] += gamma * delta;
|
||||
a->tdd[i] += delta * delta;
|
||||
a->D[i + 0] += 2.0 * a->sy[j] * alpha;
|
||||
a->D[i + 1] += 2.0 * a->sy[j] * beta;
|
||||
a->G[i + 0] += 2.0 * a->sy[j] * gamma;
|
||||
a->G[i + 1] += 2.0 * a->sy[j] * delta;
|
||||
}
|
||||
for (i = 0; i < ints; i++)
|
||||
{
|
||||
a->A[(i + 0) * intp1 + (i + 0)] += 2.0 * a->taa[i];
|
||||
a->A[(i + 1) * intp1 + (i + 1)] = 2.0 * a->tbb[i];
|
||||
a->A[(i + 0) * intp1 + (i + 1)] = 2.0 * a->tab[i];
|
||||
a->A[(i + 1) * intp1 + (i + 0)] = 2.0 * a->tab[i];
|
||||
a->B[(i + 0) * intp1 + (i + 0)] += 2.0 * a->tag[i];
|
||||
a->B[(i + 1) * intp1 + (i + 1)] = 2.0 * a->tbd[i];
|
||||
a->B[(i + 0) * intp1 + (i + 1)] = 2.0 * a->tbg[i];
|
||||
a->B[(i + 1) * intp1 + (i + 0)] = 2.0 * a->tad[i];
|
||||
a->E[(i + 0) * intp1 + (i + 0)] += 2.0 * a->tgg[i];
|
||||
a->E[(i + 1) * intp1 + (i + 1)] = 2.0 * a->tdd[i];
|
||||
a->E[(i + 0) * intp1 + (i + 1)] = 2.0 * a->tgd[i];
|
||||
a->E[(i + 1) * intp1 + (i + 0)] = 2.0 * a->tgd[i];
|
||||
}
|
||||
for (i = 0; i < intm1; i++)
|
||||
{
|
||||
a->C[i * intp1 + (i + 0)] = +3.0 * a->h[i + 1] / a->h[i];
|
||||
a->C[i * intp1 + (i + 2)] = -3.0 * a->h[i] / a->h[i + 1];
|
||||
a->C[i * intp1 + (i + 1)] = -a->C[i * intp1 + (i + 0)] - a->C[i * intp1 + (i + 2)];
|
||||
a->F[i * intp1 + (i + 0)] = a->h[i + 1];
|
||||
a->F[i * intp1 + (i + 1)] = 2.0 * (a->h[i] + a->h[i + 1]);
|
||||
a->F[i * intp1 + (i + 2)] = a->h[i];
|
||||
}
|
||||
for (i = 0, k = 0; i < intp1; i++, k++)
|
||||
{
|
||||
for (j = 0, m = 0; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->A[i * intp1 + j];
|
||||
for (j = 0, m = intp1; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->B[j * intp1 + i];
|
||||
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->C[j * intp1 + i];
|
||||
a->RHS[k] = a->D[i];
|
||||
}
|
||||
for (i = 0, k = intp1; i < intp1; i++, k++)
|
||||
{
|
||||
for (j = 0, m = 0; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->B[i * intp1 + j];
|
||||
for (j = 0, m = intp1; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->E[i * intp1 + j];
|
||||
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->F[j * intp1 + i];
|
||||
a->RHS[k] = a->G[i];
|
||||
}
|
||||
for (i = 0, k = 2 * intp1; i < intm1; i++, k++)
|
||||
{
|
||||
for (j = 0, m = 0; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->C[i * intp1 + j];
|
||||
for (j = 0, m = intp1; j < intp1; j++, m++)
|
||||
a->MAT[k * nsize + m] = a->F[i * intp1 + j];
|
||||
for (j = 0, m = 2 * intp1; j < intm1; j++, m++)
|
||||
a->MAT[k * nsize + m] = 0.0;
|
||||
a->RHS[k] = 0.0;
|
||||
}
|
||||
decomp(nsize, a->MAT, a->ipiv, &dinfo, a->wrk);
|
||||
dsolve(nsize, a->MAT, a->ipiv, a->RHS, a->SLN);
|
||||
if (dinfo != 0)
|
||||
{
|
||||
*info = dinfo;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i <= ints; i++)
|
||||
{
|
||||
a->z[i] = a->SLN[i];
|
||||
a->zp[i] = a->SLN[i + ints + 1];
|
||||
}
|
||||
for (i = 0; i < ints; i++)
|
||||
{
|
||||
c[4 * i + 0] = a->z[i];
|
||||
c[4 * i + 1] = a->zp[i];
|
||||
c[4 * i + 2] = -3.0 / (a->h[i] * a->h[i]) * (a->z[i] - a->z[i + 1]) - 1.0 / a->h[i] * (2.0 * a->zp[i] + a->zp[i + 1]);
|
||||
c[4 * i + 3] = 2.0 / (a->h[i] * a->h[i] * a->h[i]) * (a->z[i] - a->z[i + 1]) + 1.0 / (a->h[i] * a->h[i]) * (a->zp[i] + a->zp[i + 1]);
|
||||
}
|
||||
cleanup:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
83
wdsp/bldr.hpp
Normal file
83
wdsp/bldr.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
/* lmath.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2015, 2023 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_bldr_h
|
||||
#define wdsp_bldr_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class WDSP_API BLDR
|
||||
{
|
||||
public:
|
||||
double* catxy;
|
||||
double* sx;
|
||||
double* sy;
|
||||
double* h;
|
||||
int* p;
|
||||
int* np;
|
||||
double* taa;
|
||||
double* tab;
|
||||
double* tag;
|
||||
double* tad;
|
||||
double* tbb;
|
||||
double* tbg;
|
||||
double* tbd;
|
||||
double* tgg;
|
||||
double* tgd;
|
||||
double* tdd;
|
||||
double* A;
|
||||
double* B;
|
||||
double* C;
|
||||
double* D;
|
||||
double* E;
|
||||
double* F;
|
||||
double* G;
|
||||
double* MAT;
|
||||
double* RHS;
|
||||
double* SLN;
|
||||
double* z;
|
||||
double* zp;
|
||||
double* wrk;
|
||||
int* ipiv;
|
||||
|
||||
static BLDR* create_builder(int points, int ints);
|
||||
static void destroy_builder(BLDR *a);
|
||||
static void flush_builder(BLDR *a, int points, int ints);
|
||||
static void xbuilder(BLDR *a, int points, double* x, double* y, int ints, double* t, int* info, double* c, double ptol);
|
||||
|
||||
private:
|
||||
static int fcompare(const void* a, const void* b);
|
||||
static void decomp(int n, double* a, int* piv, int* info, double* wrk);
|
||||
static void dsolve(int n, double* a, int* piv, double* b, double* x);
|
||||
static void cull(int* n, int ints, double* x, double* t, double ptol);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
281
wdsp/bps.cpp
Normal file
281
wdsp/bps.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/* bandpass.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 <QRecursiveMutex>
|
||||
|
||||
#include "comm.hpp"
|
||||
#include "bps.hpp"
|
||||
#include "fir.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "RXA.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Overlap-Save Bandpass *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void BPS::calc_bps (BPS *a)
|
||||
{
|
||||
double* impulse;
|
||||
a->infilt = new double[2 * a->size * 2]; // (double *)malloc0(2 * a->size * sizeof(dcomplex));
|
||||
a->product = new double[2 * a->size * 2]; // (double *)malloc0(2 * a->size * sizeof(dcomplex));
|
||||
impulse = FIR::fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::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);
|
||||
delete[](impulse);
|
||||
}
|
||||
|
||||
void BPS::decalc_bps (BPS *a)
|
||||
{
|
||||
fftw_destroy_plan(a->CRev);
|
||||
fftw_destroy_plan(a->CFor);
|
||||
delete[] (a->mults);
|
||||
delete[] (a->product);
|
||||
delete[] (a->infilt);
|
||||
}
|
||||
|
||||
BPS* 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 = new 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 BPS::destroy_bps (BPS *a)
|
||||
{
|
||||
decalc_bps (a);
|
||||
delete a;
|
||||
}
|
||||
|
||||
void BPS::flush_bps (BPS *a)
|
||||
{
|
||||
memset (a->infilt, 0, 2 * a->size * sizeof (dcomplex));
|
||||
}
|
||||
|
||||
void BPS::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 (dcomplex));
|
||||
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(dcomplex));
|
||||
}
|
||||
else if (a->in != a->out)
|
||||
memcpy (a->out, a->in, a->size * sizeof (dcomplex));
|
||||
}
|
||||
|
||||
void BPS::setBuffers_bps (BPS *a, double* in, double* out)
|
||||
{
|
||||
decalc_bps (a);
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
calc_bps (a);
|
||||
}
|
||||
|
||||
void BPS::setSamplerate_bps (BPS *a, int rate)
|
||||
{
|
||||
decalc_bps (a);
|
||||
a->samplerate = rate;
|
||||
calc_bps (a);
|
||||
}
|
||||
|
||||
void BPS::setSize_bps (BPS *a, int size)
|
||||
{
|
||||
decalc_bps (a);
|
||||
a->size = size;
|
||||
calc_bps (a);
|
||||
}
|
||||
|
||||
void BPS::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 *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void BPS::SetBPSRun (RXA& rxa, int run)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.bp1.p->run = run;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BPS::SetBPSFreqs (RXA& rxa, double f_low, double f_high)
|
||||
{
|
||||
double* impulse;
|
||||
BPS *a1;
|
||||
rxa.csDSP.lock();
|
||||
a1 = rxa.bps1.p;
|
||||
if ((f_low != a1->f_low) || (f_high != a1->f_high))
|
||||
{
|
||||
a1->f_low = f_low;
|
||||
a1->f_high = f_high;
|
||||
delete[] (a1->mults);
|
||||
impulse = FIR::fir_bandpass(a1->size + 1, f_low, f_high, a1->samplerate, a1->wintype, 1, 1.0 / (double)(2 * a1->size));
|
||||
a1->mults = FIR::fftcv_mults (2 * a1->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BPS::SetBPSWindow (RXA& rxa, int wintype)
|
||||
{
|
||||
double* impulse;
|
||||
BPS *a1;
|
||||
rxa.csDSP.lock();
|
||||
a1 = rxa.bps1.p;
|
||||
if ((a1->wintype != wintype))
|
||||
{
|
||||
a1->wintype = wintype;
|
||||
delete[] (a1->mults);
|
||||
impulse = FIR::fir_bandpass(a1->size + 1, a1->f_low, a1->f_high, a1->samplerate, a1->wintype, 1, 1.0 / (double)(2 * a1->size));
|
||||
a1->mults = FIR::fftcv_mults (2 * a1->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
// UNCOMMENT properties when pointers in place in txa
|
||||
void BPS::SetBPSRun (TXA& txa, int run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.bp1.p->run = run;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BPS::SetBPSFreqs (TXA& txa, double f_low, double f_high)
|
||||
{
|
||||
double* impulse;
|
||||
BPS *a;
|
||||
txa.csDSP.lock();
|
||||
a = txa.bps0.p;
|
||||
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||
{
|
||||
a->f_low = f_low;
|
||||
a->f_high = f_high;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bps1.p;
|
||||
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||
{
|
||||
a->f_low = f_low;
|
||||
a->f_high = f_high;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bps2.p;
|
||||
if ((f_low != a->f_low) || (f_high != a->f_high))
|
||||
{
|
||||
a->f_low = f_low;
|
||||
a->f_high = f_high;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass(a->size + 1, f_low, f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void BPS::SetBPSWindow (TXA& txa, int wintype)
|
||||
{
|
||||
double* impulse;
|
||||
BPS *a;
|
||||
txa.csDSP.lock();
|
||||
a = txa.bps0.p;
|
||||
if (a->wintype != wintype)
|
||||
{
|
||||
a->wintype = wintype;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bps1.p;
|
||||
if (a->wintype != wintype)
|
||||
{
|
||||
a->wintype = wintype;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass(a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
a = txa.bps2.p;
|
||||
if (a->wintype != wintype)
|
||||
{
|
||||
a->wintype = wintype;
|
||||
delete[] (a->mults);
|
||||
impulse = FIR::fir_bandpass (a->size + 1, a->f_low, a->f_high, a->samplerate, a->wintype, 1, 1.0 / (double)(2 * a->size));
|
||||
a->mults = FIR::fftcv_mults (2 * a->size, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
91
wdsp/bps.hpp
Normal file
91
wdsp/bps.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/* bandpass.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_bps_h
|
||||
#define wdsp_bps_h
|
||||
|
||||
#include "fftw3.h"
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
class TXA;
|
||||
|
||||
class WDSP_API BPS
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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);
|
||||
static void destroy_bps (BPS *a);
|
||||
static void flush_bps (BPS *a);
|
||||
static void xbps (BPS *a, int pos);
|
||||
static void setBuffers_bps (BPS *a, double* in, double* out);
|
||||
static void setSamplerate_bps (BPS *a, int rate);
|
||||
static void setSize_bps (BPS *a, int size);
|
||||
static void setFreqs_bps (BPS *a, double f_low, double f_high);
|
||||
// RXA Prototypes
|
||||
static void SetBPSRun (RXA& rxa, int run);
|
||||
static void SetBPSFreqs (RXA& rxa, double low, double high);
|
||||
static void SetBPSWindow (RXA& rxa, int wintype);
|
||||
// TXA Prototypes
|
||||
static void SetBPSRun (TXA& txa, int run);
|
||||
static void SetBPSFreqs (TXA& txa, double low, double high);
|
||||
static void SetBPSWindow (TXA& txa, int wintype);
|
||||
|
||||
private:
|
||||
static void calc_bps (BPS *a);
|
||||
static void decalc_bps (BPS *a);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
||||
|
||||
|
29078
wdsp/calculus.cpp
Normal file
29078
wdsp/calculus.cpp
Normal file
File diff suppressed because it is too large
Load Diff
45
wdsp/calculus.hpp
Normal file
45
wdsp/calculus.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
/* calculus.hpp
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_calculus_h
|
||||
#define wdsp_calculus_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class WDSP_API Calculus
|
||||
{
|
||||
public:
|
||||
static const double GG[];
|
||||
static const double GGS[];
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
132
wdsp/cblock.cpp
Normal file
132
wdsp/cblock.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/* cblock.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2016 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "cblock.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void CBL::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* CBL::create_cbl
|
||||
(
|
||||
int run,
|
||||
int buff_size,
|
||||
double *in_buff,
|
||||
double *out_buff,
|
||||
int mode,
|
||||
int sample_rate,
|
||||
double tau
|
||||
)
|
||||
{
|
||||
CBL *a = new 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 CBL::destroy_cbl(CBL *a)
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
|
||||
void CBL::flush_cbl (CBL *a)
|
||||
{
|
||||
a->prevIin = 0.0;
|
||||
a->prevQin = 0.0;
|
||||
a->prevIout = 0.0;
|
||||
a->prevQout = 0.0;
|
||||
}
|
||||
|
||||
void CBL::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 (dcomplex));
|
||||
}
|
||||
|
||||
void CBL::setBuffers_cbl (CBL *a, double* in, double* out)
|
||||
{
|
||||
a->in_buff = in;
|
||||
a->out_buff = out;
|
||||
}
|
||||
|
||||
void CBL::setSamplerate_cbl (CBL *a, int rate)
|
||||
{
|
||||
a->sample_rate = rate;
|
||||
calc_cbl (a);
|
||||
}
|
||||
|
||||
void CBL::setSize_cbl (CBL *a, int size)
|
||||
{
|
||||
a->buff_size = size;
|
||||
flush_cbl (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* RXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void CBL::SetCBLRun(RXA& rxa, int setit)
|
||||
{
|
||||
rxa.csDSP.lock();
|
||||
rxa.cbl.p->run = setit;
|
||||
rxa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
78
wdsp/cblock.hpp
Normal file
78
wdsp/cblock.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
/* cblock.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_cblock_h
|
||||
#define wdsp_cblock_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class RXA;
|
||||
|
||||
class WDSP_API CBL
|
||||
{
|
||||
public:
|
||||
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
|
||||
|
||||
static CBL* create_cbl
|
||||
(
|
||||
int run,
|
||||
int buff_size,
|
||||
double *in_buff,
|
||||
double *out_buff,
|
||||
int mode,
|
||||
int sample_rate,
|
||||
double tau
|
||||
);
|
||||
static void destroy_cbl (CBL *a);
|
||||
static void flush_cbl (CBL *a);
|
||||
static void xcbl (CBL *a);
|
||||
static void setBuffers_cbl (CBL *a, double* in, double* out);
|
||||
static void setSamplerate_cbl (CBL *a, int rate);
|
||||
static void setSize_cbl (CBL *a, int size);
|
||||
// RXA Properties
|
||||
static void SetCBLRun(RXA& rxa, int setit);
|
||||
|
||||
private:
|
||||
static void calc_cbl (CBL *a);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
521
wdsp/cfcomp.cpp
Normal file
521
wdsp/cfcomp.cpp
Normal file
@ -0,0 +1,521 @@
|
||||
/* cfcomp.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2017, 2021 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "cfcomp.hpp"
|
||||
#include "meterlog10.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void CFCOMP::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 CFCOMP::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 CFCOMP::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] = std::max (a->F[i], 0.0);
|
||||
a->F[i] = std::min (a->F[i], fmax);
|
||||
a->G[i] = std::max (a->G[i], 0.0);
|
||||
}
|
||||
sary = new double[3 * a->nfreqs]; // (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];
|
||||
}
|
||||
delete[] (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);
|
||||
delete[] sary;
|
||||
}
|
||||
|
||||
void CFCOMP::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 = new double[a->fsize]; // (double *)malloc0 (a->fsize * sizeof(double));
|
||||
a->inaccum = new double[a->iasize]; // (double *)malloc0 (a->iasize * sizeof(double));
|
||||
a->forfftin = new double[a->fsize]; // (double *)malloc0 (a->fsize * sizeof(double));
|
||||
a->forfftout = new double[a->msize * 2]; // (double *)malloc0 (a->msize * sizeof(complex));
|
||||
a->cmask = new double[a->msize]; // (double *)malloc0 (a->msize * sizeof(double));
|
||||
a->mask = new double[a->msize]; // (double *)malloc0 (a->msize * sizeof(double));
|
||||
a->cfc_gain = new double[a->msize]; // (double *)malloc0 (a->msize * sizeof(double));
|
||||
a->revfftin = new double[a->msize * 2]; // (double *)malloc0 (a->msize * sizeof(complex));
|
||||
a->revfftout = new double[a->fsize]; // (double *)malloc0 (a->fsize * sizeof(double));
|
||||
a->save = new double*[a->ovrlp]; // (double **)malloc0(a->ovrlp * sizeof(double *));
|
||||
for (i = 0; i < a->ovrlp; i++)
|
||||
a->save[i] = new double[a->fsize]; // (double *)malloc0(a->fsize * sizeof(double));
|
||||
a->outaccum = new double[a->oasize]; // (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 = new double[a->nfreqs + 2]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
a->gp = new double[a->nfreqs + 2]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
a->ep = new double[a->nfreqs + 2]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
a->comp = new double[a->msize]; // (double *) malloc0 (a->msize * sizeof (double));
|
||||
a->peq = new double[a->msize]; // (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 = new double[a->msize]; // (double*)malloc0 (a->msize * sizeof(double));
|
||||
a->delta_copy = new double[a->msize]; // (double*)malloc0 (a->msize * sizeof(double));
|
||||
a->cfc_gain_copy = new double[a->msize]; // (double*)malloc0 (a->msize * sizeof(double));
|
||||
}
|
||||
|
||||
void CFCOMP::decalc_cfcomp(CFCOMP *a)
|
||||
{
|
||||
int i;
|
||||
delete[] (a->cfc_gain_copy);
|
||||
delete[] (a->delta_copy);
|
||||
delete[] (a->delta);
|
||||
delete[] (a->peq);
|
||||
delete[] (a->comp);
|
||||
delete[] (a->ep);
|
||||
delete[] (a->gp);
|
||||
delete[] (a->fp);
|
||||
|
||||
fftw_destroy_plan(a->Rrev);
|
||||
fftw_destroy_plan(a->Rfor);
|
||||
delete[](a->outaccum);
|
||||
for (i = 0; i < a->ovrlp; i++)
|
||||
delete[](a->save[i]);
|
||||
delete[](a->save);
|
||||
delete[](a->revfftout);
|
||||
delete[](a->revfftin);
|
||||
delete[](a->cfc_gain);
|
||||
delete[](a->mask);
|
||||
delete[](a->cmask);
|
||||
delete[](a->forfftout);
|
||||
delete[](a->forfftin);
|
||||
delete[](a->inaccum);
|
||||
delete[](a->window);
|
||||
}
|
||||
|
||||
CFCOMP* 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 = new 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 = new double[a->nfreqs]; // (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||
a->G = new double[a->nfreqs]; // (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||
a->E = new double[a->nfreqs]; // (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 CFCOMP::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 CFCOMP::destroy_cfcomp (CFCOMP *a)
|
||||
{
|
||||
decalc_cfcomp (a);
|
||||
delete[] (a->E);
|
||||
delete[] (a->G);
|
||||
delete[] (a->F);
|
||||
delete (a);
|
||||
}
|
||||
|
||||
|
||||
void CFCOMP::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 CFCOMP::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 (dcomplex));
|
||||
}
|
||||
|
||||
void CFCOMP::setBuffers_cfcomp (CFCOMP *a, double* in, double* out)
|
||||
{
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
}
|
||||
|
||||
void CFCOMP::setSamplerate_cfcomp (CFCOMP *a, int rate)
|
||||
{
|
||||
decalc_cfcomp (a);
|
||||
a->rate = rate;
|
||||
calc_cfcomp (a);
|
||||
}
|
||||
|
||||
void CFCOMP::setSize_cfcomp (CFCOMP *a, int size)
|
||||
{
|
||||
decalc_cfcomp (a);
|
||||
a->bsize = size;
|
||||
calc_cfcomp (a);
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void CFCOMP::SetCFCOMPRun (TXA& txa, int run)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
if (a->run != run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
a->run = run;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CFCOMP::SetCFCOMPPosition (TXA& txa, int pos)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
if (a->position != pos)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
a->position = pos;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CFCOMP::SetCFCOMPprofile (TXA& txa, int nfreqs, double* F, double* G, double *E)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
txa.csDSP.lock();
|
||||
a->nfreqs = nfreqs;
|
||||
delete[] (a->E);
|
||||
delete[] (a->F);
|
||||
delete[] (a->G);
|
||||
a->F = new double[a->nfreqs]; // (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||
a->G = new double[a->nfreqs]; // (double *)malloc0 (a->nfreqs * sizeof (double));
|
||||
a->E = new double[a->nfreqs]; // (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));
|
||||
delete[] (a->ep);
|
||||
delete[] (a->gp);
|
||||
delete[] (a->fp);
|
||||
a->fp = new double[a->nfreqs]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
a->gp = new double[a->nfreqs]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
a->ep = new double[a->nfreqs]; // (double *) malloc0 ((a->nfreqs + 2) * sizeof (double));
|
||||
calc_comp(a);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void CFCOMP::SetCFCOMPPrecomp (TXA& txa, double precomp)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
if (a->precomp != precomp)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
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];
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CFCOMP::SetCFCOMPPeqRun (TXA& txa, int run)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
if (a->peq_run != run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
a->peq_run = run;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CFCOMP::SetCFCOMPPrePeq (TXA& txa, double prepeq)
|
||||
{
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
txa.csDSP.lock();
|
||||
a->prepeq = prepeq;
|
||||
a->prepeqlin = pow (10.0, 0.05 * a->prepeq);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void CFCOMP::GetCFCOMPDisplayCompression (TXA& txa, double* comp_values, int* ready)
|
||||
{
|
||||
int i;
|
||||
CFCOMP *a = txa.cfcomp.p;
|
||||
txa.csDSP.lock();
|
||||
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;
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
if (*ready)
|
||||
{
|
||||
for (i = 0; i < a->msize; i++)
|
||||
comp_values[i] = 20.0 * MemLog::mlog10 (a->cfc_gain_copy[i] / (a->cfc_gain_copy[i] - a->delta_copy[i]));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
||||
|
152
wdsp/cfcomp.hpp
Normal file
152
wdsp/cfcomp.hpp
Normal file
@ -0,0 +1,152 @@
|
||||
/* cfcomp.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2017, 2021 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_cfcomp_h
|
||||
#define wdsp_cfcomp_h
|
||||
|
||||
#include "fftw3.h"
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class TXA;
|
||||
|
||||
class WDSP_API CFCOMP
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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
|
||||
);
|
||||
static void destroy_cfcomp (CFCOMP *a);
|
||||
static void flush_cfcomp (CFCOMP *a);
|
||||
static void xcfcomp (CFCOMP *a, int pos);
|
||||
static void setBuffers_cfcomp (CFCOMP *a, double* in, double* out);
|
||||
static void setSamplerate_cfcomp (CFCOMP *a, int rate);
|
||||
static void setSize_cfcomp (CFCOMP *a, int size);
|
||||
// TXA Properties
|
||||
static void SetCFCOMPRun (TXA& txa, int run);
|
||||
static void SetCFCOMPPosition (TXA& txa, int pos);
|
||||
static void SetCFCOMPprofile (TXA& txa, int nfreqs, double* F, double* G, double *E);
|
||||
static void SetCFCOMPPrecomp (TXA& txa, double precomp);
|
||||
static void SetCFCOMPPeqRun (TXA& txa, int run);
|
||||
static void SetCFCOMPPrePeq (TXA& txa, double prepeq);
|
||||
static void GetCFCOMPDisplayCompression (TXA& txa, double* comp_values, int* ready);
|
||||
|
||||
private:
|
||||
static void calc_cfcwindow (CFCOMP *a);
|
||||
static int fCOMPcompare (const void *a, const void *b);
|
||||
static void calc_comp (CFCOMP *a);
|
||||
static void calc_cfcomp(CFCOMP *a);
|
||||
static void decalc_cfcomp(CFCOMP *a);
|
||||
static void calc_mask (CFCOMP *a);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
260
wdsp/cfir.cpp
Normal file
260
wdsp/cfir.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/* cfir.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2014, 2016, 2021 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "cfir.hpp"
|
||||
#include "fir.hpp"
|
||||
#include "firmin.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
void CFIR::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 = FIRCORE::create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse);
|
||||
delete[] (impulse);
|
||||
}
|
||||
|
||||
void CFIR::decalc_cfir (CFIR *a)
|
||||
{
|
||||
FIRCORE::destroy_fircore (a->p);
|
||||
}
|
||||
|
||||
CFIR* 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 = new 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 CFIR::destroy_cfir (CFIR *a)
|
||||
{
|
||||
decalc_cfir (a);
|
||||
delete (a);
|
||||
}
|
||||
|
||||
void CFIR::flush_cfir (CFIR *a)
|
||||
{
|
||||
FIRCORE::flush_fircore (a->p);
|
||||
}
|
||||
|
||||
void CFIR::xcfir (CFIR *a)
|
||||
{
|
||||
if (a->run)
|
||||
FIRCORE::xfircore (a->p);
|
||||
else if (a->in != a->out)
|
||||
memcpy (a->out, a->in, a->size * sizeof (dcomplex));
|
||||
}
|
||||
|
||||
void CFIR::setBuffers_cfir (CFIR *a, double* in, double* out)
|
||||
{
|
||||
decalc_cfir (a);
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
calc_cfir (a);
|
||||
}
|
||||
|
||||
void CFIR::setSamplerate_cfir (CFIR *a, int rate)
|
||||
{
|
||||
decalc_cfir (a);
|
||||
a->runrate = rate;
|
||||
calc_cfir (a);
|
||||
}
|
||||
|
||||
void CFIR::setSize_cfir (CFIR *a, int size)
|
||||
{
|
||||
decalc_cfir (a);
|
||||
a->size = size;
|
||||
calc_cfir (a);
|
||||
}
|
||||
|
||||
void CFIR::setOutRate_cfir (CFIR *a, int rate)
|
||||
{
|
||||
decalc_cfir (a);
|
||||
a->cicrate = rate;
|
||||
calc_cfir (a);
|
||||
}
|
||||
|
||||
double* CFIR::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 = new double[N]; // (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 = new double[x_samps + 1]; // (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::fir_fsamp (N, A, rtype, 1.0, wintype);
|
||||
// print_impulse ("cfirImpulse.txt", N, impulse, 1, 0);
|
||||
delete[] (A);
|
||||
return impulse;
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void CFIR::SetCFIRRun (TXA& txa, int run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.cfir.p->run = run;
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
void CFIR::SetCFIRNC(TXA& txa, int nc)
|
||||
{
|
||||
// NOTE: 'nc' must be >= 'size'
|
||||
CFIR *a;
|
||||
txa.csDSP.lock();
|
||||
a = txa.cfir.p;
|
||||
if (a->nc != nc)
|
||||
{
|
||||
a->nc = nc;
|
||||
decalc_cfir(a);
|
||||
calc_cfir(a);
|
||||
}
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
108
wdsp/cfir.hpp
Normal file
108
wdsp/cfir.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
/* cfir.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2014, 2016 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_cfir_h
|
||||
#define wdsp_cfir_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class FIRCORE;
|
||||
class TXA;
|
||||
|
||||
class WDSP_API CFIR
|
||||
{
|
||||
public:
|
||||
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;
|
||||
|
||||
static 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
|
||||
);
|
||||
static void destroy_cfir (CFIR *a);
|
||||
static void flush_cfir (CFIR *a);
|
||||
static void xcfir (CFIR *a);
|
||||
static void setBuffers_cfir (CFIR *a, double* in, double* out);
|
||||
static void setSamplerate_cfir (CFIR *a, int rate);
|
||||
static void setSize_cfir (CFIR *a, int size);
|
||||
static void setOutRate_cfir (CFIR *a, int rate);
|
||||
static 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
|
||||
);
|
||||
// TXA Properties
|
||||
static void SetCFIRRun(TXA& txa, int run);
|
||||
static void SetCFIRNC(TXA& txa, int nc);
|
||||
|
||||
private:
|
||||
static void calc_cfir (CFIR *a);
|
||||
static void decalc_cfir (CFIR *a);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
95
wdsp/channel.hpp
Normal file
95
wdsp/channel.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
/* channel.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_channel_h
|
||||
#define wdsp_channel_h
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <QRecursiveMutex>
|
||||
#include <QThread>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class WDSP_API Channel
|
||||
{
|
||||
public:
|
||||
int type;
|
||||
bool run; // thread running
|
||||
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
|
||||
QRecursiveMutex csDSP; // used to block dsp while parameters are updated or buffers flushed
|
||||
QRecursiveMutex 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;
|
||||
QThread channelThread;
|
||||
std::atomic<long> upslew;
|
||||
// struct //io buffers
|
||||
// {
|
||||
// IOB pc, pd, pe, pf; // copies for console calls, dsp, exchange, and flush thread
|
||||
// volatile long ch_upslew;
|
||||
// } iob;
|
||||
|
||||
static void create_channel (
|
||||
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
|
||||
);
|
||||
static void destroy_channel (int channel);
|
||||
static void flush_channel (int channel);
|
||||
// static void set_type (int channel, int type);
|
||||
// static void SetInputBuffsize (int channel, int in_size);
|
||||
// static void SetDSPBuffsize (int channel, int dsp_size);
|
||||
// static void SetInputSamplerate (int channel, int samplerate);
|
||||
// static void SetDSPSamplerate (int channel, int samplerate);
|
||||
// static void SetOutputSamplerate (int channel, int samplerate);
|
||||
// static void SetAllRates (int channel, int in_rate, int dsp_rate, int out_rate);
|
||||
// static int SetChannelState (int channel, int state, int dmode);
|
||||
};
|
||||
|
||||
#endif
|
80
wdsp/comm.hpp
Normal file
80
wdsp/comm.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
/* comm.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
// 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 dcomplex[2];
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
119
wdsp/compress.cpp
Normal file
119
wdsp/compress.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* compress.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2011, 2013, 2017 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "compress.hpp"
|
||||
#include "TXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
COMPRESSOR* create_compressor (
|
||||
int run,
|
||||
int buffsize,
|
||||
double* inbuff,
|
||||
double* outbuff,
|
||||
double gain )
|
||||
{
|
||||
COMPRESSOR *a = new COMPRESSOR;
|
||||
a->run = run;
|
||||
a->inbuff = inbuff;
|
||||
a->outbuff = outbuff;
|
||||
a->buffsize = buffsize;
|
||||
a->gain = gain;
|
||||
return a;
|
||||
}
|
||||
|
||||
void COMPRESSOR::destroy_compressor (COMPRESSOR *a)
|
||||
{
|
||||
delete (a);
|
||||
}
|
||||
|
||||
void COMPRESSOR::flush_compressor (COMPRESSOR *)
|
||||
{
|
||||
}
|
||||
|
||||
void COMPRESSOR::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 (dcomplex));
|
||||
}
|
||||
|
||||
void COMPRESSOR::setBuffers_compressor (COMPRESSOR *a, double* in, double* out)
|
||||
{
|
||||
a->inbuff = in;
|
||||
a->outbuff = out;
|
||||
}
|
||||
|
||||
void COMPRESSOR::setSamplerate_compressor (COMPRESSOR *, int)
|
||||
{
|
||||
}
|
||||
|
||||
void COMPRESSOR::setSize_compressor (COMPRESSOR *a, int size)
|
||||
{
|
||||
a->buffsize = size;
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* TXA Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void COMPRESSOR::SetCompressorRun (TXA& txa, int run)
|
||||
{
|
||||
if (txa.compressor.p->run != run)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.compressor.p->run = run;
|
||||
TXA::SetupBPFilters (txa);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void COMPRESSOR::SetCompressorGain (TXA& txa, double gain)
|
||||
{
|
||||
txa.csDSP.lock();
|
||||
txa.compressor.p->gain = pow (10.0, gain / 20.0);
|
||||
txa.csDSP.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
66
wdsp/compress.hpp
Normal file
66
wdsp/compress.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/* compress.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2011, 2013 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_compressor_h
|
||||
#define wdsp_compressor_h
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class TXA;
|
||||
|
||||
class WDSP_API COMPRESSOR
|
||||
{
|
||||
public:
|
||||
int run;
|
||||
int buffsize;
|
||||
double *inbuff;
|
||||
double *outbuff;
|
||||
double gain;
|
||||
|
||||
static COMPRESSOR* create_compressor (
|
||||
int run,
|
||||
int buffsize,
|
||||
double* inbuff,
|
||||
double* outbuff,
|
||||
double gain
|
||||
);
|
||||
static void destroy_compressor (COMPRESSOR *a);
|
||||
static void flush_compressor (COMPRESSOR *a);
|
||||
static void xcompressor (COMPRESSOR *a);
|
||||
static void setBuffers_compressor (COMPRESSOR *a, double* in, double* out);
|
||||
static void setSamplerate_compressor (COMPRESSOR *a, int rate);
|
||||
static void setSize_compressor (COMPRESSOR *a, int size);
|
||||
// TXA Properties
|
||||
static void SetCompressorRun (TXA& txa, int run);
|
||||
static void SetCompressorGain (TXA& txa, double gain);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
141
wdsp/delay.cpp
Normal file
141
wdsp/delay.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* delay.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2019 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "delay.hpp"
|
||||
#include "fir.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
DELAY* create_delay (int run, int size, double* in, double* out, int rate, double tdelta, double tdelay)
|
||||
{
|
||||
DELAY *a = new 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::fir_bandpass (a->ncoef,-a->ft, +a->ft, 1.0, 1, 0, (double)a->L);
|
||||
a->rsize = a->cpp + (WSDEL - 1);
|
||||
a->ring = new double[a->rsize * 2]; // (double *) malloc0 (a->rsize * sizeof (complex));
|
||||
return a;
|
||||
}
|
||||
|
||||
void DELAY::destroy_delay (DELAY *a)
|
||||
{
|
||||
delete[] (a->ring);
|
||||
delete[] (a->h);
|
||||
delete (a);
|
||||
}
|
||||
|
||||
void DELAY::flush_delay (DELAY *a)
|
||||
{
|
||||
memset (a->ring, 0, a->cpp * sizeof (dcomplex));
|
||||
a->idx_in = 0;
|
||||
}
|
||||
|
||||
void DELAY::xdelay (DELAY *a)
|
||||
{
|
||||
a->cs_update.lock();
|
||||
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 (dcomplex));
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Properties *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void DELAY::SetDelayRun (DELAY *a, int run)
|
||||
{
|
||||
a->cs_update.lock();
|
||||
a->run = run;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
double DELAY::SetDelayValue (DELAY *a, double tdelay)
|
||||
{
|
||||
double adelay;
|
||||
a->cs_update.lock();
|
||||
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;
|
||||
a->cs_update.unlock();
|
||||
return adelay;
|
||||
}
|
||||
|
||||
void DELAY::SetDelayBuffs (DELAY *a, int size, double* in, double* out)
|
||||
{
|
||||
a->cs_update.lock();
|
||||
a->size = size;
|
||||
a->in = in;
|
||||
a->out = out;
|
||||
a->cs_update.unlock();
|
||||
}
|
||||
|
||||
} // namespace WDSP
|
||||
|
79
wdsp/delay.hpp
Normal file
79
wdsp/delay.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
/* delay.h
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2013, 2019 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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 wdsp_delay_h
|
||||
#define wdsp_delay_h
|
||||
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
#define WSDEL 1025 // number of supported whole sample delays
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
class WDSP_API DELAY
|
||||
{
|
||||
public:
|
||||
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
|
||||
|
||||
QRecursiveMutex cs_update;
|
||||
|
||||
static DELAY* create_delay (int run, int size, double* in, double* out, int rate, double tdelta, double tdelay);
|
||||
static void destroy_delay (DELAY *a);
|
||||
static void flush_delay (DELAY *a);
|
||||
static void xdelay (DELAY *a);
|
||||
// Properties
|
||||
static void SetDelayRun (DELAY *a, int run);
|
||||
static double SetDelayValue (DELAY *a, double delay); // returns actual delay in seconds
|
||||
static void SetDelayBuffs (DELAY *a, int size, double* in, double* out);
|
||||
};
|
||||
|
||||
} // namespace WDSP
|
||||
|
||||
#endif
|
963
wdsp/emnr.cpp
Normal file
963
wdsp/emnr.cpp
Normal file
@ -0,0 +1,963 @@
|
||||
/* emnr.c
|
||||
|
||||
This file is part of a program that implements a Software-Defined Radio.
|
||||
|
||||
Copyright (C) 2015 Warren Pratt, NR0V
|
||||
Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel
|
||||
|
||||
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.hpp"
|
||||
#include "calculus.hpp"
|
||||
#include "emnr.hpp"
|
||||
#include "amd.hpp"
|
||||
#include "anr.hpp"
|
||||
#include "anf.hpp"
|
||||
#include "snb.hpp"
|
||||
#include "bandpass.hpp"
|
||||
#include "RXA.hpp"
|
||||
|
||||
namespace WDSP {
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Special Functions *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
// MODIFIED BESSEL FUNCTIONS OF THE 0TH AND 1ST ORDERS, Polynomial Approximations
|
||||
// M. Abramowitz and I. Stegun, Eds., "Handbook of Mathematical Functions." Washington, DC: National
|
||||
// Bureau of Standards, 1964.
|
||||
// Shanjie Zhang and Jianming Jin, "Computation of Special Functions." New York, NY, John Wiley and Sons,
|
||||
// Inc., 1996. [Sample code given in FORTRAN]
|
||||
|
||||
double EMNR::bessI0 (double x)
|
||||
{
|
||||
double res, p;
|
||||
if (x == 0.0)
|
||||
res = 1.0;
|
||||
else
|
||||
{
|
||||
if (x < 0.0) x = -x;
|
||||
if (x <= 3.75)
|
||||
{
|
||||
p = x / 3.75;
|
||||
p = p * p;
|
||||
res = ((((( 0.0045813 * p
|
||||
+ 0.0360768) * p
|
||||
+ 0.2659732) * p
|
||||
+ 1.2067492) * p
|
||||
+ 3.0899424) * p
|
||||
+ 3.5156229) * p
|
||||
+ 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 3.75 / x;
|
||||
res = exp (x) / sqrt (x)
|
||||
* (((((((( + 0.00392377 * p
|
||||
- 0.01647633) * p
|
||||
+ 0.02635537) * p
|
||||
- 0.02057706) * p
|
||||
+ 0.00916281) * p
|
||||
- 0.00157565) * p
|
||||
+ 0.00225319) * p
|
||||
+ 0.01328592) * p
|
||||
+ 0.39894228);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
double EMNR::bessI1 (double x)
|
||||
{
|
||||
|
||||
double res, p;
|
||||
if (x == 0.0)
|
||||
res = 0.0;
|
||||
else
|
||||
{
|
||||
if (x < 0.0) x = -x;
|
||||
if (x <= 3.75)
|
||||
{
|
||||
p = x / 3.75;
|
||||
p = p * p;
|
||||
res = x
|
||||
* (((((( 0.00032411 * p
|
||||
+ 0.00301532) * p
|
||||
+ 0.02658733) * p
|
||||
+ 0.15084934) * p
|
||||
+ 0.51498869) * p
|
||||
+ 0.87890594) * p
|
||||
+ 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 3.75 / x;
|
||||
res = exp (x) / sqrt (x)
|
||||
* (((((((( - 0.00420059 * p
|
||||
+ 0.01787654) * p
|
||||
- 0.02895312) * p
|
||||
+ 0.02282967) * p
|
||||
- 0.01031555) * p
|
||||
+ 0.00163801) * p
|
||||
- 0.00362018) * p
|
||||
- 0.03988024) * p
|
||||
+ 0.39894228);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// EXPONENTIAL INTEGRAL, E1(x)
|
||||
// M. Abramowitz and I. Stegun, Eds., "Handbook of Mathematical Functions." Washington, DC: National
|
||||
// Bureau of Standards, 1964.
|
||||
// Shanjie Zhang and Jianming Jin, "Computation of Special Functions." New York, NY, John Wiley and Sons,
|
||||
// Inc., 1996. [Sample code given in FORTRAN]
|
||||
|
||||
double EMNR::e1xb (double x)
|
||||
{
|
||||
double e1, ga, r, t, t0;
|
||||
int k, m;
|
||||
if (x == 0.0)
|
||||
e1 = 1.0e300;
|
||||
else if (x <= 1.0)
|
||||
{
|
||||
e1 = 1.0;
|
||||
r = 1.0;
|
||||
|
||||
for (k = 1; k <= 25; k++)
|
||||
{
|
||||
r = -r * k * x / ((k + 1.0)*(k + 1.0));
|
||||
e1 = e1 + r;
|
||||
if ( fabs (r) <= fabs (e1) * 1.0e-15 )
|
||||
break;
|
||||
}
|
||||
|
||||
ga = 0.5772156649015328;
|
||||
e1 = - ga - log (x) + x * e1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = 20 + (int)(80.0 / x);
|
||||
t0 = 0.0;
|
||||
for (k = m; k >= 1; k--)
|
||||
t0 = (double)k / (1.0 + k / (x + t0));
|
||||
t = 1.0 / (x + t0);
|
||||
e1 = exp (- x) * t;
|
||||
}
|
||||
return e1;
|
||||
}
|
||||
|
||||
/********************************************************************************************************
|
||||
* *
|
||||
* Main Body of Code *
|
||||
* *
|
||||
********************************************************************************************************/
|
||||
|
||||
void EMNR::calc_window (EMNR *a)
|
||||
{
|
||||
int i;
|
||||
double arg, sum, inv_coherent_gain;
|
||||
switch (a->wintype)
|
||||
{
|
||||
case 0:
|
||||
arg = 2.0 * PI / (double)a->fsize;
|
||||
sum = 0.0;
|
||||
for (i = 0; i < a->fsize; i++)
|
||||
{
|
||||
a->window[i] = sqrt (0.54 - 0.46 * cos((double)i * arg));
|
||||
sum += a->window[i];
|
||||
}
|
||||
inv_coherent_gain = (double)a->fsize / sum;
|
||||
for (i = 0; i < a->fsize; i++)
|
||||
a->window[i] *= inv_coherent_gain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EMNR::interpM (double* res, double x, int nvals, double* xvals, double* yvals)
|
||||
{
|
||||
if (x <= xvals[0])
|
||||
*res = yvals[0];
|
||||
else if (x >= xvals[nvals - 1])
|
||||
*res = yvals[nvals - 1];
|
||||
else
|
||||
{
|
||||
int idx = 0;
|
||||
double xllow, xlhigh, frac;
|
||||
while (x >= xvals[idx]) idx++;
|
||||
xllow = log10 (xvals[idx - 1]);
|
||||
xlhigh = log10(xvals[idx]);
|
||||
frac = (log10 (x) - xllow) / (xlhigh - xllow);
|
||||
*res = yvals[idx - 1] + frac * (yvals[idx] - yvals[idx - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void EMNR::calc_emnr(EMNR *a)
|
||||
{
|
||||
int i;
|
||||
double Dvals[18] = { 1.0, 2.0, 5.0, 8.0, 10.0, 15.0, 20.0, 30.0, 40.0,
|
||||
60.0, 80.0, 120.0, 140.0, 160.0, 180.0, 220.0, 260.0, 300.0 };
|
||||
double Mvals[18] = { 0.000, 0.260, 0.480, 0.580, 0.610, 0.668, 0.705, 0.762, 0.800,
|
||||
0.841, 0.865, 0.890, 0.900, 0.910, 0.920, 0.930, 0.935, 0.940 };
|
||||
// double Hvals[18] = { 0.000, 0.150, 0.480, 0.780, 0.980, 1.550, 2.000, 2.300, 2.520,
|
||||
// 3.100, 3.380, 4.150, 4.350, 4.250, 3.900, 4.100, 4.700, 5.000 };
|
||||
a->incr = a->fsize / a->ovrlp;
|
||||
a->gain = a->ogain / a->fsize / (double)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 = new double[a->fsize]; // (double *)malloc0(a->fsize * sizeof(double));
|
||||
a->inaccum = new double[a->iasize]; // (double *)malloc0(a->iasize * sizeof(double));
|
||||
a->forfftin = new double[a->fsize]; // (double *)malloc0(a->fsize * sizeof(double));
|
||||
a->forfftout = new double[a->msize * 2]; // (double *)malloc0(a->msize * sizeof(complex));
|
||||
a->mask = new double[a->msize]; // (double *)malloc0(a->msize * sizeof(double));
|
||||
a->revfftin = new double[a->msize * 2]; // (double *)malloc0(a->msize * sizeof(complex));
|
||||
a->revfftout = new double[a->fsize]; // (double *)malloc0(a->fsize * sizeof(double));
|
||||
a->save = new double*[a->ovrlp]; // (double **)malloc0(a->ovrlp * sizeof(double *));
|
||||
for (i = 0; i < a->ovrlp; i++)
|
||||
a->save[i] = new double[a->fsize]; // (double *)malloc0(a->fsize * sizeof(double));
|
||||
a->outaccum = new double[a->oasize]; // (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_window(a);
|
||||
|
||||
a->g.msize = a->msize;
|
||||
a->g.mask = a->mask;
|
||||
a->g.y = a->forfftout;
|
||||
a->g.lambda_y = new double[a->msize]; // (double *)malloc0(a->msize * sizeof(double));
|
||||
a->g.lambda_d = new double[a->msize]; // (double *)malloc0(a->msize * sizeof(double));
|
||||
a->g.prev_gamma = new double[a->msize]; // (double *)malloc0(a->msize * sizeof(double));
|
||||
a->g.prev_mask = new double[a->msize]; // (double *)malloc0(a->msize * sizeof(double));
|
||||
|
||||
a->g.gf1p5 = sqrt(PI) / 2.0;
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.98);
|
||||
a->g.alpha = exp(-a->incr / a->rate / tau);
|
||||
}
|
||||
a->g.eps_floor = 1.0e-300;
|
||||
a->g.gamma_max = 1000.0;
|
||||
a->g.q = 0.2;
|
||||
for (i = 0; i < a->g.msize; i++)
|
||||
{
|
||||
a->g.prev_mask[i] = 1.0;
|
||||
a->g.prev_gamma[i] = 1.0;
|
||||
}
|
||||
a->g.gmax = 10000.0;
|
||||
//
|
||||
a->g.GG = new double[241 * 241]; // (double *)malloc0(241 * 241 * sizeof(double));
|
||||
a->g.GGS = new double[241 * 241]; // (double *)malloc0(241 * 241 * sizeof(double));
|
||||
if ((a->g.fileb = fopen("calculus", "rb")))
|
||||
{
|
||||
std::size_t lgg = fread(a->g.GG, sizeof(double), 241 * 241, a->g.fileb);
|
||||
if (lgg != 241 * 241) {
|
||||
fprintf(stderr, "GG file has an invalid size\n");
|
||||
}
|
||||
std::size_t lggs =fread(a->g.GGS, sizeof(double), 241 * 241, a->g.fileb);
|
||||
if (lggs != 241 * 241) {
|
||||
fprintf(stderr, "GGS file has an invalid size\n");
|
||||
}
|
||||
fclose(a->g.fileb);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (a->g.GG, Calculus::GG, 241 * 241 * sizeof(double));
|
||||
memcpy (a->g.GGS, Calculus::GGS, 241 * 241 * sizeof(double));
|
||||
}
|
||||
//
|
||||
|
||||
a->np.incr = a->incr;
|
||||
a->np.rate = a->rate;
|
||||
a->np.msize = a->msize;
|
||||
a->np.lambda_y = a->g.lambda_y;
|
||||
a->np.lambda_d = a->g.lambda_d;
|
||||
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.7);
|
||||
a->np.alphaCsmooth = exp(-a->np.incr / a->np.rate / tau);
|
||||
}
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.96);
|
||||
a->np.alphaMax = exp(-a->np.incr / a->np.rate / tau);
|
||||
}
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.7);
|
||||
a->np.alphaCmin = exp(-a->np.incr / a->np.rate / tau);
|
||||
}
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.3);
|
||||
a->np.alphaMin_max_value = exp(-a->np.incr / a->np.rate / tau);
|
||||
}
|
||||
a->np.snrq = -a->np.incr / (0.064 * a->np.rate);
|
||||
{
|
||||
double tau = -128.0 / 8000.0 / log(0.8);
|
||||
a->np.betamax = exp(-a->np.incr / a->np.rate / tau);
|
||||
}
|
||||
a->np.invQeqMax = 0.5;
|
||||
a->np.av = 2.12;
|
||||
a->np.Dtime = 8.0 * 12.0 * 128.0 / 8000.0;
|
||||
a->np.U = 8;
|
||||
a->np.V = (int)(0.5 + (a->np.Dtime * a->np.rate / (a->np.U * a->np.incr)));
|
||||
if (a->np.V < 4) a->np.V = 4;
|
||||
if ((a->np.U = (int)(0.5 + (a->np.Dtime * a->np.rate / (a->np.V * a->np.incr)))) < 1) a->np.U = 1;
|
||||
a->np.D = a->np.U * a->np.V;
|
||||
interpM(&a->np.MofD, a->np.D, 18, Dvals, Mvals);
|
||||
interpM(&a->np.MofV, a->np.V, 18, Dvals, Mvals);
|
||||
a->np.invQbar_points[0] = 0.03;
|
||||
a->np.invQbar_points[1] = 0.05;
|
||||
a->np.invQbar_points[2] = 0.06;
|
||||
a->np.invQbar_points[3] = 1.0e300;
|
||||
{
|
||||
double db;
|
||||
db = 10.0 * log10(8.0) / (12.0 * 128 / 8000);
|
||||
a->np.nsmax[0] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate);
|
||||
db = 10.0 * log10(4.0) / (12.0 * 128 / 8000);
|
||||
a->np.nsmax[1] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / a->np.rate);
|
||||
db = 10.0 * log10(2.0) / (12.0 * 128 / 8000);
|
||||
a->np.nsmax[2] = pow(10.0, db / 10.0 * a->np.V * a->np.incr / |